I definitely already wrote it, I just thought I'd taken it out again! (I can't remember why, though...)usul wrote: Perhaps you already built it in and forgot about it!?!
Still, good to hear that you've got it working.
Probably, at some point, yeah.usul wrote:I just realized something about the combat system in the Game Engine, fighters and enemies never miss. Will you be integrating a system where you take into account each character's stats (such as agility, attack, defense) to test whether or not each attack hits or misses?
This is also something you can do yourself, though - and there's two places you could do it.
If you want it to apply to every attack of any kind - physical, magical, etc - then this kind of thing is the responsibility of the AttackResolver. If you check in engine-schema.rpy, around line 280 the AttackResolver stuff starts. There's a DefaultAttackResolver, which is the very basic one used for most of the demos, and later there's an ElementalAttackResolver, which has the Fire/Water/Earth RPS elements stuff built in. Check on line 155 of grid_demo.rpy to see a demonstration of how to use CustomSchema to get your own custom AttackResolver into the game.
Basically, the ResolveAttack method on the relevant AttackResolver is called whenever one Fighter attacks another - which gets triggered by a call to Battle.Attack, as seen on line 176 of engine-skills.rpy, for example. The parameters are the attacking fighter, the strength of the attack, the list of attributes applied to that attack, the target fighter, and if applicable the range the attack was carried out at. The AttackResolver is expected to perform whatever game-state changes need to be performed for that attack - so call the fighter.Damage method to inflict however much damage is appropriate (the engine will check for Fighter death automatically) and do any other things (maybe an attack with the 'poison' attribute has a chance of adding the 'poison' Effect to the target fighter, for example). If you inflict a damage greater than 0, it's taken off the target fighter's health; if you inflict a damage less than zero, the target fighter is healed up to a maximum of their base health (fighter.BaseStats.Health).
So to write an AttackResolver which works exactly like the ElementalAttackResolver but checks the fighter's 'Skill' stat to see if they hit, you might write something like this:
Code: Select all
class SkillBasedAttackResolver(ElementalAttackResolver):
def SetUpFighter(self, fighter):
fighter.RegisterStat('Skill', 75)
def ResolveAttack(self, attacker, attack, attributes, target, range=1, **parameters):
#Check skill - which is a percentage chance of hitting
if ((renpy.random.random()*100) <= attacker.Stats.Skill):
# it's a hit, so we perform the attack as normal
super(SkillBasedAttackResolver, self).ResolveAttack(attacker, attack, attributes, target, range=range, **parameters)
else:
# it's a miss, so we announce this to the user
attacker._battle.Announce(attacker.Name + " missed!")
The second way of doing it would be to make similar modifications (or create a similar alternative to) the AttackSkill skill which starts on line 158 of engine-skills.rpy. Here you could actually check for a hit before calling the attack resolver, and limit it entirely to attacks made through the attack skill - maybe you have a different way of checking for a hit for melee attacks, ranged attacks and magic attacks.