100 lines
3.2 KiB
Rust
100 lines
3.2 KiB
Rust
use game_service::battle::BattleBuilder;
|
|
use logic::battle::{LogicComponent, LogicObjectBody, LogicVector2, COMPONENT_COMBAT};
|
|
use logic::data::{table, LogicDataRef, LogicDataTables};
|
|
use logic::model::LogicClientAvatar;
|
|
use std::path::Path;
|
|
use std::sync::Arc;
|
|
use titan::LogicLong;
|
|
fn assets() -> std::path::PathBuf {
|
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../assets")
|
|
}
|
|
fn avatar(low: i32) -> LogicClientAvatar {
|
|
let account = LogicLong::new(0, low);
|
|
LogicClientAvatar {
|
|
avatar_id: account,
|
|
account_id: account,
|
|
home_id: account,
|
|
name_change_state: -1,
|
|
..LogicClientAvatar::default()
|
|
}
|
|
}
|
|
#[test]
|
|
fn shooter_double_update_on_fire() {
|
|
let root = assets();
|
|
let tables = LogicDataTables::load_from_dir(&root).expect("tables");
|
|
LogicDataTables::install(Arc::new(tables));
|
|
let builder = BattleBuilder::new(&root);
|
|
let mut mode = builder
|
|
.build(
|
|
LogicDataRef::by_name(table::LOCATIONS, "PvP_goblin"),
|
|
LogicDataRef::None,
|
|
LogicDataRef::by_name(table::ARENAS, "Arena_T"),
|
|
vec![avatar(5), avatar(0)],
|
|
[None, None],
|
|
1,
|
|
)
|
|
.expect("battle");
|
|
let spell = LogicDataRef::spell("Archer");
|
|
for entry in builder.summon(&spell, LogicVector2::new(14500, 23500), 0, 0, 100) {
|
|
mode.battle.objects.push(entry);
|
|
}
|
|
const ARCHER_LOAD_TIME: i32 = 1000;
|
|
let load_timer_of = |mode: &logic::battle::LogicGameMode, id: i32| -> Option<i32> {
|
|
mode.battle.objects.objects.iter().find_map(|entry| {
|
|
if entry.global_id.0?.instance_id != id {
|
|
return None;
|
|
}
|
|
match entry.components.get(COMPONENT_COMBAT)? {
|
|
Some(LogicComponent::Combat(combat)) => Some(combat.load_timer),
|
|
_ => None,
|
|
}
|
|
})
|
|
};
|
|
let archer_ref = mode
|
|
.battle
|
|
.objects
|
|
.objects
|
|
.iter()
|
|
.find(|entry| entry.data.name() == "Archer")
|
|
.map(|entry| entry.global_id)
|
|
.expect("the archer is on the board");
|
|
let archer = archer_ref
|
|
.0
|
|
.expect("the archer has a global id")
|
|
.instance_id;
|
|
let mut shots = 0usize;
|
|
let mut seen: Vec<logic::battle::LogicGameObjectRef> = Vec::new();
|
|
for tick in 0..(20 * 20) {
|
|
mode.battle.tick(tick);
|
|
let fresh: Vec<_> = mode
|
|
.battle
|
|
.objects
|
|
.objects
|
|
.iter()
|
|
.filter_map(|entry| match &entry.body {
|
|
LogicObjectBody::Projectile(shot) if shot.source == archer_ref => {
|
|
Some(entry.global_id)
|
|
}
|
|
_ => None,
|
|
})
|
|
.filter(|id| !seen.contains(id))
|
|
.collect();
|
|
for id in &fresh {
|
|
seen.push(*id);
|
|
}
|
|
if fresh.is_empty() {
|
|
continue;
|
|
}
|
|
shots += 1;
|
|
let load_timer = load_timer_of(&mode, archer).expect("the archer has a combat component");
|
|
assert_eq!(
|
|
load_timer,
|
|
ARCHER_LOAD_TIME - logic::battle::TICK_MILLISECONDS,
|
|
"t={tick}"
|
|
);
|
|
}
|
|
assert!(
|
|
shots > 1,
|
|
"shots={shots}"
|
|
);
|
|
}
|