deal the summoner a starting hand
the card bar was empty because the hand lives on the king tower, not on the battle. LogicSummoner::decode gates a whole block behind one boolean - setEncodeDeckDataEnabled on the client side - and we always wrote it false, so the client kept the hand and the draw queue it was born with, which is nothing. the block holds four deck indices for the hand, then two int lists: the draw queue getNextSpell walks and the used pile reshuffleDeck folds back into it. we now hand out the first four slots and queue the rest, leave the used pile empty and keep last used at -1, which is what getLastUsedSpell reads as "none". starting mana comes from the START_MANA global instead of zero, and the field after last-used is named after clearSpellCooldowns, which is the only thing that writes it.
This commit is contained in:
parent
58d137ccd2
commit
3cba764841
2 changed files with 35 additions and 7 deletions
|
|
@ -2,16 +2,18 @@ use std::path::{Path, PathBuf};
|
||||||
use logic::battle::{
|
use logic::battle::{
|
||||||
LogicBattle, LogicCharacter, LogicCharacterBuffComponent, LogicCombatComponent, LogicComponent,
|
LogicBattle, LogicCharacter, LogicCharacterBuffComponent, LogicCombatComponent, LogicComponent,
|
||||||
LogicGameMode, LogicGameObject, LogicGameObjectEntry, LogicGameObjectManager,
|
LogicGameMode, LogicGameObject, LogicGameObjectEntry, LogicGameObjectManager,
|
||||||
LogicGameObjectRef, LogicHitpointComponent, LogicObjectBody, LogicSummoner, LogicTilemap,
|
LogicGameObjectRef, LogicHitpointComponent, LogicObjectBody, LogicSummoner, LogicSummonerDeck,
|
||||||
|
LogicTilemap,
|
||||||
LogicTime, LogicVector2, BATTLE_TYPE_NPC, CHARACTER_OBJECT_TYPE, DIRECTION_BOTTOM,
|
LogicTime, LogicVector2, BATTLE_TYPE_NPC, CHARACTER_OBJECT_TYPE, DIRECTION_BOTTOM,
|
||||||
DIRECTION_TOP, SUBTILE_UNITS,
|
DIRECTION_TOP, SUBTILE_UNITS,
|
||||||
};
|
};
|
||||||
use logic::model::{LogicClientAvatar, LogicSpellDeck};
|
use logic::model::{LogicClientAvatar, LogicSpellDeck};
|
||||||
use logic::{table, LogicDataRef, LogicDataTables, LogicRandom};
|
use logic::{table, LogicDataRef, LogicDataTables, LogicGlobals, LogicRandom};
|
||||||
pub const LOCATION_FILE_COLUMN: &str = "FileName";
|
pub const LOCATION_FILE_COLUMN: &str = "FileName";
|
||||||
pub const CHARACTER_KING_TOWER: &str = "KingTower";
|
pub const CHARACTER_KING_TOWER: &str = "KingTower";
|
||||||
pub const CHARACTER_PRINCESS_TOWER: &str = "PrincessTower";
|
pub const CHARACTER_PRINCESS_TOWER: &str = "PrincessTower";
|
||||||
pub const BUFF_ARRAY_TABLE: i32 = table::DAMAGE_TYPES;
|
pub const BUFF_ARRAY_TABLE: i32 = table::DAMAGE_TYPES;
|
||||||
|
pub const START_MANA_GLOBAL: &str = "START_MANA";
|
||||||
pub struct TowerSpec {
|
pub struct TowerSpec {
|
||||||
pub data: LogicDataRef,
|
pub data: LogicDataRef,
|
||||||
pub instance: i32,
|
pub instance: i32,
|
||||||
|
|
@ -20,10 +22,12 @@ pub struct TowerSpec {
|
||||||
pub level_index: i32,
|
pub level_index: i32,
|
||||||
pub is_leader: bool,
|
pub is_leader: bool,
|
||||||
pub summoner: bool,
|
pub summoner: bool,
|
||||||
|
pub deck_slots: usize,
|
||||||
}
|
}
|
||||||
pub struct BattleBuilder {
|
pub struct BattleBuilder {
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
buff_type_count: usize,
|
buff_type_count: usize,
|
||||||
|
start_mana: i32,
|
||||||
}
|
}
|
||||||
fn tile_to_units(tile: i32) -> i32 {
|
fn tile_to_units(tile: i32) -> i32 {
|
||||||
tile.saturating_mul(SUBTILE_UNITS)
|
tile.saturating_mul(SUBTILE_UNITS)
|
||||||
|
|
@ -54,6 +58,7 @@ impl BattleBuilder {
|
||||||
Self {
|
Self {
|
||||||
root: root.as_ref().to_path_buf(),
|
root: root.as_ref().to_path_buf(),
|
||||||
buff_type_count,
|
buff_type_count,
|
||||||
|
start_mana: LogicGlobals::number(START_MANA_GLOBAL),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn buff_type_count(&self) -> usize {
|
pub fn buff_type_count(&self) -> usize {
|
||||||
|
|
@ -78,6 +83,7 @@ impl BattleBuilder {
|
||||||
level_index,
|
level_index,
|
||||||
is_leader,
|
is_leader,
|
||||||
summoner,
|
summoner,
|
||||||
|
deck_slots,
|
||||||
} = spec;
|
} = spec;
|
||||||
let hitpoints = data
|
let hitpoints = data
|
||||||
.data()
|
.data()
|
||||||
|
|
@ -105,6 +111,8 @@ impl BattleBuilder {
|
||||||
let body = if summoner {
|
let body = if summoner {
|
||||||
LogicObjectBody::Summoner(Box::new(LogicSummoner {
|
LogicObjectBody::Summoner(Box::new(LogicSummoner {
|
||||||
character,
|
character,
|
||||||
|
deck: Some(LogicSummonerDeck::starting(deck_slots)),
|
||||||
|
mana: self.start_mana,
|
||||||
..LogicSummoner::default()
|
..LogicSummoner::default()
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -145,6 +153,10 @@ impl BattleBuilder {
|
||||||
"no KingTower row in the character tables",
|
"no KingTower row in the character tables",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
let deck_slots = [
|
||||||
|
decks[0].as_ref().map(LogicSpellDeck::filled_slot_count).unwrap_or(0),
|
||||||
|
decks[1].as_ref().map(LogicSpellDeck::filled_slot_count).unwrap_or(0),
|
||||||
|
];
|
||||||
let mut objects = LogicGameObjectManager::default();
|
let mut objects = LogicGameObjectManager::default();
|
||||||
let mut leaders = [LogicGameObjectRef::NONE; 2];
|
let mut leaders = [LogicGameObjectRef::NONE; 2];
|
||||||
let mut towers: [Vec<LogicGameObjectRef>; 2] = [Vec::new(), Vec::new()];
|
let mut towers: [Vec<LogicGameObjectRef>; 2] = [Vec::new(), Vec::new()];
|
||||||
|
|
@ -159,6 +171,7 @@ impl BattleBuilder {
|
||||||
level_index: 0,
|
level_index: 0,
|
||||||
is_leader: true,
|
is_leader: true,
|
||||||
summoner: true,
|
summoner: true,
|
||||||
|
deck_slots: deck_slots[owner],
|
||||||
});
|
});
|
||||||
leaders[owner] = entry.global_id;
|
leaders[owner] = entry.global_id;
|
||||||
objects.push(entry);
|
objects.push(entry);
|
||||||
|
|
@ -175,6 +188,7 @@ impl BattleBuilder {
|
||||||
level_index: 0,
|
level_index: 0,
|
||||||
is_leader: false,
|
is_leader: false,
|
||||||
summoner: false,
|
summoner: false,
|
||||||
|
deck_slots: 0,
|
||||||
});
|
});
|
||||||
towers[owner].push(entry.global_id);
|
towers[owner].push(entry.global_id);
|
||||||
objects.push(entry);
|
objects.push(entry);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::battle::logic_game_object::{LogicGameObject, LogicVector2};
|
||||||
pub const DIRECTION_TOP: i32 = 256;
|
pub const DIRECTION_TOP: i32 = 256;
|
||||||
pub const DIRECTION_BOTTOM: i32 = -256;
|
pub const DIRECTION_BOTTOM: i32 = -256;
|
||||||
pub const DEFAULT_SIZE: i32 = 100;
|
pub const DEFAULT_SIZE: i32 = 100;
|
||||||
|
pub const SUMMONER_HAND_SIZE: usize = 4;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct LogicCharacter {
|
pub struct LogicCharacter {
|
||||||
pub level_index: i32,
|
pub level_index: i32,
|
||||||
|
|
@ -92,26 +93,39 @@ pub struct LogicSummoner {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct LogicSummonerDeck {
|
pub struct LogicSummonerDeck {
|
||||||
pub field_220: i32,
|
pub field_220: i32,
|
||||||
pub hand: [i32; 4],
|
pub hand: [i32; SUMMONER_HAND_SIZE],
|
||||||
pub draw_pile: Vec<i32>,
|
pub draw_pile: Vec<i32>,
|
||||||
pub used_pile: Vec<i32>,
|
pub used_pile: Vec<i32>,
|
||||||
pub last_used_index: i32,
|
pub last_used_index: i32,
|
||||||
pub field_248: i32,
|
pub spell_cooldown: i32,
|
||||||
pub field_240: i32,
|
pub field_240: i32,
|
||||||
}
|
}
|
||||||
impl Default for LogicSummonerDeck {
|
impl Default for LogicSummonerDeck {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
field_220: 0,
|
field_220: 0,
|
||||||
hand: [-1; 4],
|
hand: [-1; SUMMONER_HAND_SIZE],
|
||||||
draw_pile: Vec::new(),
|
draw_pile: Vec::new(),
|
||||||
used_pile: Vec::new(),
|
used_pile: Vec::new(),
|
||||||
last_used_index: -1,
|
last_used_index: -1,
|
||||||
field_248: 0,
|
spell_cooldown: 0,
|
||||||
field_240: 0,
|
field_240: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl LogicSummonerDeck {
|
||||||
|
pub fn starting(slot_count: usize) -> Self {
|
||||||
|
let mut hand = [-1; SUMMONER_HAND_SIZE];
|
||||||
|
for (slot, index) in hand.iter_mut().zip(0..slot_count as i32) {
|
||||||
|
*slot = index;
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
hand,
|
||||||
|
draw_pile: (SUMMONER_HAND_SIZE as i32..slot_count as i32).collect(),
|
||||||
|
..Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl LogicSummoner {
|
impl LogicSummoner {
|
||||||
pub fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()> {
|
pub fn encode(&self, writer: &mut ByteStreamWriter) -> Result<()> {
|
||||||
self.character.encode(writer)?;
|
self.character.encode(writer)?;
|
||||||
|
|
@ -132,7 +146,7 @@ impl LogicSummoner {
|
||||||
writer.write_vint(*value);
|
writer.write_vint(*value);
|
||||||
}
|
}
|
||||||
writer.write_vint(deck.last_used_index);
|
writer.write_vint(deck.last_used_index);
|
||||||
writer.write_vint(deck.field_248);
|
writer.write_vint(deck.spell_cooldown);
|
||||||
writer.write_vint(deck.field_240);
|
writer.write_vint(deck.field_240);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue