Merge branch 'combos'

This commit is contained in:
ntr
2019-02-21 15:03:21 +11:00
30 changed files with 1388 additions and 588 deletions
+23 -23
View File
@@ -55,43 +55,43 @@ Debuff `Base enemy debuff - reduce enemy speed`
# Nature Type (red) #
Bite - (Attack + 3R) Deal significant `Red` damage
Strangle - (Stun + 3R) - Applies stun and physical dot
Regenerate - (Buff + 3R) Restore red defense for target ally
Snare - (Debuff + 3R) Disable enemy red skills for (3?) turns
Parry - (Block + 3R) Avoid all damage for this turn
Bite - (Attack RR) Deal significant `Red` damage
Strangle - (Stun RR) - Applies stun and physical dot
Regenerate - (Buff RR) Restore red defense for target ally
Snare - (Debuff RR) Disable enemy red skills for (3?) turns
Parry - (Block RR) Avoid all damage for this turn
# Destruction Type (blue) #
Blast - (Attack + 3B) Deal significant `Blue` damage
Ruin - (Stun + 3B) - AOE stun on the enemy team for remaind of turn
Amplify - (Buff + 3B) Increased blue damage dealt by target ally
Curse - (Debuff + 3B) Decrease damage dealt by target enemy
Plague Shield - (Block + 3B) Apply dot debuff to attackers
Blast - (Attack BB) Deal significant `Blue` damage
Ruin - (Stun BB) - AOE stun on the enemy team for remaind of turn
Amplify - (Buff BB) Increased blue damage dealt by target ally
Curse - (Debuff BB) Decrease damage dealt by target enemy
Plague Shield - (Block BB) Apply dot debuff to attackers
# Non-Violence Type (green) #
Heal - (Attack + 3G) Heal ally for X
Throw - (Stun + 3G) - Disable target and increase damage taken
Triage - (Buff + 3G) Buff which heals ally for X over Y turns
Purge - (Debuff + 3G) - Remove all enemy target buffs
Reflect - (Block + 3G) - Will use targetted attacks on source
Heal - (Attack GG) Heal ally for X
Throw - (Stun GG) - Disable target and increase damage taken
Triage - (Buff GG) Buff which heals ally for X over Y turns
Purge - (Debuff GG) - Remove all enemy target buffs
Reflect - (Block GG) - Will use targetted attacks on source
# Chaos Type (red / blue) #
Bannish - (Attack + 1R + 2B) - deal `Hybrid Red & Blue` + enemy can't attack or be attacked 3 turns
Hex - (Stun + 2R + 1B) - enemy stunned for 3 turns
Haste - (Buff + 2R + 1B) - significantly increase ally speed
Slow - (Debuff + 1R + 2B) - significantly decrease enemy speed
Taunt - (Block + 2B + 1R) - Redirect all enemy targetted skills
Bannish - (Attack RB) - deal `Hybrid Red & Blue` + enemy can't attack or be attacked 3 turns
Hex - (Stun RB) - enemy stunned for 3 turns
Haste - (Buff RB) - significantly increase ally speed
Slow - (Debuff RB) - significantly decrease enemy speed
Taunt - (Block RB) - Redirect all enemy targetted skills
# Purity Type (red / green) #
Slay - (Attack + 1G + 2R) - deal `Red` damage. Bonus damage if the target has blue defense
Slay - (Attack + 1G + 1R) - deal `Red` damage. Bonus damage if the target has blue defense
Silence - (Stun + 2G + 1R) - enemy can't use blue skills for 3 turns
Purify - (Buff + 2G + 1R) - remove all debuffs from target
Empower - (Buff + 1G + 2R) - Increased red damage dealt by target ally
???? - (Debuff + 1R + 2B) - ???
Empower - (Buff + 1G + 1R) - Increased red damage dealt by target ally
???? - (Debuff RB) - ???
Shield - (Block + 2G + 1R) - Take no blue damage for the next 3 turns
# Technology Type (green / blue) type - ??? maybe rework and rename #
+9 -9
View File
@@ -6,16 +6,16 @@
Rare `Increased Stamina`
Common `Increased Evasion rating`
Common `Increased Spell Shield rating`
Common `Increased Armour rating`
Common `Increased Blue Shield rating`
Common `Increased RedShield rating`
Common `Increased Healing done`
Common `Increased Healing received`
Common `Increased Spell Damage`
Common `Increased Physical Damage`
Common `Increased Blue Damage`
Common `Increased Red Damage`
Uncommon `Reduced hp loss penalty to evade chance`
Uncommon `Increased base evasion chance per X evasion rating`
Uncommon `Increased % mitigation from armour`
Uncommon `Increased % mitigation from red_shield`
Uncommon `Increased % mitigation from spell shield`
Uncommon `Increased damage over time`
@@ -30,11 +30,11 @@ Rare `25% hex for blast`
Rare `cooldown reduction`
Rare `effect duration`
Rare `increased phys dmg, 0 spell damage`
Rare `increased spell dmg, 0 phys damage`
Rare `increased phys damage, 0 spell damage`
Rare `increased spell damage, 0 phys damage`
Rare `increased phys dmg, silenced`
Rare `increased spell dmg, snared`
Rare `increased phys damage, silenced`
Rare `increased spell damage, snared`
Rare `increased speed, increased durations`
Rare `increased speed, increased cooldowns`
+3 -3
View File
@@ -21,11 +21,11 @@ resolve phase:
2.2 <- attack (normal resolve)
1.1 <- hexed (no skills for the rest of this turn and next)
## Dmg Chart
## Damage Chart
| Physical | Magic | Modifiers |
| Red | Magic | Modifiers |
| ------ | ------ | ------ |
| dmg | dmg | speed |
| damage | damage | speed |
| evasion | resistance | cooldowns |
| reduction | absorption? | durations |
+166
View File
@@ -0,0 +1,166 @@
### Specs ###
Numbers are placeholder
`Specs get a bonus dependent on the total of Red / Green / Blue in team skills`
# Example to meet 5 red tag bonus
In your team Cryp #1 has `Strike`, Cryp #2 has `Slay` and `Heal`, Cryp #3 has `Snare`
- RR skill `Strike` contributes 2 red tags to the total red tags (2 total)
- RG skill `Slay` contributes 1 red tag to the total red tags (3 total)
- GG skill `Heal` contirubes 0 red tags to the total red tags (3 total)
- RR skill `Snare` contirubes 2 red tags to the total red tags (5 total)
# Specs also have `Class points`
Basic specs (Damage / Health / Defense) will generate class points
Advanced specs (Skill Specific Damage, Cooldown reduction, Increased durations, etc) will consume class points
### Generic Specs
(Base white skills not upgraded count as have 1 tag basic ?)
# Basic Damage
`Base` -> 10% inc basic damage
`Bonus` -> 3 basic tags -> +10% // 6 basic tags -> +15% // 12 basic tags -> +25%
Maximum 60% inc basic damage
# Basic % Life
`Base` -> 5% inc life
`Bonus` -> 3 basic tags -> +5% // 6 basic tags -> +10% // 12 basic tags -> +15%
Maximum 35% inc life
# Basic Speed
`Base` -> 5% inc speed
`Bonus` -> 3 basic tags -> +10% // 6 basic tags -> +15% // 12 basic tags -> +20%
Maximum 50% inc speed
# Basic Class Spec
`Base` -> +2 all class points
`Bonus` -> 3 basic tags -> +2 // 6 basic tags -> +4 // 12 basic tags -> +6
Maximum +14 all class points
# Basic Duration
### Increased Damage Combos ###
Generate by combining `Generic Spec (Basic Damage)` with respective RGB
# Red Damage (Dmg + RR)
Add 5 `Nature` Class Points
`Base` -> 10% inc red dmg
`Bonus` 5 red tags -> +10% // 10 red tags -> +15% // 20 red tags -> +25%
Maximum +60% red damage
# Blue Damage (Dmg + BB) #
Add 5 `Destruction` Class Points
`Base` -> 10% inc blue dmg
`Bonus` 5 blue tags -> +10% // 10 blue tags -> +15% // 20 blue tags -> +25%
Maximum +60% blue damage
# Healing (Dmg + GG) #
Add 5 `Non-Violence` Class Points
`Base` -> 10% inc healing
`Bonus` 5 green tags -> +10% // 10 green tags -> +15% // 20 green tags -> +25%
Maximum +60% inc healing
# Red damage and healing (Dmg + RG)
Add 5 `Purity` Class Points
`Base` -> 5% inc red damage and 5% inc healing
`Bonus` (2R + 2G tags) -> +5% + 5% // (5R + 5G tags) -> +10% + 10% % // (10R + 10G) tags -> +15% + 15%
Maximum +35% inc red damage and 35% inc healing
# Red and blue damage (Dmg + RB)
Add 5 `Chaos` Class Points
`Base` -> 5% inc red damage and 5% inc healing
`Bonus` (2 red + 2 green tags) -> +5% + 5% // (5 red + 5 green tags) -> +10% + 10% % // 20 green tags -> +15% + 15%
Maximum +35% inc damage and 35% inc healing
# Blue damage and healing (Dmg + BG)
Add 5 `??????` Class Points
`Base` -> 5% inc blue damage and 5% inc healing
`Bonus` (2B + 2G tags) -> +5% + 5% // (5B + 5G tags) -> +10% + 10% % // (10B + 10G) tags -> +15% + 15%
Maximum +35% inc blue damage and 35% inc healing
### Increased Life Combos ###
Generate by combining `Generic Spec (Basic Life)` with respective RGB
# Increased % Red Shield (Basic %HP + 2R)
Add 5 Nature Class Points
`Base` -> 10% inc red shield
`Bonus` 5 red tags -> +10% // 10 red tags -> +15% // 20 red tags -> +20%
Maximum +55% inc red shield
# Increased % Red Shield and Life (Basic %HP + 1R1G)
Add 5 Purity Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2R + 2G tags) -> +5% + 5% // (5R + 5G tags) -> +10% + 10% % // (10R + 10G) tags -> +15% + 15%
Maximum +35% inc red shield and 35% inc life
# Increased % Blue Shield (Basic %HP + 2B)
Add 5 Destruction Class Points
`Base` -> 10% inc red shield
`Bonus` 5 blue tags -> +10% // 10 blue tags -> +15% // 20 blue tags -> +20%
Maximum +55% inc blue shield
# Increased % Blue Shield and Life (Basic %HP + 1B1G)
Add 5 ??? Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2B + 2G tags) -> +5% + 5% // (5B + 5G tags) -> +10% + 10% % // (10B + 10G) tags -> +15% + 15%
Maximum +35% inc blue shield and 35% inc life
# Increased % Life (Basic %HP + 2G)
Add 5 Non-Violence Class Points
`Base` -> 10% inc hp
`Bonus` 5 green tags -> +10% // 10 green tags -> +15% // 20 green tags -> +20%
Maximum +55% inc hp
# Increased % Blue and Red Shield (Basic %HP + 1B1R)
Add 5 Chaos Class Points
`Base` -> 5% inc red shield and 5% inc life
`Bonus` (2B + 2R tags) -> +5% + 5% // (5B + 5R tags) -> +10% + 10% % // (10B + 10R) tags -> +15% + 15%
Maximum +35% inc blue shield and 35% inc red shield
## Upgraded Attack Spec Combos
# Increased Strike Damage (Combine Strike + Red Damage Spec x 2)
Consumes 15 Nature Class Points
`Base` -> 15% increased strike damage
`Bonus` 5 red tags -> +15% // 10 red tags -> +20% // 20 red tags -> +30%
Maximum 80% increased strike damage
# Improved Heal (Combine Heal + Healing Spec x 2)
Consumes 15 Non-Violence Class Points
`Base` -> 15% increased heal healing
`Bonus` 5 green tags -> +15% // green red tags -> +20% // green red tags -> +30%
Maximum 80% increased heal healing
# Increased Blast Damage (Combine Blast + Blue Spec x 2)
Consumes 15 Destruction Class Points
`Base` -> 15% increased blast damage
`Bonus` 5 blue tags -> +15% // 10 blue tags -> +20% // 20 blue tags -> +30%
Maximum 80% increased blast damage
# Increased Slay Damage (Combine Slay + Red Damage Spec + Healing Spec)
Consumes 15 Purity Class Points
`Base` -> 15% increased slay damage
`Bonus` (2R + 2G) tags -> +15% // (5R + 5G) tags -> +20% // (10R + 10G) tags -> +30%
Maximum 80% increased slay damage
# Increased Banish Damage (Combine Slay + Red Damage Spec + Blue Damage Spec)
Consumes 15 Chaos Class Points
`Base` -> 15% increased slay damage
`Bonus` (2R + 2B) tags -> +15% // (5R + 5B) tags -> +20% // (10R + 10B) tags -> +30%
Maximum 80% increased banish damage
## Other Combos
# Increased % Red Speed (Basic Speed + 2R)
Add 5 Nature Class Points
`Base` -> 15% inc red speed
`Bonus` 5 red tags -> +15% // 10 red tags -> +20% // 20 red tags -> +25%
Maximum 80% inc red speed
# Nature Affinity (Basic Class spec + 2R)
`Base` -> 10 Nature Class Points
`Bonus` 5 red tags -> +10 // 10 red tags -> +15 // 20 red tags -> +20
Maximum 45 Nature Class Points
+1 -33
View File
@@ -30,7 +30,7 @@
* phys is faster and chaotic
* spells are slow and reliable
* defensives are implicit
* armour is restored, not gained
* red_shield is restored, not gained
* players can feel aggressive
# ask sam
@@ -56,38 +56,6 @@ taunt
## NOW
inventory + drops table
id
data
game
drops_buy(game_id, index)
drops_get()
inventory_get()
reduce balance
move drop into inventory
drops_update()
inventory_update()
-> inventory
inventory_combine(game_id, [indices])
inventory_get()
new item =
match base item
match modifiers
update inventory[base_index]
inventory_update()
-> inventory
## SOON
* clean up categories
* why is the text fucked?
+64 -64
View File
@@ -45,14 +45,14 @@ pub enum Stat {
Hp,
Speed,
Stamina,
PhysicalDamage,
PhysicalDamageTaken,
SpellDamage,
SpellDamageTaken,
RedDamage,
RedDamageTaken,
BlueDamage,
BlueDamageTaken,
Healing,
HealingTaken,
Armour,
SpellShield,
RedShield,
BlueShield,
Evasion,
}
@@ -136,13 +136,13 @@ pub struct CrypRecover {
pub struct Cryp {
pub id: Uuid,
pub account: Uuid,
pub phys_dmg: CrypStat,
pub spell_dmg: CrypStat,
pub red_damage: CrypStat,
pub red_shield: CrypStat,
pub blue_shield: CrypStat,
pub blue_damage: CrypStat,
pub speed: CrypStat,
pub stamina: CrypStat,
pub hp: CrypStat,
pub armour: CrypStat,
pub spell_shield: CrypStat,
pub evasion: CrypStat,
pub xp: u64,
pub lvl: u8,
@@ -164,13 +164,13 @@ impl Cryp {
return Cryp {
id,
account: id,
phys_dmg: CrypStat { base: 0, value: 0, stat: Stat::PhysicalDamage },
spell_dmg: CrypStat { base: 0, value: 0, stat: Stat::SpellDamage },
red_damage: CrypStat { base: 0, value: 0, stat: Stat::RedDamage },
red_shield: CrypStat { base: 0, value: 0, stat: Stat::RedShield },
blue_damage: CrypStat { base: 0, value: 0, stat: Stat::BlueDamage },
blue_shield: CrypStat { base: 0, value: 0, stat: Stat::BlueShield },
speed: CrypStat { base: 0, value: 0, stat: Stat::Speed },
stamina: CrypStat { base: 0, value: 0, stat: Stat::Stamina },
hp: CrypStat { base: 0, value: 0, stat: Stat::Hp },
armour: CrypStat { base: 0, value: 0, stat: Stat::Armour },
spell_shield: CrypStat { base: 0, value: 0, stat: Stat::SpellShield },
evasion: CrypStat { base: 0, value: 0, stat: Stat::Evasion },
lvl: 0,
xp: 0,
@@ -238,15 +238,15 @@ impl Cryp {
let evasion_max = 5;
match stat {
Stat::PhysicalDamage => self.phys_dmg.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::SpellDamage => self.spell_dmg.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::RedDamage => self.red_damage.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::BlueDamage => self.blue_damage.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Speed => self.speed.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Stamina => {
self.stamina.set(rng.gen_range(stam_min, stam_max), &self.specs);
self.hp.set(self.stamina.base, &self.specs)
},
Stat::SpellShield => self.spell_shield.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Armour => self.armour.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::BlueShield => self.blue_shield.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::RedShield => self.red_shield.set(rng.gen_range(stat_min, stat_max), &self.specs),
Stat::Evasion => self.evasion.set(rng.gen_range(evasion_min, evasion_max), &self.specs),
_ => panic!("{:?} not a rollable stat", stat),
};
@@ -262,8 +262,8 @@ impl Cryp {
self.xp = xp;
self.roll_stat(Stat::PhysicalDamage);
self.roll_stat(Stat::SpellDamage);
self.roll_stat(Stat::RedDamage);
self.roll_stat(Stat::BlueDamage);
self.roll_stat(Stat::Speed);
self.roll_stat(Stat::Stamina);
@@ -306,7 +306,7 @@ impl Cryp {
return Ok(self.recalculate_stats());
}
pub fn spec_remove(mut self, spec: Spec) -> Result<Cryp, Error> {
pub fn spec_remove(&mut self, spec: Spec) -> Result<&mut Cryp, Error> {
let find_spec = |spec_v: &Vec<Spec>| spec_v.iter().position(|s| s.spec == spec.spec);
match spec.level {
@@ -324,18 +324,18 @@ impl Cryp {
},
};
Ok(self)
Ok(self.recalculate_stats())
}
fn recalculate_stats(&mut self) -> &mut Cryp {
self.stamina.recalculate(&self.specs);
self.hp.recalculate(&self.specs);
self.phys_dmg.recalculate(&self.specs);
self.spell_dmg.recalculate(&self.specs);
self.red_damage.recalculate(&self.specs);
self.red_shield.recalculate(&self.specs);
self.blue_damage.recalculate(&self.specs);
self.blue_shield.recalculate(&self.specs);
self.evasion.recalculate(&self.specs);
self.armour.recalculate(&self.specs);
self.spell_shield.recalculate(&self.specs);
self.speed.recalculate(&self.specs);
self
@@ -468,24 +468,24 @@ impl Cryp {
// }
// Stats
pub fn phys_dmg(&self) -> u64 {
let phys_dmg_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::PhysicalDamage))
pub fn red_damage(&self) -> u64 {
let red_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::RedDamage))
.map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>();
let modified_phys_dmg = phys_dmg_mods.iter().fold(self.phys_dmg.value, |acc, m| m.apply(acc));
return modified_phys_dmg;
let modified_red_damage = red_damage_mods.iter().fold(self.red_damage.value, |acc, m| m.apply(acc));
return modified_red_damage;
}
pub fn spell_dmg(&self) -> u64 {
let spell_dmg_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::SpellDamage))
pub fn blue_damage(&self) -> u64 {
let blue_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::BlueDamage))
.map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>();
let modified_spell_dmg = spell_dmg_mods.iter().fold(self.spell_dmg.value, |acc, m| m.apply(acc));
return modified_spell_dmg;
let modified_blue_damage = blue_damage_mods.iter().fold(self.blue_damage.value, |acc, m| m.apply(acc));
return modified_blue_damage;
}
pub fn skill_speed(&self, s: Skill) -> u64 {
@@ -518,7 +518,7 @@ impl Cryp {
ResolutionResult::Healing {
amount: 0,
overhealing: 0,
category: Category::PhysHeal,
category: Category::RedHeal,
immunity: immunity.clone(),
};
}
@@ -546,12 +546,12 @@ impl Cryp {
return ResolutionResult::Healing {
amount: healing,
overhealing,
category: Category::PhysHeal,
category: Category::RedHeal,
immunity,
};
}
pub fn deal_phys_dmg(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
pub fn deal_red_damage(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
let immunity = self.immune(skill);
let immune = immunity.immune;
@@ -559,29 +559,29 @@ impl Cryp {
return ResolutionResult::Damage {
amount: 0,
mitigation: 0,
category: Category::PhysDmg,
category: Category::RedDamage,
immunity,
};
}
let phys_dmg_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::PhysicalDamageTaken))
let red_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::RedDamageTaken))
.map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>();
// println!("{:?}", phys_dmg_mods);
// println!("{:?}", red_damage_mods);
let modified_dmg = phys_dmg_mods.iter().fold(amount, |acc, m| m.apply(acc));
let modified_damage = red_damage_mods.iter().fold(amount, |acc, m| m.apply(acc));
// calculate amount of damage armour will not absorb
// eg 50 armour 25 dmg -> 0 remainder 25 mitigation
// 50 armour 100 dmg -> 50 remainder 50 mitigation
// 50 armour 5 dmg -> 0 remainder 5 mitigation
let remainder = modified_dmg.saturating_sub(self.armour.value);
let mitigation = modified_dmg.saturating_sub(remainder);
// calculate amount of damage red_shield will not absorb
// eg 50 red_shield 25 damage -> 0 remainder 25 mitigation
// 50 red_shield 100 damage -> 50 remainder 50 mitigation
// 50 red_shield 5 damage -> 0 remainder 5 mitigation
let remainder = modified_damage.saturating_sub(self.red_shield.value);
let mitigation = modified_damage.saturating_sub(remainder);
// reduce armour by mitigation amount
self.armour.reduce(mitigation);
// reduce red_shield by mitigation amount
self.red_shield.reduce(mitigation);
// deal remainder to hp
self.hp.reduce(remainder);
@@ -589,12 +589,12 @@ impl Cryp {
return ResolutionResult::Damage {
amount: remainder,
mitigation,
category: Category::PhysDmg,
category: Category::RedDamage,
immunity,
};
}
pub fn deal_spell_dmg(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
pub fn deal_blue_damage(&mut self, skill: Skill, amount: u64) -> ResolutionResult {
let immunity = self.immune(skill);
let immune = immunity.immune;
@@ -602,29 +602,29 @@ impl Cryp {
return ResolutionResult::Damage {
amount: 0,
mitigation: 0,
category: Category::SpellDmg,
category: Category::BlueDamage,
immunity,
};
}
let spell_dmg_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::SpellDamageTaken))
let blue_damage_mods = self.effects.iter()
.filter(|e| e.effect.modifications().contains(&Stat::BlueDamageTaken))
.map(|cryp_effect| cryp_effect.effect)
.collect::<Vec<Effect>>();
// println!("{:?}", spell_dmg_mods);
// println!("{:?}", blue_damage_mods);
let modified_dmg = spell_dmg_mods.iter().fold(amount, |acc, m| m.apply(acc));
let remainder = modified_dmg.saturating_sub(self.armour.value);
let mitigation = modified_dmg.saturating_sub(remainder);
let modified_damage = blue_damage_mods.iter().fold(amount, |acc, m| m.apply(acc));
let remainder = modified_damage.saturating_sub(self.blue_shield.value);
let mitigation = modified_damage.saturating_sub(remainder);
self.armour.reduce(mitigation);
self.blue_shield.reduce(mitigation);
self.hp.reduce(remainder);
return ResolutionResult::Damage {
amount: remainder,
mitigation,
category: Category::SpellDmg,
category: Category::BlueDamage,
immunity,
};
}
@@ -734,7 +734,7 @@ pub fn cryp_forget(params: CrypForgetParams, tx: &mut Transaction, account: &Acc
pub fn cryp_unspec(params: CrypUnspecParams, tx: &mut Transaction, account: &Account) -> Result<Cryp, Error> {
let mut cryp = cryp_get(tx, params.id, account.id)?;
cryp = cryp.spec_remove(params.spec)?;
cryp.spec_remove(params.spec)?;
return cryp_write(cryp, tx);
}
+7 -14
View File
@@ -11,7 +11,6 @@ use account::Account;
use rpc::{GameStateParams, GameSkillParams, GamePveParams, GamePvpParams, GameJoinParams};
use cryp::{Cryp, cryp_get};
use skill::{Skill, Cast, ResolutionResult};
use item::{item_drop};
use zone::{node_finish};
use mob::{generate_mob_team};
@@ -685,12 +684,6 @@ pub fn game_update(game: &Game, tx: &mut Transaction) -> Result<(), Error> {
result.iter().next().ok_or(format_err!("game {:?} could not be written", game))?;
if game.finished() {
if let Some(t) = game.winner() {
if !t.id.is_nil() {
item_drop(tx, t.id, game.mode)?;
}
}
// check for zone update
if let Some((z, i)) = game.zone {
node_finish(game, z, i, tx)?;
@@ -854,7 +847,7 @@ mod tests {
.learn(Skill::TestTouch)
.learn(Skill::TestBlock)
.learn(Skill::TestParry)
.learn(Skill::TestDrain)
.learn(Skill::TestSiphon)
.learn(Skill::Empower)
.learn(Skill::Stun)
.learn(Skill::Block)
@@ -868,7 +861,7 @@ mod tests {
.learn(Skill::TestTouch)
.learn(Skill::TestBlock)
.learn(Skill::TestParry)
.learn(Skill::TestDrain)
.learn(Skill::TestSiphon)
.learn(Skill::Empower)
.learn(Skill::Stun)
.learn(Skill::Block)
@@ -1014,12 +1007,12 @@ mod tests {
let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone();
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().phys_dmg.force(u64::max_value());
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().red_damage.force(u64::max_value());
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().speed.force(u64::max_value());
// just in case
// remove all mitigation
game.team_by_id(x_team.id).cryp_by_id(x_cryp.id).unwrap().armour.force(0);
game.team_by_id(x_team.id).cryp_by_id(x_cryp.id).unwrap().red_shield.force(0);
let _x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestStun).unwrap();
game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::Attack).unwrap();
@@ -1088,7 +1081,7 @@ mod tests {
}
#[test]
fn drain_test() {
fn siphon_test() {
let mut game = create_test_game();
let x_team = game.teams[0].clone();
@@ -1097,7 +1090,7 @@ mod tests {
let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone();
let _x_drain_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestDrain).unwrap();
let _x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_cryp.id), Skill::TestSiphon).unwrap();
let _y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_cryp.id), Skill::TestTouch).unwrap();
game.resolve_phase_start();
@@ -1107,7 +1100,7 @@ mod tests {
game.resolve_phase_start();
assert!(game.resolved.iter().any(|r| r.skill == Skill::DrainTick));
assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick));
}
#[test]
+7 -7
View File
@@ -938,7 +938,7 @@ mod tests {
.learn(Skill::TestTouch)
.learn(Skill::TestBlock)
.learn(Skill::TestParry)
.learn(Skill::TestDrain)
.learn(Skill::TestSiphon)
.learn(Skill::Empower)
.learn(Skill::Block)
.create();
@@ -950,7 +950,7 @@ mod tests {
.learn(Skill::TestTouch)
.learn(Skill::TestBlock)
.learn(Skill::TestParry)
.learn(Skill::TestDrain)
.learn(Skill::TestSiphon)
.learn(Skill::Empower)
.learn(Skill::Block)
.create();
@@ -1104,7 +1104,7 @@ mod tests {
let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone();
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().phys_dmg.set(u64::max_value());
game.team_by_id(y_team.id).cryp_by_id(y_cryp.id).unwrap().red_damage.set(u64::max_value());
let x_stun_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestStun).unwrap();
let y_attack_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::Attack).unwrap();
@@ -1194,7 +1194,7 @@ mod tests {
}
#[test]
fn drain_test() {
fn siphon_test() {
let mut game = create_test_game();
let x_team = game.teams[0].clone();
@@ -1203,13 +1203,13 @@ mod tests {
let x_cryp = x_team.cryps[0].clone();
let y_cryp = y_team.cryps[0].clone();
let x_drain_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestDrain).unwrap();
let x_siphon_id = game.add_skill(x_team.id, x_cryp.id, Some(y_team.id), Skill::TestSiphon).unwrap();
let y_touch_id = game.add_skill(y_team.id, y_cryp.id, Some(x_team.id), Skill::TestTouch).unwrap();
game.target_phase_start();
game.add_target(x_team.id, x_cryp.id, y_touch_id).unwrap();
game.add_target(y_team.id, y_cryp.id, x_drain_id).unwrap();
game.add_target(y_team.id, y_cryp.id, x_siphon_id).unwrap();
game.resolve_phase_start();
@@ -1218,7 +1218,7 @@ mod tests {
game.target_phase_start();
assert!(game.resolved.iter().any(|r| r.skill == Skill::DrainTick));
assert!(game.resolved.iter().any(|r| r.skill == Skill::SiphonTick));
}
#[test]
+26 -26
View File
@@ -17,19 +17,19 @@ use spec::{Spec, SpecType};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum ItemAction {
RerollPhysDamage,
RerollSpellDamage,
RerollRedDamage,
RerollBlueDamage,
RerollSpeed,
RerollStamina,
RerollArmour,
RerollSpellShield,
RerollRedShield,
RerollBlueShield,
RerollEvasion,
SpecPhysDmg5,
SpecSpellDmg5,
SpecArmour5,
SpecSpellShield5,
SpecSpellEvasion5,
SpecRedDamage5,
SpecBlueDamage5,
SpecRedShield5,
SpecBlueShield5,
SpecBlueEvasion5,
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
@@ -44,24 +44,24 @@ impl Item {
pub fn new(action: ItemAction, account_id: Uuid) -> Item {
let id = Uuid::new_v4();
return Item {
id,
account: account_id,
action,
id,
account: account_id,
action,
};
}
fn apply(&mut self, tx: &mut Transaction, target: Uuid) -> Result<(), Error> {
match self.action {
ItemAction::RerollStamina => reroll(self, tx, target, Stat::Stamina),
ItemAction::RerollPhysDamage => reroll(self, tx, target, Stat::PhysicalDamage),
ItemAction::RerollSpellDamage => reroll(self, tx, target, Stat::SpellDamage),
ItemAction::RerollRedDamage => reroll(self, tx, target, Stat::RedDamage),
ItemAction::RerollBlueDamage => reroll(self, tx, target, Stat::BlueDamage),
ItemAction::RerollSpeed => reroll(self, tx, target, Stat::Speed),
ItemAction::RerollArmour => reroll(self, tx, target, Stat::Armour),
ItemAction::RerollSpellShield => reroll(self, tx, target, Stat::SpellShield),
ItemAction::RerollRedShield => reroll(self, tx, target, Stat::RedShield),
ItemAction::RerollBlueShield => reroll(self, tx, target, Stat::BlueShield),
ItemAction::RerollEvasion => reroll(self, tx, target, Stat::Evasion),
ItemAction::SpecPhysDmg5 => spec_add(self, tx, target, SpecType::PhysDamage5),
ItemAction::SpecSpellDmg5 => spec_add(self, tx, target, SpecType::SpellDamage5),
ItemAction::SpecRedDamage5 => spec_add(self, tx, target, SpecType::RedDamage5),
ItemAction::SpecBlueDamage5 => spec_add(self, tx, target, SpecType::BlueDamage5),
_ => unimplemented!(),
}
}
@@ -86,8 +86,8 @@ fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> {
match mode {
GameMode::Normal => vec![
(ItemAction::RerollStamina, 1),
(ItemAction::RerollPhysDamage, 1),
(ItemAction::RerollSpellDamage, 1),
(ItemAction::RerollRedDamage, 1),
(ItemAction::RerollBlueDamage, 1),
],
GameMode::Pvp => vec![
(ItemAction::RerollSpeed, 1),
@@ -96,19 +96,19 @@ fn mode_drops(mode: GameMode) -> Vec<(ItemAction, usize)> {
GameMode::Zone2v2Caster |
GameMode::Zone3v3MeleeMiniboss => vec![
(ItemAction::RerollEvasion, 1),
(ItemAction::RerollArmour, 1),
(ItemAction::RerollSpellShield, 1),
(ItemAction::RerollRedShield, 1),
(ItemAction::RerollBlueShield, 1),
],
GameMode::Zone3v3HealerBoss => vec![
(ItemAction::RerollSpeed, 1),
],
// _ => vec![
// (ItemAction::RerollStamina, 1),
// (ItemAction::RerollPhysDamage, 1),
// (ItemAction::RerollSpellDamage, 1),
// (ItemAction::RerollRedDamage, 1),
// (ItemAction::RerollBlueDamage, 1),
// (ItemAction::RerollSpeed, 1),
// (ItemAction::RerollArmour, 1),
// (ItemAction::RerollSpellShield, 1),
// (ItemAction::RerollRedShield, 1),
// (ItemAction::RerollBlueShield, 1),
// (ItemAction::RerollEvasion, 1),
// ],
}
+3 -1
View File
@@ -26,10 +26,12 @@ mod spec;
// mod passives;
mod rpc;
mod account;
mod item;
// mod item;
mod zone;
mod mob;
mod vbox;
use dotenv::dotenv;
use net::{start};
+151 -77
View File
@@ -18,10 +18,10 @@ use net::Db;
use cryp::{Cryp, cryp_spawn, cryp_learn, cryp_forget, cryp_unspec};
use game::{Game, game_state, game_pve, game_pvp, game_join, game_joinable_list, game_skill};
use account::{Account, account_create, account_login, account_from_token, account_cryps, account_zone};
use item::{Item, ItemAction, items_list, item_use, item_create};
use skill::{Skill};
use zone::{Zone, zone_create, zone_join, zone_close};
use spec::{Spec};
use vbox::{Vbox, vbox_state, vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_drop};
pub struct Rpc;
@@ -76,11 +76,14 @@ impl Rpc {
"zone_join" => Rpc::zone_join(data, &mut tx, account.unwrap(), client),
"zone_close" => Rpc::zone_close(data, &mut tx, account.unwrap(), client),
"account_cryps" => Rpc::account_cryps(data, &mut tx, account.unwrap(), client),
"account_items" => Rpc::account_items(data, &mut tx, account.unwrap(), client),
"account_zone" => Rpc::account_zone(data, &mut tx, account.unwrap(), client),
"item_use" => Rpc::item_use(data, &mut tx, account.unwrap(), client),
"press_r" => Rpc::press_r(data, &mut tx, account.unwrap(), client),
"vbox_state" => Rpc::vbox_state(data, &mut tx, account.unwrap(), client),
"vbox_accept" => Rpc::vbox_accept(data, &mut tx, account.unwrap(), client),
"vbox_apply" => Rpc::vbox_apply(data, &mut tx, account.unwrap(), client),
"vbox_drop" => Rpc::vbox_drop(data, &mut tx, account.unwrap(), client),
"vbox_combine" => Rpc::vbox_combine(data, &mut tx, account.unwrap(), client),
"vbox_discard" => Rpc::vbox_discard(data, &mut tx, account.unwrap(), client),
_ => Err(format_err!("unknown method - {:?}", v.method)),
};
@@ -251,8 +254,6 @@ impl Rpc {
Ok(cryp_list)
}
fn account_create(data: Vec<u8>, tx: &mut Transaction, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
match from_slice::<AccountCreateMsg>(&data) {
Ok(v) => Ok(RpcResponse {
@@ -290,7 +291,7 @@ impl Rpc {
let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Decay }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Blast }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Drain }, tx, &account)?;
cryp_learn(CrypLearnParams { id: cryp.id, skill: Skill::Siphon }, tx, &account)?;
let name: String = iter::repeat(()).map(|()| rng.sample(Alphanumeric)).take(8).collect();
let cryp = cryp_spawn(CrypSpawnParams { name }, tx, &account)?;
@@ -314,13 +315,6 @@ impl Rpc {
})
}
fn account_items(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
})
}
fn account_zone(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
Ok(RpcResponse {
method: "zone_state".to_string(),
@@ -328,49 +322,6 @@ impl Rpc {
})
}
fn press_r(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
for action in [
ItemAction::RerollPhysDamage,
ItemAction::RerollSpellDamage,
ItemAction::RerollSpeed,
ItemAction::RerollStamina,
ItemAction::RerollArmour,
ItemAction::RerollSpellShield,
ItemAction::RerollEvasion,
ItemAction::SpecPhysDmg5,
ItemAction::SpecSpellDmg5,
].into_iter() {
let item = Item::new(*action, account.id);
item_create(item, tx, account.id)?;
}
let res = RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
};
return Ok(res);
}
fn item_use(data: Vec<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<ItemUseMsg>(&data).or(Err(err_msg("invalid params")))?;
item_use(msg.params, tx, &account)?;
Rpc::send_msg(client, RpcResponse {
method: "account_items".to_string(),
params: RpcResult::ItemList(items_list(tx, &account)?)
})?;
let cryps_list = RpcResponse {
method: "account_cryps".to_string(),
params: RpcResult::CrypList(account_cryps(tx, &account)?)
};
return Ok(cryps_list);
}
fn zone_create(_data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
// let _msg = from_slice::<ZoneCreateMsg>(&data).or(Err(err_msg("invalid params")))?;
@@ -404,6 +355,77 @@ impl Rpc {
return Ok(response);
}
fn vbox_state(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxStateMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_state(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_accept(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxAcceptMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_accept(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_discard(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxDiscardMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_discard(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_combine(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxCombineMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_combine(msg.params, tx, &account)?)
};
return Ok(response);
}
fn vbox_apply(data: Vec<u8>, tx: &mut Transaction, account: Account, client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxApplyMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_apply(msg.params, tx, &account)?)
};
Rpc::send_msg(client, RpcResponse {
method: "account_cryps".to_string(),
params: RpcResult::CrypList(account_cryps(tx, &account)?)
})?;
return Ok(response);
}
fn vbox_drop(data: Vec<u8>, tx: &mut Transaction, account: Account, _client: &mut WebSocket<TcpStream>) -> Result<RpcResponse, Error> {
let msg = from_slice::<VboxDropMsg>(&data).or(Err(err_msg("invalid params")))?;
let response = RpcResponse {
method: "vbox_state".to_string(),
params: RpcResult::VboxState(vbox_drop(msg.params, tx, &account)?)
};
return Ok(response);
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
@@ -422,10 +444,10 @@ pub enum RpcResult {
CrypList(Vec<Cryp>),
GameState(Game),
GameJoinableList(Vec<Game>),
ItemList(Vec<Item>),
ItemUse(()),
ZoneState(Zone),
ZoneClose(()),
VboxState(Vbox),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
@@ -589,24 +611,6 @@ struct AccountCrypsMsg {
params: (),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct ItemListMsg {
method: String,
params: (),
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct ItemUseMsg {
method: String,
params: ItemUseParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct ItemUseParams {
pub item: Uuid,
pub target: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct ZoneCreateMsg {
method: String,
@@ -637,6 +641,76 @@ pub struct ZoneCloseParams {
pub zone_id: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxStateMsg {
method: String,
params: VboxStateParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxStateParams {
pub game_id: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxAcceptMsg {
method: String,
params: VboxAcceptParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxAcceptParams {
pub game_id: Uuid,
pub index: usize,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxDiscardMsg {
method: String,
params: VboxDiscardParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxDiscardParams {
pub game_id: Uuid,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxCombineMsg {
method: String,
params: VboxCombineParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxCombineParams {
pub game_id: Uuid,
pub indices: Vec<usize>,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxApplyMsg {
method: String,
params: VboxApplyParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxApplyParams {
pub game_id: Uuid,
pub cryp_id: Uuid,
pub index: usize,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
struct VboxDropMsg {
method: String,
params: VboxDropParams,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct VboxDropParams {
pub game_id: Uuid,
pub index: usize,
}
// #[cfg(test)]
// mod tests {
+165 -165
View File
@@ -125,9 +125,9 @@ pub enum Effect {
Triage,
Decay,
Regen,
Drain,
Siphon,
SpeedDrain,
SpeedSiphon,
SpeedIncrease,
Ko,
@@ -137,13 +137,13 @@ impl Effect {
pub fn immune(&self, skill: Skill) -> bool {
match self {
Effect::Parry => match skill.category() {
Category::Spell => false,
Category::Physical => true,
Category::Blue => false,
Category::Red => true,
_ => false,
},
Effect::Shield => match skill.category() {
Category::Spell => true,
Category::Physical => false,
Category::Blue => true,
Category::Red => false,
_ => false,
},
Effect::Banish => true,
@@ -157,18 +157,18 @@ impl Effect {
Effect::Hex => true,
Effect::Banish => true,
Effect::Silence => match skill.category() {
Category::Spell => true,
Category::Physical => false,
Category::Blue => true,
Category::Red => false,
_ => false,
},
Effect::Snare => match skill.category() {
Category::Spell => false,
Category::Physical => true,
Category::Blue => false,
Category::Red => true,
_ => false,
},
Effect::Ko => match skill.category() {
Category::SpellTick => false,
Category::BlueTick => false,
_ => true,
},
_ => false,
@@ -177,12 +177,12 @@ impl Effect {
pub fn modifications(&self) -> Vec<Stat> {
match self {
Effect::Empower => vec![Stat::PhysicalDamage],
Effect::Vulnerable => vec![Stat::PhysicalDamageTaken],
Effect::Block => vec![Stat::PhysicalDamageTaken],
Effect::Empower => vec![Stat::RedDamage],
Effect::Vulnerable => vec![Stat::RedDamageTaken],
Effect::Block => vec![Stat::RedDamageTaken],
Effect::Amplify => vec![Stat::SpellDamage],
Effect::Curse => vec![Stat::SpellDamageTaken],
Effect::Amplify => vec![Stat::BlueDamage],
Effect::Curse => vec![Stat::BlueDamageTaken],
Effect::Haste => vec![Stat::Speed],
Effect::Slow => vec![Stat::Speed],
@@ -216,43 +216,43 @@ impl Effect {
pub fn category(&self) -> Category {
match self {
// physical
Effect::Stun => Category::PhysDebuff,
Effect::Block => Category::PhysBuff,
Effect::Parry => Category::PhysBuff,
Effect::Bleed => Category::PhysDebuff,
Effect::Leech => Category::PhysDebuff,
Effect::Airborne => Category::PhysDebuff,
Effect::Untouchable => Category::PhysBuff,
Effect::Deadly => Category::PhysBuff,
Effect::Vulnerable => Category::PhysDebuff,
Effect::Fury => Category::PhysBuff,
Effect::Blind => Category::PhysDebuff,
Effect::Snare => Category::PhysDebuff,
Effect::Stun => Category::RedDebuff,
Effect::Block => Category::RedBuff,
Effect::Parry => Category::RedBuff,
Effect::Bleed => Category::RedDebuff,
Effect::Leech => Category::RedDebuff,
Effect::Airborne => Category::RedDebuff,
Effect::Untouchable => Category::RedBuff,
Effect::Deadly => Category::RedBuff,
Effect::Vulnerable => Category::RedDebuff,
Effect::Fury => Category::RedBuff,
Effect::Blind => Category::RedDebuff,
Effect::Snare => Category::RedDebuff,
Effect::Empower => Category::PhysBuff,
Effect::Empower => Category::RedBuff,
// magic
Effect::Hex => Category::SpellDebuff,
Effect::Curse => Category::SpellDebuff,
Effect::Banish => Category::SpellDebuff, // todo randomise
Effect::Slow => Category::SpellDebuff,
Effect::Haste => Category::SpellBuff,
Effect::Enslave => Category::SpellDebuff,
Effect::Mesmerise => Category::SpellDebuff,
Effect::Amplify => Category::SpellBuff,
Effect::Silence => Category::SpellDebuff,
Effect::Hex => Category::BlueDebuff,
Effect::Curse => Category::BlueDebuff,
Effect::Banish => Category::BlueDebuff, // todo randomise
Effect::Slow => Category::BlueDebuff,
Effect::Haste => Category::BlueBuff,
Effect::Enslave => Category::BlueDebuff,
Effect::Mesmerise => Category::BlueDebuff,
Effect::Amplify => Category::BlueBuff,
Effect::Silence => Category::BlueDebuff,
// magic immunity
Effect::Shield => Category::SpellBuff,
Effect::Shield => Category::BlueBuff,
// effects over time
Effect::Triage => Category::SpellBuff,
Effect::Decay => Category::SpellDebuff,
Effect::Regen => Category::SpellBuff,
Effect::Drain => Category::SpellDebuff,
Effect::Triage => Category::BlueBuff,
Effect::Decay => Category::BlueDebuff,
Effect::Regen => Category::BlueBuff,
Effect::Siphon => Category::BlueDebuff,
Effect::SpeedDrain => Category::SpellDebuff,
Effect::SpeedIncrease => Category::SpellBuff,
Effect::SpeedSiphon => Category::BlueDebuff,
Effect::SpeedIncrease => Category::BlueBuff,
Effect::Ko => Category::Ko,
}
@@ -283,7 +283,7 @@ impl Effect {
Effect::Triage => 3,
Effect::Decay => 3,
Effect::Drain => 2,
Effect::Siphon => 2,
_ => {
println!("{:?} does not have a duration", self);
@@ -296,18 +296,18 @@ impl Effect {
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Category {
Physical,
PhysHeal,
PhysDmg,
PhysDebuff,
PhysBuff,
PhysTick,
Spell,
SpellDmg,
SpellHeal,
SpellDebuff,
SpellBuff,
SpellTick,
Red,
RedHeal,
RedDamage,
RedDebuff,
RedBuff,
RedTick,
Blue,
BlueDamage,
BlueHeal,
BlueDebuff,
BlueBuff,
BlueTick,
Ko,
}
@@ -318,8 +318,8 @@ pub enum Skill {
// -----------------
// Nature
// -----------------
Block, // reduce dmg
Parry, // avoid all dmg
Block, // reduce damage
Parry, // avoid all damage
Snare,
Paralyse,
@@ -345,7 +345,7 @@ pub enum Skill {
Heal,
Triage, // hot
TriageTick,
Throw, // no dmg stun, adds vulnerable
Throw, // no damage stun, adds vulnerable
Charm,
Calm,
Rez,
@@ -360,8 +360,8 @@ pub enum Skill {
Amplify,
Decay, // dot
DecayTick, // dot
Drain,
DrainTick,
Siphon,
SiphonTick,
Curse,
Plague, // aoe dot
Ruin, // aoe
@@ -389,12 +389,12 @@ pub enum Skill {
Haste,
Slow,
// used by tests, no cd, no dmg
// used by tests, no cd, no damage
TestTouch,
TestStun,
TestBlock,
TestParry,
TestDrain,
TestSiphon,
}
impl Skill {
@@ -405,8 +405,8 @@ impl Skill {
// -----------------
// Nature
// -----------------
Skill::Block => None, // reduce dmg
Skill::Parry => None, // avoid all dmg
Skill::Block => None, // reduce damage
Skill::Parry => None, // avoid all damage
Skill::Snare => Some(1),
Skill::Paralyse => Some(1),
@@ -431,7 +431,7 @@ impl Skill {
Skill::Heal => None,
Skill::Triage => None, // hot
Skill::TriageTick => None,
Skill::Throw => Some(1), // no dmg stun, adds vulnerable
Skill::Throw => Some(1), // no damage stun, adds vulnerable
Skill::Charm => Some(1),
Skill::Calm => None,
Skill::Rez => Some(2),
@@ -443,8 +443,8 @@ impl Skill {
Skill::Amplify => Some(1),
Skill::Decay => None, // dot
Skill::DecayTick => None,
Skill::Drain => Some(1),
Skill::DrainTick => None,
Skill::Siphon => Some(1),
Skill::SiphonTick => None,
Skill::Curse => Some(1),
Skill::Plague => Some(1), // aoe dot
Skill::Ruin => Some(2), // aoe
@@ -478,95 +478,95 @@ impl Skill {
Skill::TestTouch => None,
Skill::TestStun => None,
Skill::TestBlock => None,
Skill::TestDrain => None,
Skill::TestSiphon => None,
Skill::TestParry => None,
}
}
pub fn category(&self) -> Category {
match self {
Skill::Attack => Category::Physical,
Skill::Attack => Category::Red,
// -----------------
// Nature
// -----------------
Skill::Block => Category::Physical, // reduce dmg
Skill::Parry => Category::Physical, // avoid all dmg
Skill::Snare => Category::Physical,
Skill::Block => Category::Red, // reduce damage
Skill::Parry => Category::Red, // avoid all damage
Skill::Snare => Category::Red,
Skill::Paralyse => Category::Physical,
Skill::Strangle => Category::Physical,
Skill::Paralyse => Category::Red,
Skill::Strangle => Category::Red,
// Strangle
Skill::Stun => Category::Physical,
Skill::Stun => Category::Red,
// -----------------
// Technology
// -----------------
Skill::Replicate => Category::Physical,
Skill::Swarm => Category::Physical,
Skill::Orbit => Category::Physical,
Skill::Repair => Category::Physical,
Skill::Scan => Category::Physical, // track?
Skill::Replicate => Category::Red,
Skill::Swarm => Category::Red,
Skill::Orbit => Category::Red,
Skill::Repair => Category::Red,
Skill::Scan => Category::Red, // track?
// -----------------
// Preservation
// -----------------
Skill::Heal => Category::Physical,
Skill::Triage => Category::Spell, // hot
Skill::TriageTick => Category::SpellTick, // hot
Skill::Throw => Category::Physical, // no dmg stun, adds vulnerable
Skill::Charm => Category::Spell,
Skill::Calm => Category::Physical,
Skill::Rez => Category::Spell,
Skill::Heal => Category::Red,
Skill::Triage => Category::Blue, // hot
Skill::TriageTick => Category::BlueTick, // hot
Skill::Throw => Category::Red, // no damage stun, adds vulnerable
Skill::Charm => Category::Blue,
Skill::Calm => Category::Red,
Skill::Rez => Category::Blue,
// -----------------
// Destruction
// -----------------
Skill::Blast => Category::Spell,
Skill::Amplify => Category::Spell,
Skill::Decay => Category::Spell, // dot
Skill::DecayTick => Category::SpellTick, // hot
Skill::Drain => Category::Spell,
Skill::DrainTick => Category::SpellTick, // hot
Skill::Curse => Category::Spell,
Skill::Plague => Category::Spell, // aoe dot
Skill::Ruin => Category::Spell, // aoe
Skill::Blast => Category::Blue,
Skill::Amplify => Category::Blue,
Skill::Decay => Category::Blue, // dot
Skill::DecayTick => Category::BlueTick, // hot
Skill::Siphon => Category::Blue,
Skill::SiphonTick => Category::BlueTick, // hot
Skill::Curse => Category::Blue,
Skill::Plague => Category::Blue, // aoe dot
Skill::Ruin => Category::Blue, // aoe
// -----------------
// Purity
// -----------------
// Skill::Precision => 1,
Skill::Empower => Category::Physical,
Skill::Slay => Category::Physical,
Skill::Shield => Category::Spell,
Skill::Silence => Category::Spell,
Skill::Inquiry => Category::Spell,
Skill::Purify => Category::Spell,
Skill::Purge => Category::Spell,
Skill::Empower => Category::Red,
Skill::Slay => Category::Red,
Skill::Shield => Category::Blue,
Skill::Silence => Category::Blue,
Skill::Inquiry => Category::Blue,
Skill::Purify => Category::Blue,
Skill::Purge => Category::Blue,
// -----------------
// Chaos
// -----------------
Skill::Banish => Category::Spell,
Skill::Hex => Category::Spell,
Skill::Fear => Category::Spell,
Skill::Taunt => Category::Spell,
Skill::Pause => Category::Spell, // extend durations
Skill::Banish => Category::Blue,
Skill::Hex => Category::Blue,
Skill::Fear => Category::Blue,
Skill::Taunt => Category::Blue,
Skill::Pause => Category::Blue, // extend durations
// Skill::Lag => 2, //
Skill::Haste => Category::Spell,
Skill::Slow => Category::Spell,
Skill::Haste => Category::Blue,
Skill::Slow => Category::Blue,
// -----------------
// Test
// -----------------
Skill::TestTouch => Category::Physical,
Skill::TestStun => Category::Physical,
Skill::TestParry => Category::Physical,
Skill::TestBlock => Category::Physical,
Skill::TestDrain => Category::Spell,
Skill::TestTouch => Category::Red,
Skill::TestStun => Category::Red,
Skill::TestParry => Category::Red,
Skill::TestBlock => Category::Red,
Skill::TestSiphon => Category::Blue,
}
}
@@ -574,7 +574,7 @@ impl Skill {
match self {
Skill::TriageTick => true,
Skill::DecayTick => true,
Skill::DrainTick => true,
Skill::SiphonTick => true,
_ => false,
}
}
@@ -583,10 +583,10 @@ impl Skill {
match self {
// defensive block
Skill::Block => 10, // reduce dmg
Skill::Parry => 10, // avoid all dmg
Skill::Block => 10, // reduce damage
Skill::Parry => 10, // avoid all damage
Skill::Snare => 10,
Skill::Shield => 10, // avoid magic dmg,
Skill::Shield => 10, // avoid magic damage,
// fast phys combat
Skill::Attack => 5,
@@ -607,14 +607,14 @@ impl Skill {
// general combat
Skill::DecayTick => 2, // hot
Skill::Drain => 2,
Skill::DrainTick => 2, // hot
Skill::Siphon => 2,
Skill::SiphonTick => 2, // hot
Skill::Hex => 2,
Skill::Pause => 2, // extend durations
Skill::Plague => 2, // aoe dot
Skill::Silence => 2,
Skill::Stun => 2,
Skill::Throw => 2, // no dmg stun, adds vulnerable
Skill::Throw => 2, // no damage stun, adds vulnerable
Skill::TriageTick => 2, // hot
Skill::Heal => 1,
@@ -644,7 +644,7 @@ impl Skill {
Skill::TestStun => 5,
Skill::TestBlock => 10,
Skill::TestParry => 10,
Skill::TestDrain => 10,
Skill::TestSiphon => 10,
}
}
@@ -664,7 +664,7 @@ impl Skill {
return resolution;
}
match self.category() == Category::Physical {
match self.category() == Category::Red {
true => {
if let Some(evasion) = target.evade(*self) {
resolution.results.push(evasion);
@@ -703,7 +703,7 @@ impl Skill {
Skill::Heal => heal(source, target, resolution),
Skill::Triage => triage(source, target, resolution), // hot
Skill::TriageTick => triage_tick(source, target, resolution), // hot
Skill::Throw => throw(source, target, resolution), // no dmg stun, adds vulnerable
Skill::Throw => throw(source, target, resolution), // no damage stun, adds vulnerable
Skill::Charm => panic!("nyi"), // target casts random spell on teammate
Skill::Calm => panic!("nyi"), // physical fear, taunt removal
Skill::Rez => panic!("nyi"),
@@ -712,11 +712,11 @@ impl Skill {
// Destruction
// -----------------
Skill::Blast => blast(source, target, resolution),
Skill::Amplify => amplify(source, target, resolution), // increase magic dmg
Skill::Amplify => amplify(source, target, resolution), // increase magic damage
Skill::Decay => decay(source, target, resolution), // dot
Skill::DecayTick => decay_tick(source, target, resolution), // dot
Skill::Drain => drain(source, target, resolution),
Skill::DrainTick => drain_tick(source, target, resolution), // hot
Skill::Siphon => siphon(source, target, resolution),
Skill::SiphonTick => siphon_tick(source, target, resolution), // hot
Skill::Curse => curse(source, target, resolution),
Skill::Plague => panic!("nyi"), // dot that spreads every turn
Skill::Ruin => panic!("nyi"), // aoe version of blast
@@ -725,9 +725,9 @@ impl Skill {
// Purity
// -----------------
// Skill::Precision => panic!("nyi"),
Skill::Empower => empower(source, target, resolution), // increased phys dmg
Skill::Slay => panic!("nyi"), // phys dmg mult by target magic dmg
Skill::Shield => shield(source, target, resolution), // target is immune to magic dmg and fx
Skill::Empower => empower(source, target, resolution), // increased phys damage
Skill::Slay => panic!("nyi"), // phys damage mult by target magic damage
Skill::Shield => shield(source, target, resolution), // target is immune to magic damage and fx
Skill::Silence => silence(source, target, resolution), // target cannot cast spells
Skill::Inquiry => panic!("nyi"), //
Skill::Purify => purify(source, target, resolution), // dispel all debuffs
@@ -751,7 +751,7 @@ impl Skill {
Skill::TestStun => stun(source, target, resolution),
Skill::TestBlock => block(source, target, resolution),
Skill::TestParry => parry(source, target, resolution),
Skill::TestDrain => drain(source, target, resolution),
Skill::TestSiphon => siphon(source, target, resolution),
}
}
@@ -780,8 +780,8 @@ impl Skill {
}
fn attack(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.phys_dmg();
resolution.results.push(target.deal_phys_dmg(Skill::Attack, amount));
let amount = cryp.red_damage();
resolution.results.push(target.deal_red_damage(Skill::Attack, amount));
return resolution;
}
@@ -828,7 +828,7 @@ fn empower(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> R
}
fn heal(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg();
let amount = cryp.blue_damage();
resolution.results.push(target.heal(Skill::Heal, amount));
return resolution;
}
@@ -858,14 +858,14 @@ fn triage(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
}
fn triage_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg().wrapping_div(2);
let amount = cryp.blue_damage().wrapping_div(2);
resolution.results.push(target.heal(Skill::TriageTick, amount));
return resolution;
}
fn blast(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg();
resolution.results.push(target.deal_spell_dmg(Skill::Blast, amount));
let amount = cryp.blue_damage();
resolution.results.push(target.deal_blue_damage(Skill::Blast, amount));
return resolution;
}
@@ -898,8 +898,8 @@ fn decay(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Reso
}
fn decay_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg();
resolution.results.push(target.deal_spell_dmg(Skill::DecayTick, amount));
let amount = cryp.blue_damage();
resolution.results.push(target.deal_blue_damage(Skill::DecayTick, amount));
return resolution;
}
@@ -915,28 +915,28 @@ fn curse(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
return resolution;;
}
fn drain(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let drain = CrypEffect {
effect: Effect::Drain,
duration: Effect::Drain.duration(),
tick: Some(Cast::new_tick(cryp, target, Skill::DrainTick)),
fn siphon(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let siphon = CrypEffect {
effect: Effect::Siphon,
duration: Effect::Siphon.duration(),
tick: Some(Cast::new_tick(cryp, target, Skill::SiphonTick)),
};
resolution.results.push(target.add_effect(Skill::Drain, drain));
resolution.results.push(target.add_effect(Skill::Siphon, siphon));
return resolution;;
}
fn drain_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.spell_dmg();
let drain_dmg = target.deal_spell_dmg(Skill::DrainTick, amount);
resolution.results.push(drain_dmg.clone());
fn siphon_tick(cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Resolution {
let amount = cryp.blue_damage();
let siphon_damage = target.deal_blue_damage(Skill::SiphonTick, amount);
resolution.results.push(siphon_damage.clone());
match drain_dmg {
match siphon_damage {
ResolutionResult::Damage { amount, mitigation, category: _, immunity } => {
if !immunity.immune {
resolution.results.push(cryp.heal(Skill::Heal, amount));
}
},
_ => panic!("drain tick dmg not dealt {:?}", drain_dmg),
_ => panic!("siphon tick damage not dealt {:?}", siphon_damage),
}
return resolution;
@@ -960,7 +960,7 @@ fn purge(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Res
if !immune {
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if ce.effect.category() == Category::SpellBuff {
if ce.effect.category() == Category::BlueBuff {
target.effects.remove(i);
resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() });
}
@@ -976,7 +976,7 @@ fn purify(_cryp: &mut Cryp, target: &mut Cryp, mut resolution: Resolution) -> Re
if !immune {
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if ce.effect.category() == Category::SpellDebuff {
if ce.effect.category() == Category::BlueDebuff {
target.effects.remove(i);
resolution.results.push(ResolutionResult::Removal { effect: ce.effect, immunity: immunity.clone() });
}
@@ -1011,7 +1011,7 @@ mod tests {
.learn(Skill::Heal)
.create();
x.deal_phys_dmg(Skill::Attack, 5);
x.deal_red_damage(Skill::Attack, 5);
heal(&mut y, &mut x, Resolution::new(Skill::Heal));
}
@@ -1051,7 +1051,7 @@ mod tests {
.create();
// ensure it doesn't have 0 pd
x.phys_dmg.force(100);
x.red_damage.force(100);
y.hp.force(500);
block(&mut y.clone(), &mut y, Resolution::new(Skill::Block));
@@ -1078,13 +1078,13 @@ mod tests {
.create();
// ensure it doesn't have 0 sd
x.spell_dmg.force(50);
x.blue_damage.force(50);
// remove all mitigation
y.armour.force(0);
y.spell_shield.force(0);
y.red_shield.force(0);
y.blue_shield.force(0);
y.deal_phys_dmg(Skill::Attack, 5);
y.deal_red_damage(Skill::Attack, 5);
let prev_hp = y.hp();
let res = Resolution::new(Skill::Triage);
@@ -1118,11 +1118,11 @@ mod tests {
.level(8)
.create();
x.spell_dmg.force(50);
x.blue_damage.force(50);
amplify(&mut x.clone(), &mut x, Resolution::new(Skill::Amplify));
assert!(x.effects.iter().any(|e| e.effect == Effect::Amplify));
assert_eq!(x.spell_dmg(), 100);
assert_eq!(x.blue_damage(), 100);
}
#[test]
+8 -8
View File
@@ -25,30 +25,30 @@ impl Spec {
pub fn apply(&self, modified: u64, base: u64) -> u64 {
match self.spec {
SpecType::PhysDamage5 => modified + (base * 5 / 100),
SpecType::SpellDamage5 => modified + (base * 5 / 100),
SpecType::RedDamage5 => modified + (base * 5 / 100),
SpecType::BlueDamage5 => modified + (base * 5 / 100),
}
}
}
#[derive(Debug,Copy,Clone,Serialize,Deserialize,PartialEq)]
pub enum SpecType {
PhysDamage5,
SpellDamage5,
RedDamage5,
BlueDamage5,
}
impl SpecType {
fn affects(&self) -> Stat {
match *self {
SpecType::PhysDamage5 => Stat::PhysicalDamage,
SpecType::SpellDamage5 => Stat::SpellDamage,
SpecType::RedDamage5 => Stat::RedDamage,
SpecType::BlueDamage5 => Stat::BlueDamage,
}
}
fn level(&self) -> SpecLevel {
match *self {
SpecType::PhysDamage5 => SpecLevel::Common,
SpecType::SpellDamage5 => SpecLevel::Common,
SpecType::RedDamage5 => SpecLevel::Common,
SpecType::BlueDamage5 => SpecLevel::Common,
}
}
}
+406
View File
@@ -0,0 +1,406 @@
use std::iter;
use uuid::Uuid;
// drops
use rand::prelude::*;
use rand::{thread_rng};
use rand::distributions::{WeightedIndex};
use serde_cbor::{from_slice, to_vec};
use postgres::transaction::Transaction;
use failure::Error;
use failure::err_msg;
use account::Account;
use rpc::{VboxStateParams, VboxAcceptParams, VboxDiscardParams, VboxCombineParams, VboxApplyParams, VboxDropParams};
use skill::{Skill};
use cryp::{cryp_get, cryp_write};
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
pub enum Var {
Blue,
Green,
Red,
Attack,
Block,
Stun,
Buff,
Debuff,
Amplify,
Banish,
Blast,
Curse,
Empower,
Haste,
Heal,
Hex,
Parry,
Purge,
Purify,
Reflect,
Ruin,
Shield,
Silence,
Slay,
Slow,
Snare,
Strangle,
Strike,
Siphon,
Survival,
Taunt,
Throw,
Toxic,
Triage,
}
impl Var {
fn is_base(&self) -> bool {
match self {
Var::Attack |
Var::Block |
Var::Stun |
Var::Debuff |
Var::Buff => true,
_ => false,
}
}
fn skill(&self) -> Result<Skill, Error> {
match self {
Var::Amplify => Ok(Skill::Amplify),
Var::Banish => Ok(Skill::Banish),
Var::Blast => Ok(Skill::Blast),
Var::Curse => Ok(Skill::Curse),
Var::Empower => Ok(Skill::Empower),
Var::Haste => Ok(Skill::Haste),
Var::Heal => Ok(Skill::Heal),
Var::Hex => Ok(Skill::Hex),
Var::Parry => Ok(Skill::Parry),
Var::Purge => Ok(Skill::Purge),
Var::Purify => Ok(Skill::Purify),
// Var::Reflect => Ok(Skill::Reflect),
Var::Ruin => Ok(Skill::Ruin),
Var::Shield => Ok(Skill::Shield),
Var::Silence => Ok(Skill::Silence),
Var::Slay => Ok(Skill::Slay),
Var::Slow => Ok(Skill::Slow),
Var::Snare => Ok(Skill::Snare),
Var::Strangle => Ok(Skill::Strangle),
// Var::Strike => Ok(Skill::Strike),
// Var::Survival => Ok(Skill::Survival),
// Var::Taunt => Ok(Skill::Taunt),
Var::Throw => Ok(Skill::Throw),
// Var::Toxic => Ok(Skill::Toxic),
Var::Triage => Ok(Skill::Triage),
_ => Err(err_msg("not a usable var"))
}
}
}
#[derive(Debug,Clone,Copy,PartialEq,Serialize,Deserialize)]
enum ColourCode {
RR,
GG,
BB,
RG,
BR,
GB,
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Vbox {
pub id: Uuid,
pub balance: u16,
pub free: Vec<Var>,
pub bound: Vec<Var>,
pub game: Uuid,
pub account: Uuid,
}
impl Vbox {
pub fn new(account_id: Uuid, game_id: Uuid) -> Vbox {
Vbox {
id: Uuid::new_v4(),
account: account_id,
game: game_id,
free: vec![],
bound: vec![],
balance: 0,
}
}
pub fn fill(mut self: Vbox) -> Vbox {
let vars = vec![
(Var::Red, 1),
(Var::Green, 1),
(Var::Blue, 1),
(Var::Attack, 1),
(Var::Block, 1),
(Var::Buff, 1),
(Var::Debuff, 1),
(Var::Stun, 1),
];
self.free = iter::
repeat_with(|| {
let mut rng = thread_rng();
let dist = WeightedIndex::new(vars.iter().map(|item| item.1)).unwrap();
return vars[dist.sample(&mut rng)].0;
})
.take(8)
.collect::<Vec<Var>>();
self
}
pub fn accept(&mut self, i: usize) -> Result<&mut Vbox, Error> {
if self.bound.len() >= 9 {
return Err(err_msg("too many vars bound"));
}
self.free.get(i).ok_or(format_err!("no var at index {:?}", i))?;
self.bound.push(self.free.remove(i));
Ok(self)
}
pub fn drop(&mut self, i: usize) -> Result<&mut Vbox, Error> {
self.bound.get(i).ok_or(format_err!("no var at index {:?}", i))?;
self.bound.remove(i);
// balance update
Ok(self)
}
pub fn combine(&mut self, mut indices: Vec<usize>) -> Result<&mut Vbox, Error> {
if indices.len() != 3 {
return Err(err_msg("exactly 3 indices required"));
}
if !indices.iter().all(|i| self.bound.get(*i).is_some()) {
return Err(err_msg("var missing index"));
}
// have to sort the indices and keep track of the iteration
// because when removing the elements the array shifts
indices.sort();
let mut vars = indices
.iter()
.enumerate()
.map(|(i, index)| {
self.bound.remove(*index - i)
})
.collect::<Vec<Var>>();
let base_index = vars
.iter()
.position(|v| v.is_base())
.ok_or(err_msg("no base item selected"))?;
let base = vars.remove(base_index);
// fold colours into RGB
let colours = vars
.iter()
.fold([0, 0, 0], |mut acc, c| {
match c {
Var::Red => acc[0] += 1,
Var::Green => acc[1] += 1,
Var::Blue => acc[2] += 1,
_ => (),
};
acc
});
let colour_code = match colours {
[2,0,0] => ColourCode::RR,
[0,2,0] => ColourCode::GG,
[0,0,2] => ColourCode::BB,
[1,1,0] => ColourCode::RG,
[0,1,1] => ColourCode::GB,
[1,0,1] => ColourCode::BR,
_ => return Err(err_msg("not a combo")),
};
let new = match base {
Var::Attack => match colour_code {
ColourCode::RR => Var::Strike,
ColourCode::GG => Var::Heal,
ColourCode::BB => Var::Blast,
ColourCode::RG => Var::Slay, //
ColourCode::GB => return Err(err_msg("unhandled skill combo")),
ColourCode::BR => Var::Banish, //
},
Var::Block => match colour_code {
ColourCode::RR => Var::Parry,
ColourCode::GG => Var::Reflect,
ColourCode::BB => Var::Toxic,
ColourCode::RG => Var::Taunt,
ColourCode::GB => Var::Shield,
ColourCode::BR => return Err(err_msg("unhandled skill combo")),
},
Var::Buff => match colour_code {
ColourCode::RR => Var::Empower,
ColourCode::GG => Var::Triage,
ColourCode::BB => Var::Amplify,
ColourCode::RG => Var::Survival,
ColourCode::GB => return Err(err_msg("unhandled skill combo")),
ColourCode::BR => Var::Haste,
},
Var::Debuff => match colour_code {
ColourCode::RR => Var::Snare,
ColourCode::GG => Var::Purge,
ColourCode::BB => Var::Curse,
ColourCode::RG => return Err(err_msg("unhandled skill combo")),
ColourCode::GB => Var::Siphon,
ColourCode::BR => Var::Slow,
},
Var::Stun => match colour_code {
ColourCode::RR => Var::Strangle,
ColourCode::GG => Var::Throw,
ColourCode::BB => Var::Ruin,
ColourCode::RG => return Err(err_msg("unhandled skill combo")),
ColourCode::GB => Var::Silence,
ColourCode::BR => Var::Hex,
},
_ => panic!("wrong base {:?}", base),
};
self.bound.push(new);
Ok(self)
}
}
pub fn vbox_create(vbox: Vbox, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let vbox_bytes = to_vec(&vbox)?;
let query = "
INSERT INTO vbox (id, account, game, data)
VALUES ($1, $2, $3, $4)
RETURNING id;
";
let result = tx
.query(query, &[&vbox.id, &account.id, &vbox.game, &vbox_bytes])?;
result.iter().next().ok_or(format_err!("no vbox written"))?;
// println!("{:} wrote vbox", vbox.id);
return Ok(vbox);
}
pub fn vbox_write(vbox: Vbox, tx: &mut Transaction) -> Result<Vbox, Error> {
let vbox_bytes = to_vec(&vbox)?;
let query = "
UPDATE vbox
SET data = $1
WHERE id = $2
RETURNING id, account, data;
";
let result = tx
.query(query, &[&vbox_bytes, &vbox.id])?;
result.iter().next().ok_or(err_msg("no vbox row returned"))?;
// println!("{:?} wrote vbox", vbox.id);
return Ok(vbox);
}
pub fn vbox_get(tx: &mut Transaction, game_id: Uuid, account: &Account) -> Result<Vbox, Error> {
let query = "
SELECT *
FROM vbox
WHERE account = $1
AND game = $2;
";
let result = tx
.query(query, &[&account.id, &game_id])?;
let returned = match result.iter().next() {
Some(row) => row,
None => return Err(err_msg("vbox not found")),
};
// tells from_slice to cast into a cryp
let vbox_bytes: Vec<u8> = returned.get("data");
let vbox = from_slice::<Vbox>(&vbox_bytes)?;
return Ok(vbox);
}
pub fn vbox_state(params: VboxStateParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
match vbox_get(tx, params.game_id, account) {
Ok(v) => Ok(v),
Err(e) => {
println!("{:?}", e);
vbox_create(Vbox::new(account.id, params.game_id).fill(), tx, account)
}
}
}
pub fn vbox_discard(params: VboxDiscardParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let vbox = vbox_get(tx, params.game_id, account)?;
return vbox_write(vbox.fill(), tx);
}
pub fn vbox_accept(params: VboxAcceptParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.accept(params.index)?;
return vbox_write(vbox, tx);
}
pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.combine(params.indices)?;
return vbox_write(vbox, tx);
}
pub fn vbox_drop(params: VboxDropParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
vbox.drop(params.index)?;
return vbox_write(vbox, tx);
}
pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result<Vbox, Error> {
let mut vbox = vbox_get(tx, params.game_id, account)?;
let mut cryp = cryp_get(tx, params.cryp_id, account.id)?;
let var = vbox.bound.remove(params.index);
// done here because i teach them a tonne of skills for tests
let max_skills = 4;
if cryp.skills.len() >= max_skills {
return Err(format_err!("cryp at max skills ({:?})", max_skills));
}
let skill = var.skill()?;
cryp = cryp.learn(skill);
cryp_write(cryp, tx)?;
return vbox_write(vbox, tx);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn combine_test() {
let mut vbox = Vbox::new(Uuid::new_v4(), Uuid::new_v4());
vbox.bound = vec![Var::Attack, Var::Green, Var::Green];
vbox.combine(vec![1,2,0]).unwrap();
assert_eq!(vbox.bound[0], Var::Heal);
}
}