bugs ahoy and icons

This commit is contained in:
ntr 2019-04-10 18:31:11 +10:00
parent 4747bc7dec
commit 5b5de416e1
13 changed files with 330 additions and 140 deletions

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="1.375in" height="0.555556in"
viewBox="0 0 99 40">
<path id="Unnamed #8"
fill="none" stroke="black" stroke-width="1"
d="M 3.91,34.64
C 3.91,34.64 95.00,34.64 95.00,34.64M 3.91,25.09
C 3.91,25.09 95.00,25.09 95.00,25.09M 3.82,14.00
C 3.82,14.00 94.91,14.00 94.91,14.00M 3.91,4.00
C 3.91,4.00 95.00,4.00 95.00,4.00" />
</svg>

After

Width:  |  Height:  |  Size: 624 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="1.38889in" height="0.555556in"
viewBox="0 0 100 40">
<path id="Path"
fill="none" stroke="black" stroke-width="1"
d="M 50.00,4.00
C 50.00,4.00 50.00,36.00 50.00,36.00M 4.00,20.00
C 4.00,20.00 96.00,20.00 96.00,20.00" />
</svg>

After

Width:  |  Height:  |  Size: 505 B

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="1.375in" height="0.555556in"
viewBox="0 0 99 40">
<path id="Path #6"
fill="none" stroke="black" stroke-width="1"
d="M 4.00,35.00
C 4.00,35.00 95.00,35.00 95.00,35.00M 8.91,29.91
C 8.91,29.91 89.91,29.91 89.91,29.91M 14.91,24.91
C 14.91,24.91 85.00,25.00 85.00,25.00M 21.00,19.00
C 21.00,19.00 78.91,18.91 78.91,18.91M 15.09,14.18
C 15.09,14.18 85.00,14.09 85.00,14.09M 9.00,9.09
C 9.00,9.09 89.91,9.09 89.91,9.09M 4.00,4.09
C 4.00,4.09 94.91,4.09 94.91,4.09" />
</svg>

After

Width:  |  Height:  |  Size: 803 B

View File

@ -412,8 +412,8 @@ header {
}
.vbox-table td svg {
stroke-width: 1.5px;
height: 95%;
stroke-width: 2px;
height: 96%;
vertical-align: text-bottom;
}

View File

@ -229,7 +229,7 @@ module.exports = {
upgrades: 'combine with 2 red / blue / green',
},
LifeI: {
GreenLifeI: {
description: 'Increases life',
colours: ['green'],
thresholds: [5, 10, 20],

View File

@ -1,31 +1,31 @@
const preact = require('preact');
module.exports = function triangle(classes) {
module.exports = function vboxColour(classes) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 40" className={classes} >
<path id="Unnamed"
fill="none" strokeWidth="1px"
d="M 21.18,19.55
C 21.18,19.55 78.55,19.55 78.55,19.55M 85.00,14.00
C 85.00,14.00 85.00,25.00 85.00,25.00
d="M 20,20
C 20,20 80,20 80,20M 85.00,15.00
C 85.00,15.00 85.00,25.00 85.00,25.00
85.00,25.00 15.00,25.00 15.00,25.00
15.00,25.00 15.00,14.00 15.00,14.00
15.00,14.00 85.00,14.00 85.00,14.00 Z
M 85.00,14.00
C 85.00,14.00 85.00,25.00 85.00,25.00
15.00,25.00 15.00,15.00 15.00,15.00
15.00,15.00 85.00,15.00 85.00,15.00 Z
M 85.00,15.00
C 85.00,15.00 85.00,25.00 85.00,25.00
85.00,25.00 15.00,25.00 15.00,25.00
15.00,25.00 15.00,14.00 15.00,14.00
15.00,14.00 85.00,14.00 85.00,14.00 Z
M 95.00,4.00
C 95.00,4.00 95.00,35.00 95.00,35.00
95.00,35.00 4.00,35.00 4.00,35.00
4.00,35.00 4.00,4.00 4.00,4.00
4.00,4.00 95.00,4.00 95.00,4.00 Z
M 90.00,9.00
C 90.00,9.00 90.00,30.00 90.00,30.00
90.00,30.00 9.00,30.00 9.00,30.00
9.00,30.00 9.00,9.00 9.00,9.00
9.00,9.00 90.00,9.00 90.00,9.00 Z" />
15.00,25.00 15.00,15.00 15.00,15.00
15.00,15.00 85.00,15.00 85.00,15.00 Z
M 95.00,5.00
C 95.00,5.00 95.00,35.00 95.00,35.00
95.00,35.00 5.00,35.00 5.00,35.00
5.00,35.00 5.00,5.00 5.00,5.00
5.00,5.00 95.00,5.00 95.00,5.00 Z
M 90.00,10.00
C 90.00,10.00 90.00,30.00 90.00,30.00
90.00,30.00 10.00,30.00 10.00,30.00
10.00,30.00 10.00,10.00 10.00,10.00
10.00,10.00 90.00,10.00 90.00,10.00 Z" />
</svg>
);
}
};

View File

@ -92,9 +92,9 @@ const SPECS = {
};
const COLOUR_ICONS = {
red: { colour: 'red', caption: 'red', svg: shapes.hexagon },
blue: { colour: 'blue', caption: 'blue', svg: shapes.hexagon },
green: { colour: 'green', caption: 'green', svg: shapes.hexagon },
red: { colour: 'red', caption: 'red', svg: shapes.square },
blue: { colour: 'blue', caption: 'blue', svg: shapes.square },
green: { colour: 'green', caption: 'green', svg: shapes.square },
};
module.exports = {

View File

@ -270,7 +270,13 @@ impl Game {
}
for (team_id, mob_id, target_id, s) in pve_skills {
self.add_skill(team_id, mob_id, target_id, s).expect("unable to add pve mob skill");
match self.add_skill(team_id, mob_id, target_id, s) {
Ok(_) => (),
Err(e) => {
println!("{:?}", self.cryp_by_id(mob_id));
panic!("{:?} unable to add pve mob skill {:?}", e, s);
},
}
}
self

View File

@ -59,7 +59,9 @@ impl Instance {
self.players = iter::repeat_with(|| {
let bot_id = Uuid::new_v4();
let cryps = instance_mobs(bot_id);
Player::new(bot_id, self.id, &bot_id.to_string(), cryps).set_bot(true)
let mut p = Player::new(bot_id, self.id, &bot_id.to_string(), cryps).set_bot(true);
p.autobuy();
p
})
.take(15)
.collect::<Vec<Player>>();
@ -199,16 +201,7 @@ impl Instance {
fn bot_vbox_phase(&mut self) -> &mut Instance {
for bot in self.players.iter_mut().filter(|p| p.bot) {
bot.vbox.fill();
// paths for what to do
// use a spec
// craft a spec
// craft a skill
// check for cryps w/ no skills
// create a skill()
// find base
// pick 2 random colours
bot.autobuy();
bot.set_ready(true);
}
@ -585,6 +578,7 @@ mod tests {
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
player.autobuy();
instance.add_player(player.clone());
assert!(instance.can_start());
@ -605,4 +599,13 @@ mod tests {
assert_eq!(instance.rounds.len(), 3);
}
#[test]
fn instance_bot_vbox_test() {
let mut instance = Instance::new();
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, instance.id, &"test".to_string(), cryps).set_bot(true);
}
}

View File

@ -33,8 +33,8 @@ pub fn generate_mob() -> Cryp {
pub fn instance_mobs(team_id: Uuid) -> Vec<Cryp> {
iter::repeat_with(||
generate_mob()
.set_account(team_id)
.learn(Skill::Attack))
.set_account(team_id))
// .learn(Skill::Attack))
.take(3)
.collect::<Vec<Cryp>>()
}

View File

@ -1,4 +1,5 @@
use uuid::Uuid;
use rand::prelude::*;
use serde_cbor::{from_slice, to_vec};
@ -8,11 +9,13 @@ use failure::Error;
use failure::err_msg;
use account::Account;
use cryp::{Cryp, cryp_get};
use vbox::{Vbox};
use cryp::{Cryp, Colours, cryp_get};
use vbox::{Vbox, Var, VarEffect};
use rpc::{PlayerStateParams, PlayerCrypsSetParams};
use instance::{instance_get, instance_update};
const DISCARD_COST: u16 = 5;
#[derive(Debug,Clone,Copy,Serialize,Deserialize)]
pub struct Score {
pub wins: u8,
@ -74,6 +77,193 @@ impl Player {
pub fn cryp_get(&mut self, id: Uuid) -> Result<&mut Cryp, Error> {
self.cryps.iter_mut().find(|c| c.id == id).ok_or(err_msg("cryp not found"))
}
pub fn autobuy(&mut self) -> &mut Player {
let mut rng = thread_rng();
// first check if any cryps have no skills
// if there is one find an item in vbox that gives a skill
while let Some(c) = self.cryps.iter().position(|c| c.skills.len() == 0) {
if let Some(s) = self.vbox.bound.iter().position(|v| v.into_skill().is_some()) {
let cryp_id = self.cryps[c].id;
self.vbox_apply(s, cryp_id).expect("could not apply");
continue;
}
println!("no skills available...");
}
// now keep buying and applying items cause whynot
// inb4 montecarlo gan
loop {
let (target_cryp_i, target_cryp_id) = match self.cryps.iter().any(|c| c.skills.len() < 3) {
true => {
let mut target_cryp_i = 0;
for (j, c) in self.cryps.iter().enumerate() {
if c.skills.len() < self.cryps[target_cryp_i].skills.len() {
target_cryp_i = j;
}
}
(target_cryp_i, self.cryps[target_cryp_i].id)
},
false => {
let i = rng.gen_range(0, 3);
(i, self.cryps[i].id)
},
};
let needs_skills = self.cryps[target_cryp_i].skills.len() < 3;
let group_i = match needs_skills {
true => 1,
false => 2,
};
if self.vbox.bound.len() < 3 {
if (needs_skills && self.vbox.bits < 4) || self.vbox.bits < 5 {
// println!("insufficient balance");
return self;
}
// get 2 colours and something else
if self.vbox.free[0].len() < 2 {
return self;
}
self.vbox_accept(0, 0).expect("could't accept colour 0");
self.vbox_accept(0, 0).expect("could't accept colour 1");
self.vbox_accept(group_i, 0).expect("could't accept group 0");
}
// println!("{:?}", self.vbox.bound);
let skills = [Var::Attack, Var::Block, Var::Buff, Var::Debuff, Var::Stun];
let combo_i = match group_i {
1 => self.vbox.bound.iter().position(|v| skills.contains(v)).expect("no skill found"),
2 => self.vbox.bound.iter().position(|v| v.into_spec().is_some()).expect("no spec found"),
_ => panic!("unknown group_i"),
};
// first 2 colours can be whatever
match self.vbox_combine(vec![0, 1, combo_i]) {
Ok(_) => {
// println!("refined {:?}", self.vbox.bound[self.vbox.bound.len() - 1]);
}
Err(e) => println!("{:?}", e),
};
let var_i = self.vbox.bound.len() - 1;
match self.vbox_apply(var_i, target_cryp_id) {
Ok(_) => {
// println!("{:?} improved", self.cryps[target_cryp_i].name);
},
Err(e) => println!("{:?}", e),
}
}
}
pub fn vbox_discard(&mut self) -> Result<&mut Player, Error> {
self.vbox.balance_sub(DISCARD_COST)?;
self.vbox.fill();
Ok(self)
}
pub fn vbox_accept(&mut self, group: usize, index: usize) -> Result<&mut Player, Error> {
self.vbox.accept(group, index)?;
Ok(self)
}
pub fn vbox_combine(&mut self, indices: Vec<usize>) -> Result<&mut Player, Error> {
self.vbox.combine(indices)?;
Ok(self)
}
pub fn vbox_reclaim(&mut self, index: usize) -> Result<&mut Player, Error> {
self.vbox.reclaim(index)?;
Ok(self)
}
pub fn vbox_apply(&mut self, index: usize, cryp_id: Uuid) -> Result<&mut Player, Error> {
let var = self.vbox.bound.remove(index);
match var.effect() {
Some(VarEffect::Skill) => {
let skill = var.into_skill().ok_or(format_err!("var {:?} has no associated skill", var))?;
let cryp = self.cryp_get(cryp_id)?;
// done here because i teach them a tonne of skills for tests
let max_skills = 3;
if cryp.skills.len() >= max_skills {
return Err(format_err!("cryp at max skills ({:?})", max_skills));
}
if cryp.knows(skill) {
return Err(format_err!("cryp already knows skill ({:?})" , skill));
}
cryp.learn_mut(skill);
},
Some(VarEffect::Spec) => {
let spec = var.into_spec().ok_or(format_err!("var {:?} has no associated spec", var))?;
let cryp = self.cryp_get(cryp_id)?;
cryp.spec_add(spec)?;
},
None => return Err(err_msg("var has no effect on cryps")),
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
blue: tc.blue + c.colours.blue
}
});
for cryp in self.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
}
Ok(self)
}
pub fn vbox_unequip(&mut self, target: Var, cryp_id: Uuid) -> Result<&mut Player, Error> {
if self.vbox.bound.len() >= 9 {
return Err(err_msg("too many vars bound"));
}
match target.effect() {
Some(VarEffect::Skill) => {
let skill = target.into_skill().ok_or(format_err!("var {:?} has no associated skill", target))?;
let cryp = self.cryp_get(cryp_id)?;
cryp.forget(skill)?;
},
Some(VarEffect::Spec) => {
let spec = target.into_spec().ok_or(format_err!("var {:?} has no associated spec", target))?;
let cryp = self.cryp_get(cryp_id)?;
cryp.spec_remove(spec)?;
},
None => return Err(err_msg("var has no effect on cryps")),
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = self.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
blue: tc.blue + c.colours.blue
}
});
for cryp in self.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
}
self.vbox.bound.push(target);
self.vbox.bound.sort_unstable();
Ok(self)
}
}
pub fn player_get(tx: &mut Transaction, account_id: Uuid, instance_id: Uuid) -> Result<Player, Error> {
@ -191,3 +381,19 @@ pub fn player_mm_cryps_set(params: PlayerCrypsSetParams, tx: &mut Transaction, a
}
}
}
#[cfg(test)]
mod tests {
use mob::instance_mobs;
use super::*;
#[test]
fn player_bot_vbox_test() {
let player_account = Uuid::new_v4();
let cryps = instance_mobs(player_account);
let mut player = Player::new(player_account, Uuid::new_v4(), &"test".to_string(), cryps).set_bot(true);
player.autobuy();
println!("{:#?}", player);
}
}

View File

@ -1075,23 +1075,23 @@ fn silence(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Re
}
fn purge(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions {
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if [Category::BlueBuff, Category::RedBuff].contains(&ce.effect.category()) {
target.effects.remove(i);
while let Some(i) = target.effects
.iter()
.position(|ce| [Category::BlueBuff, Category::RedBuff].contains(&ce.effect.category())) {
let ce = target.effects.remove(i);
results.push(Resolution::new(source, target).event(Event::Removal { effect: ce.effect }));
}
}
return results;
}
fn purify(source: &mut Cryp, target: &mut Cryp, mut results: Resolutions) -> Resolutions {
for (i, ce) in target.effects.clone().iter_mut().enumerate() {
if [Category::BlueDebuff, Category::RedDebuff].contains(&ce.effect.category()) {
target.effects.remove(i);
while let Some(i) = target.effects
.iter()
.position(|ce| [Category::BlueDebuff, Category::RedDebuff].contains(&ce.effect.category())) {
let ce = target.effects.remove(i);
results.push(Resolution::new(source, target).event(Event::Removal { effect: ce.effect }));
}
}
return results;
}

View File

@ -101,7 +101,7 @@ pub enum Var {
TestSiphon,
}
enum VarEffect {
pub enum VarEffect {
Skill,
Spec,
}
@ -167,7 +167,7 @@ impl Var {
}
}
fn effect(&self) -> Option<VarEffect> {
pub fn effect(&self) -> Option<VarEffect> {
if let Some(_skill) = self.into_skill() {
return Some(VarEffect::Skill);
}
@ -177,7 +177,7 @@ impl Var {
return None;
}
fn into_skill(&self) -> Option<Skill> {
pub fn into_skill(&self) -> Option<Skill> {
match self {
Var::Attack => Some(Skill::Attack),
Var::Amplify => Some(Skill::Amplify),
@ -215,7 +215,7 @@ impl Var {
}
}
fn into_spec(&self) -> Option<Spec> {
pub fn into_spec(&self) -> Option<Spec> {
match *self {
Var::Speed => Some(Spec::Speed),
Var::RedSpeedI => Some(Spec::RedSpeedI),
@ -255,6 +255,7 @@ impl From<Skill> for Var {
Skill::Blast => Var::Blast,
Skill::Block => Var::Block,
Skill::Curse => Var::Curse,
Skill::Clutch => Var::Clutch,
Skill::Decay => Var::Decay,
Skill::Empower => Var::Empower,
Skill::Haste => Var::Haste,
@ -363,7 +364,7 @@ fn get_combos() -> Vec<Combo> {
Combo { units: vec![Var::Attack, Var::Blue, Var::Blue], var: Var::Blast },
Combo { units: vec![Var::Attack, Var::Red, Var::Green], var: Var::Purify },
Combo { units: vec![Var::Attack, Var::Green, Var::Blue], var: Var::Decay },
// Combo { units: vec![Var::Attack, Var::Red, Var::Blue], var: Var::Blast },
Combo { units: vec![Var::Attack, Var::Red, Var::Blue], var: Var::Blast }, // AAAAAAAAAAAAAAAAAA
Combo { units: vec![Var::Damage, Var::Red, Var::Red], var: Var::RedDamageI },
Combo { units: vec![Var::Damage, Var::Green, Var::Green], var: Var::GreenDamageI },
@ -495,6 +496,7 @@ impl Vbox {
// actually move
self.bound.push(self.free[i].remove(j));
self.bound.sort_unstable();
Ok(self)
}
@ -535,118 +537,45 @@ impl Vbox {
let combo = combos.iter().find(|c| c.units == input).ok_or(err_msg("not a combo"))?;
self.bound.push(combo.var);
self.bound.sort_unstable();
Ok(self)
}
}
const DISCARD_COST: u16 = 5;
pub fn vbox_discard(params: VboxDiscardParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
player.vbox.balance_sub(DISCARD_COST)?;
player.vbox.fill();
player.vbox_discard()?;
return player_update(tx, player, false);
}
pub fn vbox_accept(params: VboxAcceptParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
player.vbox.accept(params.group, params.index)?;
player.vbox_accept(params.group, params.index)?;
return player_update(tx, player, false);
}
pub fn vbox_combine(params: VboxCombineParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
player.vbox.combine(params.indices)?;
player.vbox_combine(params.indices)?;
return player_update(tx, player, false);
}
pub fn vbox_reclaim(params: VboxReclaimParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
player.vbox.reclaim(params.index)?;
player.vbox_reclaim(params.index)?;
return player_update(tx, player, false);
}
pub fn vbox_apply(params: VboxApplyParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
let var = player.vbox.bound.remove(params.index);
match var.effect() {
Some(VarEffect::Skill) => {
let skill = var.into_skill().ok_or(format_err!("var {:?} has no associated skill", var))?;
let cryp = player.cryp_get(params.cryp_id)?;
// done here because i teach them a tonne of skills for tests
let max_skills = 3;
if cryp.skills.len() >= max_skills {
return Err(format_err!("cryp at max skills ({:?})", max_skills));
}
cryp.learn_mut(skill);
},
Some(VarEffect::Spec) => {
let spec = var.into_spec().ok_or(format_err!("var {:?} has no associated spec", var))?;
let cryp = player.cryp_get(params.cryp_id)?;
cryp.spec_add(spec)?;
},
None => return Err(err_msg("var has no effect on cryps")),
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = player.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
blue: tc.blue + c.colours.blue
}
});
for cryp in player.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
}
player.vbox_apply(params.index, params.cryp_id)?;
return player_update(tx, player, false);
}
pub fn vbox_unequip(params: VboxUnequipParams, tx: &mut Transaction, account: &Account) -> Result<Player, Error> {
let mut player = player_get(tx, account.id, params.instance_id)?;
if player.vbox.bound.len() >= 9 {
return Err(err_msg("too many vars bound"));
}
println!("{:?}", params);
match params.target.effect() {
Some(VarEffect::Skill) => {
let skill = params.target.into_skill().ok_or(format_err!("var {:?} has no associated skill", params.target))?;
let cryp = player.cryp_get(params.cryp_id)?;
cryp.forget(skill)?;
},
Some(VarEffect::Spec) => {
let spec = params.target.into_spec().ok_or(format_err!("var {:?} has no associated spec", params.target))?;
let cryp = player.cryp_get(params.cryp_id)?;
cryp.spec_remove(spec)?;
},
None => return Err(err_msg("var has no effect on cryps")),
}
// now the var has been applied
// recalculate the stats of the whole team
let team_colours = player.cryps.iter().fold(Colours::new(), |tc, c| {
Colours {
red: tc.red + c.colours.red,
green: tc.green + c.colours.green,
blue: tc.blue + c.colours.blue
}
});
for cryp in player.cryps.iter_mut() {
cryp.apply_modifiers(&team_colours);
}
player.vbox.bound.push(params.target);
player.vbox_unequip(params.target, params.cryp_id)?;
return player_update(tx, player, false);
}