Battle System

Monkey Forums/Monkey Programming/Battle System

BradMangham(Posted 2017) [#1]
Hi Everyone,

I am creating a small RPG style game with a turn based combat system. So far it looks like this.

If intersects(player.x,player.y,16,16,goblin.x,goblin.y,16,16) Then
	Print "Battle Initiated"
		While goblin.health > 0 
                        Print("Player's Turn")
			damage = (player.attack * player.attackModifier) - (goblin.defence * goblin.defenceModifier)
			goblin.health = goblin.health - damage
			Print("Player attacked for "+damage+" health")
			Print("Enemy's Turn")
			damage = (goblin.attack * goblin.attackModifier) - (player.defence * player.defenceModifier)
			player.health = player.health - damage
			Print("Enemy attacked for "+damage+" health")
			If goblin.health <= 0 Then
				Print("Enemy Killed!")
				goblin_Collection.Remove goblin
				player.EXP += 150
				Exit
			Elseif player.health <= 0 Then
				Print("Player Killed!")
				GameState = "MENU"
			        Exit
			Else
				Continue
			End
	        Wend
	End


The game is not text based, so the print statements are just for debugging purposes.

Is there a way I can slow down the battle? (possibly to one turn per second/per few seconds). I've tried changing the update rate during the battle to no avail.

Thanks!


Xaron(Posted 2017) [#2]
For every update you could measure the milliseconds passed since last update and use that as a base factor:

Globals (you can use members of course as well!)
Global gLastFrameTime:Int
Global gPassedTimeForTurn:Int
Global gSpeed:Float = 2.0


In OnUpdate():
Local passedTime:Int = Millisecs() - gLastFrameTime
gPassedTimeForTurn += passedTime
gLastFrameTime = Millisecs()


your modified code:
If intersects(player.x,player.y,16,16,goblin.x,goblin.y,16,16) Then
	Print "Battle Initiated"
	Local speedFactor:Float = gSpeed * Float( passedTime ) / 1000.0
		While goblin.health > 0 
                        Print("Player's Turn")
			damage = speedFactor * ((player.attack * player.attackModifier) - (goblin.defence * goblin.defenceModifier))
			goblin.health = goblin.health - damage
			Print("Player attacked for "+damage+" health")
			Print("Enemy's Turn")
			damage = speedFactor * ((goblin.attack * goblin.attackModifier) - (player.defence * player.defenceModifier))
			player.health = player.health - damage
			Print("Enemy attacked for "+damage+" health")
			If goblin.health <= 0 Then
				Print("Enemy Killed!")
				goblin_Collection.Remove goblin
				player.EXP += 150
				Exit
			Elseif player.health <= 0 Then
				Print("Player Killed!")
				GameState = "MENU"
			        Exit
			Else
				Continue
			End
	        Wend
	End


This might be probably more suitable for realtime games. As I see you make a turn based one. In that case you will have kind of a state machine anyway so you won't need that. The most easy thing would be just a bool flag. So when a turn is made, you set this to true. In case you want to make one turn every 5 seconds, you could do this:

If intersects(player.x,player.y,16,16,goblin.x,goblin.y,16,16) Then
If( gPassedTimeForTurn > 5000 )
	gPassedTimeForTurn = 0
	Print "Battle Initiated"
		While goblin.health > 0 
                        Print("Player's Turn")
			damage = (player.attack * player.attackModifier) - (goblin.defence * goblin.defenceModifier)
			goblin.health = goblin.health - damage
			Print("Player attacked for "+damage+" health")
			Print("Enemy's Turn")
			damage = (goblin.attack * goblin.attackModifier) - (player.defence * player.defenceModifier)
			player.health = player.health - damage
			Print("Enemy attacked for "+damage+" health")
			If goblin.health <= 0 Then
				Print("Enemy Killed!")
				goblin_Collection.Remove goblin
				player.EXP += 150
				Exit
			Elseif player.health <= 0 Then
				Print("Player Killed!")
				GameState = "MENU"
			        Exit
			Else
				Continue
			End
	        Wend
	End
End



BradMangham(Posted 2017) [#3]
Hi,

Thanks for the solution!

I figured it would probably have something to do with the 'millisecs()' function, but I couldn't find anything that suited my needs. Anyway, thank you again!


Gerry Quinn(Posted 2017) [#4]
Usually in this kind of game, the player moves, then the monsters move. So you would take the player's input and show it, then wait for a while and show the goblin's move. Then make it clear that it's time for an input from the player.

In many old roguelikes, an input was required before every important event, so there would be a message box with stuff like like:

You hit the goblin. It was a good hit! --MORE--
The goblin hits you for 7 damage.
You drink the potion of health. 12 health restored! --MORE--
The goblin misses you.
Your light is getting dim.

..and you would have to press SPACE to get past each --MORE--, as well as inputting your own actions. Monsters that just move would all do so instantly during the monster turn.

If not doing something like that, you'll need a timer to slow events down. Floating damage numbers that move up and fade like an action RPG are an option, if you're up to programming that. (It requires an animation loop that proceeds regardless of input.)