Skip to content

Commit

Permalink
Fusion & Stacking in shop via panel drag;
Browse files Browse the repository at this point in the history
Fusion conditions for 2 & 3 houses combination;
  • Loading branch information
makscee committed Jan 26, 2024
1 parent 290ca96 commit 558378b
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 76 deletions.
3 changes: 2 additions & 1 deletion server/src/arena_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ fn run_stack(ctx: ReducerContext, target: u64, dragged: u64) -> Result<(), Strin
let (_, mut run) = ArenaRun::get_by_identity(&ctx.sender)?;
let (i_target, target) = run.find_team(target)?;
let (i_dragged, dragged) = run.find_team(dragged)?;
if !target.unit.houses.eq(&dragged.unit.houses) {
let d_houses = dragged.unit.houses.split("+").collect_vec();
if !target.unit.houses.split("+").any(|h| d_houses.contains(&h)) {
return Err("Houses should match for stacking".to_owned());
}
let target = &mut run.state.team[i_target].unit;
Expand Down
7 changes: 7 additions & 0 deletions src/components/var_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,13 @@ impl VarState {
pub fn get_color_at(&self, var: VarName, t: f32) -> Result<Color> {
self.get_value_at(var, t)?.get_color()
}
pub fn get_houses_vec(&self) -> Result<Vec<String>> {
Ok(self
.get_string(VarName::Houses)?
.split("+")
.map(|s| s.to_owned())
.collect_vec())
}
pub fn find_value(mut entity: Entity, var: VarName, t: f32, world: &World) -> Result<VarValue> {
let mut result = None;
loop {
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ impl RepresentationPlugin {
.map(|(e, r)| (e, r.clone()))
.collect_vec();
let t = get_play_head();
let dragged = world.get_resource::<DraggedUnit>().unwrap().0;
let dragged = world
.get_resource::<DraggedUnit>()
.unwrap()
.0
.map(|(d, _)| d);
for (entity, rep) in reps {
let context = Context::from_owner(entity, world);
let mapping: HashMap<VarName, VarValue> =
Expand Down
83 changes: 68 additions & 15 deletions src/plugins/shop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use bevy_egui::egui::Order;
pub struct ShopPlugin;

#[derive(Resource, Clone)]
struct ShopData {
pub struct ShopData {
update_callback: UpdateCallbackId<ArenaRun>,
fusion_candidates: Option<((Entity, Entity), Vec<PackedUnit>)>,
pub fusion_candidates: Option<((Entity, Entity), Vec<PackedUnit>)>,
}

const REROLL_PRICE: i32 = 1;
Expand Down Expand Up @@ -83,6 +83,10 @@ impl ShopPlugin {
fn fuse_front(world: &mut World) {
let entity_a = UnitPlugin::find_unit(Faction::Team, 1, world).unwrap();
let entity_b = UnitPlugin::find_unit(Faction::Team, 2, world).unwrap();
Self::start_fuse(entity_a, entity_b, world);
}

pub fn start_fuse(entity_a: Entity, entity_b: Entity, world: &mut World) {
let a = PackedUnit::pack(entity_a, world);
let b = PackedUnit::pack(entity_b, world);
let fusions = PackedUnit::fuse(a, b, world);
Expand Down Expand Up @@ -166,6 +170,11 @@ impl ShopPlugin {
pub fn ui(world: &mut World) {
let ctx = &egui_context(world);
let mut data = world.remove_resource::<ShopData>().unwrap();
if data.fusion_candidates.is_some() {
Self::show_fusion_options(&mut data, world);
world.insert_resource(data);
return;
}

let pos = UnitPlugin::get_slot_position(Faction::Shop, 0) - vec2(1.0, 0.0);
let pos = world_to_screen(pos.extend(0.0), world);
Expand Down Expand Up @@ -211,17 +220,13 @@ impl ShopPlugin {
Self::go_to_battle(world);
}
});
Self::show_fusion_options(&mut data, world);
world.insert_resource(data);
}

fn show_fusion_options(data: &mut ShopData, world: &mut World) {
let ctx = &egui_context(world);
if let Some(((entity_a, entity_b), candidates)) = &mut data.fusion_candidates {
let len = candidates.len();
if len == 0 {
return;
}
window("CHOOSE FUSION")
.order(Order::Foreground)
.set_width(len as f32 * 240.0)
Expand Down Expand Up @@ -257,6 +262,9 @@ impl ShopPlugin {
}
});
});
if candidates.len() == 0 {
data.fusion_candidates = None;
}
}
}

Expand Down Expand Up @@ -284,40 +292,85 @@ impl ShopPlugin {
let ctx = &egui_context(world);
let cursor_pos = CameraPlugin::cursor_world_pos(world).context("Failed to get cursor")?;
let dragged = world.resource::<DraggedUnit>().0;
if let Some(dragged) = dragged {
if let Some((dragged, action)) = dragged {
let mut new_action = DragAction::None;
let dragged_state = VarState::get(dragged, world);
let dragged_name = dragged_state.get_string(VarName::Name)?;
let dragged_houses = dragged_state.get_houses_vec()?;
let dragged_level = dragged_state.get_int(VarName::Level)?;
for entity in UnitPlugin::collect_faction(Faction::Team, world) {
if entity == dragged {
continue;
}
let state = VarState::get(entity, world);
let same_slot = state.get_int(VarName::Slot).context("Failed to get slot")?
== UnitPlugin::get_closest_slot(cursor_pos, Faction::Team).0 as i32;
let same_name = dragged_name.eq(&state.get_string(VarName::Name)?);
if same_name {
let houses = state.get_houses_vec()?;
let level = state.get_int(VarName::Level)?;
let same_house = dragged_houses.iter().any(|h| houses.contains(h));
if same_house {
let stacks = state.get_int(VarName::Stacks)?;
let level = state.get_int(VarName::Level)?;
let color = if same_slot { yellow() } else { white() };
let color = if matches!(action, DragAction::Stack(e) if e == entity) {
yellow()
} else {
white()
};
window("STACK")
.id(entity)
.set_width(150.0)
.title_bar(false)
.stroke(false)
.entity_anchor(entity, Align2::CENTER_BOTTOM, vec2(0.0, 2.2), world)
.show(ctx, |ui| {
frame(ui, |ui| {
if frame(ui, |ui| {
ui.label("+STACK".add_color(color).rich_text().size(24.0));
ui.label(format!("Level {level}").add_color(color).rich_text());
ui.label(
format!("{stacks}/{}", level + 1)
.add_color(light_gray())
.rich_text(),
);
});
})
.response
.hovered()
{
new_action = DragAction::Stack(entity);
};
});
} else if level >= houses.len() as i32 + 1
&& houses.len() < 3
&& dragged_level >= level
&& dragged_houses.len() == 1
&& !houses.contains(&dragged_houses[0])
{
let color = if matches!(action, DragAction::Fuse(e) if e == entity) {
yellow()
} else {
white()
};
window("FUSE")
.id(entity)
.set_width(150.0)
.title_bar(false)
.stroke(false)
.entity_anchor(entity, Align2::CENTER_BOTTOM, vec2(0.0, 2.2), world)
.show(ctx, |ui| {
if frame(ui, |ui| {
ui.label("FUSE".add_color(color).rich_text().size(24.0));
})
.response
.hovered()
{
new_action = DragAction::Fuse(entity);
};
});
}
}
for slot in 1..TEAM_SLOTS {
let pos = UnitPlugin::get_slot_position(Faction::Team, slot);
if (pos - cursor_pos).length() < 1.0 {
new_action = DragAction::Insert(slot);
}
}
world.resource_mut::<DraggedUnit>().0 = Some((dragged, new_action));
} else {
for entity in UnitPlugin::collect_faction(Faction::Team, world) {
let state = VarState::get(entity, world);
Expand Down
118 changes: 60 additions & 58 deletions src/plugins/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ impl UnitPlugin {
let dragged = world.resource::<DraggedUnit>().0;
for (unit, ind) in Self::collect_faction(faction, world)
.into_iter()
.filter(|u| dragged != Some(*u))
.filter(|u| match dragged {
Some((d, _)) => d != *u,
None => true,
})
.sorted_by_key(|x| VarState::get(*x, world).get_int(VarName::Slot).unwrap())
.zip(1..)
.collect_vec()
Expand Down Expand Up @@ -235,9 +238,13 @@ impl UnitPlugin {
mut team: Query<Entity, With<ActiveTeam>>,
mut dragged: ResMut<DraggedUnit>,
mut commands: Commands,
shop_data: Res<ShopData>,
) {
if shop_data.fusion_candidates.is_some() {
return;
}
debug!("Drag unit start {:?}", event.target);
dragged.0 = Some(event.target);
dragged.0 = Some((event.target, DragAction::None));
for entity in team.iter_mut() {
commands.entity(entity).insert(Pickable::IGNORE);
}
Expand All @@ -255,72 +262,58 @@ impl UnitPlugin {
}

commands.add(|world: &mut World| {
let dragged = world.resource::<DraggedUnit>().0.unwrap();
world.resource_mut::<DraggedUnit>().0 = None;
let ClosestSlot(slot, _, stackable) = *world.resource::<ClosestSlot>();
let target = Self::find_unit(Faction::Team, slot, world);
if stackable && !target.is_some_and(|target| target.eq(&dragged)) {
let target = Self::get_id(target.unwrap(), world).unwrap();
let dragged = Self::get_id(dragged, world).unwrap();
run_stack(target, dragged);
} else {
let t = GameTimer::get().insert_head();
VarState::get_mut(dragged, world).insert_simple(
VarName::Slot,
VarValue::Int(slot as i32),
t,
);
let sorted_ids = UnitPlugin::collect_faction_ids(Faction::Team, world)
.into_iter()
.map(|(id, entity)| {
(
id,
VarState::get(entity, world).get_int(VarName::Slot).unwrap(),
)
})
.sorted_by_key(|(_, s)| *s)
.map(|(id, _)| id)
.collect_vec();
run_team_reorder(sorted_ids);
if let Some((dragged, action)) = world.resource::<DraggedUnit>().0 {
world.resource_mut::<DraggedUnit>().0 = None;
match action {
DragAction::Fuse(target) => {
ShopPlugin::start_fuse(target, dragged, world);
}
DragAction::Stack(target) => {
let target = Self::get_id(target, world).unwrap();
let dragged = Self::get_id(dragged, world).unwrap();
run_stack(target, dragged);
}
DragAction::Insert(_) | DragAction::None => {
let sorted_ids = UnitPlugin::collect_faction_ids(Faction::Team, world)
.into_iter()
.map(|(id, entity)| {
(
id,
VarState::get(entity, world).get_int(VarName::Slot).unwrap(),
)
})
.sorted_by_key(|(_, s)| *s)
.map(|(id, _)| id)
.collect_vec();
run_team_reorder(sorted_ids);
}
DragAction::Sell => todo!(),
}
Self::fill_slot_gaps(Faction::Team, world);
Self::translate_to_slots(world);
}
Self::fill_slot_gaps(Faction::Team, world);
Self::translate_to_slots(world);
});
}

pub fn drag_unit(world: &mut World) {
if let Some(dragged) = world.resource::<DraggedUnit>().0 {
if let Some((dragged, action)) = world.resource::<DraggedUnit>().0 {
if let Some(cursor_pos) = CameraPlugin::cursor_world_pos(world) {
let mut transform = world.get_mut::<Transform>(dragged).unwrap();
transform.translation = cursor_pos.extend(0.0);
VarState::get_mut(dragged, world)
.init(VarName::Position, VarValue::Vec2(cursor_pos));
if let Some(prev_closest) = world.get_resource::<ClosestSlot>() {
let closest_slot = Self::get_closest_slot(cursor_pos, Faction::Team);
if prev_closest.0 != closest_slot.0 {
let name = VarState::get(dragged, world)
.get_string(VarName::Name)
.unwrap();
let stackable = if Self::find_unit(Faction::Team, closest_slot.0, world)
.is_some_and(|entity| {
VarState::get(entity, world)
.get_string(VarName::Name)
.unwrap()
.eq(&name)
}) {
true
} else {
Self::make_slot_gap(Faction::Team, closest_slot.0 as i32, world);
Self::translate_to_slots(world);
false
};
world.insert_resource(ClosestSlot(
closest_slot.0,
closest_slot.1,
stackable,
));
}
match action {
DragAction::Insert(slot) => {
let mut state = VarState::get_mut(dragged, world);
let slot = slot as i32;
if state.get_int(VarName::Slot).unwrap() != slot {
state.init(VarName::Slot, VarValue::Int(slot));
UnitPlugin::make_slot_gap(Faction::Team, slot, world);
UnitPlugin::translate_to_slots(world);
}
}
_ => {}
}
}
}
Expand Down Expand Up @@ -414,8 +407,17 @@ impl Faction {
#[derive(Resource, Default)]
pub struct HoveredUnit(pub Option<Entity>);

#[derive(Resource, Default, Debug)]
pub struct DraggedUnit(pub Option<Entity>);
#[derive(Resource, Default, Debug, Clone, Copy)]
pub struct DraggedUnit(pub Option<(Entity, DragAction)>);

#[derive(Debug, Copy, Clone)]
pub enum DragAction {
None,
Fuse(Entity),
Stack(Entity),
Insert(usize),
Sell,
}

#[derive(Component)]
pub struct ActiveTeam;
2 changes: 1 addition & 1 deletion src/resourses/packed_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ impl PackedUnit {
rep.mapping.insert(
VarName::Color,
Expression::Value(VarValue::Color(
Pools::get_house_color(&b.houses, world).unwrap(),
Pools::get_house_color(&b.houses.split("+").next().unwrap(), world).unwrap(),
)),
);
rep
Expand Down

0 comments on commit 558378b

Please sign in to comment.