Sign in to follow this  
BUnzaga

Attack Styles... how?

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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...


//@"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 &gt; amount)
{ this.decreaseBase(base-amount);
return;}
else
{ this.increaseBase(amount - base);
return;}
}
this.increaseBase = function(amount)
{ if(amount &lt;= [[0]])
{ return;}
else
{ base += amount;
return;}}
this.decreaseBase = function(amount)
{ if(amount &lt;=[[0]])
{ return;}
else if(base - amount &lt; [[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 &gt; amount)
{
this.decreaseMax(max - amount);
return;}
else
{ this.increaseMax(amount - max);
return;}
}
this.increaseMax = function(amount)
{ if(amount &lt;= [[0]])
{ return;}
else
{ max += amount;
return;}}
this.decreaseMax = function(amount)
{ if(amount &lt;= [[0]])
{ return;}
else if(max - amount &lt; [[1]])
{ max = [[1]];
current = [[1]];
return;}
else
{ max -= amount;
if(current &gt; max)
{ current = max;}
return;}}
//current
var current = max;
this.getCurrent = function()
{ return current;}
this.setCurrent = function(amount)
{ if(current == amount)
{ return;}
else if(current &gt; amount)
{ this.decreaseCurrent(current-amount);
return;}
else
{ this.increaseCurrent(amount - current);
return;}
}
this.increaseCurrent = function(amount)
{ if(amount &lt;= [[0]])
{ return;}
else if(current + amount &gt; max)
{ current = max;
return;}
else
{ current += amount;
return;}}
this.decreaseCurrent = function(amount)
{ if(amount &lt;= [[0]])
{ return;}
else if(current - amount &lt; [[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...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this