common/src/gameplay_modes.rs

275 lines
7.3 KiB
Rust
Raw Normal View History

2024-01-30 06:38:43 +00:00
use std::collections::{HashSet,HashMap};
use crate::model::ModelId;
use crate::gameplay_style;
2024-02-01 08:04:07 +00:00
use crate::updatable::Updatable;
2024-01-30 06:38:43 +00:00
2024-02-01 08:04:07 +00:00
#[derive(Clone)]
2024-01-30 06:38:43 +00:00
pub struct StageElement{
2024-02-01 08:04:07 +00:00
stage_id:StageId,//which stage spawn to send to
2024-01-30 06:38:43 +00:00
force:bool,//allow setting to lower spawn id i.e. 7->3
behaviour:StageElementBehaviour
}
2024-02-01 08:04:07 +00:00
impl StageElement{
#[inline]
pub const fn new(stage_id:StageId,force:bool,behaviour:StageElementBehaviour)->Self{
Self{
stage_id,
force,
behaviour,
}
}
#[inline]
pub const fn stage_id(&self)->StageId{
self.stage_id
}
#[inline]
pub const fn force(&self)->bool{
self.force
}
#[inline]
pub const fn behaviour(&self)->StageElementBehaviour{
self.behaviour
}
}
2024-01-30 06:38:43 +00:00
2024-02-01 08:04:07 +00:00
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
2024-01-30 06:38:43 +00:00
pub enum StageElementBehaviour{
SpawnAt,//must be standing on top to get effect. except cancollide false
Trigger,
Teleport,
Platform,
//Check(point) acts like a trigger if you haven't hit all the checkpoints on previous stages yet.
//Note that all stage elements act like this, this is just the isolated behaviour.
Check,
Checkpoint,//this is a combined behaviour for Ordered & Unordered in case a model is used multiple times or for both.
}
2024-02-01 08:04:07 +00:00
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq)]
pub struct CheckpointId(u32);
impl CheckpointId{
pub const FIRST:Self=Self(0);
}
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
2024-01-30 06:38:43 +00:00
pub struct StageId(u32);
2024-02-01 08:04:07 +00:00
impl StageId{
pub const FIRST:Self=Self(0);
}
#[derive(Clone)]
2024-01-30 06:38:43 +00:00
pub struct Stage{
spawn:ModelId,
2024-02-01 08:04:07 +00:00
//open world support lol
ordered_checkpoints_count:u32,
unordered_checkpoints_count:u32,
//currently loaded checkpoint models
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
unordered_checkpoints:HashSet<ModelId>,
}
impl Stage{
pub fn new(spawn:ModelId)->Self{
Self{
spawn,
ordered_checkpoints_count:0,
unordered_checkpoints_count:0,
ordered_checkpoints:HashMap::new(),
unordered_checkpoints:HashSet::new(),
}
}
#[inline]
pub const fn spawn(&self)->ModelId{
self.spawn
}
#[inline]
pub const fn is_empty(&self)->bool{
self.is_complete(0,0)
}
#[inline]
pub const fn is_complete(&self,ordered_checkpoints_count:u32,unordered_checkpoints_count:u32)->bool{
self.ordered_checkpoints_count==ordered_checkpoints_count&&self.unordered_checkpoints_count==unordered_checkpoints_count
}
#[inline]
pub fn is_next_ordered_checkpoint(&self,next_ordered_checkpoint_id:CheckpointId,model_id:ModelId)->bool{
self.ordered_checkpoints.get(&next_ordered_checkpoint_id).is_some_and(|&next_checkpoint|model_id==next_checkpoint)
}
#[inline]
pub fn is_unordered_checkpoint(&self,model_id:ModelId)->bool{
self.unordered_checkpoints.contains(&model_id)
}
}
#[derive(Default)]
pub struct StageUpdate{
2024-01-30 06:38:43 +00:00
//other behaviour models of this stage can have
2024-02-01 08:04:07 +00:00
ordered_checkpoints:HashMap<CheckpointId,ModelId>,
2024-01-30 06:38:43 +00:00
unordered_checkpoints:HashSet<ModelId>,
}
2024-02-01 08:04:07 +00:00
impl Updatable<StageUpdate> for Stage{
fn update(&mut self,update:StageUpdate){
self.ordered_checkpoints.extend(update.ordered_checkpoints);
self.unordered_checkpoints.extend(update.unordered_checkpoints);
}
}
2024-01-30 06:38:43 +00:00
2024-02-01 08:04:07 +00:00
#[derive(Clone,Copy,Hash,Eq,PartialEq)]
pub enum Zone{
Start,
2024-01-30 06:38:43 +00:00
Finish,
2024-02-01 08:04:07 +00:00
Anticheat,
2024-01-30 06:38:43 +00:00
}
2024-02-01 08:04:07 +00:00
#[derive(Clone,Copy,Hash,id::Id,Eq,PartialEq,Ord,PartialOrd)]
2024-01-30 06:38:43 +00:00
pub struct ModeId(u32);
2024-02-01 08:04:07 +00:00
impl ModeId{
pub const MAIN:Self=Self(0);
pub const BONUS:Self=Self(1);
}
#[derive(Clone)]
2024-01-30 06:38:43 +00:00
pub struct Mode{
style:gameplay_style::StyleModifiers,
2024-02-01 08:04:07 +00:00
start:ModelId,//when you press reset you go here
zones:HashMap<ModelId,Zone>,
stages:Vec<Stage>,//when you load the map you go to stages[0].spawn
2024-01-30 06:38:43 +00:00
//mutually exlusive stage element behaviour
elements:HashMap<ModelId,StageElement>,
jump_limit:HashMap<ModelId,u32>,
}
impl Mode{
2024-02-01 08:04:07 +00:00
pub fn new(style:gameplay_style::StyleModifiers,start:ModelId)->Self{
Self{
style,
start,
zones:HashMap::new(),
stages:Vec::new(),
elements:HashMap::new(),
jump_limit:HashMap::new(),
}
}
pub const fn get_start(&self)->ModelId{
self.start
}
pub const fn get_style(&self)->&gameplay_style::StyleModifiers{
&self.style
}
pub fn push_stage(&mut self,stage:Stage){
self.stages.push(stage)
}
pub fn get_stage_mut(&mut self,stage:StageId)->Option<&mut Stage>{
self.stages.get_mut(stage.0 as usize)
}
2024-01-30 06:38:43 +00:00
pub fn get_spawn_model_id(&self,stage:StageId)->Option<ModelId>{
self.stages.get(stage.0 as usize).map(|s|s.spawn)
}
2024-02-01 08:04:07 +00:00
pub fn get_zone(&self,model_id:ModelId)->Option<&Zone>{
self.zones.get(&model_id)
}
pub fn get_stage(&self,stage_id:StageId)->Option<&Stage>{
self.stages.get(stage_id.0 as usize)
}
pub fn get_element(&self,model_id:ModelId)->Option<&StageElement>{
self.elements.get(&model_id)
}
pub fn get_jump_limit(&self,model_id:ModelId)->Option<u32>{
self.jump_limit.get(&model_id).copied()
}
//TODO: put this in the SNF
2024-01-30 06:38:43 +00:00
pub fn denormalize_data(&mut self){
//expand and index normalized data
2024-02-01 08:04:07 +00:00
self.zones.insert(self.start,Zone::Start);
2024-01-30 06:38:43 +00:00
for (stage_id,stage) in self.stages.iter().enumerate(){
self.elements.insert(stage.spawn,StageElement{
2024-02-01 08:04:07 +00:00
stage_id:StageId(stage_id as u32),
2024-01-30 06:38:43 +00:00
force:false,
behaviour:StageElementBehaviour::SpawnAt,
});
2024-02-01 08:04:07 +00:00
for (_,&model) in &stage.ordered_checkpoints{
self.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32),
2024-01-30 06:38:43 +00:00
force:false,
behaviour:StageElementBehaviour::Checkpoint,
});
}
2024-02-01 08:04:07 +00:00
for &model in &stage.unordered_checkpoints{
self.elements.insert(model,StageElement{
stage_id:StageId(stage_id as u32),
2024-01-30 06:38:43 +00:00
force:false,
behaviour:StageElementBehaviour::Checkpoint,
});
}
}
}
}
2024-02-01 08:04:07 +00:00
//this would be nice as a macro
2024-01-30 06:38:43 +00:00
#[derive(Default)]
2024-02-01 08:04:07 +00:00
pub struct ModeUpdate{
zones:HashMap<ModelId,Zone>,
stages:HashMap<StageId,StageUpdate>,
//mutually exlusive stage element behaviour
elements:HashMap<ModelId,StageElement>,
jump_limit:HashMap<ModelId,u32>,
}
impl Updatable<ModeUpdate> for Mode{
fn update(&mut self,update:ModeUpdate){
self.zones.extend(update.zones);
for (stage,stage_update) in update.stages{
if let Some(stage)=self.stages.get_mut(stage.0 as usize){
stage.update(stage_update);
}
}
self.elements.extend(update.elements);
self.jump_limit.extend(update.jump_limit);
}
}
impl ModeUpdate{
pub fn zone(model_id:ModelId,zone:Zone)->Self{
let mut mu=Self::default();
mu.zones.insert(model_id,zone);
mu
}
pub fn stage(stage_id:StageId,stage_update:StageUpdate)->Self{
let mut mu=Self::default();
mu.stages.insert(stage_id,stage_update);
mu
}
pub fn element(model_id:ModelId,element:StageElement)->Self{
let mut mu=Self::default();
mu.elements.insert(model_id,element);
mu
}
pub fn jump_limit(model_id:ModelId,jump_limit:u32)->Self{
let mut mu=Self::default();
mu.jump_limit.insert(model_id,jump_limit);
mu
}
pub fn map_stage_element_ids<F:Fn(StageId)->StageId>(&mut self,f:F){
for (_,stage_element) in self.elements.iter_mut(){
stage_element.stage_id=f(stage_element.stage_id);
}
}
}
#[derive(Default,Clone)]
2024-01-30 06:38:43 +00:00
pub struct Modes{
modes:Vec<Mode>,
}
impl Modes{
2024-02-01 08:04:07 +00:00
pub fn new(modes:Vec<Mode>)->Self{
Self{
modes,
}
}
pub fn push_mode(&mut self,mode:Mode){
self.modes.push(mode)
2024-01-30 06:38:43 +00:00
}
pub fn get_mode(&self,mode:ModeId)->Option<&Mode>{
self.modes.get(mode.0 as usize)
}
2024-02-01 08:04:07 +00:00
}
pub struct ModesUpdate{
modes:HashMap<ModeId,ModeUpdate>,
}
impl Updatable<ModesUpdate> for Modes{
fn update(&mut self,update:ModesUpdate){
for (mode,mode_update) in update.modes{
if let Some(mode)=self.modes.get_mut(mode.0 as usize){
mode.update(mode_update);
}
}
2024-01-30 06:38:43 +00:00
}
}