Attack Styles... how?
I am trying to figure out how to work combat styles into my game, and I'm having a rough time of it.
Basically there are different skill lines, such as 1h, 2h, duel weild, etc.
With each skill line comes different attack styles which have different bonuses, such as attack rate increase, a bleed effect, damage bonus, etc.
The problem I am running into, is how do I maintain these different attack styles?
I was thinking of creating a basic attack sequence and then just plug in different information from an array of attacks.
attack(attacker, defender, style)
make sure the attacker has the style
make sure the attacker is using the correct weapon for the style
check attacker skill vs defender skill
if the attacker misses, return MISSED
else check attacker skill vs defender block skill
if the defender blocks, return BLOCKED
else check attacker skill vs defender parry skill
if the defender blocks, return PARRIED
else return HIT
So now I have a switch that decides on what animation to play, based on the result of the combat check.
case MISSED
play the attackers MISSED animation for the weapon he is using.
case BLOCKED
play the defenders block animation for the shield he is using.
calculate if and how much skill the defender should gain in BLOCK.
case PARRIED
play the defenders parry animation for the weapon he is using.
calculate if and how much skill the defender should gain in PARRY.
case HIT
play the attackers animation for the style he is using
calculate how much damage should be done based on the attackers weapon, base skill, and the defenders armor.
remove damage from the defender
play the defenders got hit animation
calculate if and how much skill the attacker should gain in the weapon type.
So in this system, attacker and defender are objects which contain pointers to their weapons and skills, and attack styles. The attack styles are also objects which contain information such as what animation goes with it, what weapon is required to do the attack, what sort of bonuses you get for the attack, how much stamina to drain, etc.
Is this the best way? Or what do you guys suggest?
I could post actual code, but it is all done in javascript. I wasn't sure if that would be better, or if just explaining it would be.
The engine I am using uses javascript, so here is sort of a sloppy example of what I have so far. Think of these as object classes...
I am still new to role play game development, so please let me know if there is a better way to do this stuff.
The main problem is, where do I store what animation to use? In the attack style? In the weapon? IE: for this weapon, I use this parry animation, for this shield, I use this block animation, etc.
Is this a good overall framework for the game, or am I making some common noobie errors?
Thanks n advance...
//@"Skill.js"//@"Stat.js"//@"MeleeAttack.js"//@"Weapon.js"//@"AttackStyle.js"function UserCharacter(stringId, _3dMesh, Vector3D, Rotation3D){ var my = this; var lastTic = system.timer; var weaponSpeed = [[[100]]]; const SLASH=[[[0]]]; BLOCK=[[[1]]]; PARRY=[[[2]]]; DODGE = [[[3]]]; ONEHAND = [[[4]]]; const RIGHTHAND=[[[0]]];LEFTHAND=[[[1]]];LEFTSHIELD=[[[2]]]; const HEALTH = [[[0]]]; STAMINA=[[[1]]]; POWER=[[[2]]]; /** mesh */ var chrMesh = _3dScene.objectAdd(stringId, _3dMesh, Vector3D, Rotation3D); this.getMesh = function(){return chrMesh;} this.setMesh = function(mt){chrMesh.type = mt;} /** Stats */ this.stamina = new Stat(STAMINA, "Stamina",[[[100]]]); this.health = new Stat(HEALTH, "Health",[[[200]]]); this.power = new Stat(POWER, "Power",[[[100]]]); /** Combat */ var isAttacking = false; this.setIsAttacking = function(torf){isAttacking = torf;} this.getIsAttacking = function(){return isAttacking;} var inCombat = false; this.getInCombat = function(){return inCombat;} this.setInCombat = function(ic){inCombat = ic;} this.toggleInCombat = function(){inCombat =! inCombat;} var lastAttackTime = system.timer; this.getLastAttackTime = function(){return lastAttackTime;} this.setLastAttackTime = function(lat){lastAttackTime = lat;} var target; this.getTarget = function(){return target;} this.setTarget = function(t){target=t;} /** Rest */ var atRest = true; this.getAtRest = function(){return atRest;} this.setAtRest = function(ar){atRest = ar;} this.toggleAtRest = function(){atRest =! atRest;} /** Skills */ // SLASH=[[[0]]]; BLOCK=[[[1]]]; PARRY=[[[2]]]; DODGE = [[[3]]]; ONEHAND = [[[4]]]; this.slash = new Skill([[[0]]], "Slash", [[[0]]].[[[0]]]); this.block = new Skill([[[1]]], "Block", [[[0]]].[[[0]]]); this.parry = new Skill([[[2]]], "Parry", [[[0]]].[[[0]]]); this.dodge = new Skill([[[3]]], "Dodge", [[[0]]].[[[0]]]); this.onehand = new Skill([[[4]]], "One Handed", [[[0]]].[[[0]]]); var skillValue = [this.slash, this.block, this.parry, this.dodge, this.onehand]; //this.increaseSkill = function(skill, amount) //{ //skillValue[skill] += amount; //} //this.decreaseDecrease = function(skill, amount) //{ //skillValue[skill] -= amount; //} this.getSkill = function(skill) { return skillValue[skill]; } /** equipment */ this.attackStyles = []; var equipment = [RIGHTHAND, LEFTHAND, LEFTSHIELD]; var equippedWeapon; this.equipWeapon = function(item) { equipment[item.getSlot()] = item; switch(item.getSlot()) { case RIGHTHAND: equipment[RIGHTHAND].getMesh().attach(chrMesh.id,"rightHandAttach",true, true, true); equippedWeapon = equipment[RIGHTHAND]; weaponSpeed = equippedWeapon.getSpeed(); this.attackStyles[[[[0]]]] = new AttackStyle(equippedWeapon.getSecondarySkill(), "base_attack_"+equippedWeapon.getSecondarySkill(),[[[0]]],[[[0]]],[[[0]]],[[[0]]], null, [[[0]]], [[[1]]].[[[5]]]); break; case LEFTHAND: break; case LEFTSHIELD: equipment[LEFTSHIELD].getMesh().attach(chrMesh.id,"leftShieldAttach",true, true, true); break; } } this.getEquippedWeapon = function(){return equippedWeapon;} this.hasStyle = function(s) { for(var i1 = [[[0]]];i1 < this.attackStyles.length;i1++) { if(s == this.attackStyles[i1]) { return true; } } return false; } /** update */ this.update = function() { if(inCombat && atRest){this.setAtRest(false);} if(!inCombat && !atRest){this.setAtRest(true);} if(inCombat) { if(system.timer - my.lastTic >= gameTic) { this.health.increase(this.health.getRegen()/[[[2]]]); this.stamina.increase(this.stamina.getRegen()/[[[2]]]); this.power.increase(this.power.getRegen()/[[[2]]]); } if(system.timer - lastAttackTime >= weaponSpeed && !isAttacking) { actionQue.add(new MeleeAttack(my, target, this.attackStyles[[[[0]]]])); } } else if(atRest) { if(system.timer - my.lastTic >= gameTic) { this.health.increase(this.health.getRegen()*[[[2]]]); this.stamina.increase(this.stamina.getRegen()*[[[2]]]); this.power.increase(this.power.getRegen()*[[[2]]]); } } } this.getStringId = function(){return stringId;} this.toString = function() { return this.getStringId()+":\n"+this.stamina+"\n"+this.health+"\n"+this.power; }}
function Skill(intId, stringId, base){ var outer = this; //base this.getBase = function() { return base;} this.setBase = function(amount) { if(base == amount) { return;} else if(base > amount) { this.decreaseBase(base-amount); return;} else { this.increaseBase(amount - base); return;} } this.increaseBase = function(amount) { if(amount <= [[[0]]]) { return;} else { base += amount; return;}} this.decreaseBase = function(amount) { if(amount <=[[[0]]]) { return;} else if(base - amount < [[[0]]]) { base = [[[0]]]; return;} else { base -= amount; return;}} //current var current = base; this.getCurrent = function() { return current;} this.setCurrent = function(amount) { if(current == amount) { return;} else if(current > amount) { this.decreaseCurrent(current-amount); return;} else { this.increaseCurrent(amount - current); return;} } this.increaseCurrent = function(amount) { if(amount <= [[[0]]]) { return;} else { current += amount; return;}} this.decreaseCurrent = function(amount) { if(amount <= [[[0]]]) { return;} else if(current - amount < [[[0]]]) { current = [[[0]]]; return;} else { current -= amount; return;}} //misc this.getIntId = function() { return intId;} this.getStringId = function() { return stringId;} this.toString = function() { //[STAT][intId][stringId][current][base] return "[SKILL][" + intId + "][\"" + stringId + "\"][" + current + "][" + base +"]";}}
function Stat(intId, stringId, base){ var outer = this; //base is the raw stat before anything is applied this.getBase = function() { return base;} this.setBase = function(amount) { if(base == amount) { return;} else if(base > amount) { this.decreaseBase(base-amount); return;} else { this.increaseBase(amount - base); return;} } this.increaseBase = function(amount) { if(amount <= [[0]]) { return;} else { base += amount; return;}} this.decreaseBase = function(amount) { if(amount <=[[0]]) { return;} else if(base - amount < [[1]]) { base = [[1]]; return;} else { base -= amount; return;}} //max var max = base; this.getMax = function() { return max;} this.setMax = function(amount) { if(max == amount) { return;} else if(max > amount) { this.decreaseMax(max - amount); return;} else { this.increaseMax(amount - max); return;} } this.increaseMax = function(amount) { if(amount <= [[0]]) { return;} else { max += amount; return;}} this.decreaseMax = function(amount) { if(amount <= [[0]]) { return;} else if(max - amount < [[1]]) { max = [[1]]; current = [[1]]; return;} else { max -= amount; if(current > max) { current = max;} return;}} //current var current = max; this.getCurrent = function() { return current;} this.setCurrent = function(amount) { if(current == amount) { return;} else if(current > amount) { this.decreaseCurrent(current-amount); return;} else { this.increaseCurrent(amount - current); return;} } this.increaseCurrent = function(amount) { if(amount <= [[0]]) { return;} else if(current + amount > max) { current = max; return;} else { current += amount; return;}} this.decreaseCurrent = function(amount) { if(amount <= [[0]]) { return;} else if(current - amount < [[0]]) { current = [[0]]; return;} else { current -= amount; return;}} //misc this.getIntId = function() { return intId;} this.getStringId = function() { return stringId;} this.toString = function() { //[STAT][intId][stringId][current][max][base] return "[STAT][" + intId + "][\"" + stringId + "\"][" + current + "][" + max +"][" + base +"]";}}
//const SLASH=[[[0]]]; BLOCK=[[[1]]]; PARRY=[[[2]]]; DODGE = [[[3]]]; ONEHAND = [[[4]]];function MeleeAttack(attacker, defender, style){ var startTime = system.timer; print(attacker.hasStyle(style)); if(attacker.hasStyle(style)) { print(attacker.getEquippedWeapon().getSecondarySkill()); print(style.getWeaponType()); print(attacker.getEquippedWeapon().getSecondarySkill() == style.getWeaponType()); if(attacker.getEquippedWeapon().getSecondarySkill() == style.getWeaponType()) { attacker.setIsAttacking(true); var combatResult = combatCheck(attacker, defender, style); switch(combatResult) { case "missed": actionQue.add(new SoundDelay(.[[[5]]], _3dScene, "woosh")); attacker.getMesh().animationMergeRemove(style.getAttackAnimation()); attacker.getMesh().animationMergeAdd(style.getAttackAnimation()); break; case "blocked": actionQue.add(new SoundDelay(.[[[65]]], _3dScene, "block")); defender.getMesh().animationMergeRemove("block"); defender.getMesh().animationMergeAdd("block"); attacker.getMesh().animationMergeRemove(style.getAttackAnimation()); attacker.getMesh().animationMergeAdd(style.getAttackAnimation()); break; case "dodged": break; case "parried": actionQue.add(new SoundDelay(.[[[65]]], _3dScene, "parry")); defender.getMesh().animationMergeRemove("parry"); defender.getMesh().animationMergeAdd("parry"); attacker.getMesh().animationMergeRemove(style.getAttackAnimation()); attacker.getMesh().animationMergeAdd(style.getAttackAnimation()); break; case "hit": actionQue.add(new SoundDelay(.[[[65]]], _3dScene, "hurt")); attacker.getMesh().animationMergeRemove(style.getAttackAnimation()); attacker.getMesh().animationMergeAdd(style.getAttackAnimation()); break; } } } else { return new ErrorMessage("Attacker does not have this style."); } this.update = function() { if(system.timer - startTime >= style.getAttackDelay()) { attacker.setIsAttacking(false); attacker.setLastAttackTime(system.timer); actionQue.remove(this); } }}function combatCheck(a, d, s){ var aS = a.getSkill(a.getEquippedWeapon().getSecondarySkill()).getCurrent(); var dS = d.getSkill(d.getEquippedWeapon().getSecondarySkill()).getCurrent(); var chance = ((aS+[[[1]]])/((dS+[[[1]]])+ (aS+[[[1]]]))+(aS*s.getAttackBonus())); if(chance<.[[[02]]]){chance=.[[[02]]];} if(chance<Math.random()) { return "missed"; } else { print(d.getStringId()); print(d.getSkill(BLOCK)); print("Block Chance:"+((((d.getSkill(BLOCK).getCurrent()/[[[4]]])+[[[5]]])*.[[[01]]])-(d.getSkill(BLOCK).getCurrent()*s.getBlockMinus()))); var blockChance = ((((d.getSkill(BLOCK).getCurrent()/[[[4]]])+[[[5]]])*.[[[01]]])-(d.getSkill(BLOCK).getCurrent()*s.getBlockMinus())); if(Math.random() < blockChance) { return "blocked"; } print("Parry Chance:"+((((d.getSkill(PARRY).getCurrent()/[[[4]]])+[[[5]]])*.[[[01]]])-(d.getSkill(PARRY).getCurrent()*s.getBlockMinus()))); var parryChance = ((((d.getSkill(PARRY).getCurrent()/[[[4]]])+[[[5]]])*.[[[01]]])-(d.getSkill(PARRY).getCurrent()*s.getParryMinus())); if(Math.random()< parryChance) { return "parried"; } return "hit"; }}
function Weapon(name, description, baseSkill, secondarySkill, damageMin, damageMax, slot, mesh3d, speed){ var weapMesh = _3dScene.objectAdd(mesh3d+"_"+generateUniqueNumber(), mesh3d); //print(weapMesh.id); this.getMesh = function(){return weapMesh;} this.setMesh = function(wm){weapMesh = wp;} this.getName = function(){return name;} this.setName = function(n){name = n;} this.getDescription = function(){return description;} this.setDescription = function(d){description = d;} this.getBaseSkill = function(){return baseSkill;} this.setBaseSkill = function(bs){baseSkill = bs;} this.getSecondarySkill = function(){return secondarySkill;} this.getDamageMin = function(){return damageMin;} this.setDamageMin = function(dm){damageMin = dm;} this.getDamageMax = function(){return damageMax;} this.setDamageMax = function(dm){damageMax = dm;} this.getSlot = function(){return slot;} this.setSlot = function(s){slot = s;} this.getMesh3d = function(){return mesh3d;} this.setMesh3d = function(m3d){mesh3d = m3d;} this.getSpeed = function(){return speed;} this.setSpeed = function(s){speed = s;}}
function AttackStyle(weaponType, getAttackAnimation, attackBonus, blockMinus, dodgeMinus, parryMinus, effect, speedModifire, attackDelay){ this.getWeaponType = function(){return weaponType;} this.getAttackAnimation = function(){return getAttackAnimation;} this.getAttackBonus = function(){return attackBonus;} this.getBlockMinus = function(){return blockMinus;} this.getDodgeMinus = function(){return dodgeMinus;} this.getParryMinus = function(){return parryMinus;} this.getEffect = function(){return effect;} this.getSpeedModifire = function(){return speedModifire;} this.getAttackDelay = function(){return attackDelay;}}
I am still new to role play game development, so please let me know if there is a better way to do this stuff.
The main problem is, where do I store what animation to use? In the attack style? In the weapon? IE: for this weapon, I use this parry animation, for this shield, I use this block animation, etc.
Is this a good overall framework for the game, or am I making some common noobie errors?
Thanks n advance...
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement