mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-24 10:59:20 +00:00
weapon refactor + bunch of minor stuff
This commit is contained in:
parent
c0c48783a9
commit
a1d546215f
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +0,0 @@
|
|||
#Thu Feb 18 11:02:22 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
172
gradlew
vendored
172
gradlew
vendored
|
@ -1,172 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
84
gradlew.bat
vendored
84
gradlew.bat
vendored
|
@ -1,84 +0,0 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
|
@ -55,6 +55,12 @@ bitfield! {
|
|||
pub hit_right_bigger_half, set_hit_right_bigger_half: 19; // 0x80000
|
||||
}
|
||||
|
||||
impl Flag {
|
||||
pub fn hit_anything(&self) -> bool {
|
||||
(self.0 & 0x2ff) != 0
|
||||
}
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Equipment(u16);
|
||||
|
|
|
@ -122,10 +122,17 @@ pub struct BulletRects {
|
|||
pub b013_missile_l1: [Rect<u16>; 4],
|
||||
pub b014_missile_l2: [Rect<u16>; 4],
|
||||
pub b015_missile_l3: [Rect<u16>; 4],
|
||||
pub b019_bubble_l1: [Rect<u16>; 4],
|
||||
pub b020_bubble_l2: [Rect<u16>; 4],
|
||||
pub b021_bubble_l3: [Rect<u16>; 4],
|
||||
pub b022_bubble_spines: [Rect<u16>; 6],
|
||||
pub b023_blade_slash: [Rect<u16>; 10],
|
||||
pub b025_blade_l1: [Rect<u16>; 8],
|
||||
pub b026_blade_l2: [Rect<u16>; 8],
|
||||
pub b027_blade_l3: [Rect<u16>; 8],
|
||||
pub b028_super_missile_l1: [Rect<u16>; 4],
|
||||
pub b029_super_missile_l2: [Rect<u16>; 4],
|
||||
pub b030_super_missile_l3: [Rect<u16>; 4],
|
||||
pub b034_nemesis_l1: [Rect<u16>; 8],
|
||||
pub b035_nemesis_l2: [Rect<u16>; 8],
|
||||
pub b036_nemesis_l3: [Rect<u16>; 8],
|
||||
|
@ -1015,14 +1022,12 @@ impl EngineConstants {
|
|||
Rect { left: 112, top: 0, right: 128, bottom: 16 },
|
||||
],
|
||||
b011_machine_gun_l2: [
|
||||
|
||||
Rect { left: 64, top: 16, right: 80, bottom: 32 },
|
||||
Rect { left: 80, top: 16, right: 96, bottom: 32 },
|
||||
Rect { left: 96, top: 16, right: 112, bottom: 32 },
|
||||
Rect { left: 112, top: 16, right: 128, bottom: 32 },
|
||||
Rect { left: 64, top: 16, right: 80, bottom: 32 },
|
||||
Rect { left: 80, top: 16, right: 96, bottom: 32 },
|
||||
Rect { left: 96, top: 16, right: 112, bottom: 32 },
|
||||
Rect { left: 112, top: 16, right: 128, bottom: 32 },
|
||||
],
|
||||
b012_machine_gun_l3: [
|
||||
|
||||
Rect { left: 64, top: 32, right: 80, bottom: 48 },
|
||||
Rect { left: 80, top: 32, right: 96, bottom: 48 },
|
||||
Rect { left: 96, top: 32, right: 112, bottom: 48 },
|
||||
|
@ -1038,13 +1043,40 @@ impl EngineConstants {
|
|||
Rect { left: 0, top: 16, right: 16, bottom: 32 },
|
||||
Rect { left: 16, top: 16, right: 32, bottom: 32 },
|
||||
Rect { left: 32, top: 16, right: 48, bottom: 32 },
|
||||
Rect { left: 48, top: 16, right: 64, bottom: 32 },],
|
||||
Rect { left: 48, top: 16, right: 64, bottom: 32 },
|
||||
],
|
||||
b015_missile_l3: [
|
||||
Rect { left: 0, top: 32, right: 16, bottom: 48 },
|
||||
Rect { left: 16, top: 32, right: 32, bottom: 48 },
|
||||
Rect { left: 32, top: 32, right: 48, bottom: 48 },
|
||||
Rect { left: 48, top: 32, right: 64, bottom: 48 },
|
||||
],
|
||||
b019_bubble_l1: [
|
||||
Rect { left: 192, top: 0, right: 200, bottom: 8 },
|
||||
Rect { left: 200, top: 0, right: 208, bottom: 8 },
|
||||
Rect { left: 208, top: 0, right: 216, bottom: 8 },
|
||||
Rect { left: 216, top: 0, right: 224, bottom: 8 },
|
||||
],
|
||||
b020_bubble_l2: [
|
||||
Rect { left: 192, top: 8, right: 200, bottom: 16 },
|
||||
Rect { left: 200, top: 8, right: 208, bottom: 16 },
|
||||
Rect { left: 208, top: 8, right: 216, bottom: 16 },
|
||||
Rect { left: 216, top: 8, right: 224, bottom: 16 },
|
||||
],
|
||||
b021_bubble_l3: [
|
||||
Rect { left: 240, top: 16, right: 248, bottom: 24 },
|
||||
Rect { left: 248, top: 16, right: 256, bottom: 24 },
|
||||
Rect { left: 240, top: 24, right: 248, bottom: 32 },
|
||||
Rect { left: 248, top: 24, right: 256, bottom: 32 },
|
||||
],
|
||||
b022_bubble_spines: [
|
||||
Rect { left: 224, top: 0, right: 232, bottom: 8 },
|
||||
Rect { left: 232, top: 0, right: 240, bottom: 8 },
|
||||
Rect { left: 224, top: 0, right: 232, bottom: 8 },
|
||||
Rect { left: 232, top: 0, right: 240, bottom: 8 },
|
||||
Rect { left: 224, top: 8, right: 232, bottom: 16 },
|
||||
Rect { left: 232, top: 8, right: 240, bottom: 16 },
|
||||
],
|
||||
b023_blade_slash: [
|
||||
Rect { left: 0, top: 64, right: 24, bottom: 88 }, // left
|
||||
Rect { left: 24, top: 64, right: 48, bottom: 88 },
|
||||
|
@ -1087,6 +1119,24 @@ impl EngineConstants {
|
|||
Rect { left: 296, top: 48, right: 320, bottom: 72 }, // down
|
||||
Rect { left: 296, top: 24, right: 320, bottom: 48 },
|
||||
],
|
||||
b028_super_missile_l1: [
|
||||
Rect { left: 120, top: 96, right: 136, bottom: 112 },
|
||||
Rect { left: 136, top: 96, right: 152, bottom: 112 },
|
||||
Rect { left: 152, top: 96, right: 168, bottom: 112 },
|
||||
Rect { left: 168, top: 96, right: 184, bottom: 112 },
|
||||
],
|
||||
b029_super_missile_l2: [
|
||||
Rect { left: 184, top: 96, right: 200, bottom: 112 },
|
||||
Rect { left: 200, top: 96, right: 216, bottom: 112 },
|
||||
Rect { left: 216, top: 96, right: 232, bottom: 112 },
|
||||
Rect { left: 232, top: 96, right: 248, bottom: 112 },
|
||||
],
|
||||
b030_super_missile_l3: [
|
||||
Rect { left: 120, top: 96, right: 136, bottom: 112 },
|
||||
Rect { left: 136, top: 96, right: 152, bottom: 112 },
|
||||
Rect { left: 152, top: 96, right: 168, bottom: 112 },
|
||||
Rect { left: 168, top: 96, right: 184, bottom: 112 },
|
||||
],
|
||||
b034_nemesis_l1: [
|
||||
Rect { left: 0, top: 112, right: 32, bottom: 128 }, // left
|
||||
Rect { left: 0, top: 128, right: 32, bottom: 144 },
|
||||
|
@ -1098,24 +1148,24 @@ impl EngineConstants {
|
|||
Rect { left: 112, top: 112, right: 128, bottom: 144 },
|
||||
],
|
||||
b035_nemesis_l2: [
|
||||
Rect { left: 0, top: 240, right: 32, bottom: 256 }, // left
|
||||
Rect { left: 0, top: 256, right: 32, bottom: 272 },
|
||||
Rect { left: 32, top: 240, right: 48, bottom: 272 }, // up
|
||||
Rect { left: 48, top: 240, right: 64, bottom: 272 },
|
||||
Rect { left: 64, top: 240, right: 96, bottom: 256 }, // right
|
||||
Rect { left: 64, top: 256, right: 96, bottom: 272 },
|
||||
Rect { left: 96, top: 240, right: 112, bottom: 272 }, // down
|
||||
Rect { left: 112, top: 240, right: 128, bottom: 272 },
|
||||
Rect { left: 128, top: 112, right: 160, bottom: 128 }, // left
|
||||
Rect { left: 128, top: 128, right: 160, bottom: 144 },
|
||||
Rect { left: 160, top: 112, right: 176, bottom: 144 }, // up
|
||||
Rect { left: 176, top: 112, right: 192, bottom: 144 },
|
||||
Rect { left: 192, top: 112, right: 224, bottom: 128 }, // right
|
||||
Rect { left: 192, top: 128, right: 224, bottom: 144 },
|
||||
Rect { left: 224, top: 112, right: 240, bottom: 144 }, // down
|
||||
Rect { left: 240, top: 112, right: 256, bottom: 144 },
|
||||
],
|
||||
b036_nemesis_l3: [
|
||||
Rect { left: 32, top: 112, right: 64, bottom: 128 }, // left
|
||||
Rect { left: 32, top: 128, right: 64, bottom: 144 },
|
||||
Rect { left: 64, top: 112, right: 80, bottom: 144 }, // up
|
||||
Rect { left: 80, top: 112, right: 96, bottom: 144 },
|
||||
Rect { left: 96, top: 112, right: 128, bottom: 128 }, // right
|
||||
Rect { left: 96, top: 128, right: 128, bottom: 144 },
|
||||
Rect { left: 128, top: 112, right: 144, bottom: 144 }, // down
|
||||
Rect { left: 144, top: 112, right: 160, bottom: 144 },
|
||||
Rect { left: 0, top: 144, right: 32, bottom: 160 }, // left
|
||||
Rect { left: 0, top: 160, right: 32, bottom: 176 },
|
||||
Rect { left: 32, top: 144, right: 48, bottom: 176 }, // up
|
||||
Rect { left: 48, top: 144, right: 64, bottom: 176 },
|
||||
Rect { left: 64, top: 144, right: 96, bottom: 160 }, // right
|
||||
Rect { left: 64, top: 160, right: 96, bottom: 176 },
|
||||
Rect { left: 96, top: 144, right: 112, bottom: 176 }, // down
|
||||
Rect { left: 112, top: 144, right: 128, bottom: 176 },
|
||||
],
|
||||
b037_spur_l1: [
|
||||
Rect { left: 128, top: 32, right: 144, bottom: 48 }, // horizontal
|
||||
|
|
|
@ -321,7 +321,7 @@ pub struct GlutinTexture {
|
|||
context_active: Arc<RefCell<bool>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
// #[repr(C)] // since we determine field offset dynamically, doesn't really matter
|
||||
#[derive(Copy, Clone)]
|
||||
struct VertexData {
|
||||
position: (f32, f32),
|
||||
|
|
|
@ -15,7 +15,6 @@ use std::time::Instant;
|
|||
|
||||
use directories::ProjectDirs;
|
||||
use lazy_static::lazy_static;
|
||||
use log::*;
|
||||
use pretty_env_logger::env_logger::Env;
|
||||
|
||||
use crate::builtin_fs::BuiltinFS;
|
||||
|
@ -33,7 +32,6 @@ use crate::texture_set::{G_MAG, I_MAG};
|
|||
mod bmfont;
|
||||
mod bmfont_renderer;
|
||||
mod builtin_fs;
|
||||
mod bullet;
|
||||
mod caret;
|
||||
mod common;
|
||||
mod components;
|
||||
|
@ -209,8 +207,8 @@ pub fn init() -> GameResult {
|
|||
};
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
info!("Resource directory: {:?}", resource_dir);
|
||||
info!("Initializing engine...");
|
||||
log::info!("Resource directory: {:?}", resource_dir);
|
||||
log::info!("Initializing engine...");
|
||||
|
||||
let mut context = Context::new();
|
||||
mount_vfs(&mut context, Box::new(BuiltinFS::new()));
|
||||
|
|
0
src/netplay/mod.rs
Normal file
0
src/netplay/mod.rs
Normal file
|
@ -1,6 +1,6 @@
|
|||
use std::mem::MaybeUninit;
|
||||
|
||||
use crate::bullet::BulletManager;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::common::{Direction, interpolate_fix9_scale};
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
use crate::bullet::BulletManager;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Direction, Rect};
|
||||
use crate::npc::boss::BossNPC;
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::framework::error::GameResult;
|
|||
use num_traits::abs;
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::bullet::BulletManager;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::common::{Condition, interpolate_fix9_scale, Rect};
|
||||
use crate::common::Direction;
|
||||
use crate::common::Flag;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use num_traits::abs;
|
||||
|
||||
use crate::bullet::Bullet;
|
||||
use crate::weapon::bullet::Bullet;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, Direction, Flag, Rect};
|
||||
use crate::map::NPCData;
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
use std::clone::Clone;
|
||||
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameResult;
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::clamp;
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{Condition, Direction, Equipment, Flag, interpolate_fix9_scale, Rect};
|
||||
use crate::common::{interpolate_fix9_scale, Condition, Direction, Equipment, Flag, Rect};
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::input::dummy_player_controller::DummyPlayerController;
|
||||
use crate::input::player_controller::PlayerController;
|
||||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::rng::RNG;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::npc::list::NPCList;
|
||||
|
||||
mod player_hit;
|
||||
|
||||
|
@ -82,8 +82,8 @@ pub struct Player {
|
|||
pub appearance: PlayerAppearance,
|
||||
pub controller: Box<dyn PlayerController>,
|
||||
weapon_offset_y: i8,
|
||||
index_x: i32,
|
||||
index_y: i32,
|
||||
camera_target_x: i32,
|
||||
camera_target_y: i32,
|
||||
splash: bool,
|
||||
booster_switch: u8,
|
||||
bubble: u8,
|
||||
|
@ -119,8 +119,8 @@ impl Player {
|
|||
control_mode: constants.my_char.control_mode,
|
||||
question: false,
|
||||
booster_fuel: 0,
|
||||
index_x: 0,
|
||||
index_y: 0,
|
||||
camera_target_x: 0,
|
||||
camera_target_y: 0,
|
||||
splash: false,
|
||||
up: false,
|
||||
down: false,
|
||||
|
@ -177,11 +177,7 @@ impl Player {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let physics = if self.flags.in_water() {
|
||||
state.constants.my_char.water_physics
|
||||
} else {
|
||||
state.constants.my_char.air_physics
|
||||
};
|
||||
let physics = if self.flags.in_water() { state.constants.my_char.water_physics } else { state.constants.my_char.air_physics };
|
||||
|
||||
self.question = false;
|
||||
|
||||
|
@ -202,15 +198,10 @@ impl Player {
|
|||
}
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
let trigger_only_down = self.controller.trigger_down()
|
||||
&& !self.controller.trigger_up()
|
||||
&& !self.controller.trigger_left()
|
||||
&& !self.controller.trigger_right();
|
||||
let trigger_only_down =
|
||||
self.controller.trigger_down() && !self.controller.trigger_up() && !self.controller.trigger_left() && !self.controller.trigger_right();
|
||||
|
||||
let only_down = self.controller.move_down()
|
||||
&& !self.controller.move_up()
|
||||
&& !self.controller.move_left()
|
||||
&& !self.controller.move_right();
|
||||
let only_down = self.controller.move_down() && !self.controller.move_up() && !self.controller.move_left() && !self.controller.move_right();
|
||||
|
||||
if trigger_only_down && only_down && !self.cond.interacted() && !state.control_flags.interactions_disabled() {
|
||||
self.cond.set_interacted(true);
|
||||
|
@ -250,13 +241,15 @@ impl Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else { // air movement
|
||||
} else {
|
||||
// air movement
|
||||
if state.control_flags.control_enabled() {
|
||||
if self.controller.trigger_jump() && self.booster_fuel != 0 {
|
||||
if self.equip.has_booster_0_8() {
|
||||
self.booster_switch = 1;
|
||||
|
||||
if self.vel_y > 0x100 { // 0.5fix9
|
||||
if self.vel_y > 0x100 {
|
||||
// 0.5fix9
|
||||
self.vel_y /= 2;
|
||||
}
|
||||
} else if state.settings.infinite_booster || self.equip.has_booster_2_0() {
|
||||
|
@ -301,11 +294,13 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
if (state.settings.infinite_booster || self.equip.has_booster_2_0()) && self.booster_switch != 0
|
||||
&& (!self.controller.jump() || self.booster_fuel == 0) {
|
||||
if (state.settings.infinite_booster || self.equip.has_booster_2_0())
|
||||
&& self.booster_switch != 0
|
||||
&& (!self.controller.jump() || self.booster_fuel == 0)
|
||||
{
|
||||
match self.booster_switch {
|
||||
1 => { self.vel_x /= 2 }
|
||||
2 => { self.vel_y /= 2 }
|
||||
1 => self.vel_x /= 2,
|
||||
2 => self.vel_y /= 2,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -320,21 +315,19 @@ impl Player {
|
|||
self.up = self.controller.move_up();
|
||||
self.down = self.controller.move_down() && !self.flags.hit_bottom_wall();
|
||||
|
||||
if self.controller.trigger_jump() && (self.flags.hit_bottom_wall()
|
||||
|| self.flags.hit_right_slope()
|
||||
|| self.flags.hit_left_slope())
|
||||
&& !self.flags.force_up() {
|
||||
if self.controller.trigger_jump()
|
||||
&& (self.flags.hit_bottom_wall() || self.flags.hit_right_slope() || self.flags.hit_left_slope())
|
||||
&& !self.flags.force_up()
|
||||
{
|
||||
self.vel_y = -physics.jump;
|
||||
state.sound_manager.play_sfx(15);
|
||||
}
|
||||
}
|
||||
|
||||
// stop interacting when moved
|
||||
if state.control_flags.control_enabled() && (self.controller.move_left()
|
||||
|| self.controller.move_right()
|
||||
|| self.controller.move_up()
|
||||
|| self.controller.jump()
|
||||
|| self.controller.shoot()) {
|
||||
if state.control_flags.control_enabled()
|
||||
&& (self.controller.move_left() || self.controller.move_right() || self.controller.move_up() || self.controller.jump() || self.controller.shoot())
|
||||
{
|
||||
self.cond.set_interacted(false);
|
||||
}
|
||||
|
||||
|
@ -424,7 +417,8 @@ impl Player {
|
|||
|
||||
if (self.flags.hit_bottom_wall() && self.flags.hit_right_bigger_half() && self.vel_x < 0)
|
||||
|| (self.flags.hit_bottom_wall() && self.flags.hit_left_bigger_half() && self.vel_x > 0)
|
||||
|| (self.flags.hit_bottom_wall() && self.flags.hit_left_smaller_half() && self.flags.hit_right_smaller_half()) {
|
||||
|| (self.flags.hit_bottom_wall() && self.flags.hit_left_smaller_half() && self.flags.hit_right_smaller_half())
|
||||
{
|
||||
self.vel_y = 0x400; // 2.0fix9
|
||||
}
|
||||
}
|
||||
|
@ -450,14 +444,13 @@ impl Player {
|
|||
|
||||
for _ in 0..7 {
|
||||
droplet.x = self.x + (state.game_rng.range(-8..8) * 0x200) as i32;
|
||||
droplet.vel_x = if vertical_splash {
|
||||
(self.vel_x + state.game_rng.range(-0x200..0x200) as i32) - (self.vel_x / 2)
|
||||
} else if horizontal_splash {
|
||||
self.vel_x + state.game_rng.range(-0x200..0x200) as i32
|
||||
} else {
|
||||
0 as i32
|
||||
|
||||
droplet.vel_x = self.vel_x + state.game_rng.range(-0x200..0x200);
|
||||
droplet.vel_y = match () {
|
||||
_ if vertical_splash => state.game_rng.range(-0x200..0x80) - (self.vel_y / 2),
|
||||
_ if horizontal_splash => state.game_rng.range(-0x200..0x80),
|
||||
_ => 0,
|
||||
};
|
||||
droplet.vel_y = state.game_rng.range(-0x200..0x80) as i32;
|
||||
|
||||
let _ = npc_list.spawn(0x100, droplet.clone());
|
||||
}
|
||||
|
@ -478,30 +471,34 @@ impl Player {
|
|||
}
|
||||
|
||||
// camera
|
||||
self.index_x = clamp(self.index_x + self.direction.vector_x() * 0x200, -0x8000, 0x8000);
|
||||
self.camera_target_x = clamp(self.camera_target_x + self.direction.vector_x() * 0x200, -0x8000, 0x8000);
|
||||
|
||||
if state.control_flags.control_enabled() && self.controller.look_up() {
|
||||
self.index_y -= 0x200; // 1.0fix9
|
||||
if self.index_y < -0x8000 { // -64.0fix9
|
||||
self.index_y = -0x8000;
|
||||
self.camera_target_y -= 0x200; // 1.0fix9
|
||||
if self.camera_target_y < -0x8000 {
|
||||
// -64.0fix9
|
||||
self.camera_target_y = -0x8000;
|
||||
}
|
||||
} else if state.control_flags.control_enabled() && self.controller.look_down() {
|
||||
self.index_y += 0x200; // 1.0fix9
|
||||
if self.index_y > 0x8000 { // -64.0fix9
|
||||
self.index_y = 0x8000;
|
||||
self.camera_target_y += 0x200; // 1.0fix9
|
||||
if self.camera_target_y > 0x8000 {
|
||||
// -64.0fix9
|
||||
self.camera_target_y = 0x8000;
|
||||
}
|
||||
} else {
|
||||
if self.index_y > 0x200 { // 1.0fix9
|
||||
self.index_y -= 0x200;
|
||||
if self.camera_target_y > 0x200 {
|
||||
// 1.0fix9
|
||||
self.camera_target_y -= 0x200;
|
||||
}
|
||||
|
||||
if self.index_y < -0x200 { // 1.0fix9
|
||||
self.index_y += 0x200;
|
||||
if self.camera_target_y < -0x200 {
|
||||
// 1.0fix9
|
||||
self.camera_target_y += 0x200;
|
||||
}
|
||||
}
|
||||
|
||||
self.target_x = self.x + self.index_x;
|
||||
self.target_y = self.y + self.index_y;
|
||||
self.target_x = self.x + self.camera_target_x;
|
||||
self.target_y = self.y + self.camera_target_y;
|
||||
|
||||
if self.vel_x > physics.resist || self.vel_x < -physics.resist {
|
||||
self.x += self.vel_x;
|
||||
|
@ -687,7 +684,7 @@ impl GameEntity<&NPCList> for Player {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<> {
|
||||
fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult {
|
||||
if !self.cond.alive() || self.cond.hidden() || (self.shock_counter / 2 % 2 != 0) {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -697,23 +694,31 @@ impl GameEntity<&NPCList> for Player {
|
|||
match self.direction {
|
||||
Direction::Left => {
|
||||
batch.add_rect(
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time) - 8.0,
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time) + self.weapon_offset_y as f32,
|
||||
interpolate_fix9_scale(
|
||||
self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time,
|
||||
) - 8.0,
|
||||
interpolate_fix9_scale(
|
||||
self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time,
|
||||
) + self.weapon_offset_y as f32,
|
||||
&self.weapon_rect,
|
||||
);
|
||||
}
|
||||
Direction::Right => {
|
||||
batch.add_rect(
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time),
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time) + self.weapon_offset_y as f32,
|
||||
interpolate_fix9_scale(
|
||||
self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time,
|
||||
),
|
||||
interpolate_fix9_scale(
|
||||
self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time,
|
||||
) + self.weapon_offset_y as f32,
|
||||
&self.weapon_rect,
|
||||
);
|
||||
}
|
||||
|
@ -726,12 +731,16 @@ impl GameEntity<&NPCList> for Player {
|
|||
{
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
|
||||
batch.add_rect(
|
||||
interpolate_fix9_scale(self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time),
|
||||
interpolate_fix9_scale(self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time),
|
||||
interpolate_fix9_scale(
|
||||
self.prev_x - self.display_bounds.left as i32 - frame.prev_x,
|
||||
self.x - self.display_bounds.left as i32 - frame.x,
|
||||
state.frame_time,
|
||||
),
|
||||
interpolate_fix9_scale(
|
||||
self.prev_y - self.display_bounds.left as i32 - frame.prev_y,
|
||||
self.y - self.display_bounds.left as i32 - frame.y,
|
||||
state.frame_time,
|
||||
),
|
||||
&self.anim_rect,
|
||||
);
|
||||
batch.draw(ctx)?;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use log::info;
|
||||
use num_traits::{abs, clamp};
|
||||
|
||||
use crate::bullet::BulletManager;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::{fix9_scale, interpolate_fix9_scale, Color, Direction, FadeDirection, FadeState, Rect};
|
||||
use crate::components::boss_life_bar::BossLifeBar;
|
||||
|
|
647
src/weapon.rs
647
src/weapon.rs
|
@ -1,647 +0,0 @@
|
|||
use num_derive::FromPrimitive;
|
||||
|
||||
use crate::bullet::{Bullet, BulletManager};
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::inventory::Inventory;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, FromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum WeaponType {
|
||||
None = 0,
|
||||
Snake = 1,
|
||||
PolarStar = 2,
|
||||
Fireball = 3,
|
||||
MachineGun = 4,
|
||||
MissileLauncher = 5,
|
||||
Bubbler = 7,
|
||||
Blade = 9,
|
||||
SuperMissileLauncher = 10,
|
||||
Nemesis = 12,
|
||||
Spur = 13,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum WeaponLevel {
|
||||
None = 0,
|
||||
Level1 = 1,
|
||||
Level2 = 2,
|
||||
Level3 = 3,
|
||||
}
|
||||
|
||||
impl WeaponLevel {
|
||||
pub fn next(self) -> WeaponLevel {
|
||||
match self {
|
||||
WeaponLevel::None => WeaponLevel::Level1,
|
||||
WeaponLevel::Level1 => WeaponLevel::Level2,
|
||||
WeaponLevel::Level2 => WeaponLevel::Level3,
|
||||
WeaponLevel::Level3 => WeaponLevel::Level3,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev(self) -> WeaponLevel {
|
||||
match self {
|
||||
WeaponLevel::None => WeaponLevel::Level1,
|
||||
WeaponLevel::Level1 => WeaponLevel::Level1,
|
||||
WeaponLevel::Level2 => WeaponLevel::Level1,
|
||||
WeaponLevel::Level3 => WeaponLevel::Level2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Weapon {
|
||||
pub wtype: WeaponType,
|
||||
pub level: WeaponLevel,
|
||||
pub experience: u16,
|
||||
pub ammo: u16,
|
||||
pub max_ammo: u16,
|
||||
counter1: u16,
|
||||
counter2: u16,
|
||||
}
|
||||
|
||||
impl Weapon {
|
||||
pub fn new(wtype: WeaponType, level: WeaponLevel, experience: u16, ammo: u16, max_ammo: u16) -> Weapon {
|
||||
Weapon { wtype, level, experience, ammo, max_ammo, counter1: 0, counter2: 0 }
|
||||
}
|
||||
|
||||
/// Consume a specified amount of bullets, returns true if there was enough ammo.
|
||||
pub fn consume_ammo(&mut self, amount: u16) -> bool {
|
||||
if self.max_ammo == 0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.ammo >= amount {
|
||||
self.ammo -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Refill a specified amount of bullets.
|
||||
pub fn refill_ammo(&mut self, amount: u16) {
|
||||
if self.max_ammo != 0 {
|
||||
self.ammo = self.ammo.saturating_add(amount).min(self.max_ammo);
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_snake(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&[1, 2, 3], player_id) < 4 {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 1,
|
||||
WeaponLevel::Level2 => 2,
|
||||
WeaponLevel::Level3 => 3,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
// todo switch to first weapon
|
||||
return;
|
||||
}
|
||||
|
||||
self.counter1 = self.counter1.wrapping_add(1);
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
let mut bullet = Bullet::new(player.x - 0x600, player.y - 10 * 0x200, btype, player_id, Direction::Up, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x600, player.y - 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
let mut bullet = Bullet::new(player.x + 0x600, player.y - 10 * 0x200, btype, player_id, Direction::Up, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x600, player.y - 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
let mut bullet = Bullet::new(player.x - 0x600, player.y + 10 * 0x200, btype, player_id, Direction::Bottom, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x600, player.y + 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
let mut bullet = Bullet::new(player.x + 0x600, player.y + 10 * 0x200, btype, player_id, Direction::Bottom, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x600, player.y + 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
let mut bullet = Bullet::new(player.x - 0xc00, player.y + 0x400, btype, player_id, Direction::Left, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
let mut bullet = Bullet::new(player.x + 0xc00, player.y + 0x400, btype, player_id, Direction::Right, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(33);
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_polar_star(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&[4, 5, 6], player_id) < 2 {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 4,
|
||||
WeaponLevel::Level2 => 5,
|
||||
WeaponLevel::Level3 => 6,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
state.sound_manager.play_sfx(49);
|
||||
} else {
|
||||
state.sound_manager.play_sfx(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_fireball(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
let max_bullets = self.level as usize + 1;
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&[7, 8, 9], player_id) < max_bullets {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 7,
|
||||
WeaponLevel::Level2 => 8,
|
||||
WeaponLevel::Level3 => 9,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
// todo switch to first weapon
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x800, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x800, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x800, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x800, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x800, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x800, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x800, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x800, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x400, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x400, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(34)
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_machine_gun(&mut self, player: &mut Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
const BULLETS: [u16; 3] = [10, 11, 12];
|
||||
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) >= 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
if player.controller.shoot() {
|
||||
self.counter2 = 0; // recharge time counter
|
||||
self.counter1 += 1; // autofire counter
|
||||
|
||||
if self.counter1 > 5 {
|
||||
self.counter1 = 0;
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 10,
|
||||
WeaponLevel::Level2 => 11,
|
||||
WeaponLevel::Level3 => 12,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
player.vel_y += 0x100;
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
if player.vel_y > 0 {
|
||||
player.vel_y /= 2;
|
||||
}
|
||||
if player.vel_y > -0x400 {
|
||||
player.vel_y = (player.vel_y - 0x200).max(-0x400);
|
||||
}
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x1800, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x1800, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
state.sound_manager.play_sfx(49);
|
||||
} else {
|
||||
state.sound_manager.play_sfx(32);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.counter1 = 6;
|
||||
self.counter2 += 1;
|
||||
|
||||
if (player.equip.has_turbocharge() && self.counter2 > 1) || self.counter2 > 4 {
|
||||
self.counter2 = 0;
|
||||
self.refill_ammo(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_blade(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
const BULLETS: [u16; 3] = [25, 26, 27];
|
||||
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&BULLETS, player_id) == 0 {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 25,
|
||||
WeaponLevel::Level2 => 26,
|
||||
WeaponLevel::Level3 => 27,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x800, btype, player_id, Direction::Up, &state.constants);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x800, btype, player_id, Direction::Up, &state.constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0xc00, btype, player_id, Direction::Bottom, &state.constants);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0xc00, btype, player_id, Direction::Bottom, &state.constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y - 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y - 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(34)
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_nemesis(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
const BULLETS: [u16; 3] = [34, 35, 36];
|
||||
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&BULLETS, player_id) < 2 {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 34,
|
||||
WeaponLevel::Level2 => 35,
|
||||
WeaponLevel::Level3 => 36,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1800, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1800, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1800, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1800, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x2c00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x2000, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x2c00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x2000, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match self.level {
|
||||
WeaponLevel::Level1 => state.sound_manager.play_sfx(117),
|
||||
WeaponLevel::Level2 => state.sound_manager.play_sfx(49),
|
||||
WeaponLevel::Level3 => state.sound_manager.play_sfx(60),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_spur(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
inventory: &mut Inventory,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
let mut shoot = false;
|
||||
let btype;
|
||||
|
||||
if player.controller.shoot() {
|
||||
inventory.add_xp(if player.equip.has_turbocharge() { 3 } else { 2 }, player, state);
|
||||
self.counter1 += 1;
|
||||
|
||||
if (self.counter1 / 2 % 2) != 0 {
|
||||
match self.level {
|
||||
WeaponLevel::Level1 => {
|
||||
state.sound_manager.play_sfx(59);
|
||||
}
|
||||
WeaponLevel::Level2 => {
|
||||
state.sound_manager.play_sfx(60);
|
||||
}
|
||||
WeaponLevel::Level3 => {
|
||||
if let (_, _, false) = inventory.get_current_max_exp(&state.constants) {
|
||||
state.sound_manager.play_sfx(61);
|
||||
}
|
||||
}
|
||||
WeaponLevel::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.counter1 > 0 {
|
||||
shoot = true;
|
||||
self.counter1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if let (_, _, true) = inventory.get_current_max_exp(&state.constants) {
|
||||
if self.counter2 == 0 {
|
||||
self.counter2 = 1;
|
||||
state.sound_manager.play_sfx(65);
|
||||
}
|
||||
} else {
|
||||
self.counter2 = 0;
|
||||
}
|
||||
|
||||
let level = self.level;
|
||||
if !player.controller.shoot() {
|
||||
inventory.reset_current_weapon_xp();
|
||||
}
|
||||
|
||||
match level {
|
||||
WeaponLevel::Level1 => {
|
||||
btype = 6;
|
||||
shoot = false;
|
||||
}
|
||||
WeaponLevel::Level2 => btype = 37,
|
||||
WeaponLevel::Level3 => {
|
||||
if self.counter2 == 1 {
|
||||
btype = 39;
|
||||
} else {
|
||||
btype = 38;
|
||||
}
|
||||
}
|
||||
WeaponLevel::None => unreachable!(),
|
||||
}
|
||||
|
||||
const BULLETS: [u16; 6] = [44, 45, 46, 47, 48, 49];
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) == 0 && (player.controller.trigger_shoot() || shoot) {
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
} else {
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let sound = match btype {
|
||||
6 => 49,
|
||||
37 => 62,
|
||||
38 => 63,
|
||||
39 => 64,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
state.sound_manager.play_sfx(sound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
inventory: &mut Inventory,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
if !player.cond.alive() || player.cond.hidden() {
|
||||
return;
|
||||
}
|
||||
|
||||
// todo lua hook
|
||||
|
||||
match self.wtype {
|
||||
WeaponType::None => {}
|
||||
WeaponType::Snake => self.tick_snake(player, player_id, bullet_manager, state),
|
||||
WeaponType::PolarStar => self.tick_polar_star(player, player_id, bullet_manager, state),
|
||||
WeaponType::Fireball => self.tick_fireball(player, player_id, bullet_manager, state),
|
||||
WeaponType::MachineGun => self.tick_machine_gun(player, player_id, bullet_manager, state),
|
||||
WeaponType::MissileLauncher => {}
|
||||
WeaponType::Bubbler => {}
|
||||
WeaponType::Blade => self.tick_blade(player, player_id, bullet_manager, state),
|
||||
WeaponType::SuperMissileLauncher => {}
|
||||
WeaponType::Nemesis => self.tick_nemesis(player, player_id, bullet_manager, state),
|
||||
WeaponType::Spur => self.tick_spur(player, player_id, inventory, bullet_manager, state),
|
||||
}
|
||||
}
|
||||
}
|
46
src/weapon/blade.rs
Normal file
46
src/weapon/blade.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_blade(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
const BULLETS: [u16; 3] = [25, 26, 27];
|
||||
|
||||
if !player.controller.trigger_shoot() || bullet_manager.count_bullets_multi(&BULLETS, player_id) > 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 25,
|
||||
WeaponLevel::Level2 => 26,
|
||||
WeaponLevel::Level3 => 27,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x800, btype, player_id, Direction::Up, &state.constants);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x800, btype, player_id, Direction::Up, &state.constants);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0xc00, btype, player_id, Direction::Bottom, &state.constants);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0xc00, btype, player_id, Direction::Bottom, &state.constants);
|
||||
}
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y - 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y - 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(34);
|
||||
}
|
||||
}
|
133
src/weapon/bubbler.rs
Normal file
133
src/weapon/bubbler.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::WeaponLevel::Level1;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_bubbler(
|
||||
&mut self,
|
||||
player: &Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
const BULLETS: [u16; 3] = [19, 20, 21];
|
||||
|
||||
if self.level == WeaponLevel::Level1 {
|
||||
if !player.controller.trigger_shoot() {
|
||||
self.counter2 += 1;
|
||||
if self.counter2 > 20 {
|
||||
self.counter2 = 0;
|
||||
self.refill_ammo(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) > 3 {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
// todo spawn "empty" text
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = 19;
|
||||
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(48);
|
||||
} else {
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) > 15 {
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = if self.level == WeaponLevel::Level2 { 20 } else { 21 };
|
||||
|
||||
if !player.controller.shoot() {
|
||||
self.counter1 = 6;
|
||||
self.counter2 += 1;
|
||||
|
||||
if self.counter2 > 1 {
|
||||
self.counter2 = 0;
|
||||
self.refill_ammo(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.counter2 = 0; // recharge time counter
|
||||
self.counter1 += 1; // autofire counter
|
||||
|
||||
if self.counter1 > 6 {
|
||||
self.counter1 = 0;
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
// todo spawn "empty" text
|
||||
return;
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y - 0x2000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y - 0x2000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y + 0x2000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y + 0x2000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(48);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ use crate::engine_constants::{BulletData, EngineConstants};
|
|||
use crate::npc::list::NPCList;
|
||||
use crate::npc::NPC;
|
||||
use crate::physics::{PhysicalEntity, OFF_X, OFF_Y};
|
||||
use crate::player::TargetPlayer;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::rng::{XorShift, Xoroshiro32PlusPlus, RNG};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::stage::Stage;
|
||||
|
@ -22,22 +22,10 @@ pub struct BulletManager {
|
|||
impl BulletManager {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> BulletManager {
|
||||
BulletManager {
|
||||
bullets: Vec::with_capacity(64),
|
||||
new_bullets: Vec::with_capacity(8),
|
||||
seeder: XorShift::new(0x359c482f),
|
||||
}
|
||||
BulletManager { bullets: Vec::with_capacity(64), new_bullets: Vec::with_capacity(8), seeder: XorShift::new(0x359c482f) }
|
||||
}
|
||||
|
||||
pub fn create_bullet(
|
||||
&mut self,
|
||||
x: i32,
|
||||
y: i32,
|
||||
btype: u16,
|
||||
owner: TargetPlayer,
|
||||
direction: Direction,
|
||||
constants: &EngineConstants,
|
||||
) {
|
||||
pub fn create_bullet(&mut self, x: i32, y: i32, btype: u16, owner: TargetPlayer, direction: Direction, constants: &EngineConstants) {
|
||||
let mut bullet = Bullet::new(x, y, btype, owner, direction, constants);
|
||||
bullet.rng = Xoroshiro32PlusPlus::new(self.seeder.next_u32());
|
||||
|
||||
|
@ -49,13 +37,7 @@ impl BulletManager {
|
|||
self.bullets.push(bullet);
|
||||
}
|
||||
|
||||
pub fn tick_bullets(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&dyn PhysicalEntity; 2],
|
||||
npc_list: &NPCList,
|
||||
stage: &mut Stage,
|
||||
) {
|
||||
pub fn tick_bullets(&mut self, state: &mut SharedGameState, players: [&Player; 2], npc_list: &NPCList, stage: &mut Stage) {
|
||||
let mut i = 0;
|
||||
while i < self.bullets.len() {
|
||||
{
|
||||
|
@ -126,14 +108,7 @@ pub struct Bullet {
|
|||
}
|
||||
|
||||
impl Bullet {
|
||||
pub fn new(
|
||||
x: i32,
|
||||
y: i32,
|
||||
btype: u16,
|
||||
owner: TargetPlayer,
|
||||
direction: Direction,
|
||||
constants: &EngineConstants,
|
||||
) -> Bullet {
|
||||
pub fn new(x: i32, y: i32, btype: u16, owner: TargetPlayer, direction: Direction, constants: &EngineConstants) -> Bullet {
|
||||
let bullet = constants.weapon.bullet_table.get(btype as usize).unwrap_or_else(|| &BulletData {
|
||||
damage: 0,
|
||||
life: 0,
|
||||
|
@ -374,7 +349,7 @@ impl Bullet {
|
|||
}
|
||||
}
|
||||
|
||||
fn tick_fireball(&mut self, state: &mut SharedGameState, players: [&dyn PhysicalEntity; 2], npc_list: &NPCList) {
|
||||
fn tick_fireball(&mut self, state: &mut SharedGameState, players: [&Player; 2], npc_list: &NPCList) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > self.lifetime {
|
||||
self.cond.set_alive(false);
|
||||
|
@ -382,9 +357,7 @@ impl Bullet {
|
|||
return;
|
||||
}
|
||||
|
||||
if (self.flags.hit_left_wall() && self.flags.hit_right_wall())
|
||||
|| (self.flags.hit_top_wall() && self.flags.hit_bottom_wall())
|
||||
{
|
||||
if (self.flags.hit_left_wall() && self.flags.hit_right_wall()) || (self.flags.hit_top_wall() && self.flags.hit_bottom_wall()) {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
state.sound_manager.play_sfx(28);
|
||||
|
@ -470,8 +443,7 @@ impl Bullet {
|
|||
|
||||
let dir_offset = if self.direction == Direction::Left { 0 } else { 3 };
|
||||
|
||||
self.anim_rect =
|
||||
state.constants.weapon.bullet_rects.b008_009_fireball_l2_3[self.anim_num as usize + dir_offset];
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b008_009_fireball_l2_3[self.anim_num as usize + dir_offset];
|
||||
|
||||
let mut npc = NPC::create(129, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
|
@ -566,6 +538,253 @@ impl Bullet {
|
|||
}
|
||||
}
|
||||
|
||||
fn tick_bubble_1(&mut self, state: &mut SharedGameState) {
|
||||
if self.flags.hit_anything() {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.vel_x = -0x600,
|
||||
Direction::Up => self.vel_y = -0x600,
|
||||
Direction::Right => self.vel_x = 0x600,
|
||||
Direction::Bottom => self.vel_y = 0x600,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.vel_x += 0x2a,
|
||||
Direction::Up => self.vel_y += 0x2a,
|
||||
Direction::Right => self.vel_x -= 0x2a,
|
||||
Direction::Bottom => self.vel_y -= 0x2a,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 40 {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::SmallProjectileDissipation, Direction::Left);
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 3 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 3 {
|
||||
self.anim_num = 3;
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b019_bubble_l1[self.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_bubble_2(&mut self, state: &mut SharedGameState) {
|
||||
if (self.direction == Direction::Left && self.flags.hit_left_wall())
|
||||
|| (self.direction == Direction::Right && self.flags.hit_right_wall())
|
||||
|| (self.direction == Direction::Up && self.flags.hit_top_wall())
|
||||
|| (self.direction == Direction::Bottom && self.flags.hit_bottom_wall())
|
||||
{
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
self.vel_x = -0x600;
|
||||
self.vel_y = self.rng.range(-0x100..0x100);
|
||||
}
|
||||
Direction::Up => {
|
||||
self.vel_y = -0x600;
|
||||
self.vel_x = self.rng.range(-0x100..0x100);
|
||||
}
|
||||
Direction::Right => {
|
||||
self.vel_x = 0x600;
|
||||
self.vel_y = self.rng.range(-0x100..0x100);
|
||||
}
|
||||
Direction::Bottom => {
|
||||
self.vel_y = 0x600;
|
||||
self.vel_x = self.rng.range(-0x100..0x100);
|
||||
}
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.vel_x += 0x10,
|
||||
Direction::Up => self.vel_y += 0x10,
|
||||
Direction::Right => self.vel_x -= 0x10,
|
||||
Direction::Bottom => self.vel_y -= 0x10,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > 60 {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::SmallProjectileDissipation, Direction::Left);
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 3 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 3 {
|
||||
self.anim_num = 3;
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b020_bubble_l2[self.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_bubble_3(&mut self, state: &mut SharedGameState, players: [&Player; 2], new_bullets: &mut Vec<Bullet>) {
|
||||
let player = players[self.owner.index()];
|
||||
|
||||
self.action_counter += 1;
|
||||
|
||||
if self.action_counter > 100 || !player.controller.shoot() {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::ProjectileDissipation, Direction::Left);
|
||||
state.sound_manager.play_sfx(100);
|
||||
|
||||
match () {
|
||||
_ if player.up => new_bullets.push(Bullet::new(self.x, self.y, 22, self.owner, Direction::Up, &state.constants)),
|
||||
_ if player.down => new_bullets.push(Bullet::new(self.x, self.y, 22, self.owner, Direction::Bottom, &state.constants)),
|
||||
_ => new_bullets.push(Bullet::new(self.x, self.y, 22, self.owner, player.direction, &state.constants)),
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if self.action_counter == 0 {
|
||||
self.action_counter = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
self.vel_x = self.rng.range(-0x400..-0x200);
|
||||
self.vel_y = self.rng.range(-4..4) * 0x200 / 2;
|
||||
}
|
||||
Direction::Up => {
|
||||
self.vel_y = self.rng.range(-0x400..-0x200);
|
||||
self.vel_x = self.rng.range(-4..4) * 0x200 / 2;
|
||||
}
|
||||
Direction::Right => {
|
||||
self.vel_x = self.rng.range(0x200..0x400);
|
||||
self.vel_y = self.rng.range(-4..4) * 0x200 / 2;
|
||||
}
|
||||
Direction::Bottom => {
|
||||
self.vel_y = self.rng.range(0x80..0x100);
|
||||
self.vel_x = self.rng.range(-4..4) * 0x200 / 2;
|
||||
}
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
self.vel_x += (player.x - self.x).signum() * 0x20;
|
||||
self.vel_y += (player.y - self.y).signum() * 0x20;
|
||||
|
||||
if self.vel_x < 0 && self.flags.hit_left_wall() {
|
||||
self.vel_x = 0x400;
|
||||
}
|
||||
|
||||
if self.vel_x > 0 && self.flags.hit_right_wall() {
|
||||
self.vel_x = -0x400;
|
||||
}
|
||||
|
||||
if self.vel_y < 0 && self.flags.hit_top_wall() {
|
||||
self.vel_y = 0x400;
|
||||
}
|
||||
|
||||
if self.vel_y > 0 && self.flags.hit_bottom_wall() {
|
||||
self.vel_y = -0x400;
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 3 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 3 {
|
||||
self.anim_num = 3;
|
||||
}
|
||||
}
|
||||
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b021_bubble_l3[self.anim_num as usize];
|
||||
}
|
||||
|
||||
fn tick_bubble_spines(&mut self, state: &mut SharedGameState) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > self.lifetime || self.flags.hit_bottom_wall() {
|
||||
self.cond.set_alive(false);
|
||||
|
||||
state.create_caret(self.x, self.y, CaretType::Shoot, Direction::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
let val = self.rng.range(10..16);
|
||||
// what the fuck
|
||||
self.vel_x = (((val * -0x200).rotate_left(1) & 1) - val * 0x200) / 2;
|
||||
}
|
||||
Direction::Up => {
|
||||
let val = self.rng.range(10..16);
|
||||
// what the fuck
|
||||
self.vel_y = (((val * -0x200).rotate_left(1) & 1) - val * 0x200) / 2;
|
||||
}
|
||||
Direction::Right => {
|
||||
self.vel_x = (self.rng.range(10..16) * 0x200) / 2;
|
||||
}
|
||||
Direction::Bottom => {
|
||||
self.vel_y = (self.rng.range(10..16) * 0x200) / 2;
|
||||
}
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
|
||||
self.anim_counter += 1;
|
||||
if self.anim_counter > 1 {
|
||||
self.anim_counter = 0;
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 1 {
|
||||
self.anim_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b022_bubble_spines[self.anim_num as usize];
|
||||
}
|
||||
Direction::Right => {
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b022_bubble_spines[self.anim_num as usize + 2];
|
||||
}
|
||||
Direction::Up | Direction::Bottom => {
|
||||
self.anim_rect = state.constants.weapon.bullet_rects.b022_bubble_spines[self.anim_num as usize + 4];
|
||||
}
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn tick_blade_slash(&mut self, state: &mut SharedGameState) {
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
@ -768,6 +987,84 @@ impl Bullet {
|
|||
}
|
||||
}
|
||||
|
||||
fn tick_nemesis(&mut self, state: &mut SharedGameState, npc_list: &NPCList) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > self.lifetime {
|
||||
self.cond.set_alive(false);
|
||||
state.create_caret(self.x, self.y, CaretType::Shoot, Direction::Left);
|
||||
return;
|
||||
}
|
||||
|
||||
if self.action_num == 0 {
|
||||
self.action_num = 1;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => self.vel_x = -0x1000,
|
||||
Direction::Up => self.vel_y = -0x1000,
|
||||
Direction::Right => self.vel_x = 0x1000,
|
||||
Direction::Bottom => self.vel_y = 0x1000,
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
|
||||
if self.btype == 36 {
|
||||
self.vel_x /= 3;
|
||||
self.vel_y /= 3;
|
||||
}
|
||||
} else {
|
||||
if self.btype == 34 && self.action_counter % 4 == 1 {
|
||||
let mut npc = NPC::create(4, &state.npc_table);
|
||||
npc.cond.set_alive(true);
|
||||
npc.x = self.x;
|
||||
npc.y = self.y;
|
||||
|
||||
match self.direction {
|
||||
Direction::Left => {
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
npc.vel_x = -0x200;
|
||||
}
|
||||
Direction::Up => {
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = -0x200;
|
||||
}
|
||||
Direction::Right => {
|
||||
npc.vel_y = self.rng.range(-0x200..0x200);
|
||||
npc.vel_x = 0x200;
|
||||
}
|
||||
Direction::Bottom => {
|
||||
npc.vel_x = self.rng.range(-0x200..0x200);
|
||||
npc.vel_y = 0x200;
|
||||
}
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
}
|
||||
|
||||
let _ = npc_list.spawn(256, npc);
|
||||
}
|
||||
|
||||
self.x += self.vel_x;
|
||||
self.y += self.vel_y;
|
||||
}
|
||||
|
||||
self.anim_num += 1;
|
||||
if self.anim_num > 1 {
|
||||
self.anim_num = 0;
|
||||
}
|
||||
|
||||
let dir_offset = match self.direction {
|
||||
Direction::Left => 0,
|
||||
Direction::Up => 2,
|
||||
Direction::Right => 4,
|
||||
Direction::Bottom => 6,
|
||||
Direction::FacingPlayer => unreachable!(),
|
||||
} + self.anim_num as usize;
|
||||
|
||||
self.anim_rect = match self.btype {
|
||||
34 => state.constants.weapon.bullet_rects.b034_nemesis_l1[dir_offset],
|
||||
35 => state.constants.weapon.bullet_rects.b035_nemesis_l2[dir_offset],
|
||||
36 => state.constants.weapon.bullet_rects.b036_nemesis_l3[dir_offset],
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
fn tick_spur(&mut self, state: &mut SharedGameState, new_bullets: &mut Vec<Bullet>) {
|
||||
self.action_counter += 1;
|
||||
if self.action_counter > self.lifetime {
|
||||
|
@ -897,13 +1194,7 @@ impl Bullet {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
state: &mut SharedGameState,
|
||||
players: [&dyn PhysicalEntity; 2],
|
||||
npc_list: &NPCList,
|
||||
new_bullets: &mut Vec<Bullet>,
|
||||
) {
|
||||
pub fn tick(&mut self, state: &mut SharedGameState, players: [&Player; 2], npc_list: &NPCList, new_bullets: &mut Vec<Bullet>) {
|
||||
if self.life == 0 {
|
||||
self.cond.set_alive(false);
|
||||
return;
|
||||
|
@ -915,10 +1206,15 @@ impl Bullet {
|
|||
4 | 5 | 6 => self.tick_polar_star(state),
|
||||
7 | 8 | 9 => self.tick_fireball(state, players, npc_list),
|
||||
10 | 11 | 12 => self.tick_machine_gun(state, npc_list),
|
||||
19 => self.tick_bubble_1(state),
|
||||
20 => self.tick_bubble_2(state),
|
||||
21 => self.tick_bubble_3(state, players, new_bullets),
|
||||
22 => self.tick_bubble_spines(state),
|
||||
23 => self.tick_blade_slash(state),
|
||||
25 => self.tick_blade_1(state),
|
||||
26 => self.tick_blade_2(state),
|
||||
27 => self.tick_blade_3(state, new_bullets),
|
||||
34 | 35 | 36 => self.tick_nemesis(state, npc_list),
|
||||
37 | 38 | 39 => self.tick_spur(state, new_bullets),
|
||||
40 | 41 | 42 => self.tick_spur_trail(state),
|
||||
_ => self.cond.set_alive(false),
|
||||
|
@ -954,16 +1250,10 @@ impl Bullet {
|
|||
self.flags.set_hit_left_wall(true);
|
||||
}
|
||||
} else if hits[0] && !hits[2] {
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x
|
||||
&& (self.y - self.hit_bounds.top as i32) < block_y - (3 * 0x200)
|
||||
{
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x && (self.y - self.hit_bounds.top as i32) < block_y - (3 * 0x200) {
|
||||
self.flags.set_hit_left_wall(true);
|
||||
}
|
||||
} else if !hits[0]
|
||||
&& hits[2]
|
||||
&& (self.x - self.hit_bounds.left as i32) < block_x
|
||||
&& (self.y + self.hit_bounds.top as i32) > block_y + (3 * 0x200)
|
||||
{
|
||||
} else if !hits[0] && hits[2] && (self.x - self.hit_bounds.left as i32) < block_x && (self.y + self.hit_bounds.top as i32) > block_y + (3 * 0x200) {
|
||||
self.flags.set_hit_left_wall(true);
|
||||
}
|
||||
|
||||
|
@ -973,16 +1263,10 @@ impl Bullet {
|
|||
self.flags.set_hit_right_wall(true);
|
||||
}
|
||||
} else if hits[1] && !hits[3] {
|
||||
if (self.x + self.hit_bounds.right as i32) > block_x
|
||||
&& (self.y - self.hit_bounds.top as i32) < block_y - (3 * 0x200)
|
||||
{
|
||||
if (self.x + self.hit_bounds.right as i32) > block_x && (self.y - self.hit_bounds.top as i32) < block_y - (3 * 0x200) {
|
||||
self.flags.set_hit_right_wall(true);
|
||||
}
|
||||
} else if !hits[1]
|
||||
&& hits[3]
|
||||
&& (self.x + self.hit_bounds.right as i32) > block_x
|
||||
&& (self.y + self.hit_bounds.top as i32) > block_y + (3 * 0x200)
|
||||
{
|
||||
} else if !hits[1] && hits[3] && (self.x + self.hit_bounds.right as i32) > block_x && (self.y + self.hit_bounds.top as i32) > block_y + (3 * 0x200) {
|
||||
self.flags.set_hit_right_wall(true);
|
||||
}
|
||||
|
||||
|
@ -992,16 +1276,10 @@ impl Bullet {
|
|||
self.flags.set_hit_top_wall(true);
|
||||
}
|
||||
} else if hits[0] && !hits[1] {
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x - (3 * 0x200)
|
||||
&& (self.y - self.hit_bounds.top as i32) < block_y
|
||||
{
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x - (3 * 0x200) && (self.y - self.hit_bounds.top as i32) < block_y {
|
||||
self.flags.set_hit_top_wall(true);
|
||||
}
|
||||
} else if !hits[0]
|
||||
&& hits[1]
|
||||
&& (self.x + self.hit_bounds.right as i32) > block_x + (3 * 0x200)
|
||||
&& (self.y - self.hit_bounds.top as i32) < block_y
|
||||
{
|
||||
} else if !hits[0] && hits[1] && (self.x + self.hit_bounds.right as i32) > block_x + (3 * 0x200) && (self.y - self.hit_bounds.top as i32) < block_y {
|
||||
self.flags.set_hit_top_wall(true);
|
||||
}
|
||||
|
||||
|
@ -1011,16 +1289,10 @@ impl Bullet {
|
|||
self.flags.set_hit_bottom_wall(true);
|
||||
}
|
||||
} else if hits[2] && !hits[3] {
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x - (3 * 0x200)
|
||||
&& (self.y + self.hit_bounds.bottom as i32) > block_y
|
||||
{
|
||||
if (self.x - self.hit_bounds.left as i32) < block_x - (3 * 0x200) && (self.y + self.hit_bounds.bottom as i32) > block_y {
|
||||
self.flags.set_hit_bottom_wall(true);
|
||||
}
|
||||
} else if !hits[2]
|
||||
&& hits[3]
|
||||
&& (self.x + self.hit_bounds.right as i32) > block_x + (3 * 0x200)
|
||||
&& (self.y + self.hit_bounds.bottom as i32) > block_y
|
||||
{
|
||||
} else if !hits[2] && hits[3] && (self.x + self.hit_bounds.right as i32) > block_x + (3 * 0x200) && (self.y + self.hit_bounds.bottom as i32) > block_y {
|
||||
self.flags.set_hit_bottom_wall(true);
|
||||
}
|
||||
|
||||
|
@ -1034,11 +1306,7 @@ impl Bullet {
|
|||
} else if self.flags.hit_bottom_wall() {
|
||||
self.y = block_y - self.hit_bounds.top as i32;
|
||||
}
|
||||
} else if self.flags.hit_left_wall()
|
||||
|| self.flags.hit_top_wall()
|
||||
|| self.flags.hit_right_wall()
|
||||
|| self.flags.hit_bottom_wall()
|
||||
{
|
||||
} else if self.flags.hit_left_wall() || self.flags.hit_top_wall() || self.flags.hit_right_wall() || self.flags.hit_bottom_wall() {
|
||||
self.vanish(state);
|
||||
}
|
||||
}
|
||||
|
@ -1174,9 +1442,7 @@ impl PhysicalEntity for Bullet {
|
|||
let _ = npc_list.spawn(0x100, npc.clone());
|
||||
}
|
||||
|
||||
if let Some(tile) =
|
||||
stage.map.tiles.get_mut(stage.map.width as usize * (y + oy) as usize + (x + ox) as usize)
|
||||
{
|
||||
if let Some(tile) = stage.map.tiles.get_mut(stage.map.width as usize * (y + oy) as usize + (x + ox) as usize) {
|
||||
*tile = tile.wrapping_sub(1);
|
||||
}
|
||||
}
|
73
src/weapon/fireball.rs
Normal file
73
src/weapon/fireball.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_fireball(
|
||||
&mut self,
|
||||
player: &Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
let max_bullets = self.level as usize + 1;
|
||||
if player.controller.trigger_shoot() && bullet_manager.count_bullets_multi(&[7, 8, 9], player_id) < max_bullets {
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 7,
|
||||
WeaponLevel::Level2 => 8,
|
||||
WeaponLevel::Level3 => 9,
|
||||
WeaponLevel::None => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
// todo switch to first weapon
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x800, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x800, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x800, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x800, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x800, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x800, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x800, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x800, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x400, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x400, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(34)
|
||||
}
|
||||
}
|
||||
}
|
112
src/weapon/machine_gun.rs
Normal file
112
src/weapon/machine_gun.rs
Normal file
|
@ -0,0 +1,112 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_machine_gun(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
const BULLETS: [u16; 3] = [10, 11, 12];
|
||||
|
||||
if !player.controller.shoot() {
|
||||
self.counter1 = 6;
|
||||
self.counter2 += 1;
|
||||
|
||||
if (player.equip.has_turbocharge() && self.counter2 > 1) || self.counter2 > 4 {
|
||||
self.counter2 = 0;
|
||||
self.refill_ammo(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) > 4 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.counter2 = 0; // recharge time counter
|
||||
self.counter1 += 1; // autofire counter
|
||||
|
||||
if self.counter1 > 5 {
|
||||
self.counter1 = 0;
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 10,
|
||||
WeaponLevel::Level2 => 11,
|
||||
WeaponLevel::Level3 => 12,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
// todo spawn "empty" text
|
||||
return;
|
||||
}
|
||||
|
||||
match () {
|
||||
_ if player.up => {
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
player.vel_y += 0x100;
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ if player.down => {
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
if player.vel_y > 0 {
|
||||
player.vel_y /= 2;
|
||||
}
|
||||
if player.vel_y > -0x400 {
|
||||
player.vel_y = (player.vel_y - 0x200).max(-0x400);
|
||||
}
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x600, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x600, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x600, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x1800, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x1800, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
state.sound_manager.play_sfx(49);
|
||||
} else {
|
||||
state.sound_manager.play_sfx(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
src/weapon/missile_launcher.rs
Normal file
14
src/weapon/missile_launcher.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::Weapon;
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_missile_launcher(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {}
|
||||
}
|
132
src/weapon/mod.rs
Normal file
132
src/weapon/mod.rs
Normal file
|
@ -0,0 +1,132 @@
|
|||
use num_derive::FromPrimitive;
|
||||
|
||||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::inventory::Inventory;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::{Bullet, BulletManager};
|
||||
|
||||
mod blade;
|
||||
mod bubbler;
|
||||
pub mod bullet;
|
||||
mod fireball;
|
||||
mod machine_gun;
|
||||
mod missile_launcher;
|
||||
mod nemesis;
|
||||
mod polar_star;
|
||||
mod snake;
|
||||
mod spur;
|
||||
mod super_missile_launcher;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, FromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum WeaponType {
|
||||
None = 0,
|
||||
Snake = 1,
|
||||
PolarStar = 2,
|
||||
Fireball = 3,
|
||||
MachineGun = 4,
|
||||
MissileLauncher = 5,
|
||||
Bubbler = 7,
|
||||
Blade = 9,
|
||||
SuperMissileLauncher = 10,
|
||||
Nemesis = 12,
|
||||
Spur = 13,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum WeaponLevel {
|
||||
None = 0,
|
||||
Level1 = 1,
|
||||
Level2 = 2,
|
||||
Level3 = 3,
|
||||
}
|
||||
|
||||
impl WeaponLevel {
|
||||
pub fn next(self) -> WeaponLevel {
|
||||
match self {
|
||||
WeaponLevel::None => WeaponLevel::Level1,
|
||||
WeaponLevel::Level1 => WeaponLevel::Level2,
|
||||
WeaponLevel::Level2 => WeaponLevel::Level3,
|
||||
WeaponLevel::Level3 => WeaponLevel::Level3,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev(self) -> WeaponLevel {
|
||||
match self {
|
||||
WeaponLevel::None => WeaponLevel::Level1,
|
||||
WeaponLevel::Level1 => WeaponLevel::Level1,
|
||||
WeaponLevel::Level2 => WeaponLevel::Level1,
|
||||
WeaponLevel::Level3 => WeaponLevel::Level2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Weapon {
|
||||
pub wtype: WeaponType,
|
||||
pub level: WeaponLevel,
|
||||
pub experience: u16,
|
||||
pub ammo: u16,
|
||||
pub max_ammo: u16,
|
||||
counter1: u16,
|
||||
counter2: u16,
|
||||
}
|
||||
|
||||
impl Weapon {
|
||||
pub fn new(wtype: WeaponType, level: WeaponLevel, experience: u16, ammo: u16, max_ammo: u16) -> Weapon {
|
||||
Weapon { wtype, level, experience, ammo, max_ammo, counter1: 0, counter2: 0 }
|
||||
}
|
||||
|
||||
/// Consume a specified amount of bullets, returns true if there was enough ammo.
|
||||
pub fn consume_ammo(&mut self, amount: u16) -> bool {
|
||||
if self.max_ammo == 0 {
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.ammo >= amount {
|
||||
self.ammo -= amount;
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Refill a specified amount of bullets.
|
||||
pub fn refill_ammo(&mut self, amount: u16) {
|
||||
if self.max_ammo != 0 {
|
||||
self.ammo = self.ammo.saturating_add(amount).min(self.max_ammo);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
inventory: &mut Inventory,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
if !player.cond.alive() || player.cond.hidden() {
|
||||
return;
|
||||
}
|
||||
|
||||
// todo lua hook
|
||||
|
||||
match self.wtype {
|
||||
WeaponType::None => {}
|
||||
WeaponType::Snake => self.tick_snake(player, player_id, bullet_manager, state),
|
||||
WeaponType::PolarStar => self.tick_polar_star(player, player_id, bullet_manager, state),
|
||||
WeaponType::Fireball => self.tick_fireball(player, player_id, bullet_manager, state),
|
||||
WeaponType::MachineGun => self.tick_machine_gun(player, player_id, bullet_manager, state),
|
||||
WeaponType::MissileLauncher => self.tick_missile_launcher(player, player_id, bullet_manager, state),
|
||||
WeaponType::Bubbler => self.tick_bubbler(player, player_id, bullet_manager, state),
|
||||
WeaponType::Blade => self.tick_blade(player, player_id, bullet_manager, state),
|
||||
WeaponType::SuperMissileLauncher => self.tick_super_missile_launcher(player, player_id, bullet_manager, state),
|
||||
WeaponType::Nemesis => self.tick_nemesis(player, player_id, bullet_manager, state),
|
||||
WeaponType::Spur => self.tick_spur(player, player_id, inventory, bullet_manager, state),
|
||||
}
|
||||
}
|
||||
}
|
80
src/weapon/nemesis.rs
Normal file
80
src/weapon/nemesis.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_nemesis(
|
||||
&mut self,
|
||||
player: &Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
const BULLETS: [u16; 3] = [34, 35, 36];
|
||||
|
||||
if !player.controller.trigger_shoot() || bullet_manager.count_bullets_multi(&BULLETS, player_id) > 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 34,
|
||||
WeaponLevel::Level2 => 35,
|
||||
WeaponLevel::Level3 => 36,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
// todo spawn "empty" text
|
||||
return;
|
||||
}
|
||||
|
||||
if player.up {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1800, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1800, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else if player.down {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1800, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1800, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0x2c00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0x2000, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0x2c00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0x2000, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match self.level {
|
||||
WeaponLevel::Level1 => state.sound_manager.play_sfx(117),
|
||||
WeaponLevel::Level2 => state.sound_manager.play_sfx(49),
|
||||
WeaponLevel::Level3 => state.sound_manager.play_sfx(60),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
66
src/weapon/polar_star.rs
Normal file
66
src/weapon/polar_star.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_polar_star(
|
||||
&mut self,
|
||||
player: &Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
if !player.controller.trigger_shoot() || bullet_manager.count_bullets_multi(&[4, 5, 6], player_id) > 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 4,
|
||||
WeaponLevel::Level2 => 5,
|
||||
WeaponLevel::Level3 => 6,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
return;
|
||||
}
|
||||
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.level == WeaponLevel::Level3 {
|
||||
state.sound_manager.play_sfx(49);
|
||||
} else {
|
||||
state.sound_manager.play_sfx(32);
|
||||
}
|
||||
}
|
||||
}
|
70
src/weapon/snake.rs
Normal file
70
src/weapon/snake.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::{Bullet, BulletManager};
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_snake(&mut self, player: &Player, player_id: TargetPlayer, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
|
||||
if !player.controller.trigger_shoot() || bullet_manager.count_bullets_multi(&[1, 2, 3], player_id) > 3 {
|
||||
return;
|
||||
}
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 1,
|
||||
WeaponLevel::Level2 => 2,
|
||||
WeaponLevel::Level3 => 3,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
// todo switch to first weapon
|
||||
return;
|
||||
}
|
||||
|
||||
self.counter1 = self.counter1.wrapping_add(1);
|
||||
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
let mut bullet = Bullet::new(player.x - 0x600, player.y - 10 * 0x200, btype, player_id, Direction::Up, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x600, player.y - 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
let mut bullet = Bullet::new(player.x + 0x600, player.y - 10 * 0x200, btype, player_id, Direction::Up, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x600, player.y - 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
let mut bullet = Bullet::new(player.x - 0x600, player.y + 10 * 0x200, btype, player_id, Direction::Bottom, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x600, player.y + 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
let mut bullet = Bullet::new(player.x + 0x600, player.y + 10 * 0x200, btype, player_id, Direction::Bottom, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x600, player.y + 10 * 0x200, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left => {
|
||||
let mut bullet = Bullet::new(player.x - 0xc00, player.y + 0x400, btype, player_id, Direction::Left, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x - 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
let mut bullet = Bullet::new(player.x + 0xc00, player.y + 0x400, btype, player_id, Direction::Right, &state.constants);
|
||||
bullet.target_x = self.counter1 as i32;
|
||||
bullet_manager.push_bullet(bullet);
|
||||
state.create_caret(player.x + 0x1800, player.y + 0x400, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
state.sound_manager.play_sfx(33);
|
||||
}
|
||||
}
|
126
src/weapon/spur.rs
Normal file
126
src/weapon/spur.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::Direction;
|
||||
use crate::inventory::Inventory;
|
||||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_spur(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
inventory: &mut Inventory,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
const BULLETS: [u16; 6] = [44, 45, 46, 47, 48, 49];
|
||||
|
||||
let mut shoot = false;
|
||||
let btype;
|
||||
|
||||
if player.controller.shoot() {
|
||||
inventory.add_xp(if player.equip.has_turbocharge() { 3 } else { 2 }, player, state);
|
||||
self.counter1 += 1;
|
||||
|
||||
if (self.counter1 / 2 % 2) != 0 {
|
||||
match self.level {
|
||||
WeaponLevel::Level1 => {
|
||||
state.sound_manager.play_sfx(59);
|
||||
}
|
||||
WeaponLevel::Level2 => {
|
||||
state.sound_manager.play_sfx(60);
|
||||
}
|
||||
WeaponLevel::Level3 => {
|
||||
if let (_, _, false) = inventory.get_current_max_exp(&state.constants) {
|
||||
state.sound_manager.play_sfx(61);
|
||||
}
|
||||
}
|
||||
WeaponLevel::None => unreachable!(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.counter1 > 0 {
|
||||
shoot = true;
|
||||
self.counter1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if let (_, _, true) = inventory.get_current_max_exp(&state.constants) {
|
||||
if self.counter2 == 0 {
|
||||
self.counter2 = 1;
|
||||
state.sound_manager.play_sfx(65);
|
||||
}
|
||||
} else {
|
||||
self.counter2 = 0;
|
||||
}
|
||||
|
||||
let level = self.level;
|
||||
if !player.controller.shoot() {
|
||||
inventory.reset_current_weapon_xp();
|
||||
}
|
||||
|
||||
match level {
|
||||
WeaponLevel::Level1 => {
|
||||
btype = 6;
|
||||
shoot = false;
|
||||
}
|
||||
WeaponLevel::Level2 => btype = 37,
|
||||
WeaponLevel::Level3 => {
|
||||
if self.counter2 == 1 {
|
||||
btype = 39;
|
||||
} else {
|
||||
btype = 38;
|
||||
}
|
||||
}
|
||||
WeaponLevel::None => unreachable!(),
|
||||
}
|
||||
|
||||
if bullet_manager.count_bullets_multi(&BULLETS, player_id) > 0 || !(player.controller.trigger_shoot() || shoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.consume_ammo(1) {
|
||||
state.sound_manager.play_sfx(37);
|
||||
} else {
|
||||
match player.direction {
|
||||
Direction::Left if player.up => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.up => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y - 0x1000, btype, player_id, Direction::Up, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y - 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left if player.down => {
|
||||
bullet_manager.create_bullet(player.x - 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x - 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right if player.down => {
|
||||
bullet_manager.create_bullet(player.x + 0x200, player.y + 0x1000, btype, player_id, Direction::Bottom, &state.constants);
|
||||
state.create_caret(player.x + 0x200, player.y + 0x1000, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Left => {
|
||||
bullet_manager.create_bullet(player.x - 0xc00, player.y + 0x600, btype, player_id, Direction::Left, &state.constants);
|
||||
state.create_caret(player.x - 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Left);
|
||||
}
|
||||
Direction::Right => {
|
||||
bullet_manager.create_bullet(player.x + 0xc00, player.y + 0x600, btype, player_id, Direction::Right, &state.constants);
|
||||
state.create_caret(player.x + 0xc00, player.y + 0x600, CaretType::Shoot, Direction::Right);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let sound = match btype {
|
||||
6 => 49,
|
||||
37 => 62,
|
||||
38 => 63,
|
||||
39 => 64,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
state.sound_manager.play_sfx(sound);
|
||||
}
|
||||
}
|
||||
}
|
23
src/weapon/super_missile_launcher.rs
Normal file
23
src/weapon/super_missile_launcher.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use crate::player::{Player, TargetPlayer};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::weapon::bullet::BulletManager;
|
||||
use crate::weapon::{Weapon, WeaponLevel};
|
||||
|
||||
impl Weapon {
|
||||
pub(in crate::weapon) fn tick_super_missile_launcher(
|
||||
&mut self,
|
||||
player: &mut Player,
|
||||
player_id: TargetPlayer,
|
||||
bullet_manager: &mut BulletManager,
|
||||
state: &mut SharedGameState,
|
||||
) {
|
||||
const BULLETS: [u16; 6] = [28, 29, 30, 31, 32, 33];
|
||||
|
||||
let btype = match self.level {
|
||||
WeaponLevel::Level1 => 28,
|
||||
WeaponLevel::Level2 => 29,
|
||||
WeaponLevel::Level3 => 30,
|
||||
WeaponLevel::None => unreachable!(),
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue