use logic::model::{ LogicChest, LogicClientAvatar, LogicClientHome, LogicCommodityStore, LogicDataSlot, LogicSpell, LogicSpellCollection, LogicSpellDeck, LogicTimer, }; use titan::LogicLong; use logic::data::RESOURCE_GOLD; use logic::{table, LogicDataRef}; use crate::catalog::GOLD_RESOURCE_FALLBACK_INSTANCE; use crate::store::{OwnedCard, PlayerProfile, StoredChest}; pub const COMMODITY_RESOURCES: usize = 0; fn spell_of(owned: &OwnedCard) -> LogicSpell { LogicSpell { data: owned.card.clone(), level_index: owned.level_index, create_time: 0, count: owned.count, new_count: 0, recent_use_count: 0, new_upgrade_available: false, show_new_icon: false, } } fn chest_of(stored: &StoredChest) -> LogicChest { LogicChest { data: stored.chest.clone(), unlocked: stored.unlocked, claimed: stored.claimed, is_new: false, unlock_timer: (stored.remaining_ticks > 0).then_some(LogicTimer { remaining_ticks: stored.remaining_ticks, total_ticks: stored.total_ticks, end_timestamp: stored.end_timestamp, }), chest_id: stored.chest_id, source: stored.source, slot_index: stored.slot_index, } } fn chest_slots(profile: &PlayerProfile) -> Vec> { let mut slots = vec![None; profile.chest_slot_count]; for stored in &profile.chests { let Ok(index) = usize::try_from(stored.slot_index) else { continue; }; if index < slots.len() { slots[index] = Some(chest_of(stored)); } } slots } pub fn build_home(profile: &PlayerProfile) -> LogicClientHome { let deck = LogicSpellDeck::from_cards(profile.deck.iter().map(spell_of)); let collection = LogicSpellCollection::from_spells(profile.collection.iter().map(spell_of).collect()); let mut home = LogicClientHome { home_id: LogicLong::new(profile.account.high, profile.account.low), chest_id_counter: profile.chest_id_counter, free_chest_collect_count: profile.free_chest_collect_count, donation_capacity_limit_timer: LogicTimer::idle(), donated_capacity: 0, decks: vec![deck], spell_collection: collection, selected_deck_index: 0, chest_slots: chest_slots(profile), free_chest_timer: LogicTimer::idle(), donation_cooldown_timer: LogicTimer::idle(), free_chest: None, purchased_chest: None, crowns_towards_crown_chest: profile.crowns_towards_crown_chest, star_chest_timer_pending: false, star_chest_timer: LogicTimer::idle(), crown_chest: None, request_spells_cooldown_timer: LogicTimer::idle(), finished_tutorials: [0; 8], opened_pages: 0, last_shown_level_up: profile.exp_level, arena: profile.arena.clone(), shop_seed: -1, shop_weekday_index: -1, shop_weekday_index_seen: -1, shop_timer: LogicTimer::idle(), shop_spells: Vec::new(), share_replay_cooldown_timer: LogicTimer::idle(), send_team_mail_cooldown_timer: LogicTimer::idle(), free_chest_diamond_index: 0, crown_chest_diamond_index: 0, card_usage_stats_battle_count: profile.battle_count, royal_tv_replay_version_major: 0, royal_tv_replay_version_build: 0, royal_tv_replay_version_content: 0, seen_replay_ids: Vec::new(), card_request_message: None, requested_cards: Vec::new(), }; if profile.tutorials_finished { home.finish_all_tutorials(); } home } fn gold_resource(profile: &PlayerProfile) -> LogicDataRef { if !profile.gold_resource.is_none() { return profile.gold_resource.clone(); } let by_name = LogicDataRef::by_name(table::RESOURCES, RESOURCE_GOLD); if !by_name.is_none() { return by_name; } LogicDataRef::of(table::RESOURCES, GOLD_RESOURCE_FALLBACK_INSTANCE) } pub fn build_avatar(profile: &PlayerProfile) -> LogicClientAvatar { let account = LogicLong::new(profile.account.high, profile.account.low); let mut commodities = LogicCommodityStore::default(); commodities.set( COMMODITY_RESOURCES, vec![LogicDataSlot::new(gold_resource(profile), profile.gold)], ); LogicClientAvatar { avatar_id: account, account_id: account, home_id: account, name: profile.name.clone(), name_set_by_user: profile.name_set_by_user, name_change_state: -1, arena: profile.arena.clone(), score: profile.trophies, legacy_flag: false, commodities, diamonds: profile.diamonds, free_diamonds: profile.free_diamonds, exp_points: profile.exp_points, exp_level: profile.exp_level, cumulative_purchased_diamonds: 0, alliance: None, battle_count: profile.battle_count, win_count: profile.win_count, lose_count: profile.lose_count, win_loose_streak: 0, npc_win_count: profile.npc_win_count, npc_lose_count: profile.npc_lose_count, arena_before_last_npc_match: profile.arena.instance_id().unwrap_or(0) != 0, } }