From 652b64d4ca3e7b8a97d43fdc201d00ff113e96ea Mon Sep 17 00:00:00 2001 From: Adrien Burgun Date: Wed, 4 Oct 2023 15:58:35 +0200 Subject: [PATCH] :sparkles: :bug: append End instruction after jump labels at end, CONTROL function --- examples/difficulty.mbas | 42 +++++++++++++++++++++++++++++++ examples/procedural-waves.mbas | 15 +++++++---- src/config.rs | 31 +++++++++++++++++++++++ src/repr/mlog.rs | 10 ++++++-- src/translate/display.rs | 17 ++++++++++++- src/translate/mod.rs | 14 +++++++++++ tests/examples/world-print.0.mlog | 1 + tests/examples/world-print.1.mlog | 1 + 8 files changed, 123 insertions(+), 8 deletions(-) create mode 100644 examples/difficulty.mbas diff --git a/examples/difficulty.mbas b/examples/difficulty.mbas new file mode 100644 index 0000000..602cc6e --- /dev/null +++ b/examples/difficulty.mbas @@ -0,0 +1,42 @@ +READ(difficulty, cell1, 3) + +IF difficulty == 0 THEN + difficulty = 2 + WRITE(difficulty, cell1, 3) +END IF +PRINT "Difficulty: " + +IF difficulty == 1 THEN + PRINT "<[green]Easy[white]>[gray] Medium Hard " +ELSE + IF difficulty == 2 THEN + PRINT " [gray]Easy [white]<[yellow]Medium[white]>[gray] Hard " + ELSE + PRINT "[gray]Easy Medium [white]<[red]Hard[white]>" + END IF +END IF +PRINT_FLUSH(message1) + +difficulty = 0 + +easy = switch1.@enabled +IF easy THEN + difficulty = 1 + CONTROL(enabled, switch1, false) +END IF + +medium = switch2.@enabled +IF medium THEN + difficulty = 2 + CONTROL(enabled, switch2, false) +END IF + +hard = switch3.@enabled +IF hard THEN + difficulty = 3 + CONTROL(enabled, switch3, false) +END IF + +IF difficulty != 0 THEN + WRITE(difficulty, cell1, 3) +END IF diff --git a/examples/procedural-waves.mbas b/examples/procedural-waves.mbas index 9e08c10..a86218d 100644 --- a/examples/procedural-waves.mbas +++ b/examples/procedural-waves.mbas @@ -16,14 +16,19 @@ LOOP WHILE remaining > 0 WHILE true wave = wave + 1 - REM TODO: difficult control wave multiplier - LET progression = POW(wave / 4, 0.75) + READ(difficulty, cell1, 3) + difficulty = difficulty - 1 + LET progression_mult = 5 - difficulty / 2 + LET units_mult = 0.5 + difficulty / 2 + LET max_progression = 8 + difficulty * 2 + + LET progression = POW(wave / progression_mult, 0.75) REM TODO: optimize duplicate operations - progression = MIN(progression / 2 + rand(progression / 2), 10) + progression = MIN(progression / 2 + rand(progression / 2), max_progression) LET units = 2 + SQRT(progression) * 4 + RAND(progression * 2) - REM TODO: difficulty control unit amount - units = CEIL(units * 1) + + units = MIN(CEIL(units * units_mult), 20) LET tank_units = FLOOR(RAND(units)) LET mech_units = FLOOR(RAND(units - tank_units)) LET air_units = units - tank_units - mech_units diff --git a/src/config.rs b/src/config.rs index aea5194..c6778d6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -65,6 +65,37 @@ impl Default for Config { }), ); + special_functions.insert( + String::from("control"), + Box::new(|arguments| { + let BasicAstExpression::Variable(buffer) = &arguments[0] else { + return Err(ParseError::InvalidArgument(arguments[0].clone())); + }; + + let expected_length = match buffer.as_str() { + "enabled" => 3, + "shoot" => 5, + "shootp" => 4, + "config" => 3, + "color" => 3, + _ => return Err(ParseError::InvalidArgument(arguments[0].clone())), + }; + + if arguments.len() != expected_length { + return Err(ParseError::InvalidArgumentCount( + String::from("control"), + expected_length, + arguments.len(), + )); + } + + Ok(BasicAstInstruction::CallBuiltin( + String::from("control"), + arguments, + )) + }), + ); + Self { builtin_functions: HashMap::from([ builtin_function!("print_flush", None, false, 1), diff --git a/src/repr/mlog.rs b/src/repr/mlog.rs index 830efa9..74f657d 100644 --- a/src/repr/mlog.rs +++ b/src/repr/mlog.rs @@ -61,6 +61,8 @@ pub enum MindustryOperation { PrintFlush(Operand), /// Available to world processors only - flushes the print buffer to a global buffer WorldPrintFlush(WorldPrintFlush), + /// Sets a property of a given block + Control(String, Vec), /// Reads `key` from `object` and puts its result into `out_name`. /// `object` may be a connection, an entity, a block, a unit type, etc. @@ -146,10 +148,12 @@ impl_operands!( mut: { Self::Generic(_name, operands) => operands.iter_mut().collect::>(), Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::>(), + Self::Control(_name, operands) => operands.iter_mut().collect::>(), }, ref: { Self::Generic(_name, operands) => operands.iter().collect::>(), Self::GenericMut(_name, _out_name, operands) => operands.iter().collect::>(), + Self::Control(_name, operands) => operands.iter().collect::>(), } ); @@ -165,7 +169,8 @@ impl MindustryOperation { value: _, cell: _, index: _, - } => false, + } + | Self::Control(_, _) => false, Self::Operator(out_name, _, _, _) | Self::UnaryOperator(out_name, _, _) @@ -214,7 +219,8 @@ impl MindustryOperation { | Self::PrintFlush(_) | Self::WorldPrintFlush(_) | Self::Generic(_, _) - | Self::GenericMut(_, _, _) => false, + | Self::GenericMut(_, _, _) + | Self::Control(_, _) => false, Self::Set(var_name, _) | Self::Operator(var_name, _, _, _) diff --git a/src/translate/display.rs b/src/translate/display.rs index 6bb42ad..888c800 100644 --- a/src/translate/display.rs +++ b/src/translate/display.rs @@ -120,12 +120,27 @@ impl std::fmt::Display for MindustryProgram { WorldPrintFlush::Toast(time) => writeln!(f, "message toast {}", time)?, }; } - MindustryOperation::Sensor { out_name, object, key } => { + MindustryOperation::Sensor { + out_name, + object, + key, + } => { writeln!(f, "sensor {out_name} {object} {key}")?; } + MindustryOperation::Control(key, arguments) => { + write!(f, "control {}", key)?; + for arg in arguments { + write!(f, " {}", arg)?; + } + writeln!(f)?; + } } } + if matches!(self.0.last(), Some(MindustryOperation::JumpLabel(_))) { + writeln!(f, "end")?; + } + Ok(()) } } diff --git a/src/translate/mod.rs b/src/translate/mod.rs index ad876ec..4e10f35 100644 --- a/src/translate/mod.rs +++ b/src/translate/mod.rs @@ -382,6 +382,20 @@ pub fn translate_ast( res.push(instruction); } + Instr::CallBuiltin(name, arguments) if name == "control" => translate_call!( + "control", + arguments, + res, + [BasicAstExpression::Variable(key), ..], + MindustryOperation::Control( + key.clone(), + arguments + .iter() + .skip(1) + .map(|arg| translate_operand!(arg, res, namer)) + .collect() + ) + ), Instr::CallBuiltin(name, arguments) => { let Some((Some(target_name), mutating, _)) = config.builtin_functions.get(name) else { diff --git a/tests/examples/world-print.0.mlog b/tests/examples/world-print.0.mlog index 8d8502f..f9e3a12 100644 --- a/tests/examples/world-print.0.mlog +++ b/tests/examples/world-print.0.mlog @@ -27,3 +27,4 @@ set main__tmp_11 1 message announce main__tmp_11 main__label_5_endif: main__label_1_endif: +end diff --git a/tests/examples/world-print.1.mlog b/tests/examples/world-print.1.mlog index 90bb624..5f31707 100644 --- a/tests/examples/world-print.1.mlog +++ b/tests/examples/world-print.1.mlog @@ -14,3 +14,4 @@ main__label_4_else: message announce 1 main__label_5_endif: main__label_1_endif: +end