diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0051b96a..8bc3b97f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -189,7 +189,7 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
target_link_libraries(${PROJECT_NAME} "${CMAKE_CURRENT_LIST_DIR}/meta/win/lib/msvc/x64/SDL2.lib"
- Ws2_32.lib opengl32.lib)
+ Ws2_32.lib opengl32.lib winmm.lib imm32.lib version.lib setupapi.lib)
else()
target_link_libraries(${PROJECT_NAME}
"${CMAKE_CURRENT_LIST_DIR}/meta/win/lib/mingw/${TOOLCHAIN_PREFIX}/libSDL2.a"
diff --git a/VisualC/HatchGameEngine.sln b/VisualC/HatchGameEngine.sln
index 15d8b17c..88fbcd5f 100644
--- a/VisualC/HatchGameEngine.sln
+++ b/VisualC/HatchGameEngine.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31112.23
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HatchGameEngine", "HatchGameEngine.vcxproj", "{EE5F89ED-FA81-458F-A2D2-3370351D9E23}"
EndProject
@@ -15,8 +15,8 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x64.ActiveCfg = Debug|x64
{EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x64.Build.0 = Debug|x64
- {EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x86.ActiveCfg = Debug|Win32
- {EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x86.Build.0 = Debug|Win32
+ {EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x86.ActiveCfg = Release|x64
+ {EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Debug|x86.Build.0 = Release|x64
{EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Release|x64.ActiveCfg = Release|x64
{EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Release|x64.Build.0 = Release|x64
{EE5F89ED-FA81-458F-A2D2-3370351D9E23}.Release|x86.ActiveCfg = Release|Win32
diff --git a/VisualC/HatchGameEngine.vcxproj b/VisualC/HatchGameEngine.vcxproj
index 76a10fef..4379a8dc 100644
--- a/VisualC/HatchGameEngine.vcxproj
+++ b/VisualC/HatchGameEngine.vcxproj
@@ -80,6 +80,7 @@
$(SolutionDir)..\meta\win\include;$(SolutionDir)..\include;$(SolutionDir)..\source;$(IncludePath)
$(SolutionDir)..\meta\win\lib\msvc\x64;$(LibraryPath)
+ true
@@ -119,19 +120,36 @@
- stdcpp17
+ stdcpp20
+ WIN32;TARGET_NAME="$(ProjectName)";GLEW_STATIC;USING_OPENGL;USING_FREETYPE;_DEBUG;_WINDOWS;DEBUG;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
copy "$(TargetPath)" "$(SolutionDir)..\builds\win\$(TargetName)-Debug.exe"
+
+ Ws2_32.lib;Wldap32.lib;Advapi32.lib;Crypt32.lib;Normaliz.lib;legacy_stdio_definitions.lib;glew32s.lib;opengl32.lib;freetype.lib;SDL2.lib;SDL2main.lib;winmm.lib;imm32.lib;version.lib;setupapi.lib;assimp.lib;zlibstatic.lib;%(AdditionalDependencies)
+ Console
+
+
+
- stdcpp17
+ stdcpp20
+ WIN32;TARGET_NAME="$(ProjectName)";GLEW_STATIC;USING_OPENGL;USING_FREETYPE;USING_ASSIMP;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ MultiThreaded
copy "$(TargetPath)" "$(SolutionDir)..\builds\win\$(TargetName)-Release.exe"
+
+ Console
+ Ws2_32.lib;Wldap32.lib;Advapi32.lib;Crypt32.lib;Normaliz.lib;legacy_stdio_definitions.lib;glew32s.lib;opengl32.lib;freetype.lib;SDL2.lib;SDL2main.lib;winmm.lib;imm32.lib;version.lib;setupapi.lib;ucrt.lib;vcruntime.lib;msvcrt.lib;assimp.lib;zlibstatic.lib;%(AdditionalDependencies)
+
+
+ libvcruntime.lib
+
@@ -310,4 +328,4 @@
-
+
\ No newline at end of file
diff --git a/VisualC/HatchGameEngine.vcxproj.filters b/VisualC/HatchGameEngine.vcxproj.filters
index d8c447fa..6e404920 100644
--- a/VisualC/HatchGameEngine.vcxproj.filters
+++ b/VisualC/HatchGameEngine.vcxproj.filters
@@ -381,6 +381,36 @@
Source Files\External Libs
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
@@ -464,9 +494,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -494,6 +521,9 @@
Source Files\External Libs
+
+ Header Files
+
diff --git a/desktop.ini b/desktop.ini
new file mode 100644
index 00000000..64d70198
--- /dev/null
+++ b/desktop.ini
@@ -0,0 +1,6 @@
+[.ShellClassInfo]
+IconResource=C:\Users\Austin\Documents\Projects\HatchGameEngine\meta\win\icon.ico,0
+[ViewState]
+Mode=
+Vid=
+FolderType=Documents
diff --git a/guides/Documentation.htm b/guides/Documentation.htm
index 3fd2639f..4f121b8b 100644
--- a/guides/Documentation.htm
+++ b/guides/Documentation.htm
@@ -50,6 +50,7 @@ Namespaces
Application
Array
Audio
+ Collision
Controller
Date
Device
@@ -121,7 +122,7 @@ Enums
FogEquation_*
GeoBooleanOp_*
GeoFillRule_*
- HitboxSide_*
+ HITBOX_*
InputBind_*
InputDevice_*
KeyBind_*
@@ -133,9 +134,9 @@ Enums
StencilOp_*
StencilTest_*
TILECOLLISION_*
- TimeOfDay_*
+ TIMEOFDAY_*
TintMode_*
- Weekday_*
+ WEEKDAY_*
Constants
Creates a new animator.
+ Returns the index of the Animator.
@@ -2052,9 +2087,9 @@ Returns a reference value to a hitbox array.
- Gets the previous animation value of an animator.
Sets the previous frame of an animator.
+ Sets the frame count of an animator.
+ Sets the loop index of an animator.
+ Sets the rotation style of an animator.
+ Adjusts the frame count of an animator by an amount.
+ Adjusts the loop index of an animator by an amount.
+ Gets the description of the game.
+ Sets the number of reserved slot IDs the engine will use when creating instances.
+ Sets the number of reserved slot IDs the engine will use when creating instances.
+ Processes movement of an instance with an outer hitbox and an inner hitbox.
+ Checks tile collision based on where an instance should check.
+ Returns whether the instance has collided with a tile.
+
+ Keeps an instance gripped to tile collision based on where an instance should check.
+ Returns whether to grip the instance.
+
+ Checks if an instance is touching another instance with their respective hitboxes.
+ Returns a Boolean value whether the entities are touching.
+
+ Checks if an instance is touching another instance with within their respective radii.
+ Returns a Boolean value whether the entities have collided.
+
+ Checks if an instance is touching another instance with their respective hitboxes and sets the values of the other instance if specified.
+ Returns the side the entities are colliding on.
+
+ Checks if an instance is touching the top of another instance with their respective hitboxes and sets the values of the other instance if specified.
+ Returns a Boolean value whether the entities have collided.
+
Draws a sprite based on an entity's current values (Sprite, CurrentAnimation, CurrentFrame, X, Y, Direction, ScaleX, ScaleY, Rotation).
Draws an animator based on its current values (Sprite, CurrentAnimation, CurrentFrame) and an entity's other values (X, Y, Direction, ScaleX, ScaleY, Rotation).
Draws a series of sprites based on a converted sprite string.
+ Resets the drawing region.
+ Gets the X position in which drawing starts to occur.
+ The X position if clipping is enabled, else 0.
+
+ Gets the Y position in which drawing starts to occur.
+ The Y position if clipping is enabled, else 0.
+
+ Gets the width in which drawing occurs.
+ The width if clipping is enabled, else 0.
+
+ Gets the height in which drawing occurs.
+ The height if clipping is enabled, else 0.
+
Determines whether or not the instance is of a specified object class.
Converts an integer to an 8-bit unsigned value.
+ Returns the converted value.
+
+ Converts an integer to a 16-bit unsigned value.
+ Returns the converted value.
+
+ Converts an integer to a 32-bit unsigned value.
+ Returns the converted value.
+
+ Converts an integer to a 64-bit unsigned value.
+ Returns the converted value.
+
Returns the result number.
+ Converts a decimal number to its fixed-point equivalent.
+ Returns the converted fixed-point Number value.
+
+ Converts a fixed-point number to its decimal equivalent.
+ Returns the converted decimal Number value.
+
Places the music onto the music stack and plays it.
Places the music onto the music stack and plays it at a time (in seconds).
- Removes the music from the music stack, stopping it if currently playing.
Completely clears the music stack, stopping all music.
- Places the music onto the music stack and plays it, looping back to the specified sample index if it reaches the end of playback.
- Places the music onto the music stack and plays it, looping back to the specified sample index if it reaches the end of playback.
- The arc cosine 256 of the angle.
+ Returns the arc tangent of a position.
+ The arc tangent of the position.
+
Gets the radia Decimal conversion of an integer, based on 256.
+ Gets the radian Decimal conversion of an integer, based on 256.
Returns a Boolean value.
- Returns an Integer value.
-
Returns a String value.
- Returns a String value.
-
Returns a String value.
- Returns an Integer value.
-
- Returns an Integer value.
-
- Returns an Integer value.
-
Returns a Boolean value.
- Returns a Boolean value.
-
- Returns a Boolean value.
-
- Returns a Boolean value.
-
Returns a Boolean value.
- Sets whether Debug Mode has been turned on in the current scene.
- Returns the first animation index with the specified name, or -1 if there was no match.
+ Checks if an animation and frame is valid within a sprite.
+ Returns the first animation index with the specified name, or -1 if there was no match.
+
Returns the Y offset of the specified sprite frame.
- Gets the hitbox of an animation and frame of a sprite.
+ Gets the hitbox of a sprite frame. If an entity is provided, the only two arguments are the entity and the hitboxID. Else, there are 4 arguments.
Returns a reference value to a hitbox array.
+ Converts a string to an array of sprite indexes by comparing UTF-16 values to a frame's ID.
+ Gets the width (in pixels) of a converted sprite string.
+ Gets the UTF8 value of the character at the specified index.
+ Gets the value of the character at the specified index.
Returns the UTF8 value as an Integer.
+ Returns the value as an Integer.
Returns a String value.
- Convert a String value to its uppercase representation.
@@ -9194,9 +9345,9 @@ String.ToUpperCase
Returns:
Returns a uppercase String value.
-
-
String.ToLowerCase
- String.ToLowerCase(string)
+
+
String.ToLowercase
+ String.ToLowercase(string)
Convert a String value to its lowercase representation.
Parameters:
@@ -9618,6 +9769,36 @@ View.SetPosition
z (Number): Desired Z position
+
+
View.AdjustX
+ View.AdjustX(viewInde, )
+ Adjusts the x - axis position of the camera for the specified view by an amount.
+ Parameters:
+
+ viewIndex(Integer) : Index of the view.
+ x(Number) : Desired X adjust amount.
+
+
+
+
View.AdjustY
+ View.AdjustY(viewIndex, y)
+ Adjusts the y-axis position of the camera for the specified view by an amount.
+ Parameters:
+
+ viewIndex (Integer): Index of the view.
+ y (Number): Desired Y adjust amount.
+
+
+
+
View.AdjustX
+ View.AdjustX(viewIndex, z)
+ Adjusts the z-axis position of the camera for the specified view by an amount.
+ Parameters:
+
+ viewIndex (Integer): Index of the view.
+ z (Number): Desired Z adjust amount.
+
+
View.SetAngle
View.SetAngle(viewIndex, x, y, z)
@@ -9912,11 +10093,11 @@ View.CheckOnScreen
Parameters:
instance (Instance): The instance to check.
- rangeX (Decimal): The x range to check, or null if an update region width should be used.
- rangeY (Decimal): The y range to check, or null if an update region height should be used.
+ rangeX (Decimal): The x range to check, or null
if the instance's update region width should be used.
+ rangeY (Decimal): The y range to check, or null
if the instance's update region height should be used.
Returns:
- Returns whether or not the instance is on screen on any view.
+ Returns whether the instance is on screen on any view.
View.CheckPosOnScreen
@@ -10032,7 +10213,7 @@ XML.Parse
Returns:
Returns a Map value if the text can be decoded, otherwise returns null
.
- 725 out of 784 functions have descriptions.
+ 737 out of 796 functions have descriptions.
Instance methods
@@ -10390,6 +10571,12 @@
instance.Alpha
Default: 0.0
A field that may be used in instance.Render
for changing the opacity of a sprite.
+
+
instance.BlendMode
+ Type: Integer
+ Default: BlendMode_NORMAL
+ A field that may be used in instance.Render
for changing the BlendMode of a sprite.
+
instance.Priority
Type: Integer
@@ -10412,7 +10599,7 @@ instance.Sprite
instance.CurrentAnimation
Type: Integer
Default: -1
- The current sprite animation index of the entity.
+ The current sprite animation index of the entity.
instance.CurrentFrame
@@ -10462,6 +10649,18 @@ instance.AnimationSpeedAdd
Default: 0
+
+
instance.PrevAnimation
+ Type: Integer
+ Default: -1
+ The previous sprite animation index of the entity, if it was changed.
+
+
+
instance.RotationStyle
+ Type: Integer
+ Default: 0
+ The way in which a sprite will rotate in some cases.
+
instance.AutoAnimate
Type: Boolean
@@ -10504,6 +10703,12 @@ instance.ViewOverrideFlag
Default: 0
+
+
instance.Visible
+ Type: Boolean
+ Default: true
+ Whether the entity will render.
+
instance.UpdateRegionW
Type: Decimal
@@ -10758,7 +10963,7 @@ instance.Persistence
Default: Persistence_NONE
Whether the entity persists between scenes.
- 73 out of 77 fields have descriptions.
+ 77 out of 81 fields have descriptions.
Enums
@@ -10793,6 +10998,10 @@
ACTIVE_YBOUNDS
ACTIVE_RBOUNDS
Entity updates within a radius. (uses UpdateRegionW)
+
+
ACTIVE_DISABLED
+ Entity will not even reach a point where it would check for an update.
+
Axis_LEFTX
Left controller stick X.
@@ -11245,20 +11454,20 @@ GeoFillRule_Positive
GeoFillRule_Negative
Only subregions that have winding counts lesser than zero (< 0) are filled.
-
-
HitboxSide_LEFT
+
+
HITBOX_LEFT
Left side, slot 0 of a hitbox array.
-
-
HitboxSide_TOP
+
+
HITBOX_TOP
Top side, slot 1 of a hitbox array.
-
-
HitboxSide_RIGHT
+
+
HITBOX_RIGHT
Right side, slot 2 of a hitbox array.
-
-
HitboxSide_BOTTOM
+
+
HITBOX_BOTTOM
Bottom side, slot 3 of a hitbox array.
@@ -11893,20 +12102,20 @@
TILECOLLISION_DOWN
TILECOLLISION_UP
Entity expects upward gravity for tile collision.
-
-
TimeOfDay_MORNING
+
+
TIMEOFDAY_MORNING
The early hours of the day (5AM to 11AM, or 05:00 to 11:00).
-
-
TimeOfDay_MIDDAY
+
+
TIMEOFDAY_MIDDAY
The middle hours of the day (12PM to 4PM, or 12:00 to 16:00).
-
-
TimeOfDay_EVENING
+
+
TIMEOFDAY_EVENING
The later hours of the day (5PM to 8PM, or 17:00 to 20:00).
-
-
TimeOfDay_NIGHT
+
+
TIMEOFDAY_NIGHT
The very late and very early hours of the day (9PM to 4AM, or 21:00 to 4:00).
@@ -11925,35 +12134,35 @@
TintMode_SRC_BLEND
TintMode_DST_BLEND
Blends the destination pixel with the tint color.
-
-
Weekday_SUNDAY
+
+
WEEKDAY_SUNDAY
The first day of the week.
-
-
Weekday_MONDAY
+
+
WEEKDAY_MONDAY
The second day of the week.
-
-
Weekday_TUESDAY
+
+
WEEKDAY_TUESDAY
The third day of the week.
-
-
Weekday_WEDNESDAY
+
+
WEEKDAY_WEDNESDAY
The fourth day of the week.
-
-
Weekday_THURSDAY
+
+
WEEKDAY_THURSDAY
The fifth day of the week.
-
-
Weekday_FRIDAY
+
+
WEEKDAY_FRIDAY
The sixth day of the week.
-
-
Weekday_SATURDAY
+
+
WEEKDAY_SATURDAY
The seventh day of the week.
- 298 out of 298 enums have descriptions.
+ 299 out of 299 enums have descriptions.
Constants
diff --git a/include/Engine/Application.h b/include/Engine/Application.h
index 80ff1496..d9cb6f21 100644
--- a/include/Engine/Application.h
+++ b/include/Engine/Application.h
@@ -26,35 +26,53 @@ class Application {
static string ParseGameVersion(XMLNode* versionNode);
static void LoadGameInfo();
static int HandleAppEvents(void* data, SDL_Event* event);
+ static void DrawDevString(const char* string, int x, int y, int align, bool isSelected);
+ static void OpenDevMenu();
+ static void CloseDevMenu();
+ static void SetBlendColor(int color);
+ static void DrawRectangle(float x, float y, float width, float height, int color, int alpha, bool screenRelative);
+ static void DevMenu_DrawMainMenu();
+ static void DevMenu_MainMenu();
+ static void DevMenu_CategorySelectMenu();
+ static void DevMenu_SceneSelectMenu();
+ static void DevMenu_SettingsMenu();
+ static void DevMenu_ModsMenu();
public:
- static vector CmdLineArgs;
- static INI* Settings;
- static char SettingsFile[4096];
- static XMLNode* GameConfig;
- static int TargetFPS;
- static float CurrentFPS;
- static bool Running;
- static bool GameStart;
- static SDL_Window* Window;
- static char WindowTitle[256];
- static int WindowWidth;
- static int WindowHeight;
- static int DefaultMonitor;
- static Platforms Platform;
- static char EngineVersion[256];
- static char GameTitle[256];
- static char GameTitleShort[256];
- static char GameVersion[256];
- static char GameDescription[256];
- static int UpdatesPerFrame;
- static bool Stepper;
- static bool Step;
- static int MasterVolume;
- static int MusicVolume;
- static int SoundVolume;
- static int StartSceneNum;
- static bool DevMenuActivated;
+ static vector CmdLineArgs;
+ static INI* Settings;
+ static char SettingsFile[4096];
+ static XMLNode* GameConfig;
+ static int TargetFPS;
+ static float CurrentFPS;
+ static bool Running;
+ static bool GameStart;
+ static SDL_Window* Window;
+ static char WindowTitle[256];
+ static int WindowWidth;
+ static int WindowHeight;
+ static int DefaultMonitor;
+ static Platforms Platform;
+ static char EngineVersion[256];
+ static char GameTitle[256];
+ static char GameTitleShort[256];
+ static char GameVersion[256];
+ static char GameDescription[256];
+ static int UpdatesPerFrame;
+ static bool Stepper;
+ static bool Step;
+ static int MasterVolume;
+ static int MusicVolume;
+ static int SoundVolume;
+ static int StartSceneNum;
+ static bool DevMenuActivated;
+ static int ViewableVariableCount;
+ static ViewableVariable ViewableVariableList[64];
+ static DeveloperMenu DevMenu;
+ static int DeveloperDarkFont;
+ static int DeveloperLightFont;
+ static int ReservedSlotIDs;
+ static bool DevShowHitboxes;
static void Init(int argc, char* args[]);
static void SetTargetFrameRate(int targetFPS);
@@ -85,6 +103,9 @@ class Application {
static void SaveSettings();
static void SaveSettings(const char* filename);
static void SetSettingsFilename(const char* filename);
+ static void AddViewableVariable(const char* name, void* value, int type, int min, int max);
+ static Uint16* UTF8toUTF16(const char* utf8String);
+ static int LoadDevFont(const char* fileName);
};
#endif /* ENGINE_APPLICATION_H */
diff --git a/include/Engine/InputManager.h b/include/Engine/InputManager.h
index 2de33b66..620d40b9 100644
--- a/include/Engine/InputManager.h
+++ b/include/Engine/InputManager.h
@@ -99,6 +99,12 @@ class InputManager {
static bool IsAnyActionHeld(unsigned playerID, unsigned device);
static bool IsAnyActionPressed(unsigned playerID, unsigned device);
static bool IsAnyActionReleased(unsigned playerID, unsigned device);
+ static bool IsActionHeldByAny(unsigned actionID);
+ static bool IsActionPressedByAny(unsigned actionID);
+ static bool IsActionReleasedByAny(unsigned actionID);
+ static bool IsActionHeldByAny(unsigned actionID, unsigned device);
+ static bool IsActionPressedByAny(unsigned actionID, unsigned device);
+ static bool IsActionReleasedByAny(unsigned actionID, unsigned device);
static bool IsPlayerUsingDevice(unsigned playerID, unsigned device);
static float GetAnalogActionInput(unsigned playerID, unsigned actionID);
static InputBind* GetPlayerInputBind(unsigned playerID, unsigned actionID, unsigned index, bool isDefault);
diff --git a/include/Engine/Math/Math.h b/include/Engine/Math/Math.h
index 7a950aae..ab55daaa 100644
--- a/include/Engine/Math/Math.h
+++ b/include/Engine/Math/Math.h
@@ -31,6 +31,7 @@ class Math {
static int Tan256(int angle);
static int ASin256(int angle);
static int ACos256(int angle);
+ static unsigned int ArcTanLookup(int X, int Y);
static int CeilPOT(int n);
static float Abs(float n);
static float Max(float a, float b);
diff --git a/include/Engine/Scene.h b/include/Engine/Scene.h
index 4532012c..d0b15831 100644
--- a/include/Engine/Scene.h
+++ b/include/Engine/Scene.h
@@ -185,7 +185,7 @@ class Scene {
static bool CheckObjectCollisionBox(Entity* thisEntity, CollisionBox* thisHitbox, Entity* otherEntity, CollisionBox* otherHitbox, bool setValues);
static bool CheckObjectCollisionPlatform(Entity* thisEntity, CollisionBox* thisHitbox, Entity* otherEntity, CollisionBox* otherHitbox, bool setValues);
static bool ObjectTileCollision(Entity* entity, int cLayers, int cMode, int cPlane, int xOffset, int yOffset, bool setPos);
- static bool ObjectTileGrip(Entity* entity, int cLayers, int cMode, int cPlane, float xOffset, float yOffset, float tolerance);
+ static bool ObjectTileGrip(Entity* entity, int cLayers, int cMode, int cPlane, int xOffset, int yOffset, float tolerance);
static void ProcessObjectMovement(Entity* entity, CollisionBox* outerBox, CollisionBox* innerBox);
static void ProcessPathGrip();
static void ProcessAirCollision_Down();
diff --git a/include/Engine/Types/Entity.h b/include/Engine/Types/Entity.h
index 15076623..40908d04 100644
--- a/include/Engine/Types/Entity.h
+++ b/include/Engine/Types/Entity.h
@@ -42,6 +42,7 @@ class Entity {
float OnScreenRegionBottom = 0.0f;
int ViewRenderFlag = 0xFFFFFFFF;
int ViewOverrideFlag = 0;
+ int Visible = true;
float RenderRegionW = 0.0f;
float RenderRegionH = 0.0f;
float RenderRegionTop = 0.0f;
@@ -54,6 +55,7 @@ class Entity {
float ScaleY = 1.0;
float Rotation = 0.0;
float Alpha = 1.0;
+ int BlendMode = BlendMode_NORMAL;
int AutoPhysics = false;
int Priority = 0;
int PriorityListIndex = -1;
@@ -67,6 +69,8 @@ class Entity {
int CurrentFrameCount = 0;
float AnimationSpeedMult = 1.0;
int AnimationSpeedAdd = 0;
+ int PrevAnimation = 0;
+ int RotationStyle = ROTSTYLE_NONE;
int AutoAnimate = true;
float AnimationSpeed = 0.0;
float AnimationTimer = 0.0;
diff --git a/meta/win/lib/msvc/x64/SDL2.lib b/meta/win/lib/msvc/x64/SDL2.lib
index 7257de63..79960231 100644
Binary files a/meta/win/lib/msvc/x64/SDL2.lib and b/meta/win/lib/msvc/x64/SDL2.lib differ
diff --git a/meta/win/lib/msvc/x64/SDL2main.lib b/meta/win/lib/msvc/x64/SDL2main.lib
new file mode 100644
index 00000000..d4c94947
Binary files /dev/null and b/meta/win/lib/msvc/x64/SDL2main.lib differ
diff --git a/meta/win/lib/msvc/x64/assimp.lib b/meta/win/lib/msvc/x64/assimp.lib
new file mode 100644
index 00000000..c8690c13
Binary files /dev/null and b/meta/win/lib/msvc/x64/assimp.lib differ
diff --git a/meta/win/lib/msvc/x64/freetype.lib b/meta/win/lib/msvc/x64/freetype.lib
new file mode 100644
index 00000000..984db595
Binary files /dev/null and b/meta/win/lib/msvc/x64/freetype.lib differ
diff --git a/meta/win/lib/msvc/x64/zlibstatic.lib b/meta/win/lib/msvc/x64/zlibstatic.lib
new file mode 100644
index 00000000..d7095f0d
Binary files /dev/null and b/meta/win/lib/msvc/x64/zlibstatic.lib differ
diff --git a/meta/win/lib/msvc/x86/assimp-vc143-mt.lib b/meta/win/lib/msvc/x86/assimp-vc143-mt.lib
new file mode 100644
index 00000000..6a21fe5d
Binary files /dev/null and b/meta/win/lib/msvc/x86/assimp-vc143-mt.lib differ
diff --git a/source/Engine/Application.cpp b/source/Engine/Application.cpp
index be343e8b..5afa1394 100644
--- a/source/Engine/Application.cpp
+++ b/source/Engine/Application.cpp
@@ -10,6 +10,9 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
@@ -53,46 +56,55 @@ extern "C" {
Platforms Application::Platform = Platforms::Unknown;
#endif
-vector Application::CmdLineArgs;
+INI* Application::Settings = NULL;
+char Application::SettingsFile[4096];
+vector Application::CmdLineArgs;
-INI* Application::Settings = NULL;
-char Application::SettingsFile[4096];
+XMLNode* Application::GameConfig = NULL;
-XMLNode* Application::GameConfig = NULL;
+int TargetFPS = 60;
+bool Application::Running = false;
+bool Application::GameStart = false;
+int Application::TargetFPS = DEFAULT_TARGET_FRAMERATE;
+float Application::CurrentFPS = DEFAULT_TARGET_FRAMERATE;
-int Application::TargetFPS = DEFAULT_TARGET_FRAMERATE;
-float Application::CurrentFPS = DEFAULT_TARGET_FRAMERATE;
-bool Application::Running = false;
-bool Application::GameStart = false;
+SDL_Window* Application::Window = NULL;
+char Application::WindowTitle[256];
+int Application::WindowWidth = 848;
+int Application::WindowHeight = 480;
+int Application::DefaultMonitor = 0;
-SDL_Window* Application::Window = NULL;
-char Application::WindowTitle[256];
-int Application::WindowWidth = 848;
-int Application::WindowHeight = 480;
-int Application::DefaultMonitor = 0;
+char Application::EngineVersion[256];
-char Application::EngineVersion[256];
+char Application::GameTitle[256];
+char Application::GameTitleShort[256];
+char Application::GameVersion[256];
+char Application::GameDescription[256];
-char Application::GameTitle[256];
-char Application::GameTitleShort[256];
-char Application::GameVersion[256];
-char Application::GameDescription[256];
+int Application::UpdatesPerFrame = 1;
+bool Application::Stepper = false;
+bool Application::Step = false;
-int Application::UpdatesPerFrame = 1;
-bool Application::Stepper = false;
-bool Application::Step = false;
+int Application::MasterVolume = 100;
+int Application::MusicVolume = 100;
+int Application::SoundVolume = 100;
-int Application::MasterVolume = 100;
-int Application::MusicVolume = 100;
-int Application::SoundVolume = 100;
+int Application::StartSceneNum = 0;
-int Application::StartSceneNum = 0;
+bool Application::DevMenuActivated = false;
+int Application::ViewableVariableCount = 0;
+ViewableVariable Application::ViewableVariableList[64];
+DeveloperMenu Application::DevMenu;
+int Application::DeveloperDarkFont = -1;
+int Application::DeveloperLightFont = -1;
-bool Application::DevMenuActivated = false;
+int Application::ReservedSlotIDs = 0;
+
+bool Application::DevShowHitboxes = false;
char StartingScene[256];
-bool DevMenu = false;
+bool DevMode = false;
bool ShowFPS = false;
bool TakeSnapshot = false;
bool DoNothing = false;
@@ -180,6 +192,10 @@ void Application::Init(int argc, char* args[]) {
SDL_WINDOWPOS_CENTERED_DISPLAY(defaultMonitor), SDL_WINDOWPOS_CENTERED_DISPLAY(defaultMonitor),
Application::WindowWidth, Application::WindowHeight, window_flags);
+ bool fullscreen = false;
+ Application::Settings->GetBool("display", "fullscreen", &fullscreen);
+ Application::SetWindowFullscreen(fullscreen);
+
if (Application::Platform == Platforms::iOS) {
SDL_SetWindowFullscreen(Application::Window, SDL_WINDOW_FULLSCREEN);
}
@@ -440,7 +456,7 @@ void Application::UpdateWindowTitle() {
else titleText += ", "; \
titleText += text
- if (DevMenu) {
+ if (DevMode) {
if (ResourceManager::UsingDataFolder) {
ADD_TEXT("using Resources folder");
}
@@ -465,6 +481,11 @@ void Application::UpdateWindowTitle() {
if (Stepper) {
ADD_TEXT("Frame Stepper ON");
}
+
+ if (Application::DevShowHitboxes) {
+ ADD_TEXT("Showing Hitboxes");
+ }
+
#undef ADD_TEXT
if (paren)
@@ -585,12 +606,13 @@ void Application::LoadKeyBinds() {
GET_KEY("devShowTileCol", DevTileCol, Key_F7);
GET_KEY("devShowObjectRegions", DevObjectRegions, Key_F8);
GET_KEY("devQuit", DevQuit, Key_ESCAPE);
+ GET_KEY("devShowHitboxes", DevShowHitboxes, Key_F11);
#undef GET_KEY
}
void Application::LoadDevSettings() {
- Application::Settings->GetBool("dev", "devMenu", &DevMenu);
+ Application::Settings->GetBool("dev", "devMenu", &DevMode);
Application::Settings->GetBool("dev", "viewPerformance", &ShowFPS);
Application::Settings->GetBool("dev", "donothing", &DoNothing);
Application::Settings->GetInteger("dev", "fastforward", &UpdatesPerFastForward);
@@ -660,12 +682,14 @@ void Application::PollEvents() {
break;
}
- if (DevMenu) {
+ if (DevMode) {
// Quit game (dev)
if (key == KeyBindsSDL[(int)KeyBind::DevQuit]) {
- Running = false;
- // Application::DevMenuActivated ^= 1;
- // Log::Print(Log::LOG_VERBOSE, "Dev Menu Activated: %d", DevMenuActivated);
+ if (Application::DevMenuActivated)
+ Application::CloseDevMenu();
+ else
+ Application::OpenDevMenu();
+ Log::Print(Log::LOG_VERBOSE, "Dev Menu Activated: %d", Application::DevMenuActivated);
break;
}
// Restart application (dev)
@@ -767,6 +791,17 @@ void Application::PollEvents() {
Application::UpdateWindowTitle();
break;
}
+ else if (key == KeyBindsSDL[(int)KeyBind::DevShowHitboxes]) {
+ Application::DevShowHitboxes = !Application::DevShowHitboxes;
+ Application::UpdateWindowTitle();
+ break;
+ }
+ }
+ else {
+ // Quit game (not dev)
+ if (key == KeyBindsSDL[(int)KeyBind::DevQuit]) {
+ Running = false;
+ }
}
break;
}
@@ -817,7 +852,7 @@ void Application::RunFrame(void* p) {
Scene::ResetPerf();
MetricPollTime = 0.0;
MetricUpdateTime = 0.0;
- if ((Stepper && Step) || !Stepper) {
+ if (((Stepper && Step) || !Stepper) && !Application::DevMenuActivated) {
// Poll for inputs
MetricPollTime = Clock::GetTicks();
InputManager::Poll();
@@ -1428,10 +1463,50 @@ void Application::InitSettings(const char* filename) {
// NOTE: If no settings could be loaded, create settings with default values.
if (!Application::Settings) {
+ Log::Print(Log::LOG_IMPORTANT, "Creating default config.ini.");
+ Application::SetSettingsFilename("config.ini");
Application::Settings = INI::New(Application::SettingsFile);
+ Application::Settings->SetString("game", "modpacks", "Data.hatch");
+
Application::Settings->SetBool("display", "fullscreen", false);
Application::Settings->SetBool("display", "vsync", false);
+ Application::Settings->SetInteger("display", "defaultMonitor", 0);
+ Application::Settings->SetBool("display", "retina", false);
+ Application::Settings->SetInteger("display", "multisample", 0);
+ Application::Settings->SetBool("display", "forceSoftwareTextures", false);
+
+ Application::Settings->SetInteger("audio", "masterVolume", 0);
+ Application::Settings->SetInteger("audio", "musicVolume", 0);
+ Application::Settings->SetInteger("audio", "soundVolume", 0);
+
+ Application::Settings->SetBool("dev", "devMenu", false);
+#if WIN32 || MACOSX || LINUX || SWITCH
+ Application::Settings->SetBool("dev", "writeToFile", true);
+#endif
+ Application::Settings->SetBool("dev", "viewPerformance", false);
+ Application::Settings->SetBool("dev", "donothing", false);
+ Application::Settings->SetInteger("dev", "fastForward", 6);
+ Application::Settings->SetInteger("dev", "logLevel", 0);
+ Application::Settings->SetBool("dev", "trackMemory", false);
+ Application::Settings->SetBool("dev", "autoPerfSnapshots", false);
+ Application::Settings->SetInteger("dev", "apsMinFrameTime", 20);
+ Application::Settings->SetInteger("dev", "apsMinInterval", 5);
+ Application::Settings->SetBool("dev", "debugCompiler", false);
+ Application::Settings->SetBool("dev", "branchLimit", false);
+ Application::Settings->SetBool("dev", "exportFonts", false);
+ Application::Settings->SetString("dev", "renderer", "opengl");
+ Application::Settings->SetBool("dev", "notiles", false);
+ Application::Settings->SetBool("dev", "noobjectrender", false);
+ Application::Settings->SetBool("dev", "viewCollision", false);
+ Application::Settings->SetBool("dev", "loadAllClasses", false);
+
+ Application::Settings->SetBool("compiler", "log", false);
+ Application::Settings->SetBool("compiler", "showWarnings", false);
+ Application::Settings->SetBool("compiler", "writeDebugInfo", false);
+ Application::Settings->SetBool("compiler", "writeSourceFilename", false);
+
+ Application::SaveSettings(Application::SettingsFile);
}
int logLevel = 0;
@@ -1500,3 +1575,636 @@ int Application::HandleAppEvents(void* data, SDL_Event* event) {
return 1;
}
}
+
+void Application::AddViewableVariable(const char* name, void* value, int type, int min, int max) {
+ if (Application::ViewableVariableCount < VIEWABLEVARIABLE_COUNT) {
+ ViewableVariable* viewVar = &Application::ViewableVariableList[Application::ViewableVariableCount++];
+
+ StringUtils::Copy(viewVar->Name, name, 0x10);
+ viewVar->Value = value;
+
+ // TODO: Finish this for VMValue type
+ switch (type) {
+ case VIEWVAR_BOOL:
+ viewVar->Type = VIEWVAR_DISPLAY_BOOL;
+ viewVar->Size = sizeof(bool);
+ break;
+ }
+
+ viewVar->Min = min;
+ viewVar->Max = max;
+ }
+}
+
+Uint16* Application::UTF8toUTF16(const char* utf8String) {
+ size_t len = strlen(utf8String);
+ Uint16* utf16String = (Uint16*)malloc((len + 1) * sizeof(Uint16));
+ size_t i = 0, j = 0;
+ while (utf8String[i]) {
+ if ((utf8String[i] & 0x80) == 0) { // 1-byte
+ utf16String[j++] = utf8String[i];
+ }
+ else if ((utf8String[i] & 0xE0) == 0xC0) { // 2-byte
+ utf16String[j++] = ((utf8String[i] & 0x1F) << 6) | (utf8String[i + 1] & 0x3F);
+ i++;
+ }
+ else if ((utf8String[i] & 0xF0) == 0xE0) { // 3-byte
+ utf16String[j++] = ((utf8String[i] & 0x0F) << 12) | ((utf8String[i + 1] & 0x3F) << 6) | (utf8String[i + 2] & 0x3F);
+ i += 2;
+ }
+ i++;
+ }
+ utf16String[j] = 0;
+ return utf16String;
+}
+
+int Application::LoadDevFont(const char* fileName) {
+ ResourceType* resource = new (std::nothrow) ResourceType();
+ resource->FilenameHash = CRC32::EncryptString(fileName);
+ resource->UnloadPolicy = SCOPE_GAME;
+
+ size_t index = 0;
+ vector* list = &Scene::SpriteList;
+ if (Scene::GetResource(list, resource, index))
+ return (int)index;
+
+ bool paletteStore = Graphics::UsePalettes;
+ Graphics::UsePalettes = false;
+ resource->AsSprite = new (std::nothrow) ISprite(fileName);
+ Graphics::UsePalettes = paletteStore;
+ if (resource->AsSprite->LoadFailed) {
+ delete resource->AsSprite;
+ delete resource;
+ (*list)[index] = NULL;
+ return -1;
+ }
+ return (int)index;
+}
+
+void Application::DrawDevString(const char* string, int x, int y, int align, bool isSelected) {
+ x += Scene::Views[0].X;
+ y += Scene::Views[0].Y;
+
+ int sprite = isSelected ? Application::DeveloperLightFont : Application::DeveloperDarkFont;
+
+ if (sprite < 0) return;
+ ISprite* font = (!Scene::SpriteList[sprite]) ? NULL : Scene::SpriteList[sprite]->AsSprite;
+ if (!font || !string)
+ return;
+
+ // To hold the indices of the sprite for each character
+ std::vector spriteString;
+
+ // Decode UTF-8 string and populate spriteString
+ const char* ptr = string;
+ while (*ptr) {
+ // Decode UTF-8 character to Unicode
+ Uint32 unicodeChar = 0;
+ int bytes = 1;
+
+ if ((*ptr & 0x80) == 0) {
+ // 1-byte character (ASCII)
+ unicodeChar = *ptr;
+ }
+ else if ((*ptr & 0xE0) == 0xC0) {
+ // 2-byte character
+ unicodeChar = (*ptr & 0x1F) << 6;
+ unicodeChar |= (*(ptr + 1) & 0x3F);
+ bytes = 2;
+ }
+ else if ((*ptr & 0xF0) == 0xE0) {
+ // 3-byte character
+ unicodeChar = (*ptr & 0x0F) << 12;
+ unicodeChar |= (*(ptr + 1) & 0x3F) << 6;
+ unicodeChar |= (*(ptr + 2) & 0x3F);
+ bytes = 3;
+ }
+ else if ((*ptr & 0xF8) == 0xF0) {
+ // 4-byte character
+ unicodeChar = (*ptr & 0x07) << 18;
+ unicodeChar |= (*(ptr + 1) & 0x3F) << 12;
+ unicodeChar |= (*(ptr + 2) & 0x3F) << 6;
+ unicodeChar |= (*(ptr + 3) & 0x3F);
+ bytes = 4;
+ }
+
+ // Find the corresponding sprite frame for the Unicode character
+ bool found = false;
+ for (int f = 0; f < (int)font->Animations[0].Frames.size(); f++) {
+ if (font->Animations[0].Frames[f].Advance == (int)unicodeChar) {
+ spriteString.push_back(f);
+ found = true;
+ break;
+ }
+ }
+
+ // If not found, push -1
+ if (!found) {
+ spriteString.push_back(-1);
+ }
+
+ // Move the pointer to the next UTF-8 character
+ ptr += bytes;
+ }
+
+ if (y >= 0 && y < (int)Scene::Views[0].Height + (int)Scene::Views[0].Y) {
+ int offset = 0;
+ switch (align) {
+ default:
+ case 0: // ALIGN_LEFT
+ for (int pos = 0; pos < (int)spriteString.size(); ++pos) {
+ if (spriteString[pos] != -1) {
+ AnimFrame frame = font->Animations[0].Frames[spriteString[pos]];
+ Graphics::DrawSprite(font, 0, spriteString[pos], x, y, false, false, 1.0f, 1.0f, 0.0f);
+ x += frame.Width + 1;
+ }
+ else {
+ x += 8;
+ }
+ }
+ break;
+
+ case 2: // ALIGN_CENTER
+ for (int pos = 0; pos < (int)spriteString.size(); ++pos) {
+ if (spriteString[pos] < font->Animations[0].Frames.size() && spriteString[pos] >= 0) {
+ x += font->Animations[0].Frames[spriteString[pos]].Width / 2 + 1;
+ }
+ else {
+ x += 4;
+ }
+ }
+
+ for (int pos = (int)spriteString.size() - 1; pos >= 0; --pos) {
+ if (spriteString[pos] < font->Animations[0].Frames.size() && spriteString[pos] >= 0) {
+ AnimFrame frame = font->Animations[0].Frames[spriteString[pos]];
+ Graphics::DrawSprite(font, 0, spriteString[pos], x - frame.Width / 2, y, false, false, 1.0f, 1.0f, 0.0f);
+ x -= frame.Width;
+ }
+ else {
+ x -= 8;
+ }
+ }
+ break;
+
+ case 1: // ALIGN_RIGHT
+ offset = 8;
+ break;
+ }
+ }
+}
+
+void Application::OpenDevMenu() {
+ DevMenu.State = Application::DevMenu_MainMenu;
+ DevMenu.Selection = 0;
+ DevMenu.ScrollPos = 0;
+ DevMenu.SubSelection = 0;
+ DevMenu.SubScrollPos = 0;
+ DevMenu.Timer = 0;
+
+ AudioManager::AudioPauseAll();
+ AudioManager::Lock();
+ if (AudioManager::MusicStack.size() > 0)
+ AudioManager::MusicStack[0]->Paused = true;
+ AudioManager::Unlock();
+
+ Application::DevMenuActivated = true;
+}
+
+void Application::CloseDevMenu() {
+ Application::DevMenuActivated = false;
+
+ AudioManager::AudioUnpauseAll();
+ AudioManager::Lock();
+ if (AudioManager::MusicStack.size() > 0)
+ AudioManager::MusicStack[0]->Paused = false;
+ AudioManager::Unlock();
+}
+
+void Application::SetBlendColor(int color) {
+ Graphics::SetBlendColor(
+ (color >> 16 & 0xFF) / 255.f,
+ (color >> 8 & 0xFF) / 255.f,
+ (color & 0xFF) / 255.f, 1.0);
+}
+
+void Application::DrawRectangle(float x, float y, float width, float height, int color, int alpha, bool screenRelative) {
+ if (screenRelative) {
+ x += Scene::Views[0].X;
+ y += Scene::Views[0].Y;
+ }
+ Graphics::SetBlendColor(
+ (color >> 16 & 0xFF) / 255.f,
+ (color >> 8 & 0xFF) / 255.f,
+ (color & 0xFF) / 255.f, alpha / 256.0f);
+ Graphics::FillRectangle(x, y, width, height);
+}
+
+void Application::DevMenu_DrawMainMenu() {
+ const int selectionCount = 6;
+ bool isSelected[] = { false, false, false, false, false, false };
+ const char* selectionNames[] = { "Resume", "Restart", "Stage Select", "Settings", "Mods", "Exit" };
+ isSelected[DevMenu.Selection] = true;
+
+ View view = Scene::Views[0];
+
+ // TODO: Should be CenterY when that exists
+ int y = (((int)Scene::Views[0].Height) / 2) - 94;
+ DrawRectangle(0.0, 16.0, view.Width, 54.0, 0x000000, 0xFF, true);
+ DrawDevString("Hatch Engine Developer Menu", (int)view.Width / 2, y, 2, true);
+
+ y += 15;
+ DrawDevString(GameTitleShort, (int)view.Width / 2, y, 2, true);
+
+ DrawRectangle(0, 82.0, 128.0, 113.0, 0x000000, 0xFF, true);
+ DrawRectangle(144.0, 82.0, view.Width - 144.0, 113.0, 0x000000, 0xFF, true);
+
+ y = 100;
+ for (int i = 0; i < selectionCount; ++i) {
+ DrawDevString(selectionNames[i], 16.0, y, 0, isSelected[i]);
+ y += 15;
+ }
+ y += 20;
+}
+
+void Application::DevMenu_MainMenu() {
+ const int selectionCount = 6;
+ DevMenu_DrawMainMenu();
+
+ View view = Scene::Views[0];
+
+ if (DevMenu.ModsChanged)
+ DrawDevString("Application must restart upon resume.", (int)view.Width / 2, (((int)Scene::Views[0].Height) / 2) - 64, 2, true);
+ else
+ DrawDevString(GameVersion, (int)view.Width / 2, (((int)Scene::Views[0].Height) / 2) - 64, 2, true);
+
+ const char* tooltip;
+ switch (DevMenu.Selection) {
+ case 0: tooltip = "Resume the game."; break;
+ case 1: tooltip = "Restart the current scene."; break;
+ case 2: tooltip = "Navigate to a certain scene."; break;
+ case 3: tooltip = "Adjust the application's settings."; break;
+ case 4: tooltip = "Not currently supported."; break;
+ case 5: tooltip = "Close the appliation."; break;
+ }
+
+ DrawDevString(tooltip, 160, 93, 0, true);
+
+ if (InputManager::GetActionID("Up") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Up"))) {
+ DevMenu.Selection--;
+ DevMenu.Timer = 1;
+
+ if (DevMenu.Selection < 0)
+ DevMenu.Selection += selectionCount;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Up"))) {
+ if (DevMenu.Timer) {
+ DevMenu.Timer = ++DevMenu.Timer & 7;
+ }
+ else {
+ DevMenu.Selection--;
+ DevMenu.Timer = ++DevMenu.Timer & 7;
+
+ if (DevMenu.Selection < 0)
+ DevMenu.Selection += selectionCount;
+ }
+ }
+ }
+
+ if (InputManager::GetActionID("Down") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Down"))) {
+ DevMenu.Selection++;
+ DevMenu.Timer = 1;
+
+ if (DevMenu.Selection >= selectionCount)
+ DevMenu.Selection -= selectionCount;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Down"))) {
+ if (DevMenu.Timer) {
+ DevMenu.Timer = ++DevMenu.Timer & 7;
+ }
+ else {
+ DevMenu.Selection++;
+ DevMenu.Timer = ++DevMenu.Timer & 7;
+
+ if (DevMenu.Selection >= selectionCount)
+ DevMenu.Selection -= selectionCount;
+ }
+ }
+ }
+
+ bool confirm = false;
+ if (InputManager::GetActionID("A") != -1) {
+ confirm = InputManager::IsActionPressedByAny(InputManager::GetActionID("A"));
+ }
+
+ if ((InputManager::GetActionID("Start") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("Start")) : false) || confirm) {
+ switch (DevMenu.Selection) {
+ case 0: CloseDevMenu(); break;
+
+ case 1:
+ CloseDevMenu();
+ // Reset FPS timer
+ BenchmarkFrameCount = 0;
+
+ InputManager::ControllerStopRumble();
+
+ Scene::Restart();
+ UpdateWindowTitle();
+ break;
+
+ case 2:
+ DevMenu.State = Application::DevMenu_CategorySelectMenu;
+ DevMenu.SubSelection = 0;
+ DevMenu.Timer = 1;
+ break;
+
+ case 3:
+ DevMenu.State = Application::DevMenu_SettingsMenu;
+ DevMenu.SubSelection = 0;
+ DevMenu.Timer = 1;
+ break;
+
+ case 4:
+ DevMenu.State = Application::DevMenu_SettingsMenu;
+ DevMenu.SubSelection = 0;
+ DevMenu.Timer = 1;
+ break;
+
+ case 5:
+ Running = false;
+ break;
+ }
+ }
+ else if ((InputManager::GetActionID("B") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("B")) : false)) {
+ CloseDevMenu();
+ }
+}
+
+void Application::DevMenu_CategorySelectMenu() {
+ const int selectionCount = 6;
+ DevMenu_DrawMainMenu();
+
+ if (!ResourceManager::ResourceExists("Game/SceneConfig.xml")) {
+ DrawDevString("No SceneConfig is loaded!", 160, 93, 0, true);
+ if ((InputManager::GetActionID("B") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("B")) : false)) {
+ DevMenu.State = DevMenu_MainMenu;
+ DevMenu.SubSelection = 0;
+ DevMenu.Timer = 1;
+ }
+
+ return;
+ }
+
+ std::vector selectedCategory;
+ View view = Scene::Views[0];
+ for (size_t i = 0; i < SceneInfo::Categories.size(); i++) {
+ selectedCategory.push_back(false);
+ }
+ selectedCategory[DevMenu.SubSelection] = true;
+
+ DrawDevString("Select Scene Category...", (int)view.Width / 2, (int)view.Height / 2 - 64, 2, true);
+
+ int y = 93;
+ for (size_t i = 0; i < 7; i++) {
+ if (DevMenu.SubScrollPos + i < SceneInfo::Categories.size()) {
+ DrawDevString(SceneInfo::Categories[DevMenu.SubScrollPos + (int)i].Name, 160, y, 0, selectedCategory[(int)i]);
+ y += 15;
+ }
+ }
+
+ if (InputManager::GetActionID("Up") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Up"))) {
+ if (--DevMenu.SubSelection < 0)
+ DevMenu.SubSelection += (int)SceneInfo::Categories.size();
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+
+ DevMenu.Timer = 1;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Up"))) {
+ if (DevMenu.Timer) {
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.ScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ else {
+ if (--DevMenu.SubSelection < 0)
+ DevMenu.SubSelection += (int)SceneInfo::Categories.size();
+
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ }
+ }
+
+ if (InputManager::GetActionID("Down") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Down"))) {
+ if (++DevMenu.SubSelection == (int)SceneInfo::Categories.size())
+ DevMenu.SubSelection = 0;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+
+ DevMenu.Timer = 1;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Down"))) {
+ if (DevMenu.Timer) {
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 7)
+ DevMenu.ScrollPos = DevMenu.SubSelection - 7;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ else {
+ if (++DevMenu.SubSelection == (int)SceneInfo::Categories.size())
+ DevMenu.SubSelection = 0;
+
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 7)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 7;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ }
+ }
+
+ bool confirm = false;
+ if (InputManager::GetActionID("A") != -1) {
+ confirm = InputManager::IsActionPressedByAny(InputManager::GetActionID("A"));
+ }
+
+ if ((InputManager::GetActionID("Start") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("Start")) : false) || confirm) {
+ if ((int)SceneInfo::Categories[DevMenu.SubSelection].Count) {
+ DevMenu.State = DevMenu_SceneSelectMenu;
+ DevMenu.ListPos = DevMenu.SubSelection;
+ DevMenu.SubScrollPos = 0;
+ DevMenu.SubSelection = 0;
+ }
+ }
+ else if ((InputManager::GetActionID("B") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("B")) : false)) {
+ DevMenu.State = DevMenu_MainMenu;
+ DevMenu.SubSelection = 0;
+ DevMenu.Timer = 1;
+ }
+}
+
+void Application::DevMenu_SceneSelectMenu() {
+ DevMenu_DrawMainMenu();
+
+ View view = Scene::Views[0];
+ int selectedScene[] = { false, false, false, false, false, false, false, };
+
+ selectedScene[DevMenu.SubSelection - DevMenu.SubScrollPos] = true;
+
+ DrawDevString("Select Scene...", (int)view.Width / 2, (int)view.Height / 2 - 64, 2, true);
+
+ int y = 93;
+ SceneListCategory* list = &SceneInfo::Categories[DevMenu.ListPos];
+ int start = list->OffsetStart;
+ for (int i = 0; i < 7; i++) {
+ if (DevMenu.SubScrollPos + i < list->Count) {
+ DrawDevString(SceneInfo::Entries[start + (DevMenu.SubScrollPos + i)].Name, 160, y, 0, selectedScene[(int)i]);
+ y += 15;
+ }
+ }
+
+ if (InputManager::GetActionID("Up") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Up"))) {
+ if (start + --DevMenu.SubSelection < list->OffsetStart)
+ DevMenu.SubSelection = list->Count - 1;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+
+ DevMenu.Timer = 1;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Up"))) {
+ if (!DevMenu.Timer && start + --DevMenu.SubSelection < list->OffsetStart)
+ DevMenu.SubSelection = list->Count - 1;
+
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ }
+
+ if (InputManager::GetActionID("Down") != -1) {
+ if (InputManager::IsActionPressedByAny(InputManager::GetActionID("Down"))) {
+ if (++DevMenu.SubSelection >= list->Count)
+ DevMenu.SubSelection = 0;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+
+ DevMenu.Timer = 1;
+ }
+ else if (InputManager::IsActionHeldByAny(InputManager::GetActionID("Down"))) {
+ if (!DevMenu.Timer && ++DevMenu.SubSelection >= list->Count)
+ DevMenu.SubSelection = 0;
+
+ DevMenu.Timer = (DevMenu.Timer + 1) & 7;
+
+ if (DevMenu.SubSelection >= DevMenu.SubScrollPos) {
+ if (DevMenu.SubSelection > DevMenu.SubScrollPos + 6)
+ DevMenu.SubScrollPos = DevMenu.SubSelection - 6;
+ }
+ else {
+ DevMenu.SubScrollPos = DevMenu.SubSelection;
+ }
+ }
+ }
+
+ bool confirm = false;
+ if (InputManager::GetActionID("A") != -1) {
+ confirm = InputManager::IsActionPressedByAny(InputManager::GetActionID("A"));
+ }
+
+ if ((InputManager::GetActionID("Start") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("Start")) : false) || confirm) {
+ CloseDevMenu();
+
+ AudioManager::AudioStopAll();
+ AudioManager::ClearMusic();
+
+ const char* categoryName = list->Name;
+ const char* sceneName = SceneInfo::Entries[DevMenu.SubSelection + list->OffsetStart].Name;
+
+ int categoryID = SceneInfo::GetCategoryID(categoryName);
+ if (categoryID < 0)
+ return;
+ SceneListCategory& category = SceneInfo::Categories[categoryID];
+ if (!SceneInfo::IsEntryValid(category.OffsetStart))
+ return;
+ int entryID = SceneInfo::GetEntryIDWithinRange(category.OffsetStart, category.OffsetEnd, sceneName);
+ if (entryID < 0)
+ return;
+
+ Scene::SetCurrent(categoryName, sceneName);
+
+ std::string path = SceneInfo::GetFilename(Scene::CurrentSceneInList);
+
+ StringUtils::Copy(Scene::NextScene, path.c_str(), sizeof(Scene::NextScene));
+ }
+ else if ((InputManager::GetActionID("B") != -1 ? InputManager::IsActionPressedByAny(InputManager::GetActionID("B")) : false)) {
+ DevMenu.State = DevMenu_CategorySelectMenu;
+ DevMenu.SubScrollPos = 0;
+ DevMenu.SubSelection = 0;
+ DevMenu.ListPos = 1;
+ }
+}
+
+void Application::DevMenu_SettingsMenu() {
+
+}
+
+void Application::DevMenu_ModsMenu() {
+
+}
\ No newline at end of file
diff --git a/source/Engine/Bytecode/Compiler.cpp b/source/Engine/Bytecode/Compiler.cpp
index 740866be..0f472068 100644
--- a/source/Engine/Bytecode/Compiler.cpp
+++ b/source/Engine/Bytecode/Compiler.cpp
@@ -1474,7 +1474,7 @@ void Compiler::GetUnary(bool canAssign) {
case TOKEN_LOGICAL_NOT: EmitByte(OP_LG_NOT); break;
case TOKEN_TYPEOF: EmitByte(OP_TYPEOF); break;
- // HACK: replace these with prefix version of OP
+ // TODO: replace these with prefix version of OP
// case TOKEN_INCREMENT: EmitByte(OP_INCREMENT); break;
// case TOKEN_DECREMENT: EmitByte(OP_DECREMENT); break;
default:
diff --git a/source/Engine/Bytecode/ScriptEntity.cpp b/source/Engine/Bytecode/ScriptEntity.cpp
index 4eab3bb4..f7335993 100644
--- a/source/Engine/Bytecode/ScriptEntity.cpp
+++ b/source/Engine/Bytecode/ScriptEntity.cpp
@@ -181,6 +181,14 @@ void ScriptEntity::LinkFields() {
*/
LINK_DEC(Alpha);
/***
+ * \field BlendMode
+ * \type Integer
+ * \default BlendMode_NORMAL
+ * \ns Instance
+ * \desc A field that may be used in for changing the BlendMode of a sprite.
+ */
+ LINK_INT(BlendMode);
+ /***
* \field Priority
* \type Integer
* \default 0
@@ -210,7 +218,7 @@ void ScriptEntity::LinkFields() {
* \type Integer
* \default -1
* \ns Instance
- * \desc The current sprite animation index of the entity.
+ * \desc The current sprite animation index of the entity.
*/
LINK_INT(CurrentAnimation);
/***
@@ -278,6 +286,22 @@ void ScriptEntity::LinkFields() {
*/
LINK_INT(AnimationSpeedAdd);
/***
+ * \field PrevAnimation
+ * \type Integer
+ * \default -1
+ * \ns Instance
+ * \desc The previous sprite animation index of the entity, if it was changed.
+ */
+ LINK_INT(PrevAnimation);
+ /***
+ * \field RotationStyle
+ * \type Integer
+ * \default 0
+ * \ns Instance
+ * \desc The way in which a sprite will rotate in some cases.
+ */
+ LINK_INT(RotationStyle);
+ /***
* \field AutoAnimate
* \type Boolean
* \default true
@@ -334,6 +358,14 @@ void ScriptEntity::LinkFields() {
* \desc A bitfield similar to . Bypasses each view's entity rendering toggle set by .
*/
LINK_INT(ViewOverrideFlag);
+ /***
+ * \field Visible
+ * \type Boolean
+ * \default true
+ * \ns Instance
+ * \desc Whether the entity will render.
+ */
+ LINK_INT(ViewRenderFlag);
/***
* \field UpdateRegionW
@@ -1403,16 +1435,16 @@ VMValue ScriptEntity::VM_GetHitboxFromSprite(int argCount, VMValue* args, Uint32
* \param animation (Integer): The animation index.
* \param frame (Integer): The frame index.
* \param hitbox (Integer): The hitbox ID.
- * \return Returns an array containing the hitbox top, left, right and bottom sides in that order.
+ * \return Returns an array containing the hitbox top, left, right and bottom sides in that order.
* \ns Instance
*/
VMValue ScriptEntity::VM_ReturnHitboxFromSprite(int argCount, VMValue* args, Uint32 threadID) {
StandardLibrary::CheckArgCount(argCount, 5);
- ScriptEntity* self = GET_ENTITY(0);
- ISprite* sprite = GET_ARG(1, GetSprite);
- int animation = GET_ARG(2, GetInteger);
- int frame = GET_ARG(3, GetInteger);
- int hitbox = GET_ARG(4, GetInteger);
+ ScriptEntity* self = GET_ENTITY(0);
+ ISprite* sprite = GET_ARG(1, GetSprite);
+ int animation = GET_ARG(2, GetInteger);
+ int frame = GET_ARG(3, GetInteger);
+ int hitbox = GET_ARG(4, GetInteger);
if (!IsValidEntity(self) || !sprite)
return NULL_VAL;
diff --git a/source/Engine/Bytecode/StandardLibrary.cpp b/source/Engine/Bytecode/StandardLibrary.cpp
index 6b5c1061..1bfeaebb 100644
--- a/source/Engine/Bytecode/StandardLibrary.cpp
+++ b/source/Engine/Bytecode/StandardLibrary.cpp
@@ -521,6 +521,10 @@ bool GetAnimatorSpace(vector* list, size_t* index, bool* foundEmpty)
/***
* Animator.Create
* \desc Creates a new animator.
+ * \param sprite (Integer): The index of the sprite.
+ * \param animationID (Integer): The animator's changed animation ID.
+ * \param frameID (Integer): The animator's changed frame ID.
+ * \param unloadPolicy (Integer): When to unload the animator.
* \return Returns the index of the Animator.
* \ns Animator
*/
@@ -552,6 +556,8 @@ VMValue Animator_Create(int argCount, VMValue* args, Uint32 threadID) {
VMValue Animator_Remove(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
int animator = GET_ARG(0, GetInteger);
+ if (animator < 0 || animator >= (int)Scene::AnimatorList.size())
+ return NULL_VAL;
if (!Scene::AnimatorList[animator])
return NULL_VAL;
delete Scene::AnimatorList[animator];
@@ -710,10 +716,10 @@ VMValue Animator_GetHitbox(int argCount, VMValue* args, Uint32 threadID) {
CollisionBox box = frame.Boxes[hitboxID];
ObjArray* array = NewArray();
- array->Values->push_back(DECIMAL_VAL((float)box.Top));
- array->Values->push_back(DECIMAL_VAL((float)box.Left));
- array->Values->push_back(DECIMAL_VAL((float)box.Right));
- array->Values->push_back(DECIMAL_VAL((float)box.Bottom));
+ array->Values->push_back(INTEGER_VAL(box.Left));
+ array->Values->push_back(INTEGER_VAL(box.Top));
+ array->Values->push_back(INTEGER_VAL(box.Right));
+ array->Values->push_back(INTEGER_VAL(box.Bottom));
return OBJECT_VAL(array);
}
else {
@@ -721,13 +727,13 @@ VMValue Animator_GetHitbox(int argCount, VMValue* args, Uint32 threadID) {
}
}
/***
- * Animator.GetPreviousAnimation
+ * Animator.GetPrevAnimation
* \desc Gets the previous animation value of an animator.
* \param animator (Integer): The index of the animator.
* \return Returns an Integer value.
* \ns Animator
*/
-VMValue Animator_GetPreviousAnimation(int argCount, VMValue* args, Uint32 threadID) {
+VMValue Animator_GetPrevAnimation(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
return INTEGER_VAL(Scene::AnimatorList[GET_ARG(0, GetInteger)]->PrevAnimation);
}
@@ -786,6 +792,17 @@ VMValue Animator_GetLoopIndex(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
return INTEGER_VAL(Scene::AnimatorList[GET_ARG(0, GetInteger)]->LoopIndex);
}
+/***
+ * Animator.GetRotationStyle
+ * \desc Gets the loop index of an animator's rotation style.
+ * \param animator (Integer): The index of the animator.
+ * \return Returns an Integer value.
+ * \ns Animator
+ */
+VMValue Animator_GetRotationStyle(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL(Scene::AnimatorList[GET_ARG(0, GetInteger)]->RotationStyle);
+}
/***
* Animator.SetSprite
* \desc Sets the sprite index of an animator.
@@ -822,6 +839,18 @@ VMValue Animator_SetCurrentFrame(int argCount, VMValue* args, Uint32 threadID) {
Scene::AnimatorList[GET_ARG(0, GetInteger)]->CurrentFrame = GET_ARG(1, GetInteger);
return NULL_VAL;
}
+/***
+ * Animator.SetPrevAnimation
+ * \desc Sets the previous frame of an animator.
+ * \param animator (Integer): The animator index to change.
+ * \param prevAnimation (Integer): The animator's changed previous animation.
+ * \ns Animator
+ */
+VMValue Animator_SetPrevAnimation(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->PrevAnimation = GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
/***
* Animator.SetAnimationSpeed
* \desc Sets the animation speed of an animator.
@@ -858,6 +887,42 @@ VMValue Animator_SetDuration(int argCount, VMValue* args, Uint32 threadID) {
Scene::AnimatorList[GET_ARG(0, GetInteger)]->Duration = GET_ARG(1, GetInteger);
return NULL_VAL;
}
+/***
+ * Animator.SetFrameCount
+ * \desc Sets the frame count of an animator.
+ * \param animator (Integer): The animator index to change.
+ * \param frameCount (Integer): The animator's changed frame count.
+ * \ns Animator
+ */
+VMValue Animator_SetFrameCount(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->FrameCount = GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
+/***
+ * Animator.SetLoopIndex
+ * \desc Sets the loop index of an animator.
+ * \param animator (Integer): The animator index to change.
+ * \param loopIndex (Integer): The animator's changed loop index.
+ * \ns Animator
+ */
+VMValue Animator_SetLoopIndex(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->LoopIndex = GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
+/***
+ * Animator.SetRotationStyle
+ * \desc Sets the rotation style of an animator.
+ * \param animator (Integer): The animator index to change.
+ * \param rorationStyle (Integer): The animator's changed rotation style.
+ * \ns Animator
+ */
+VMValue Animator_SetRotationStyle(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->RotationStyle = GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
/***
* Animator.AdjustCurrentAnimation
* \desc Adjusts the current animation of an animator by an amount.
@@ -918,6 +983,30 @@ VMValue Animator_AdjustDuration(int argCount, VMValue* args, Uint32 threadID) {
Scene::AnimatorList[GET_ARG(0, GetInteger)]->Duration += GET_ARG(1, GetInteger);
return NULL_VAL;
}
+/***
+ * Animator.AdjustFrameCount
+ * \desc Adjusts the frame count of an animator by an amount.
+ * \param animator (Integer): The animator index to change.
+ * \param amount (Integer): The amount to adjust the animator's duration.
+ * \ns Animator
+ */
+VMValue Animator_AdjustFrameCount(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->FrameCount += GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
+/***
+ * Animator.AdjustLoopIndex
+ * \desc Adjusts the loop index of an animator by an amount.
+ * \param animator (Integer): The animator index to change.
+ * \param amount (Integer): The amount to adjust the animator's loop index.
+ * \ns Animator
+ */
+VMValue Animator_AdjustLoopIndex(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ Scene::AnimatorList[GET_ARG(0, GetInteger)]->LoopIndex += GET_ARG(1, GetInteger);
+ return NULL_VAL;
+}
// #endregion
// #region Application
@@ -1115,6 +1204,16 @@ VMValue Application_GetGameDescription(int argCount, VMValue* args, Uint32 threa
CHECK_ARGCOUNT(0);
return ReturnString(Application::GameDescription);
}
+/***
+ * Application.GetReservedSlotIDs
+ * \desc Sets the number of reserved slot IDs the engine will use when creating instances.
+ * \param amount (Integer): How many reserved slot IDs the engine will use.
+ * \ns Application
+ */
+VMValue Application_GetReservedSlotIDs(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return INTEGER_VAL(Application::ReservedSlotIDs);
+}
/***
* Application.SetGameTitle
* \desc Sets the title of the game.
@@ -1163,6 +1262,17 @@ VMValue Application_SetGameDescription(int argCount, VMValue* args, Uint32 threa
StringUtils::Copy(Application::GameDescription, string, sizeof(Application::GameDescription));
return NULL_VAL;
}
+/***
+ * Application.SetReservedSlotIDs
+ * \desc Sets the number of reserved slot IDs the engine will use when creating instances.
+ * \param amount (Integer): How many reserved slot IDs the engine will use.
+ * \ns Application
+ */
+VMValue Application_SetReservedSlotIDs(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ Application::ReservedSlotIDs = GET_ARG(0, GetInteger);
+ return NULL_VAL;
+}
/***
* Application.SetCursorVisible
* \desc Sets the visibility of the cursor.
@@ -1189,93 +1299,6 @@ VMValue Application_GetCursorVisible(int argCount, VMValue* args, Uint32 threadI
}
// #endregion
-// #region Audio
-/***
- * Audio.GetMasterVolume
- * \desc Gets the master volume of the audio mixer.
- * \return The master volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_GetMasterVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL(Application::MasterVolume);
-}
-/***
- * Audio.GetMusicVolume
- * \desc Gets the music volume of the audio mixer.
- * \return The music volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_GetMusicVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL(Application::MusicVolume);
-}
-/***
- * Audio.GetSoundVolume
- * \desc Gets the sound effect volume of the audio mixer.
- * \return The sound effect volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_GetSoundVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL(Application::SoundVolume);
-}
-/***
- * Audio.SetMasterVolume
- * \desc Sets the master volume of the audio mixer.
- * \param volume (Integer): The master volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_SetMasterVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- int volume = GET_ARG(0, GetInteger);
- if (volume < 0) {
- THROW_ERROR("Volume cannot be lower than 0.");
- } else if (volume > 100) {
- THROW_ERROR("Volume cannot be higher than 100.");
- } else
- Application::SetMasterVolume(volume);
-
- return NULL_VAL;
-}
-/***
- * Audio.SetMusicVolume
- * \desc Sets the music volume of the audio mixer.
- * \param volume (Integer): The music volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_SetMusicVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- int volume = GET_ARG(0, GetInteger);
- if (volume < 0) {
- THROW_ERROR("Volume cannot be lower than 0.");
- } else if (volume > 100) {
- THROW_ERROR("Volume cannot be higher than 100.");
- } else
- Application::SetMusicVolume(volume);
-
- return NULL_VAL;
-}
-/***
- * Audio.SetSoundVolume
- * \desc Sets the sound effect volume of the audio mixer.
- * \param volume (Integer): The sound effect volume, from 0 to 100.
- * \ns Audio
- */
-VMValue Audio_SetSoundVolume(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- int volume = GET_ARG(0, GetInteger);
- if (volume < 0) {
- THROW_ERROR("Volume cannot be lower than 0.");
- } else if (volume > 100) {
- THROW_ERROR("Volume cannot be higher than 100.");
- } else
- Application::SetSoundVolume(volume);
-
- return NULL_VAL;
-}
-// #endregion
-
// #region Array
/***
* Array.Create
@@ -1539,8 +1562,9 @@ VMValue Array_Sort(int argCount, VMValue* args, Uint32 threadID) {
return AS_INTEGER(result) == 1;
return false;
- });
- } else {
+ });
+ }
+ else {
std::stable_sort(array->Values->begin(), array->Values->end(), [array](const VMValue& a, const VMValue& b) {
if (IS_NOT_NUMBER(a) || IS_NOT_NUMBER(b)) {
return false;
@@ -1551,7 +1575,7 @@ VMValue Array_Sort(int argCount, VMValue* args, Uint32 threadID) {
else {
return AS_INTEGER(a) < AS_INTEGER(b);
}
- });
+ });
}
ScriptManager::Unlock();
@@ -1560,6 +1584,316 @@ VMValue Array_Sort(int argCount, VMValue* args, Uint32 threadID) {
}
// #endregion
+// #region Audio
+/***
+ * Audio.GetMasterVolume
+ * \desc Gets the master volume of the audio mixer.
+ * \return The master volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_GetMasterVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return INTEGER_VAL(Application::MasterVolume);
+}
+/***
+ * Audio.GetMusicVolume
+ * \desc Gets the music volume of the audio mixer.
+ * \return The music volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_GetMusicVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return INTEGER_VAL(Application::MusicVolume);
+}
+/***
+ * Audio.GetSoundVolume
+ * \desc Gets the sound effect volume of the audio mixer.
+ * \return The sound effect volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_GetSoundVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return INTEGER_VAL(Application::SoundVolume);
+}
+/***
+ * Audio.SetMasterVolume
+ * \desc Sets the master volume of the audio mixer.
+ * \param volume (Integer): The master volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_SetMasterVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ int volume = GET_ARG(0, GetInteger);
+ if (volume < 0) {
+ THROW_ERROR("Volume cannot be lower than 0.");
+ } else if (volume > 100) {
+ THROW_ERROR("Volume cannot be higher than 100.");
+ } else
+ Application::SetMasterVolume(volume);
+
+ return NULL_VAL;
+}
+/***
+ * Audio.SetMusicVolume
+ * \desc Sets the music volume of the audio mixer.
+ * \param volume (Integer): The music volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_SetMusicVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ int volume = GET_ARG(0, GetInteger);
+ if (volume < 0) {
+ THROW_ERROR("Volume cannot be lower than 0.");
+ } else if (volume > 100) {
+ THROW_ERROR("Volume cannot be higher than 100.");
+ } else
+ Application::SetMusicVolume(volume);
+
+ return NULL_VAL;
+}
+/***
+ * Audio.SetSoundVolume
+ * \desc Sets the sound effect volume of the audio mixer.
+ * \param volume (Integer): The sound effect volume, from 0 to 100.
+ * \ns Audio
+ */
+VMValue Audio_SetSoundVolume(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ int volume = GET_ARG(0, GetInteger);
+ if (volume < 0) {
+ THROW_ERROR("Volume cannot be lower than 0.");
+ } else if (volume > 100) {
+ THROW_ERROR("Volume cannot be higher than 100.");
+ } else
+ Application::SetSoundVolume(volume);
+
+ return NULL_VAL;
+}
+// #endregion
+
+// #region Collision
+/***
+ * Collision.ProcessObjectMovement
+ * \desc Processes movement of an instance with an outer hitbox and an inner hitbox.
+ * \param entity (Instance): The instance to move.
+ * \param outer (Array): Array containing the outer hitbox.
+ * \param inner (Array): Array containing the inner hitbox.
+ * \ns Collision
+ */
+VMValue Collision_ProcessObjectMovement(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(3);
+ ObjInstance* entity = GET_ARG(0, GetInstance);
+ ObjArray* outer = GET_ARG(1, GetArray);
+ ObjArray* inner = GET_ARG(2, GetArray);
+
+ CollisionBox outerBox;
+ CollisionBox innerBox;
+
+ if (entity && outer && inner) {
+ auto ent = (Entity*)entity->EntityPtr;
+
+ outerBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*outer->Values)[0]));
+ outerBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*outer->Values)[1]));
+ outerBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*outer->Values)[2]));
+ outerBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*outer->Values)[3]));
+
+ innerBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*inner->Values)[0]));
+ innerBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*inner->Values)[1]));
+ innerBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*inner->Values)[2]));
+ innerBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*inner->Values)[3]));
+
+ Scene::ProcessObjectMovement(ent, &outerBox, &innerBox);
+ }
+ return NULL_VAL;
+}
+/***
+ * Collision.ObjectTileCollision
+ * \desc Checks tile collision based on where an instance should check.
+ * \param entity (Instance): The instance to base the values on.
+ * \param cLayers (Bitfield): Which layers the entity can collide with.
+ * \param cMode (Integer): Collision mode of the entity (floor, left wall, roof, right wall).
+ * \param cPlane (Integer): Collision plane to get the collision of (A or B).
+ * \param xOffset (Number): How far from the entity's X value to start from.
+ * \param yOffset (Number): How far from the entity's Y value to start from.
+ * \param setPos (Boolean): Whether to set the entity's position if collision is found.
+ * \return Returns whether the instance has collided with a tile.
+ * \ns Collision
+ */
+VMValue Collision_ObjectTileCollision(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(7);
+ ObjInstance* entity = GET_ARG(0, GetInstance);
+ int cLayers = GET_ARG(1, GetInteger);
+ int cMode = GET_ARG(2, GetInteger);
+ int cPlane = GET_ARG(3, GetInteger);
+ int xOffset = (int)GET_ARG(4, GetDecimal);
+ int yOffset = (int)GET_ARG(5, GetDecimal);
+ int setPos = GET_ARG(6, GetInteger);
+
+ auto ent = (Entity*)entity->EntityPtr;
+
+ return INTEGER_VAL(Scene::ObjectTileCollision(ent, cLayers, cMode, cPlane, xOffset, yOffset, setPos));
+}
+/***
+ * Collision.ObjectTileGrip
+ * \desc Keeps an instance gripped to tile collision based on where an instance should check.
+ * \param entity (Instance): The instance to move.
+ * \param cLayers (Bitfield): Which layers the entity can collide with.
+ * \param cMode (Integer): Collision mode of the entity (floor, left wall, roof, right wall).
+ * \param cPlane (Integer): Collision plane to get the collision of (A or B).
+ * \param xOffset (Decimal): How far from the entity's X value to start from.
+ * \param yOffset (Decimal): How far from the entity's Y value to start from.
+ * \param tolerance (Decimal): How far of a tolerance the entity should check for.
+ * \return Returns whether to grip the instance.
+ * \ns Collision
+ */
+VMValue Collision_ObjectTileGrip(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(7);
+ ObjInstance* entity = GET_ARG(0, GetInstance);
+ int cLayers = GET_ARG(1, GetInteger);
+ int cMode = GET_ARG(2, GetInteger);
+ int cPlane = GET_ARG(3, GetInteger);
+ int xOffset = (int)GET_ARG(4, GetDecimal);
+ int yOffset = (int)GET_ARG(5, GetDecimal);
+ float tolerance = GET_ARG(6, GetDecimal);
+
+ auto ent = (Entity*)entity->EntityPtr;
+
+ return INTEGER_VAL(Scene::ObjectTileGrip(ent, cLayers, cMode, cPlane, xOffset, yOffset, tolerance));
+}
+/***
+ * Collision.CheckObjectCollisionTouch
+ * \desc Checks if an instance is touching another instance with their respective hitboxes.
+ * \param thisEntity (Instance): The first instance to check.
+ * \param thisHitbox (Array): Array containing the first entity's hitbox.
+ * \param otherEntity (Instance): The other instance to check.
+ * \param otherHitbox (Array): Array containing the other entity's hitbox.
+ * \return Returns a Boolean value whether the entities are touching.
+ * \ns Collision
+ */
+VMValue Collision_CheckObjectCollisionTouch(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(4);
+ ObjInstance* thisEntity = GET_ARG(0, GetInstance);
+ ObjArray* thisHitbox = GET_ARG(1, GetArray);
+ ObjInstance* otherEntity = GET_ARG(2, GetInstance);
+ ObjArray* otherHitbox = GET_ARG(3, GetArray);
+
+ auto thisEnt = (Entity*)thisEntity->EntityPtr;
+ auto otherEnt = (Entity*)otherEntity->EntityPtr;
+
+ CollisionBox thisBox;
+ CollisionBox otherBox;
+
+ thisBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[0]));
+ thisBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[1]));
+ thisBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[2]));
+ thisBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[3]));
+
+ otherBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[0]));
+ otherBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[1]));
+ otherBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[2]));
+ otherBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[3]));
+
+
+ return INTEGER_VAL(!!Scene::CheckObjectCollisionTouch(thisEnt, &thisBox, otherEnt, &otherBox));
+}
+/***
+ * Collision.CheckObjectCollisionCircle
+ * \desc Checks if an instance is touching another instance with within their respective radii.
+ * \param thisEnity (Instance): The first instance to check.
+ * \param thisRadius (Decimal): Radius of the first entity to check.
+ * \param otherEntity (Instance): The other instance to check.
+ * \param otherRadius (Array): Radius of the other entity to check.
+ * \return Returns a Boolean value whether the entities have collided.
+ * \ns Collision
+ */
+VMValue Collision_CheckObjectCollisionCircle(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(4);
+ ObjInstance* thisEntity = GET_ARG(0, GetInstance);
+ float thisRadius = GET_ARG(1, GetDecimal);
+ ObjInstance* otherEntity = GET_ARG(2, GetInstance);
+ float otherRadius = GET_ARG(3, GetDecimal);
+
+ auto thisEnt = (Entity*)thisEntity->EntityPtr;
+ auto otherEnt = (Entity*)otherEntity->EntityPtr;
+
+ return INTEGER_VAL(!!Scene::CheckObjectCollisionCircle(thisEnt, thisRadius, otherEnt, otherRadius));
+}
+/***
+ * Collision.CheckObjectCollisionBox
+ * \desc Checks if an instance is touching another instance with their respective hitboxes and sets the values of the other instance if specified.
+ * \param thisEnity (Instance): The first instance to check.
+ * \param thisHitbox (Array): Array containing the first entity's hitbox.
+ * \param otherEntity (Instance): The other instance to check.
+ * \param otherHitbox (Array): Array containing the other entity's hitbox.
+ * \param setValues (Boolean): Whether to set the values of the other entity.
+ * \return Returns the side the entities are colliding on.
+ * \ns Collision
+ */
+VMValue Collision_CheckObjectCollisionBox(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(5);
+ ObjInstance* thisEntity = GET_ARG(0, GetInstance);
+ ObjArray* thisHitbox = GET_ARG(1, GetArray);
+ ObjInstance* otherEntity = GET_ARG(2, GetInstance);
+ ObjArray* otherHitbox = GET_ARG(3, GetArray);
+ bool setValues = !!GET_ARG(4, GetInteger);
+
+ auto thisEnt = (Entity*)thisEntity->EntityPtr;
+ auto otherEnt = (Entity*)otherEntity->EntityPtr;
+
+ CollisionBox thisBox = { 0, 0, 0, 0 };
+ CollisionBox otherBox = { 0, 0, 0, 0 };
+
+ thisBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[0]));
+ thisBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[1]));
+ thisBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[2]));
+ thisBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[3]));
+
+ otherBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[0]));
+ otherBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[1]));
+ otherBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[2]));
+ otherBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[3]));
+
+ return INTEGER_VAL(Scene::CheckObjectCollisionBox(thisEnt, &thisBox, otherEnt, &otherBox, setValues));
+}
+/***
+ * Collision.CheckObjectCollisionPlatform
+ * \desc Checks if an instance is touching the top of another instance with their respective hitboxes and sets the values of the other instance if specified.
+ * \param thisEnity (Instance): The first instance to check.
+ * \param thisHitbox (Array): Array containing the first entity's hitbox.
+ * \param otherEntity (Instance): The other instance to check whether it is on top of the first instance.
+ * \param otherHitbox (Array): Array containing the other entity's hitbox.
+ * \param setValues (Boolean): Whether to set the values of the other entity.
+ * \return Returns a Boolean value whether the entities have collided.
+ * \ns Collision
+ */
+VMValue Collision_CheckObjectCollisionPlatform(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(5);
+ ObjInstance* thisEntity = GET_ARG(0, GetInstance);
+ ObjArray* thisHitbox = GET_ARG(1, GetArray);
+ ObjInstance* otherEntity = GET_ARG(2, GetInstance);
+ ObjArray* otherHitbox = GET_ARG(3, GetArray);
+ bool setValues = !!GET_ARG(4, GetInteger);
+
+ auto thisEnt = (Entity*)thisEntity->EntityPtr;
+ auto otherEnt = (Entity*)otherEntity->EntityPtr;
+
+ CollisionBox thisBox;
+ CollisionBox otherBox;
+
+ thisBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[0]));
+ thisBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[1]));
+ thisBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[2]));
+ thisBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*thisHitbox->Values)[3]));
+
+ otherBox.Left = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[0]));
+ otherBox.Top = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[1]));
+ otherBox.Right = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[2]));
+ otherBox.Bottom = AS_INTEGER(ScriptManager::CastValueAsInteger((*otherHitbox->Values)[3]));
+
+ return INTEGER_VAL(!!Scene::CheckObjectCollisionPlatform(thisEnt, &thisBox, otherEnt, &otherBox, setValues));
+}
+// #endregion
+
// #region Controller
/***
* Controller.GetCount
@@ -2190,16 +2524,19 @@ VMValue Draw_Sprite(int argCount, VMValue* args, Uint32 threadID) {
* Draw.SpriteBasic
* \desc Draws a sprite based on an entity's current values (Sprite, CurrentAnimation, CurrentFrame, X, Y, Direction, ScaleX, ScaleY, Rotation).
* \param instance (Instance): The instance to draw.
- * \paramOpt sprite (Integer): The sprite index to use if not using the entity's sprite index.
+ * \paramOpt x (Number): X position of where to draw the sprite, otherwise uses the entity's X value.
+ * \paramOpt y (Number): Y position of where to draw the sprite, otherwise uses the entity's Y value.
* \ns Draw
*/
VMValue Draw_SpriteBasic(int argCount, VMValue* args, Uint32 threadID) {
CHECK_AT_LEAST_ARGCOUNT(1);
- ObjInstance* instance = GET_ARG(0, GetInstance);
- Entity* entity = (Entity*)instance->EntityPtr;
- ISprite* sprite = GET_ARG_OPT(1, GetSprite, GetSpriteIndex(entity->Sprite, threadID));
- float rotation = 0.0f;
+ ObjInstance* instance = GET_ARG(0, GetInstance);
+ Entity* entity = (Entity*)instance->EntityPtr;
+ int x = (int)GET_ARG_OPT(1, GetDecimal, entity->X);
+ int y = (int)GET_ARG_OPT(2, GetDecimal, entity->Y);
+ ISprite* sprite = GetSpriteIndex(entity->Sprite, threadID);
+ float rotation = 0.0f;
if (entity && sprite && entity->CurrentAnimation >= 0 && entity->CurrentFrame >= 0) {
int rot = (int)entity->Rotation;
@@ -2210,11 +2547,11 @@ VMValue Draw_SpriteBasic(int argCount, VMValue* args, Uint32 threadID) {
case ROTSTYLE_90DEG: rot = (rot + 0x40) & 0x180; break;
case ROTSTYLE_180DEG: rot = (rot + 0x80) & 0x100; break;
case ROTSTYLE_STATICFRAMES: break;
- default: break;
+ default: break;
}
rotation = rot * M_PI / 256.0;
- Graphics::DrawSprite(sprite, entity->CurrentAnimation, entity->CurrentFrame, (int)entity->X, (int)entity->Y, entity->Direction & 1, entity->Direction & 2, entity->ScaleX, entity->ScaleY, rotation);
+ Graphics::DrawSprite(sprite, entity->CurrentAnimation, entity->CurrentFrame, x, y, entity->Direction & FLIP_X, entity->Direction & FLIP_Y, entity->ScaleX, entity->ScaleY, rotation);
}
return NULL_VAL;
}
@@ -2251,7 +2588,7 @@ VMValue Draw_Animator(int argCount, VMValue* args, Uint32 threadID) {
if (!sprite)
return NULL_VAL;
- int rot = (int)rotation;
+ int rot = (int)rotation;
switch (sprite->Animations[animator->CurrentAnimation].Flags) {
case ROTSTYLE_NONE: rot = 0; break;
case ROTSTYLE_FULL: rot = rot & 0x1FF; break;
@@ -2261,7 +2598,7 @@ VMValue Draw_Animator(int argCount, VMValue* args, Uint32 threadID) {
case ROTSTYLE_STATICFRAMES: break;
default: break;
}
- rotation = rot * M_PI / 256.0;
+ rotation = rot * M_PI / 256.0;
Graphics::DrawSprite(sprite, animator->CurrentAnimation, animator->CurrentFrame, x, y, flipX, flipY, scaleX, scaleY, rotation);
}
@@ -2272,6 +2609,8 @@ VMValue Draw_Animator(int argCount, VMValue* args, Uint32 threadID) {
* \desc Draws an animator based on its current values (Sprite, CurrentAnimation, CurrentFrame) and an entity's other values (X, Y, Direction, ScaleX, ScaleY, Rotation).
* \param animator (Animator): The animator to draw.
* \param instance (Instance): The instance to pull other values from.
+ * \paramOpt x (Number): X position of where to draw the sprite, otherwise uses the entity's X value.
+ * \paramOpt y (Number): Y position of where to draw the sprite, otherwise uses the entity's Y value.
* \paramOpt sprite (Integer): The sprite index to use if not using the entity's sprite index.
* \ns Draw
*/
@@ -2281,21 +2620,19 @@ VMValue Draw_AnimatorBasic(int argCount, VMValue* args, Uint32 threadID) {
Animator* animator = GET_ARG(0, GetAnimator);
ObjInstance* instance = GET_ARG(1, GetInstance);
Entity* entity = (Entity*)instance->EntityPtr;
- ISprite* sprite = (argCount > 2) ? GET_ARG(2, GetSprite) : GetSpriteIndex(animator->Sprite, threadID);
+ int x = (int)GET_ARG_OPT(2, GetDecimal, entity->X);
+ int y = (int)GET_ARG_OPT(3, GetDecimal, entity->Y);
float rotation = 0.0f;
if (!animator || !animator->Frames.size())
return NULL_VAL;
if (entity && animator->Sprite >= 0 && animator->CurrentAnimation >= 0 && animator->CurrentFrame >= 0) {
- ISprite* animatorSprite = GetSpriteIndex(animator->Sprite, threadID);
- if (animatorSprite)
- sprite = animatorSprite;
-
+ ISprite* sprite = GetSpriteIndex(animator->Sprite, threadID);
if (!sprite)
return NULL_VAL;
- int rot = (int)rotation;
+ int rot = (int)entity->Rotation;
switch (sprite->Animations[animator->CurrentAnimation].Flags) {
case ROTSTYLE_NONE: rot = 0; break;
case ROTSTYLE_FULL: rot = rot & 0x1FF; break;
@@ -2305,9 +2642,9 @@ VMValue Draw_AnimatorBasic(int argCount, VMValue* args, Uint32 threadID) {
case ROTSTYLE_STATICFRAMES: break;
default: break;
}
- rotation = rot * M_PI / 256.0;
+ rotation = rot * M_PI / 256.0;
- Graphics::DrawSprite(sprite, animator->CurrentAnimation, animator->CurrentFrame, (int)entity->X, (int)entity->Y, entity->Direction & 1, entity->Direction & 2, entity->ScaleX, entity->ScaleY, rotation);
+ Graphics::DrawSprite(sprite, animator->CurrentAnimation, animator->CurrentFrame, x, y, entity->Direction & FLIP_X, entity->Direction & FLIP_Y, entity->ScaleX, entity->ScaleY, rotation);
}
return NULL_VAL;
}
@@ -3243,7 +3580,115 @@ VMValue Draw_TextEllipsis(int argCount, VMValue* args, Uint32 threadID) {
// Graphics::DrawSprite(sprite, 0, t, x, y, false, false, 1.0f, 1.0f, 0.0f);
return NULL_VAL;
}
+/***
+ * Draw.TextArray
+ * \desc Draws a series of sprites based on a converted sprite string.
+ * \param sprite (Integer): The index of the loaded sprite to be used as text.
+ * \param animation (Integer): The animation index.
+ * \param x (Number): The X value to begin drawing.
+ * \param y (Number): The Y value to begin drawing.
+ * \param string (Array): The array containing frame indexes.
+ * \param startFrame (Integer): The index to begin drawing.
+ * \param endFrame (Integer): The index to end drawing.
+ * \param align (Integer): The text alignment.
+ * \param spacing (Integer): The space between drawn sprites.
+ * \paramOpt charOffsetsX (Array): The X offsets at which to draw per frame. Must also have charOffsetsY to be used.
+ * \paramOpt charOffsetsY (Array): The Y offsets at which to draw per frame.
+ * \ns Draw
+ */
+VMValue Draw_TextArray(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_AT_LEAST_ARGCOUNT(9);
+ if (ScriptManager::Lock()) {
+ ISprite* sprite = GET_ARG(0, GetSprite);
+ int animation = GET_ARG(1, GetInteger);
+ float x = GET_ARG(2, GetDecimal);
+ float y = GET_ARG(3, GetDecimal);
+ ObjArray* string = GET_ARG(4, GetArray);
+ int startFrame = GET_ARG(5, GetInteger);
+ int endFrame = GET_ARG(6, GetInteger);
+ int align = GET_ARG(7, GetInteger);
+ int spacing = GET_ARG(8, GetInteger);
+ ObjArray* charOffsetsX = GET_ARG_OPT(9, GetArray, NewArray());
+ ObjArray* charOffsetsY = GET_ARG_OPT(10, GetArray, NewArray());
+
+ if (sprite && string->Values) {
+ startFrame = (int)Math::Clamp(startFrame, 0, (int)string->Values->size() - 1);
+
+ if (endFrame <= 0 || endFrame > (int)string->Values->size())
+ endFrame = (int)string->Values->size();
+
+ int charOffsetIndex = 0;
+ switch (align) {
+ case 0: // ALIGN_LEFT
+ if (charOffsetsX->Values->size() && charOffsetsY->Values->size()) {
+ for (; startFrame < endFrame; ++startFrame) {
+ int curChar = AS_INTEGER(ScriptManager::CastValueAsInteger((*string->Values)[startFrame]));
+ if (curChar >= 0 && curChar < sprite->Animations[animation].FrameCount) {
+ AnimFrame frame = sprite->Animations[animation].Frames[curChar];
+ Graphics::DrawSprite(sprite,
+ animation,
+ curChar,
+ x + AS_DECIMAL(ScriptManager::CastValueAsDecimal((*charOffsetsX->Values)[charOffsetIndex])),
+ y + AS_DECIMAL(ScriptManager::CastValueAsDecimal((*charOffsetsY->Values)[charOffsetIndex])),
+ false, false, 1.0f, 1.0f, 0.0f);
+ x += spacing + frame.Width;
+ ++charOffsetIndex;
+ }
+ }
+ }
+ else {
+ for (; startFrame < endFrame; ++startFrame) {
+ int curChar = AS_INTEGER(ScriptManager::CastValueAsInteger((*string->Values)[startFrame]));
+ if (curChar >= 0 && curChar < sprite->Animations[animation].FrameCount) {
+ AnimFrame frame = sprite->Animations[animation].Frames[curChar];
+ Graphics::DrawSprite(sprite, animation, curChar, x, y, false, false, 1.0f, 1.0f, 0.0f);
+ x += spacing + frame.Width;
+ }
+ }
+ }
+ break;
+
+ case 1: // ALIGN_RIGHT
+ break;
+
+ case 2: // ALIGN_CENTER
+ --endFrame;
+ if (charOffsetsX->Values->size() && charOffsetsY->Values->size()) {
+ charOffsetIndex = endFrame;
+ for (; endFrame >= startFrame; --endFrame) {
+ int curChar = AS_INTEGER(ScriptManager::CastValueAsInteger((*string->Values)[endFrame]));
+ if (curChar >= 0 && curChar < sprite->Animations[animation].FrameCount) {
+ AnimFrame frame = sprite->Animations[animation].Frames[curChar];
+ Graphics::DrawSprite(sprite,
+ animation,
+ curChar,
+ x - (frame.Width / 2) + AS_DECIMAL(ScriptManager::CastValueAsDecimal((*charOffsetsX->Values)[charOffsetIndex])),
+ y + AS_DECIMAL(ScriptManager::CastValueAsDecimal((*charOffsetsY->Values)[charOffsetIndex])),
+ false, false, 1.0f, 1.0f, 0.0f);
+ x = (x - frame.Width) - spacing;
+ --charOffsetIndex;
+ }
+ }
+ }
+ else {
+ for (; endFrame >= startFrame; --endFrame) {
+ int curChar = AS_INTEGER(ScriptManager::CastValueAsInteger((*string->Values)[endFrame]));
+ if (curChar >= 0 && curChar < sprite->Animations[animation].FrameCount) {
+ AnimFrame frame = sprite->Animations[animation].Frames[curChar];
+ Graphics::DrawSprite(sprite, animation, curChar, x - frame.Width / 2, y, false, false, 1.0f, 1.0f, 0.0f);
+ x = (x - frame.Width) - spacing;
+ }
+ }
+ }
+ break;
+ }
+ }
+ ScriptManager::Unlock();
+ return NULL_VAL;
+ }
+ return NULL_VAL;
+}
/***
* Draw.SetBlendColor
* \desc Sets the color to be used for drawing and blending.
@@ -3896,7 +4341,8 @@ VMValue Draw_UseStrokeSmoothing(int argCount, VMValue* args, Uint32 threadID) {
*/
VMValue Draw_SetClip(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(4);
- Graphics::SetClip((int)GET_ARG(0, GetDecimal), (int)GET_ARG(1, GetDecimal), (int)GET_ARG(2, GetDecimal), (int)GET_ARG(3, GetDecimal));
+ if (GET_ARG(2, GetDecimal) > 0.0 && GET_ARG(3, GetDecimal) > 0.0)
+ Graphics::SetClip((int)GET_ARG(0, GetDecimal), (int)GET_ARG(1, GetDecimal), (int)GET_ARG(2, GetDecimal), (int)GET_ARG(3, GetDecimal));
return NULL_VAL;
}
/***
@@ -3909,6 +4355,46 @@ VMValue Draw_ClearClip(int argCount, VMValue* args, Uint32 threadID) {
Graphics::ClearClip();
return NULL_VAL;
}
+/***
+ * Draw.GetClipX
+ * \desc Gets the X position in which drawing starts to occur.
+ * \return The X position if clipping is enabled, else 0.
+ * \ns Draw
+ */
+VMValue Draw_GetClipX(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return Graphics::CurrentClip.Enabled ? INTEGER_VAL((int)Graphics::CurrentClip.X) : INTEGER_VAL(0);
+}
+/***
+ * Draw.GetClipY
+ * \desc Gets the Y position in which drawing starts to occur.
+ * \return The Y position if clipping is enabled, else 0.
+ * \ns Draw
+ */
+VMValue Draw_GetClipY(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return Graphics::CurrentClip.Enabled ? INTEGER_VAL((int)Graphics::CurrentClip.Y) : INTEGER_VAL(0);
+}
+/***
+ * Draw.GetClipWidth
+ * \desc Gets the width in which drawing occurs.
+ * \return The width if clipping is enabled, else 0.
+ * \ns Draw
+ */
+VMValue Draw_GetClipWidth(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return Graphics::CurrentClip.Enabled ? INTEGER_VAL((int)Graphics::CurrentClip.Width) : INTEGER_VAL(0);
+}
+/***
+ * Draw.GetClipHeight
+ * \desc Gets the height in which drawing occurs.
+ * \return The height if clipping is enabled, else 0.
+ * \ns Draw
+ */
+VMValue Draw_GetClipHeight(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(0);
+ return Graphics::CurrentClip.Enabled ? INTEGER_VAL((int)Graphics::CurrentClip.Height) : INTEGER_VAL(0);
+}
/***
* Draw.Save
@@ -6839,7 +7325,7 @@ VMValue Instance_GetNth(int argCount, VMValue* args, Uint32 threadID) {
/***
* Instance.IsClass
* \desc Determines whether or not the instance is of a specified object class.
- * \param instance (Instance): The instance to check.
+ * \param instance (Instance): The instance to check. If there is no instance, this automatically returns false.
* \param className (String): Name of the object class.
* \return Returns whether or not the instance is of a specified object class.
* \ns Instance
@@ -6847,6 +7333,9 @@ VMValue Instance_GetNth(int argCount, VMValue* args, Uint32 threadID) {
VMValue Instance_IsClass(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(2);
+ if (IS_NULL(args[0]))
+ return INTEGER_VAL(false);
+
ObjInstance* instance = GET_ARG(0, GetInstance);
char* objectName = GET_ARG(1, GetString);
@@ -7014,8 +7503,12 @@ VMValue Instance_ChangeClass(int argCount, VMValue* args, Uint32 threadID) {
if (!self)
return INTEGER_VAL(false);
- if (self->ChangeClass(className))
+ if (self->ChangeClass(className)) {
+ self->Instance->Fields->Clear();
+ self->LinkFields();
+ self->Initialize();
return INTEGER_VAL(true);
+ }
return INTEGER_VAL(false);
}
@@ -7395,10 +7888,7 @@ VMValue Math_Direction(int argCount, VMValue* args, Uint32 threadID) {
*/
VMValue Math_Abs(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
- if (IS_INTEGER(args[0]))
- return INTEGER_VAL((int)Math::Abs(GET_ARG(0, GetInteger)));
- else
- return DECIMAL_VAL(Math::Abs(GET_ARG(0, GetDecimal)));
+ return IS_INTEGER(args[0]) ? INTEGER_VAL((int)Math::Abs(GET_ARG(0, GetDecimal))) : DECIMAL_VAL(Math::Abs(GET_ARG(0, GetDecimal)));
}
/***
* Math.Min
@@ -7431,31 +7921,76 @@ VMValue Math_Max(int argCount, VMValue* args, Uint32 threadID) {
return DECIMAL_VAL(Math::Max(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal)));
}
/***
- * Math.Clamp
- * \desc Gets the value clamped between a range.
- * \param n (Number): Number value.
- * \param minValue (Number): Minimum range value to clamp to.
- * \param maxValue (Number): Maximum range value to clamp to.
- * \return Returns the Number value if within the range, otherwise returns closest range value.
+ * Math.Clamp
+ * \desc Gets the value clamped between a range.
+ * \param n (Number): Number value.
+ * \param minValue (Number): Minimum range value to clamp to.
+ * \param maxValue (Number): Maximum range value to clamp to.
+ * \return Returns the Number value if within the range, otherwise returns closest range value.
+ * \ns Math
+ */
+VMValue Math_Clamp(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(3);
+ if (IS_INTEGER(args[0]) && IS_INTEGER(args[1]) && IS_INTEGER(args[2]))
+ return INTEGER_VAL((int)Math::Clamp(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal)));
+ else
+ return DECIMAL_VAL(Math::Clamp(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal)));
+}
+/***
+ * Math.Sign
+ * \desc Gets the sign associated with a Decimal value.
+ * \param n (Number): Number value.
+ * \return Returns -1
if n
is negative, 1
if positive, and 0
if otherwise.
+ * \ns Math
+ */
+VMValue Math_Sign(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return DECIMAL_VAL(Math::Sign(GET_ARG(0, GetDecimal)));
+}
+/***
+ * Math.Uint8
+ * \desc Converts an integer to an 8-bit unsigned value.
+ * \param n (Integer): Integer value to convert.
+ * \return Returns the converted value.
+ * \ns Math
+ */
+VMValue Math_Uint8(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL((int)(Uint8)GET_ARG(0, GetInteger));
+}
+/***
+ * Math.Uint16
+ * \desc Converts an integer to a 16-bit unsigned value.
+ * \param n (Integer): Integer value to convert.
+ * \return Returns the converted value.
+ * \ns Math
+ */
+VMValue Math_Uint16(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL((int)(Uint16)GET_ARG(0, GetInteger));
+}
+/***
+ * Math.Uint32
+ * \desc Converts an integer to a 32-bit unsigned value.
+ * \param n (Integer): Integer value to convert.
+ * \return Returns the converted value.
* \ns Math
*/
-VMValue Math_Clamp(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(3);
- if (IS_INTEGER(args[0]) && IS_INTEGER(args[1]) && IS_INTEGER(args[2]))
- return INTEGER_VAL((int)Math::Clamp(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal)));
- else
- return DECIMAL_VAL(Math::Clamp(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal)));
+VMValue Math_Uint32(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL((int)(Uint32)GET_ARG(0, GetInteger));
}
/***
- * Math.Sign
- * \desc Gets the sign associated with a Decimal value.
- * \param n (Number): Number value.
- * \return Returns -1
if n
is negative, 1
if positive, and 0
if otherwise.
+ * Math.Uint64
+ * \desc Converts an integer to a 64-bit unsigned value.
+ * \param n (Integer): Integer value to convert.
+ * \return Returns the converted value.
* \ns Math
*/
-VMValue Math_Sign(int argCount, VMValue* args, Uint32 threadID) {
+VMValue Math_Uint64(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
- return DECIMAL_VAL(Math::Sign(GET_ARG(0, GetDecimal)));
+ return INTEGER_VAL((int)(Uint64)GET_ARG(0, GetInteger));
+ return INTEGER_VAL((int)(Uint64)GET_ARG(0, GetInteger));
}
/***
* Math.Random
@@ -7793,6 +8328,18 @@ VMValue Math_ACos256(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
return INTEGER_VAL(Math::ACos256(GET_ARG(0, GetInteger)));
}
+/***
+ * RSDK.Math.ATan2
+ * \desc Returns the arc tangent of a position.
+ * \param x (Decimal): X value of the position.
+ * \param y (Decimal): Y value of the position.
+ * \return The arc tangent of the position.
+ * \ns RSDK.Math
+ */
+VMValue Math_ATan2(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL((int)Math::ArcTanLookup((int)(GET_ARG(0, GetDecimal) * 65536.0f), (int)(GET_ARG(1, GetDecimal) * 65536.0f)));
+}
/***
* RSDK.Math.RadianToInteger
* \desc Gets the integer conversion of a radian, based on 256.
@@ -7806,7 +8353,7 @@ VMValue Math_RadianToInteger(int argCount, VMValue* args, Uint32 threadID) {
}
/***
* RSDK.Math.IntegerToRadian
- * \desc Gets the radia Decimal conversion of an integer, based on 256.
+ * \desc Gets the radian Decimal conversion of an integer, based on 256.
* \param integer (Integer): Integer value to convert.
* \return A radia Decimal value of the converted integer.
* \ns RSDK.Math
@@ -7815,6 +8362,28 @@ VMValue Math_IntegerToRadian(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
return DECIMAL_VAL((float)(GET_ARG(0, GetInteger) * M_PI / 256.0));
}
+/***
+ * RSDK.Math.ToFixed
+ * \desc Converts a decimal number to its fixed-point equivalent.
+ * \param n (Number): Number value.
+ * \return Returns the converted fixed-point Number value.
+ * \ns Math
+ */
+VMValue Math_ToFixed(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return INTEGER_VAL((int)(GET_ARG(0, GetDecimal) * 65536.0f));
+}
+/***
+ * RSDK.Math.FromFixed
+ * \desc Converts a fixed-point number to its decimal equivalent.
+ * \param n (Number): Number value.
+ * \return Returns the converted decimal Number value.
+ * \ns Math
+ */
+VMValue Math_FromFixed(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ return DECIMAL_VAL((float)GET_ARG(0, GetInteger) / 65536.0f);
+}
// #endregion
// #region Matrix
@@ -8605,54 +9174,33 @@ VMValue Model_DeleteArmature(int argCount, VMValue* args, Uint32 threadID) {
* Music.Play
* \desc Places the music onto the music stack and plays it.
* \param music (Integer): The music index to play.
- * \paramOpt panning (Decimal): Control the panning of the audio. -1.0 makes it sound in left ear only, 1.0 makes it sound in right ear, and closer to 0.0 centers it. (0.0 is the default.)
- * \paramOpt speed (Decimal): Control the speed of the audio. > 1.0 makes it faster, < 1.0 is slower, 1.0 is normal speed. (1.0 is the default.)
- * \paramOpt volume (Decimal): Controls the volume of the audio. 0.0 is muted, 1.0 is normal volume. (1.0 is the default.)
- * \paramOpt fadeInAfterFinished (Decimal): The time period to fade in the previous music track after the currently playing track finishes playing, in seconds. (0.0 disables this.)
+ * \paramOpt loopPoint (Integer): The sample index to loop back to, or -1
if the music should only play once. (-1 is the default).
+ * \paramOpt panning (Decimal): Control the panning of the audio. -1.0 makes it sound in left ear only, 1.0 makes it sound in right ear, and closer to 0.0 centers it. (0.0 is the default).
+ * \paramOpt speed (Decimal): Control the speed of the audio. > 1.0 makes it faster, < 1.0 is slower, 1.0 is normal speed. (1.0 is the default).
+ * \paramOpt volume (Decimal): Controls the volume of the audio. 0.0 is muted, 1.0 is normal volume. (1.0 is the default).
+ * \paramOpt startPoint (Decimal): The time (in seconds) to start the music at. (0.0 is the default).
+ * \paramOpt fadeInAfterFinished (Decimal): The time period to fade in the previous music track after the currently playing track finishes playing, in seconds. (0.0 is the default, which disables it).
* \ns Music
*/
VMValue Music_Play(int argCount, VMValue* args, Uint32 threadID) {
CHECK_AT_LEAST_ARGCOUNT(1);
ISound* audio = GET_ARG(0, GetMusic);
- float panning = GET_ARG_OPT(1, GetDecimal, 0.0f);
- float speed = GET_ARG_OPT(2, GetDecimal, 1.0f);
- float volume = GET_ARG_OPT(3, GetDecimal, 1.0f);
- float fadeInAfterFinished = GET_ARG_OPT(4, GetDecimal, 0.0f);
- if (fadeInAfterFinished < 0.f)
- fadeInAfterFinished = 0.f;
- if (audio)
- AudioManager::PushMusicAt(audio, 0.0, false, 0, panning, speed, volume, fadeInAfterFinished);
- return NULL_VAL;
-}
-/***
- * Music.PlayAtTime
- * \desc Places the music onto the music stack and plays it at a time (in seconds).
- * \param music (Integer): The music index to play.
- * \param startPoint (Decimal): The time (in seconds) to start the music at.
- * \paramOpt panning (Decimal): Control the panning of the audio. -1.0 makes it sound in left ear only, 1.0 makes it sound in right ear, and closer to 0.0 centers it. (0.0 is the default.)
- * \paramOpt speed (Decimal): Control the speed of the audio. > 1.0 makes it faster, < 1.0 is slower, 1.0 is normal speed. (1.0 is the default.)
- * \paramOpt volume (Decimal): Controls the volume of the audio. 0.0 is muted, 1.0 is normal volume. (1.0 is the default.)
- * \paramOpt fadeInAfterFinished (Decimal): The time period to fade in the previous music track after the currently playing track finishes playing, in seconds. (0.0 disables this.)
- * \ns Music
- */
-VMValue Music_PlayAtTime(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_AT_LEAST_ARGCOUNT(2);
- ISound* audio = GET_ARG(0, GetMusic);
- double start_point = GET_ARG(1, GetDecimal);
+ int loopPoint = GET_ARG_OPT(1, GetInteger, -1);
float panning = GET_ARG_OPT(2, GetDecimal, 0.0f);
float speed = GET_ARG_OPT(3, GetDecimal, 1.0f);
float volume = GET_ARG_OPT(4, GetDecimal, 1.0f);
- float fadeInAfterFinished = GET_ARG_OPT(5, GetDecimal, 0.0f);
+ double startPoint = GET_ARG_OPT(5, GetDecimal, 0.0);
+ float fadeInAfterFinished = GET_ARG_OPT(6, GetDecimal, 0.0f);
if (fadeInAfterFinished < 0.f)
fadeInAfterFinished = 0.f;
if (audio)
- AudioManager::PushMusicAt(audio, start_point, false, 0, panning, speed, volume, fadeInAfterFinished);
+ AudioManager::PushMusicAt(audio, startPoint, (loopPoint >= 0) ? true : false, loopPoint, panning, speed, volume, fadeInAfterFinished);
return NULL_VAL;
}
/***
* Music.Stop
* \desc Removes the music from the music stack, stopping it if currently playing.
- * \param music (Integer): The music index to play.
+ * \param music (Integer): The music index to stop.
* \ns Music
*/
VMValue Music_Stop(int argCount, VMValue* args, Uint32 threadID) {
@@ -8714,62 +9262,6 @@ VMValue Music_Clear(int argCount, VMValue* args, Uint32 threadID) {
AudioManager::ClearMusic();
return NULL_VAL;
}
-/***
- * Music.Loop
- * \desc Places the music onto the music stack and plays it, looping back to the specified sample index if it reaches the end of playback.
- * \param music (Integer): The music index to play.
- * \param loop (Boolean): Unused.
- * \param loopPoint (Integer): The sample index to loop back to.
- * \paramOpt panning (Decimal): Control the panning of the audio. -1.0 makes it sound in left ear only, 1.0 makes it sound in right ear, and closer to 0.0 centers it. (0.0 is the default.)
- * \paramOpt speed (Decimal): Control the speed of the audio. > 1.0 makes it faster, < 1.0 is slower, 1.0 is normal speed. (1.0 is the default.)
- * \paramOpt volume (Decimal): Controls the volume of the audio. 0.0 is muted, 1.0 is normal volume. (1.0 is the default.)
- * \paramOpt fadeInAfterFinished (Decimal): The time period to fade in the previous music track after the currently playing track is interrupted, in seconds. (0.0 disables this.)
- * \ns Music
- */
-VMValue Music_Loop(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_AT_LEAST_ARGCOUNT(3);
- ISound* audio = GET_ARG(0, GetMusic);
- // int loop = GET_ARG(1, GetInteger);
- int loop_point = GET_ARG(2, GetInteger);
- float panning = GET_ARG_OPT(3, GetDecimal, 0.0f);
- float speed = GET_ARG_OPT(4, GetDecimal, 1.0f);
- float volume = GET_ARG_OPT(5, GetDecimal, 1.0f);
- float fadeInAfterFinished = GET_ARG_OPT(6, GetDecimal, 0.0f);
- if (fadeInAfterFinished < 0.f)
- fadeInAfterFinished = 0.f;
- if (audio)
- AudioManager::PushMusic(audio, true, loop_point, panning, speed, volume, fadeInAfterFinished);
- return NULL_VAL;
-}
-/***
- * Music.LoopAtTime
- * \desc Places the music onto the music stack and plays it, looping back to the specified sample index if it reaches the end of playback.
- * \param music (Integer): The music index to play.
- * \param startPoint (Decimal): The time (in seconds) to start the music at.
- * \param loop (Boolean): Unused.
- * \param loopPoint (Integer): The sample index to loop back to.
- * \paramOpt panning (Decimal): Control the panning of the audio. -1.0 makes it sound in left ear only, 1.0 makes it sound in right ear, and closer to 0.0 centers it. (0.0 is the default.)
- * \paramOpt speed (Decimal): Control the speed of the audio. > 1.0 makes it faster, < 1.0 is slower, 1.0 is normal speed. (1.0 is the default.)
- * \paramOpt volume (Decimal): Controls the volume of the audio. 0.0 is muted, 1.0 is normal volume. (1.0 is the default.)
- * \paramOpt fadeInAfterFinished (Decimal): The time period to fade in the previous music track after the currently playing track is interrupted, in seconds. (0.0 disables this.)
- * \ns Music
- */
-VMValue Music_LoopAtTime(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_AT_LEAST_ARGCOUNT(4);
- ISound* audio = GET_ARG(0, GetMusic);
- double start_point = GET_ARG(1, GetDecimal);
- // int loop = GET_ARG(2, GetInteger);
- int loop_point = GET_ARG(3, GetInteger);
- float panning = GET_ARG_OPT(4, GetDecimal, 0.0f);
- float speed = GET_ARG_OPT(5, GetDecimal, 1.0f);
- float volume = GET_ARG_OPT(6, GetDecimal, 1.0f);
- float fadeInAfterFinished = GET_ARG_OPT(7, GetDecimal, 0.0f);
- if (fadeInAfterFinished < 0.f)
- fadeInAfterFinished = 0.f;
- if (audio)
- AudioManager::PushMusicAt(audio, start_point, true, loop_point, panning, speed, volume, fadeInAfterFinished);
- return NULL_VAL;
-}
/***
* Music.IsPlaying
* \desc Checks to see if the specified music is currently playing.
@@ -8895,7 +9387,7 @@ VMValue Number_AsDecimal(int argCount, VMValue* args, Uint32 threadID) {
VMValue Object_Loaded(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
- char* objectName = GET_ARG(0, GetString);
+ char* objectName = GET_ARG(0, GetString);
return INTEGER_VAL(!!Scene::ObjectLists->Exists(Scene::ObjectLists->HashFunction(objectName, strlen(objectName))));
}
@@ -9477,6 +9969,41 @@ VMValue Resources_LoadSprite(int argCount, VMValue* args, Uint32 threadID) {
}
return INTEGER_VAL((int)index);
}
+/***
+ * Resources.LoadDynamicSprite
+ * \desc Loads a Sprite resource via the current Scene's resource folder if a scene list is loaded (else a fallback folder).
+ * \param fallbackFolder (String): Folder to check if the sprite does not exist in the current Scene's resource folder.
+ * \param name (String): Name of the animation file within the resource folder.
+ * \param unloadPolicy (Integer): Whether to unload the resource at the end of the current Scene, or the game end.
+ * \return Returns the index of the Resource.
+ * \ns Resources
+ */
+VMValue Resources_LoadDynamicSprite(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(3);
+
+ char filename[4096];
+ snprintf(filename, sizeof(filename), "Sprites/%s/%s.bin", Scene::CurrentResourceFolder, GET_ARG(1, GetString));
+ if (!ResourceManager::ResourceExists(filename))
+ snprintf(filename, sizeof(filename), "Sprites/%s/%s.bin", GET_ARG(0, GetString), GET_ARG(1, GetString));
+
+ ResourceType* resource = new (std::nothrow) ResourceType();
+ resource->FilenameHash = CRC32::EncryptString(filename);
+ resource->UnloadPolicy = GET_ARG(2, GetInteger);
+
+ size_t index = 0;
+ vector* list = &Scene::SpriteList;
+ if (Scene::GetResource(list, resource, index))
+ return INTEGER_VAL((int)index);
+
+ resource->AsSprite = new (std::nothrow) ISprite(filename);
+ if (resource->AsSprite->LoadFailed) {
+ delete resource->AsSprite;
+ delete resource;
+ (*list)[index] = NULL;
+ return INTEGER_VAL(-1);
+ }
+ return INTEGER_VAL((int)index);
+}
/***
* Resources.LoadImage
* \desc Loads an Image resource, returning its Image index.
@@ -9756,291 +10283,28 @@ VMValue Resources_FileExists(int argCount, VMValue* args, Uint32 threadID) {
* \return Returns all the text in the resource as a String value if it can be read, otherwise it returns a null
value if it cannot be read.
* \ns Resources
*/
-VMValue Resources_ReadAllText(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- char* filePath = GET_ARG(0, GetString);
- Stream* stream = ResourceStream::New(filePath);
- if (!stream)
- return NULL_VAL;
-
- if (ScriptManager::Lock()) {
- size_t size = stream->Length();
- ObjString* text = AllocString(size);
- stream->ReadBytes(text->Chars, size);
- stream->Close();
- ScriptManager::Unlock();
- return OBJECT_VAL(text);
- }
- return NULL_VAL;
-}
-// #endregion
-
-// #region Scene
-#define CHECK_TILE_LAYER_POS_BOUNDS() if (layer < 0 || layer >= (int)Scene::Layers.size() || x < 0 || y < 0 || x >= Scene::Layers[layer].Width || y >= Scene::Layers[layer].Height) return NULL_VAL;
-
-/***
- * Scene.ProcessObjectMovement
- * \desc Processes movement of an instance with an outer hitbox and an inner hitboxe.
- * \param entity (Instance): The instance to move.
- * \param outer (Array): Array containing the outer hitbox.
- * \param inner (Array): Array containing the inner hitbox.
- * \ns Scene
- */
-VMValue Scene_ProcessObjectMovement(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(3);
- ObjInstance* entity = GET_ARG(0, GetInstance);
- ObjArray* outer = GET_ARG(1, GetArray);
- ObjArray* inner = GET_ARG(2, GetArray);
-
- CollisionBox outerBox;
- CollisionBox innerBox;
-
- if (entity && outer && inner) {
- auto ent = (Entity*)entity->EntityPtr;
-
- outerBox.Left = (int)AS_DECIMAL((*outer->Values)[0]);
- outerBox.Top = (int)AS_DECIMAL((*outer->Values)[1]);
- outerBox.Right = (int)AS_DECIMAL((*outer->Values)[2]);
- outerBox.Bottom = (int)AS_DECIMAL((*outer->Values)[3]);
-
- innerBox.Left = (int)AS_DECIMAL((*inner->Values)[0]);
- innerBox.Top = (int)AS_DECIMAL((*inner->Values)[1]);
- innerBox.Right = (int)AS_DECIMAL((*inner->Values)[2]);
- innerBox.Bottom = (int)AS_DECIMAL((*inner->Values)[3]);
- Scene::ProcessObjectMovement(ent, &outerBox, &innerBox);
- }
- return NULL_VAL;
-}
-/***
- * Scene.ObjectTileCollision
- * \desc Checks tile collision based on where an instance should check.
- * \param entity (Instance): The instance to base the values on.
- * \param cLayers (Bitfield): Which layers the entity can collide with.
- * \param cMode (Integer): Collision mode of the entity (floor, left wall, roof, right wall).
- * \param cPlane (Integer): Collision plane to get the collision of (A or B).
- * \param xOffset (Number): How far from the entity's X value to start from.
- * \param yOffset (Number): How far from the entity's Y value to start from.
- * \param setPos (Boolean): Whether to set the entity's position if collision is found.
- * \return Returns whether the instance has collided with a tile.
- * \ns Scene
- */
-VMValue Scene_ObjectTileCollision(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(7);
- ObjInstance* entity = GET_ARG(0, GetInstance);
- int cLayers = GET_ARG(1, GetInteger);
- int cMode = GET_ARG(2, GetInteger);
- int cPlane = GET_ARG(3, GetInteger);
- int xOffset = GET_ARG(4, GetDecimal);
- int yOffset = GET_ARG(5, GetDecimal);
- int setPos = GET_ARG(6, GetInteger);
-
- auto ent = (Entity*)entity->EntityPtr;
-
- return INTEGER_VAL(Scene::ObjectTileCollision(ent, cLayers, cMode, cPlane, xOffset, yOffset, setPos));
-}
-/***
- * Scene.ObjectTileGrip
- * \desc Keeps an instance gripped to tile collision based on where an instance should check.
- * \param entity (Instance): The instance to move.
- * \param cLayers (Bitfield): Which layers the entity can collide with.
- * \param cMode (Integer): Collision mode of the entity (floor, left wall, roof, right wall).
- * \param cPlane (Integer): Collision plane to get the collision of (A or B).
- * \param xOffset (Decimal): How far from the entity's X value to start from.
- * \param yOffset (Decimal): How far from the entity's Y value to start from.
- * \param tolerance (Decimal): How far of a tolerance the entity should check for.
- * \return Returns whether to grip the instance.
- * \ns Scene
- */
-VMValue Scene_ObjectTileGrip(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(7);
- ObjInstance* entity = GET_ARG(0, GetInstance);
- int cLayers = GET_ARG(1, GetInteger);
- int cMode = GET_ARG(2, GetInteger);
- int cPlane = GET_ARG(3, GetInteger);
- float xOffset = GET_ARG(4, GetDecimal);
- float yOffset = GET_ARG(5, GetDecimal);
- float tolerance = GET_ARG(6, GetDecimal);
-
- auto ent = (Entity*)entity->EntityPtr;
-
- return INTEGER_VAL(Scene::ObjectTileGrip(ent, cLayers, cMode, cPlane, xOffset, yOffset, tolerance));
-}
-/***
- * Scene.CheckObjectCollisionTouch
- * \desc Checks if an instance is touching another instance with their respective hitboxes.
- * \param thisEntity (Instance): The first instance to check.
- * \param thisHitbox (Array): Array containing the first entity's hitbox.
- * \param otherEntity (Instance): The other instance to check.
- * \param otherHitbox (Array): Array containing the other entity's hitbox.
- * \return Returns a Boolean value whether the entities are touching.
- * \ns Scene
- */
-VMValue Scene_CheckObjectCollisionTouch(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(4);
- ObjInstance* thisEntity = GET_ARG(0, GetInstance);
- ObjArray* thisHitbox = GET_ARG(1, GetArray);
- ObjInstance* otherEntity = GET_ARG(2, GetInstance);
- ObjArray* otherHitbox = GET_ARG(3, GetArray);
-
- auto thisEnt = (Entity*)thisEntity->EntityPtr;
- auto otherEnt = (Entity*)otherEntity->EntityPtr;
-
- CollisionBox thisBox;
- CollisionBox otherBox;
-
- if (IS_INTEGER((*thisHitbox->Values)[0])) {
- thisBox.Left = AS_INTEGER((*thisHitbox->Values)[0]);
- thisBox.Top = AS_INTEGER((*thisHitbox->Values)[1]);
- thisBox.Right = AS_INTEGER((*thisHitbox->Values)[2]);
- thisBox.Bottom = AS_INTEGER((*thisHitbox->Values)[3]);
- }
- else {
- thisBox.Left = (int)AS_DECIMAL((*thisHitbox->Values)[0]);
- thisBox.Top = (int)AS_DECIMAL((*thisHitbox->Values)[1]);
- thisBox.Right = (int)AS_DECIMAL((*thisHitbox->Values)[2]);
- thisBox.Bottom = (int)AS_DECIMAL((*thisHitbox->Values)[3]);
- }
-
- if (IS_INTEGER((*otherHitbox->Values)[0])) {
- otherBox.Left = AS_INTEGER((*otherHitbox->Values)[0]);
- otherBox.Top = AS_INTEGER((*otherHitbox->Values)[1]);
- otherBox.Right = AS_INTEGER((*otherHitbox->Values)[2]);
- otherBox.Bottom = AS_INTEGER((*otherHitbox->Values)[3]);
- }
- else {
- otherBox.Left = (int)AS_DECIMAL((*otherHitbox->Values)[0]);
- otherBox.Top = (int)AS_DECIMAL((*otherHitbox->Values)[1]);
- otherBox.Right = (int)AS_DECIMAL((*otherHitbox->Values)[2]);
- otherBox.Bottom = (int)AS_DECIMAL((*otherHitbox->Values)[3]);
- }
- return INTEGER_VAL(!!Scene::CheckObjectCollisionTouch(thisEnt, &thisBox, otherEnt, &otherBox));
-}
-/***
- * Scene.CheckObjectCollisionCircle
- * \desc Checks if an instance is touching another instance with within their respective radii.
- * \param thisEnity (Instance): The first instance to check.
- * \param thisRadius (Decimal): Radius of the first entity to check.
- * \param otherEntity (Instance): The other instance to check.
- * \param otherRadius (Array): Radius of the other entity to check.
- * \return Returns a Boolean value whether the entities have collided.
- * \ns Scene
- */
-VMValue Scene_CheckObjectCollisionCircle(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(4);
- ObjInstance* thisEntity = GET_ARG(0, GetInstance);
- float thisRadius = GET_ARG(1, GetDecimal);
- ObjInstance* otherEntity = GET_ARG(2, GetInstance);
- float otherRadius = GET_ARG(3, GetDecimal);
-
- auto thisEnt = (Entity*)thisEntity->EntityPtr;
- auto otherEnt = (Entity*)otherEntity->EntityPtr;
-
- return INTEGER_VAL(!!Scene::CheckObjectCollisionCircle(thisEnt, thisRadius, otherEnt, otherRadius));
-}
-/***
- * Scene.CheckObjectCollisionBox
- * \desc Checks if an instance is touching another instance with their respective hitboxes and sets the values of the other instance if specified.
- * \param thisEnity (Instance): The first instance to check.
- * \param thisHitbox (Array): Array containing the first entity's hitbox.
- * \param otherEntity (Instance): The other instance to check.
- * \param otherHitbox (Array): Array containing the other entity's hitbox.
- * \param setValues (Boolean): Whether to set the values of the other entity.
- * \return Returns the side the entities are colliding on.
- * \ns Scene
- */
-VMValue Scene_CheckObjectCollisionBox(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(5);
- ObjInstance* thisEntity = GET_ARG(0, GetInstance);
- ObjArray* thisHitbox = GET_ARG(1, GetArray);
- ObjInstance* otherEntity = GET_ARG(2, GetInstance);
- ObjArray* otherHitbox = GET_ARG(3, GetArray);
- bool setValues = !!GET_ARG(4, GetInteger);
-
- auto thisEnt = (Entity*)thisEntity->EntityPtr;
- auto otherEnt = (Entity*)otherEntity->EntityPtr;
-
- CollisionBox thisBox;
- CollisionBox otherBox;
-
- if (IS_INTEGER((*thisHitbox->Values)[0])) {
- thisBox.Left = AS_INTEGER((*thisHitbox->Values)[0]);
- thisBox.Top = AS_INTEGER((*thisHitbox->Values)[1]);
- thisBox.Right = AS_INTEGER((*thisHitbox->Values)[2]);
- thisBox.Bottom = AS_INTEGER((*thisHitbox->Values)[3]);
- }
- else {
- thisBox.Left = (int)AS_DECIMAL((*thisHitbox->Values)[0]);
- thisBox.Top = (int)AS_DECIMAL((*thisHitbox->Values)[1]);
- thisBox.Right = (int)AS_DECIMAL((*thisHitbox->Values)[2]);
- thisBox.Bottom = (int)AS_DECIMAL((*thisHitbox->Values)[3]);
- }
+VMValue Resources_ReadAllText(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(1);
+ char* filePath = GET_ARG(0, GetString);
+ Stream* stream = ResourceStream::New(filePath);
+ if (!stream)
+ return NULL_VAL;
- if (IS_INTEGER((*otherHitbox->Values)[0])) {
- otherBox.Left = AS_INTEGER((*otherHitbox->Values)[0]);
- otherBox.Top = AS_INTEGER((*otherHitbox->Values)[1]);
- otherBox.Right = AS_INTEGER((*otherHitbox->Values)[2]);
- otherBox.Bottom = AS_INTEGER((*otherHitbox->Values)[3]);
- }
- else {
- otherBox.Left = (int)AS_DECIMAL((*otherHitbox->Values)[0]);
- otherBox.Top = (int)AS_DECIMAL((*otherHitbox->Values)[1]);
- otherBox.Right = (int)AS_DECIMAL((*otherHitbox->Values)[2]);
- otherBox.Bottom = (int)AS_DECIMAL((*otherHitbox->Values)[3]);
+ if (ScriptManager::Lock()) {
+ size_t size = stream->Length();
+ ObjString* text = AllocString(size);
+ stream->ReadBytes(text->Chars, size);
+ stream->Close();
+ ScriptManager::Unlock();
+ return OBJECT_VAL(text);
}
- return INTEGER_VAL(Scene::CheckObjectCollisionBox(thisEnt, &thisBox, otherEnt, &otherBox, setValues));
+ return NULL_VAL;
}
-/***
- * Scene.CheckObjectCollisionPlatform
- * \desc Checks if an instance is touching the top of another instance with their respective hitboxes and sets the values of the other instance if specified.
- * \param thisEnity (Instance): The first instance to check.
- * \param thisHitbox (Array): Array containing the first entity's hitbox.
- * \param otherEntity (Instance): The other instance to check whether it is on top of the first instance.
- * \param otherHitbox (Array): Array containing the other entity's hitbox.
- * \param setValues (Boolean): Whether to set the values of the other entity.
- * \return Returns a Boolean value whether the entities have collided.
- * \ns Scene
- */
-VMValue Scene_CheckObjectCollisionPlatform(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(5);
- ObjInstance* thisEntity = GET_ARG(0, GetInstance);
- ObjArray* thisHitbox = GET_ARG(1, GetArray);
- ObjInstance* otherEntity = GET_ARG(2, GetInstance);
- ObjArray* otherHitbox = GET_ARG(3, GetArray);
- bool setValues = !!GET_ARG(4, GetInteger);
-
- auto thisEnt = (Entity*)thisEntity->EntityPtr;
- auto otherEnt = (Entity*)otherEntity->EntityPtr;
-
- CollisionBox thisBox;
- CollisionBox otherBox;
+// #endregion
- if (IS_INTEGER((*thisHitbox->Values)[0])) {
- thisBox.Left = AS_INTEGER((*thisHitbox->Values)[0]);
- thisBox.Top = AS_INTEGER((*thisHitbox->Values)[1]);
- thisBox.Right = AS_INTEGER((*thisHitbox->Values)[2]);
- thisBox.Bottom = AS_INTEGER((*thisHitbox->Values)[3]);
- }
- else {
- thisBox.Left = (int)AS_DECIMAL((*thisHitbox->Values)[0]);
- thisBox.Top = (int)AS_DECIMAL((*thisHitbox->Values)[1]);
- thisBox.Right = (int)AS_DECIMAL((*thisHitbox->Values)[2]);
- thisBox.Bottom = (int)AS_DECIMAL((*thisHitbox->Values)[3]);
- }
+// #region Scene
+#define CHECK_TILE_LAYER_POS_BOUNDS() if (layer < 0 || layer >= (int)Scene::Layers.size() || x < 0 || y < 0 || x >= Scene::Layers[layer].Width || y >= Scene::Layers[layer].Height) return NULL_VAL;
- if (IS_INTEGER((*otherHitbox->Values)[0])) {
- otherBox.Left = AS_INTEGER((*otherHitbox->Values)[0]);
- otherBox.Top = AS_INTEGER((*otherHitbox->Values)[1]);
- otherBox.Right = AS_INTEGER((*otherHitbox->Values)[2]);
- otherBox.Bottom = AS_INTEGER((*otherHitbox->Values)[3]);
- }
- else {
- otherBox.Left = (int)AS_DECIMAL((*otherHitbox->Values)[0]);
- otherBox.Top = (int)AS_DECIMAL((*otherHitbox->Values)[1]);
- otherBox.Right = (int)AS_DECIMAL((*otherHitbox->Values)[2]);
- otherBox.Bottom = (int)AS_DECIMAL((*otherHitbox->Values)[3]);
- }
- return INTEGER_VAL(!!Scene::CheckObjectCollisionPlatform(thisEnt, &thisBox, otherEnt, &otherBox, setValues));
-}
/***
* Scene.Load
* \desc Changes the active scene. If a path to a resource is provided, the active scene is changed to the one in the specified resource file. Otherwise, the active scene is changed to the currently set entry in the scene list, if it exists (see .)
@@ -10087,40 +10351,6 @@ VMValue Scene_Load(int argCount, VMValue* args, Uint32 threadID) {
return NULL_VAL;
}
-/***
- * Scene.LoadNoPersistency
- * \desc Changes active scene to the one in the specified resource file, without keeping any persistent objects. (Deprecated; use instead.)
- * \param filename (String): Filename of scene.
- * \ns Scene
- */
-VMValue Scene_LoadNoPersistency(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- char* filename = GET_ARG(0, GetString);
-
- strcpy(Scene::NextScene, filename);
- Scene::NextScene[strlen(filename)] = 0;
- Scene::NoPersistency = true;
-
- return NULL_VAL;
-}
-/***
- * Scene.LoadPosition
- * \desc Loads the scene located in the scene list's position slot, if a scene list is loaded. (Deprecated; use instead.)
- * \paramOpt persistency (Boolean): Whether or not the scene should load with persistency.
- * \ns Scene
- */
-VMValue Scene_LoadPosition(int argCount, VMValue* args, Uint32 threadID) {
- if (!SceneInfo::IsEntryValid(Scene::CurrentSceneInList))
- return NULL_VAL;
-
- std::string path = SceneInfo::GetFilename(Scene::CurrentSceneInList);
-
- StringUtils::Copy(Scene::NextScene, path.c_str(), sizeof(Scene::NextScene));
-
- Scene::NoPersistency = !!GET_ARG_OPT(1, GetInteger, false);
-
- return NULL_VAL;
-}
/***
* Scene.Change
* \desc Changes the current scene if the category name and scene name are valid. Note that this does not load the scene; you must use .
@@ -10691,16 +10921,6 @@ VMValue Scene_GetDrawGroupEntityDepthSorting(int argCount, VMValue* args, Uint32
return INTEGER_VAL(0);
return INTEGER_VAL(!!Scene::PriorityLists[drawg].EntityDepthSortingEnabled);
}
-/***
- * Scene.GetListPos
- * \desc Gets the current list position of the scene. (Deprecated; use instead.)
- * \return Returns an Integer value.
- * \ns Scene
- */
-VMValue Scene_GetListPos(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL(Scene::CurrentSceneInList);
-}
/***
* Scene.GetCurrentFolder
* \desc Gets the current folder of the scene.
@@ -10731,16 +10951,6 @@ VMValue Scene_GetCurrentResourceFolder(int argCount, VMValue* args, Uint32 threa
CHECK_ARGCOUNT(0);
return ReturnString(Scene::CurrentResourceFolder);
}
-/***
- * Scene.GetCurrentSpriteFolder
- * \desc Gets the current sprite folder of the scene. (Deprecated; use instead.)
- * \return Returns a String value.
- * \ns Scene
- */
-VMValue Scene_GetCurrentSpriteFolder(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return ReturnString(Scene::CurrentResourceFolder);
-}
/***
* Scene.GetCurrentCategory
* \desc Gets the current category name of the scene.
@@ -10751,36 +10961,6 @@ VMValue Scene_GetCurrentCategory(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(0);
return ReturnString(Scene::CurrentCategory);
}
-/***
- * Scene.GetActiveCategory
- * \desc Gets the current category number of the scene. (Deprecated; use instead.)
- * \return Returns an Integer value.
- * \ns Scene
- */
-VMValue Scene_GetActiveCategory(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL(Scene::ActiveCategory);
-}
-/***
- * Scene.GetCategoryCount
- * \desc Gets the amount of categories in the scene list. (Deprecated; use instead.)
- * \return Returns an Integer value.
- * \ns Scene
- */
-VMValue Scene_GetCategoryCount(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL((int)SceneInfo::Categories.size());
-}
-/***
- * Scene.GetStageCount
- * \desc Gets the amount of stages in the scene list. (Deprecated; use instead.)
- * \return Returns an Integer value.
- * \ns Scene
- */
-VMValue Scene_GetStageCount(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(0);
- return INTEGER_VAL((int)SceneInfo::Entries.size());
-}
/***
* Scene.GetDebugMode
* \desc Gets whether Debug Mode has been turned on in the current scene.
@@ -11035,35 +11215,6 @@ VMValue Scene_IsUsingID(int argCount, VMValue* args, Uint32 threadID) {
return INTEGER_VAL(false);
}
-/***
- * Scene.CheckValidScene
- * \desc Checks whether the scene list's position is within the list's size, if a scene list is loaded. (Deprecated; use instead.)
- * \return Returns a Boolean value.
- * \ns Scene
- */
-VMValue Scene_CheckValidScene(int argCount, VMValue* args, Uint32 threadID) {
- return Scene_IsCurrentEntryValid(argCount, args, threadID);
-}
-/***
- * Scene.CheckSceneFolder
- * \desc Checks whether the current scene's folder matches the string to check, if a scene list is loaded. (Deprecated; use instead.)
- * \param folder (String): Folder name to compare.
- * \return Returns a Boolean value.
- * \ns Scene
- */
-VMValue Scene_CheckSceneFolder(int argCount, VMValue* args, Uint32 threadID) {
- return Scene_IsUsingFolder(argCount, args, threadID);
-}
-/***
- * Scene.CheckSceneID
- * \desc Checks whether the current scene's ID matches the string to check, if a scene list is loaded. (Deprecated; use instead.)
- * \param id (String): ID to compare.
- * \return Returns a Boolean value.
- * \ns Scene
- */
-VMValue Scene_CheckSceneID(int argCount, VMValue* args, Uint32 threadID) {
- return Scene_IsUsingID(argCount, args, threadID);
-}
/***
* Scene.IsPaused
* \desc Gets whether or not the scene is paused.
@@ -11073,28 +11224,6 @@ VMValue Scene_CheckSceneID(int argCount, VMValue* args, Uint32 threadID) {
VMValue Scene_IsPaused(int argCount, VMValue* args, Uint32 threadID) {
return INTEGER_VAL((int)Scene::Paused);
}
-/***
- * Scene.SetListPos
- * \desc Sets the current list position of the scene. (Deprecated; use instead.)
- * \param sceneNum (Integer): Scene number to use.
- * \ns Scene
- */
-VMValue Scene_SetListPos(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- Scene::CurrentSceneInList = GET_ARG(0, GetInteger);
- return NULL_VAL;
-}
-/***
- * Scene.SetActiveCategory
- * \desc Sets the current category number of the scene. (Deprecated; use instead.)
- * \param categoryNum (Integer): Scene category number to use.
- * \ns Scene
- */
-VMValue Scene_SetActiveCategory(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(1);
- Scene::ActiveCategory = GET_ARG(0, GetInteger);
- return NULL_VAL;
-}
/***
* Scene.SetDebugMode
* \desc Sets whether Debug Mode has been turned on in the current scene.
@@ -11105,16 +11234,6 @@ VMValue Scene_SetDebugMode(int argCount, VMValue* args, Uint32 threadID) {
Scene::DebugMode = GET_ARG(0, GetInteger);
return NULL_VAL;
}
-/***
- * Scene.SetScene
- * \desc Sets the scene if the category and scene names exist within the scene list. (Deprecated; use instead.)
- * \param category (String): Category name.
- * \param scene (String): Scene name. If the scene name is not found but the category name is, the first scene in the category is used.
- * \ns Scene
- */
-VMValue Scene_SetScene(int argCount, VMValue* args, Uint32 threadID) {
- return Scene_Change(argCount, args, threadID);
-}
/***
* Scene.SetTile
* \desc Sets the tile at a position.
@@ -13610,6 +13729,24 @@ VMValue Sprite_GetAnimationIndexByName(int argCount, VMValue* args, Uint32 threa
}
return INTEGER_VAL(-1);
}
+/***
+ * Sprite.GetFrameExists
+ * \desc Checks if an animation and frame is valid within a sprite.
+ * \param sprite (Integer): The sprite index to check.
+ * \param animation (Integer): The animation index to check.
+ * \param frame (Integer): The sprite index to check.
+ * \return Returns the first animation index with the specified name, or -1 if there was no match.
+ * \ns Sprite
+ */
+VMValue Sprite_GetFrameExists(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(3);
+ ISprite* sprite = GET_ARG(0, GetSprite);
+ int animation = GET_ARG(1, GetInteger);
+ int frame = GET_ARG(2, GetInteger);
+ if (!sprite)
+ return INTEGER_VAL(false);
+ return (INTEGER_VAL((animation >= 0 && animation < (int)sprite->Animations.size()) && (frame >= 0 && frame < (int)sprite->Animations[animation].Frames.size())));
+}
/***
* Sprite.GetFrameLoopIndex
* \desc Gets the index of the frame that the specified animation will loop back to when it finishes.
@@ -13776,25 +13913,41 @@ VMValue Sprite_GetFrameOffsetY(int argCount, VMValue* args, Uint32 threadID) {
return INTEGER_VAL(sprite->Animations[animation].Frames[frame].OffsetY);
}
/***
- * Sprite.GetFrameHitbox
- * \desc Gets the hitbox of an animation and frame of a sprite.
- * \param sprite (Integer): The sprite index to check.
- * \param animationID (Integer): The animation index of the sprite to check.
- * \param frame (Integer): The frame index of the animation to check.
+ * Sprite.GetHitbox
+ * \desc Gets the hitbox of a sprite frame. If an entity is provided, the only two arguments are the entity and the hitboxID. Else, there are 4 arguments.
+ * \param instance (Instance):An instance with Sprite, CurrentAnimation, and CurrentFrame values (if provided).
+ * \param sprite (Integer): The sprite index to check (if an entity is not provided).
+ * \param animationID (Integer): The animation index of the sprite to check (if an entity is not provided).
+ * \param frameID (Integer): The frame index of the animation to check (if an entity is not provided).
* \param hitboxID (Integer): The index number of the hitbox.
* \return Returns a reference value to a hitbox array.
* \ns Sprite
*/
-VMValue Sprite_GetFrameHitbox(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(4);
- ISprite* sprite = GET_ARG(0, GetSprite);
- int animationID = GET_ARG(1, GetInteger);
- int frameID = GET_ARG(2, GetInteger);
- int hitboxID = GET_ARG(3, GetInteger);
+VMValue Sprite_GetHitbox(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_AT_LEAST_ARGCOUNT(2);
+ ISprite* sprite;
+ int animationID, frameID, hitboxID;
+ if (argCount == 2 && IS_INSTANCE(args[0])) {
+ ObjInstance* instance = GET_ARG(0, GetInstance);
+ Entity* entity = (Entity*)instance->EntityPtr;
+ hitboxID = GET_ARG(1, GetInteger);
+
+ sprite = GetSpriteIndex(entity->Sprite, threadID);
+ animationID = entity->CurrentAnimation;
+ frameID = entity->CurrentFrame;
+ }
+ else {
+ CHECK_ARGCOUNT(4);
+ sprite = GET_ARG(0, GetSprite);
+ animationID = GET_ARG(1, GetInteger);
+ frameID = GET_ARG(2, GetInteger);
+ hitboxID = GET_ARG(3, GetInteger);
+ }
+
ObjArray* array = NewArray();
for (int i = 0; i < 4; i++)
- array->Values->push_back(DECIMAL_VAL(0.0f));
+ array->Values->push_back(INTEGER_VAL(0));
if (sprite && animationID >= 0 && frameID >= 0) {
AnimFrame frame = sprite->Animations[animationID].Frames[frameID];
@@ -13802,18 +13955,120 @@ VMValue Sprite_GetFrameHitbox(int argCount, VMValue* args, Uint32 threadID) {
if (!(hitboxID > -1 && hitboxID < frame.BoxCount))
return OBJECT_VAL(array);
- CollisionBox box = frame.Boxes[hitboxID];
- ObjArray* hitbox = NewArray();
- hitbox->Values->push_back(DECIMAL_VAL((float)box.Top));
- hitbox->Values->push_back(DECIMAL_VAL((float)box.Left));
- hitbox->Values->push_back(DECIMAL_VAL((float)box.Right));
- hitbox->Values->push_back(DECIMAL_VAL((float)box.Bottom));
+ CollisionBox box = frame.Boxes[hitboxID];
+ ObjArray* hitbox = NewArray();
+ hitbox->Values->push_back(INTEGER_VAL(box.Left));
+ hitbox->Values->push_back(INTEGER_VAL(box.Top));
+ hitbox->Values->push_back(INTEGER_VAL(box.Right));
+ hitbox->Values->push_back(INTEGER_VAL(box.Bottom));
return OBJECT_VAL(hitbox);
}
else {
return OBJECT_VAL(array);
}
}
+/***
+ * Sprite.SetSpriteString
+ * \desc Converts a string to an array of sprite indexes by comparing UTF-16 values to a frame's ID.
+ * \param sprite (Integer): The sprite index.
+ * \param animation (Integer): The animation index containing frames with UTF-16 ID values.
+ * \param string (String): The string to convert.
+ * \ns Sprite
+ */
+VMValue Sprite_SetSpriteString(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(3);
+ ISprite* sprite = GET_ARG(0, GetSprite);
+ int animation = GET_ARG(1, GetInteger);
+ char* string = GET_ARG(2, GetString);
+
+ ObjArray* spriteString = NewArray();
+
+ if (!sprite || !string)
+ return OBJECT_VAL(spriteString);
+
+ Uint16* utf16String = Application::UTF8toUTF16(string);
+
+ if (utf16String == NULL) {
+ // Handle UTF-16 conversion failure, if needed
+ return OBJECT_VAL(spriteString);
+ }
+
+ if (animation >= 0 && animation < (int)sprite->Animations.size()) {
+ for (size_t index = 0; utf16String[index] != 0; ++index) {
+ Uint16 unicodeChar = utf16String[index];
+
+ bool found = false;
+ for (int f = 0; f < (int)sprite->Animations[animation].Frames.size(); f++) {
+ if (sprite->Animations[animation].Frames[f].Advance == (int)unicodeChar) {
+ spriteString->Values->push_back(INTEGER_VAL(f));
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ spriteString->Values->push_back(INTEGER_VAL(-1));
+ }
+ }
+
+ free(utf16String);
+ return OBJECT_VAL(spriteString);
+}
+/***
+ * Sprite.GetStringWidth
+ * \desc Gets the width (in pixels) of a converted sprite string.
+ * \param sprite (Integer): The sprite index.
+ * \param animation (Integer): The animation index.
+ * \param string (Array): The array containing frame indexes.
+ * \param startIndex (Integer): Where to start checking the width.
+ * \param spacing (Integer): The spacing (in pixels) between frames.
+ * \ns Sprite
+ */
+VMValue Sprite_GetStringWidth(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(6);
+
+ if (ScriptManager::Lock()) {
+ ISprite* sprite = GET_ARG(0, GetSprite);
+ int animation = GET_ARG(1, GetInteger);
+ ObjArray* string = GET_ARG(2, GetArray);
+ int startIndex = GET_ARG(3, GetInteger);
+ int length = GET_ARG(4, GetInteger);
+ int spacing = GET_ARG(5, GetInteger);
+
+ if (!sprite || !string->Values) {
+ ScriptManager::Unlock();
+ return INTEGER_VAL(0);
+ }
+
+ if (animation >= 0 && animation <= (int)sprite->Animations.size()) {
+ Animation anim = sprite->Animations[animation];
+
+ startIndex = (int)Math::Clamp(startIndex, 0, (int)string->Values->size() - 1);
+
+ if (length <= 0 || length > (int)string->Values->size())
+ length = (int)string->Values->size();
+
+ int w = 0;
+ for (int c = startIndex; c < length; c++) {
+ int charFrame = AS_INTEGER(ScriptManager::CastValueAsInteger((*string->Values)[c]));
+ if (charFrame < anim.Frames.size()) {
+ w += anim.Frames[charFrame].Width;
+ if (c + 1 >= length) {
+ ScriptManager::Unlock();
+ return INTEGER_VAL(w);
+ }
+
+ w += spacing;
+ }
+ }
+
+ ScriptManager::Unlock();
+ return INTEGER_VAL(w);
+ }
+
+ }
+ return INTEGER_VAL(0);
+}
/***
* Sprite.MakePalettized
* \desc Converts a sprite's colors to the ones in the specified palette index.
@@ -14490,17 +14745,28 @@ VMValue String_Split(int argCount, VMValue* args, Uint32 threadID) {
}
/***
* String.CharAt
- * \desc Gets the UTF8 value of the character at the specified index.
- * \param string (String):
- * \param index (Integer):
- * \return Returns the UTF8 value as an Integer.
+ * \desc Gets the value of the character at the specified index.
+ * \param string (String): The string containing the character.
+ * \param index (Integer): The character index to check.
+ * \paramOpt utf16 (Boolean): Whether to use UTF-16 encoding. Otherwise, UTF-8 encoding is used.
+ * \return Returns the value as an Integer.
* \ns String
*/
VMValue String_CharAt(int argCount, VMValue* args, Uint32 threadID) {
- CHECK_ARGCOUNT(2);
+ CHECK_AT_LEAST_ARGCOUNT(2);
char* string = GET_ARG(0, GetString);
- int n = GET_ARG(1, GetInteger);
- return INTEGER_VAL((Uint8)string[n]);
+ int n = GET_ARG(1, GetInteger);
+ int utf16 = GET_ARG_OPT(2, GetInteger, 0);
+
+ if (utf16) {
+ Uint16* utf16String = Application::UTF8toUTF16(string);
+ Uint16 utf16Char = utf16String[n];
+ free(utf16String);
+ return INTEGER_VAL(utf16Char);
+ }
+ else {
+ return INTEGER_VAL((Uint8)string[n]);
+ }
}
/***
* String.Length
@@ -14586,13 +14852,13 @@ VMValue String_Substring(int argCount, VMValue* args, Uint32 threadID) {
return obj;
}
/***
- * String.ToUpperCase
+ * String.ToUppercase
* \desc Convert a String value to its uppercase representation.
* \param string (String):
* \return Returns a uppercase String value.
* \ns String
*/
-VMValue String_ToUpperCase(int argCount, VMValue* args, Uint32 threadID) {
+VMValue String_ToUppercase(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
char* string = GET_ARG(0, GetString);
@@ -14611,13 +14877,13 @@ VMValue String_ToUpperCase(int argCount, VMValue* args, Uint32 threadID) {
return obj;
}
/***
- * String.ToLowerCase
+ * String.ToLowercase
* \desc Convert a String value to its lowercase representation.
* \param string (String):
* \return Returns a lowercase String value.
* \ns String
*/
-VMValue String_ToLowerCase(int argCount, VMValue* args, Uint32 threadID) {
+VMValue String_ToLowercase(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(1);
char* string = GET_ARG(0, GetString);
@@ -15676,6 +15942,48 @@ VMValue View_SetPosition(int argCount, VMValue* args, Uint32 threadID) {
Scene::Views[view_index].Z = GET_ARG(3, GetDecimal);
return NULL_VAL;
}
+/***
+* View.AdjustX
+* \desc Adjusts the x - axis position of the camera for the specified view by an amount.
+* \param viewIndex(Integer) : Index of the view.
+* \param x(Number) : Desired X adjust amount.
+* \ns View
+*/
+VMValue View_AdjustX(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ int view_index = GET_ARG(0, GetInteger);
+ CHECK_VIEW_INDEX();
+ Scene::Views[view_index].X += GET_ARG(1, GetDecimal);
+ return NULL_VAL;
+}
+/***
+* View.AdjustY
+* \desc Adjusts the y-axis position of the camera for the specified view by an amount.
+* \param viewIndex (Integer): Index of the view.
+* \param y (Number): Desired Y adjust amount.
+* \ns View
+*/
+VMValue View_AdjustY(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ int view_index = GET_ARG(0, GetInteger);
+ CHECK_VIEW_INDEX();
+ Scene::Views[view_index].Y += GET_ARG(1, GetDecimal);
+ return NULL_VAL;
+}
+/***
+* View.AdjustX
+* \desc Adjusts the z-axis position of the camera for the specified view by an amount.
+* \param viewIndex (Integer): Index of the view.
+* \param z (Number): Desired Z adjust amount.
+* \ns View
+*/
+VMValue View_AdjustZ(int argCount, VMValue* args, Uint32 threadID) {
+ CHECK_ARGCOUNT(2);
+ int view_index = GET_ARG(0, GetInteger);
+ CHECK_VIEW_INDEX();
+ Scene::Views[view_index].Z += GET_ARG(1, GetDecimal);
+ return NULL_VAL;
+}
/***
* View.SetAngle
* \desc Sets the angle of the camera for the specified view.
@@ -16098,9 +16406,9 @@ VMValue View_GetActiveCount(int argCount, VMValue* args, Uint32 threadID) {
* View.CheckOnScreen
* \desc Determines whether an instance is on screen.
* \param instance (Instance): The instance to check.
- * \param rangeX (Decimal): The x range to check, or null if an update region width should be used.
- * \param rangeY (Decimal): The y range to check, or null if an update region height should be used.
- * \return Returns whether or not the instance is on screen on any view.
+ * \param rangeX (Decimal): The x range to check, or null
if the instance's update region width should be used.
+ * \param rangeY (Decimal): The y range to check, or null
if the instance's update region height should be used.
+ * \return Returns whether the instance is on screen on any view.
* \ns View
*/
VMValue View_CheckOnScreen(int argCount, VMValue* args, Uint32 threadID) {
@@ -16108,20 +16416,14 @@ VMValue View_CheckOnScreen(int argCount, VMValue* args, Uint32 threadID) {
ObjInstance* instance = GET_ARG(0, GetInstance);
Entity* self = (Entity*)instance->EntityPtr;
- // TODO: Check if GetDecimal can get null values
- float rangeX = GET_ARG(1, GetDecimal);
- float rangeY = GET_ARG(2, GetDecimal);
if (!self)
return INTEGER_VAL(false);
- if (!rangeX)
- rangeX = self->OnScreenHitboxW;
+ float rangeX = IS_NULL(args[1]) ? self->OnScreenHitboxW : GET_ARG(1, GetDecimal);
+ float rangeY = IS_NULL(args[2]) ? self->OnScreenHitboxH : GET_ARG(2, GetDecimal);
- if (!rangeY)
- rangeY = self->OnScreenHitboxH;
-
- return INTEGER_VAL(Scene::CheckPosOnScreen(self->X, self->Y, rangeX, rangeY));
+ return INTEGER_VAL(!!Scene::CheckPosOnScreen(self->X, self->Y, rangeX, rangeY));
}
/***
* View.CheckPosOnScreen
@@ -16136,7 +16438,7 @@ VMValue View_CheckOnScreen(int argCount, VMValue* args, Uint32 threadID) {
VMValue View_CheckPosOnScreen(int argCount, VMValue* args, Uint32 threadID) {
CHECK_ARGCOUNT(4);
- return INTEGER_VAL(Scene::CheckPosOnScreen(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal), GET_ARG(3, GetDecimal)));
+ return INTEGER_VAL(!!Scene::CheckPosOnScreen(GET_ARG(0, GetDecimal), GET_ARG(1, GetDecimal), GET_ARG(2, GetDecimal), GET_ARG(3, GetDecimal)));
}
// #endregion
@@ -16464,7 +16766,7 @@ void StandardLibrary::Link() {
DEF_NATIVE(Animator, GetCurrentAnimation);
DEF_NATIVE(Animator, GetCurrentFrame);
DEF_NATIVE(Animator, GetHitbox);
- DEF_NATIVE(Animator, GetPreviousAnimation);
+ DEF_NATIVE(Animator, GetPrevAnimation);
DEF_NATIVE(Animator, GetAnimationSpeed);
DEF_NATIVE(Animator, GetAnimationTimer);
DEF_NATIVE(Animator, GetDuration);
@@ -16473,14 +16775,20 @@ void StandardLibrary::Link() {
DEF_NATIVE(Animator, SetSprite);
DEF_NATIVE(Animator, SetCurrentAnimation);
DEF_NATIVE(Animator, SetCurrentFrame);
+ DEF_NATIVE(Animator, SetPrevAnimation);
DEF_NATIVE(Animator, SetAnimationSpeed);
DEF_NATIVE(Animator, SetAnimationTimer);
DEF_NATIVE(Animator, SetDuration);
+ DEF_NATIVE(Animator, SetFrameCount);
+ DEF_NATIVE(Animator, SetLoopIndex);
+ DEF_NATIVE(Animator, SetRotationStyle);
DEF_NATIVE(Animator, AdjustCurrentAnimation);
DEF_NATIVE(Animator, AdjustCurrentFrame);
DEF_NATIVE(Animator, AdjustAnimationSpeed);
DEF_NATIVE(Animator, AdjustAnimationTimer);
DEF_NATIVE(Animator, AdjustDuration);
+ DEF_NATIVE(Animator, AdjustFrameCount);
+ DEF_NATIVE(Animator, AdjustLoopIndex);
// #endregion
// #region Application
@@ -16501,10 +16809,12 @@ void StandardLibrary::Link() {
DEF_NATIVE(Application, GetGameTitleShort);
DEF_NATIVE(Application, GetGameVersion);
DEF_NATIVE(Application, GetGameDescription);
+ DEF_NATIVE(Application, GetReservedSlotIDs);
DEF_NATIVE(Application, SetGameTitle);
DEF_NATIVE(Application, SetGameTitleShort);
DEF_NATIVE(Application, SetGameVersion);
DEF_NATIVE(Application, SetGameDescription);
+ DEF_NATIVE(Application, SetReservedSlotIDs);
DEF_NATIVE(Application, SetCursorVisible);
DEF_NATIVE(Application, GetCursorVisible);
DEF_NATIVE(Application, Quit);
@@ -16570,16 +16880,6 @@ void StandardLibrary::Link() {
DEF_ENUM_CLASS(KeyBind, DevQuit);
// #endregion
- // #region Audio
- INIT_CLASS(Audio);
- DEF_NATIVE(Audio, GetMasterVolume);
- DEF_NATIVE(Audio, GetMusicVolume);
- DEF_NATIVE(Audio, GetSoundVolume);
- DEF_NATIVE(Audio, SetMasterVolume);
- DEF_NATIVE(Audio, SetMusicVolume);
- DEF_NATIVE(Audio, SetSoundVolume);
- // #endregion
-
// #region Array
INIT_CLASS(Array);
DEF_NATIVE(Array, Create);
@@ -16595,6 +16895,27 @@ void StandardLibrary::Link() {
DEF_NATIVE(Array, Sort);
// #endregion
+ // #region Audio
+ INIT_CLASS(Audio);
+ DEF_NATIVE(Audio, GetMasterVolume);
+ DEF_NATIVE(Audio, GetMusicVolume);
+ DEF_NATIVE(Audio, GetSoundVolume);
+ DEF_NATIVE(Audio, SetMasterVolume);
+ DEF_NATIVE(Audio, SetMusicVolume);
+ DEF_NATIVE(Audio, SetSoundVolume);
+ // #endregion
+
+ // #region Collision
+ INIT_CLASS(Collision);
+ DEF_NATIVE(Collision, ProcessObjectMovement);
+ DEF_NATIVE(Collision, ObjectTileCollision);
+ DEF_NATIVE(Collision, ObjectTileGrip);
+ DEF_NATIVE(Collision, CheckObjectCollisionTouch);
+ DEF_NATIVE(Collision, CheckObjectCollisionCircle);
+ DEF_NATIVE(Collision, CheckObjectCollisionBox);
+ DEF_NATIVE(Collision, CheckObjectCollisionPlatform);
+ // #endregion
+
// #region Controller
INIT_CLASS(Controller);
DEF_NATIVE(Controller, GetCount);
@@ -16878,63 +17199,63 @@ void StandardLibrary::Link() {
// #region Weekdays
/***
- * \enum Weekday_SUNDAY
+ * \enum WEEKDAY_SUNDAY
* \desc The first day of the week.
*/
- DEF_CONST_INT("Weekday_SUNDAY", (int)Weekday::SUNDAY);
+ DEF_CONST_INT("WEEKDAY_SUNDAY", (int)Weekday::SUNDAY);
/***
- * \enum Weekday_MONDAY
+ * \enum WEEKDAY_MONDAY
* \desc The second day of the week.
*/
- DEF_CONST_INT("Weekday_MONDAY", (int)Weekday::MONDAY);
+ DEF_CONST_INT("WEEKDAY_MONDAY", (int)Weekday::MONDAY);
/***
- * \enum Weekday_TUESDAY
+ * \enum WEEKDAY_TUESDAY
* \desc The third day of the week.
*/
- DEF_CONST_INT("Weekday_TUESDAY", (int)Weekday::TUESDAY);
+ DEF_CONST_INT("WEEKDAY_TUESDAY", (int)Weekday::TUESDAY);
/***
- * \enum Weekday_WEDNESDAY
+ * \enum WEEKDAY_WEDNESDAY
* \desc The fourth day of the week.
*/
- DEF_CONST_INT("Weekday_WEDNESDAY", (int)Weekday::WEDNESDAY);
+ DEF_CONST_INT("WEEKDAY_WEDNESDAY", (int)Weekday::WEDNESDAY);
/***
- * \enum Weekday_THURSDAY
+ * \enum WEEKDAY_THURSDAY
* \desc The fifth day of the week.
*/
- DEF_CONST_INT("Weekday_THURSDAY", (int)Weekday::THURSDAY);
+ DEF_CONST_INT("WEEKDAY_THURSDAY", (int)Weekday::THURSDAY);
/***
- * \enum Weekday_FRIDAY
+ * \enum WEEKDAY_FRIDAY
* \desc The sixth day of the week.
*/
- DEF_CONST_INT("Weekday_FRIDAY", (int)Weekday::FRIDAY);
+ DEF_CONST_INT("WEEKDAY_FRIDAY", (int)Weekday::FRIDAY);
/***
- * \enum Weekday_SATURDAY
+ * \enum WEEKDAY_SATURDAY
* \desc The seventh day of the week.
*/
- DEF_CONST_INT("Weekday_SATURDAY", (int)Weekday::SATURDAY);
+ DEF_CONST_INT("WEEKDAY_SATURDAY", (int)Weekday::SATURDAY);
// #endregion
// #region TimesOfDay
/***
- * \enum TimeOfDay_MORNING
+ * \enum TIMEOFDAY_MORNING
* \desc The early hours of the day (5AM to 11AM, or 05:00 to 11:00).
*/
- DEF_CONST_INT("TimeOfDay_MORNING", (int)TimeOfDay::MORNING);
+ DEF_CONST_INT("TIMEOFDAY_MORNING", (int)TimeOfDay::MORNING);
/***
- * \enum TimeOfDay_MIDDAY
+ * \enum TIMEOFDAY_MIDDAY
* \desc The middle hours of the day (12PM to 4PM, or 12:00 to 16:00).
*/
- DEF_CONST_INT("TimeOfDay_MIDDAY", (int)TimeOfDay::MIDDAY);
+ DEF_CONST_INT("TIMEOFDAY_MIDDAY", (int)TimeOfDay::MIDDAY);
/***
- * \enum TimeOfDay_EVENING
+ * \enum TIMEOFDAY_EVENING
* \desc The later hours of the day (5PM to 8PM, or 17:00 to 20:00).
*/
- DEF_CONST_INT("TimeOfDay_EVENING", (int)TimeOfDay::EVENING);
+ DEF_CONST_INT("TIMEOFDAY_EVENING", (int)TimeOfDay::EVENING);
/***
- * \enum TimeOfDay_NIGHT
+ * \enum TIMEOFDAY_NIGHT
* \desc The very late and very early hours of the day (9PM to 4AM, or 21:00 to 4:00).
*/
- DEF_CONST_INT("TimeOfDay_NIGHT", (int)TimeOfDay::NIGHT);
+ DEF_CONST_INT("TIMEOFDAY_NIGHT", (int)TimeOfDay::NIGHT);
// #endregion
// #endregion
@@ -17038,6 +17359,7 @@ void StandardLibrary::Link() {
DEF_NATIVE(Draw, Text);
DEF_NATIVE(Draw, TextWrapped);
DEF_NATIVE(Draw, TextEllipsis);
+ DEF_NATIVE(Draw, TextArray);
DEF_NATIVE(Draw, SetBlendColor);
DEF_NATIVE(Draw, SetTextureBlend);
DEF_NATIVE(Draw, SetBlendMode);
@@ -17078,6 +17400,10 @@ void StandardLibrary::Link() {
DEF_NATIVE(Draw, UseStrokeSmoothing);
DEF_NATIVE(Draw, SetClip);
DEF_NATIVE(Draw, ClearClip);
+ DEF_NATIVE(Draw, GetClipX);
+ DEF_NATIVE(Draw, GetClipY);
+ DEF_NATIVE(Draw, GetClipWidth);
+ DEF_NATIVE(Draw, GetClipHeight);
DEF_NATIVE(Draw, Save);
DEF_NATIVE(Draw, Scale);
DEF_NATIVE(Draw, Rotate);
@@ -17647,6 +17973,10 @@ void StandardLibrary::Link() {
DEF_NATIVE(Math, Max);
DEF_NATIVE(Math, Clamp);
DEF_NATIVE(Math, Sign);
+ DEF_NATIVE(Math, Uint8);
+ DEF_NATIVE(Math, Uint16);
+ DEF_NATIVE(Math, Uint32);
+ DEF_NATIVE(Math, Uint64);
DEF_NATIVE(Math, Random);
DEF_NATIVE(Math, RandomMax);
DEF_NATIVE(Math, RandomRange);
@@ -17677,12 +18007,15 @@ void StandardLibrary::Link() {
DEF_NAMESPACED_NATIVE(Math, Tan256);
DEF_NAMESPACED_NATIVE(Math, ASin256);
DEF_NAMESPACED_NATIVE(Math, ACos256);
+ DEF_NAMESPACED_NATIVE(Math, ATan2);
DEF_NAMESPACED_NATIVE(Math, RadianToInteger);
DEF_NAMESPACED_NATIVE(Math, IntegerToRadian);
DEF_NAMESPACED_NATIVE(Math, GetRandSeed);
DEF_NAMESPACED_NATIVE(Math, SetRandSeed);
DEF_NAMESPACED_NATIVE(Math, RandomInteger);
DEF_NAMESPACED_NATIVE(Math, RandomIntegerSeeded);
+ DEF_NAMESPACED_NATIVE(Math, ToFixed);
+ DEF_NAMESPACED_NATIVE(Math, FromFixed);
// #endregion
// #region Matrix
@@ -17729,14 +18062,11 @@ void StandardLibrary::Link() {
// #region Music
INIT_CLASS(Music);
DEF_NATIVE(Music, Play);
- DEF_NATIVE(Music, PlayAtTime);
DEF_NATIVE(Music, Stop);
DEF_NATIVE(Music, StopWithFadeOut);
DEF_NATIVE(Music, Pause);
DEF_NATIVE(Music, Resume);
DEF_NATIVE(Music, Clear);
- DEF_NATIVE(Music, Loop);
- DEF_NATIVE(Music, LoopAtTime);
DEF_NATIVE(Music, IsPlaying);
DEF_NATIVE(Music, GetPosition);
DEF_NATIVE(Music, Alter);
@@ -17784,6 +18114,7 @@ void StandardLibrary::Link() {
// #region Resources
INIT_CLASS(Resources);
DEF_NATIVE(Resources, LoadSprite);
+ DEF_NATIVE(Resources, LoadDynamicSprite);
DEF_NATIVE(Resources, LoadImage);
DEF_NATIVE(Resources, LoadFont);
DEF_NATIVE(Resources, LoadModel);
@@ -17807,17 +18138,8 @@ void StandardLibrary::Link() {
// #region Scene
INIT_CLASS(Scene);
- DEF_NATIVE(Scene, ProcessObjectMovement);
- DEF_NATIVE(Scene, ObjectTileCollision);
- DEF_NATIVE(Scene, ObjectTileGrip);
- DEF_NATIVE(Scene, CheckObjectCollisionTouch);
- DEF_NATIVE(Scene, CheckObjectCollisionCircle);
- DEF_NATIVE(Scene, CheckObjectCollisionBox);
- DEF_NATIVE(Scene, CheckObjectCollisionPlatform);
DEF_NATIVE(Scene, Load);
- DEF_NATIVE(Scene, LoadNoPersistency); // deprecated
DEF_NATIVE(Scene, Change);
- DEF_NATIVE(Scene, LoadPosition); // deprecated
DEF_NATIVE(Scene, LoadTileCollisions);
DEF_NATIVE(Scene, AreTileCollisionsLoaded);
DEF_NATIVE(Scene, AddTileset);
@@ -17858,15 +18180,10 @@ void StandardLibrary::Link() {
DEF_NATIVE(Scene, GetTilesetPaletteIndex);
DEF_NATIVE(Scene, GetDrawGroupCount);
DEF_NATIVE(Scene, GetDrawGroupEntityDepthSorting);
- DEF_NATIVE(Scene, GetListPos); // deprecated
DEF_NATIVE(Scene, GetCurrentFolder);
DEF_NATIVE(Scene, GetCurrentID);
DEF_NATIVE(Scene, GetCurrentResourceFolder);
- DEF_NATIVE(Scene, GetCurrentSpriteFolder); // deprecated
DEF_NATIVE(Scene, GetCurrentCategory);
- DEF_NATIVE(Scene, GetActiveCategory);
- DEF_NATIVE(Scene, GetCategoryCount); // deprecated
- DEF_NATIVE(Scene, GetStageCount); // deprecated
DEF_NATIVE(Scene, GetDebugMode);
DEF_NATIVE(Scene, GetFirstInstance);
DEF_NATIVE(Scene, GetLastInstance);
@@ -17882,14 +18199,8 @@ void StandardLibrary::Link() {
DEF_NATIVE(Scene, IsCurrentEntryValid);
DEF_NATIVE(Scene, IsUsingFolder);
DEF_NATIVE(Scene, IsUsingID);
- DEF_NATIVE(Scene, CheckValidScene); // deprecated
- DEF_NATIVE(Scene, CheckSceneFolder); // deprecated
- DEF_NATIVE(Scene, CheckSceneID); // deprecated
DEF_NATIVE(Scene, IsPaused);
- DEF_NATIVE(Scene, SetListPos); // deprecated
- DEF_NATIVE(Scene, SetActiveCategory); // deprecated
DEF_NATIVE(Scene, SetDebugMode);
- DEF_NATIVE(Scene, SetScene); // deprecated
DEF_NATIVE(Scene, SetTile);
DEF_NATIVE(Scene, SetTileCollisionSides);
DEF_NATIVE(Scene, SetPaused);
@@ -18091,6 +18402,7 @@ void StandardLibrary::Link() {
DEF_NATIVE(Sprite, GetAnimationCount);
DEF_NATIVE(Sprite, GetAnimationName);
DEF_NATIVE(Sprite, GetAnimationIndexByName);
+ DEF_NATIVE(Sprite, GetFrameExists);
DEF_NATIVE(Sprite, GetFrameLoopIndex);
DEF_NATIVE(Sprite, GetFrameCount);
DEF_NATIVE(Sprite, GetFrameDuration);
@@ -18100,7 +18412,9 @@ void StandardLibrary::Link() {
DEF_NATIVE(Sprite, GetFrameID);
DEF_NATIVE(Sprite, GetFrameOffsetX);
DEF_NATIVE(Sprite, GetFrameOffsetY);
- DEF_NATIVE(Sprite, GetFrameHitbox);
+ DEF_NATIVE(Sprite, GetHitbox);
+ DEF_NATIVE(Sprite, SetSpriteString);
+ DEF_NATIVE(Sprite, GetStringWidth);
DEF_NATIVE(Sprite, MakePalettized);
DEF_NATIVE(Sprite, MakeNonPalettized);
// #endregion
@@ -18169,8 +18483,8 @@ void StandardLibrary::Link() {
DEF_NATIVE(String, IndexOf);
DEF_NATIVE(String, Contains);
DEF_NATIVE(String, Substring);
- DEF_NATIVE(String, ToUpperCase);
- DEF_NATIVE(String, ToLowerCase);
+ DEF_NATIVE(String, ToUppercase);
+ DEF_NATIVE(String, ToLowercase);
DEF_NATIVE(String, LastIndexOf);
DEF_NATIVE(String, ParseInteger);
DEF_NATIVE(String, ParseDecimal);
@@ -18277,6 +18591,9 @@ void StandardLibrary::Link() {
DEF_NATIVE(View, SetY);
DEF_NATIVE(View, SetZ);
DEF_NATIVE(View, SetPosition);
+ DEF_NATIVE(View, AdjustX);
+ DEF_NATIVE(View, AdjustY);
+ DEF_NATIVE(View, AdjustZ);
DEF_NATIVE(View, SetAngle);
DEF_NATIVE(View, SetSize);
DEF_NATIVE(View, SetOutputX);
@@ -18467,29 +18784,33 @@ void StandardLibrary::Link() {
* \desc Entity updates within a radius. (uses UpdateRegionW)
*/
DEF_ENUM(ACTIVE_RBOUNDS);
- // #endregion
+ /***
+ * \enum ACTIVE_DISABLED
+ * \desc Entity will not even reach a point where it would check for an update.
+ */
+ DEF_ENUM(ACTIVE_DISABLED);
// #region Hitbox Sides
/***
- * \enum HitboxSide_LEFT
+ * \enum HITBOX_LEFT
* \desc Left side, slot 0 of a hitbox array.
*/
- DEF_ENUM(HitboxSide_LEFT);
+ DEF_ENUM(HITBOX_LEFT);
/***
- * \enum HitboxSide_TOP
+ * \enum HITBOX_TOP
* \desc Top side, slot 1 of a hitbox array.
*/
- DEF_ENUM(HitboxSide_TOP);
+ DEF_ENUM(HITBOX_TOP);
/***
- * \enum HitboxSide_RIGHT
+ * \enum HITBOX_RIGHT
* \desc Right side, slot 2 of a hitbox array.
*/
- DEF_ENUM(HitboxSide_RIGHT);
+ DEF_ENUM(HITBOX_RIGHT);
/***
- * \enum HitboxSide_BOTTOM
+ * \enum HITBOX_BOTTOM
* \desc Bottom side, slot 3 of a hitbox array.
*/
- DEF_ENUM(HitboxSide_BOTTOM);
+ DEF_ENUM(HITBOX_BOTTOM);
// #endregion
/***
diff --git a/source/Engine/FontFace.cpp b/source/Engine/FontFace.cpp
index 0ef905c0..1b931368 100644
--- a/source/Engine/FontFace.cpp
+++ b/source/Engine/FontFace.cpp
@@ -238,7 +238,7 @@ ISprite* FontFace::SpriteFromFont(Stream* stream, int pixelSize, char* filename)
char testFilename[4096];
snprintf(testFilename, sizeof testFilename, "Fonts/%s_%d.bmp", filenameJustName, pixelSize);
- sprite->SpritesheetsFilenames.push_back(std::string(testFilename));
+ sprite->SpritesheetFilenames.push_back(std::string(testFilename));
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(pixelData, package->Width, package->Height, 32, package->Width * 4,
0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
diff --git a/source/Engine/Includes/Standard.h b/source/Engine/Includes/Standard.h
index a1b408e8..6183472b 100644
--- a/source/Engine/Includes/Standard.h
+++ b/source/Engine/Includes/Standard.h
@@ -69,10 +69,54 @@ enum class KeyBind {
DevTileCol,
DevObjectRegions,
DevQuit,
+ DevShowHitboxes,
Max
};
+enum {
+ VIEWVAR_INVALID,
+ VIEWVAR_BOOL,
+ VIEWVAR_UINT8,
+ VIEWVAR_UINT16,
+ VIEWVAR_UINT32,
+ VIEWVAR_INT8,
+ VIEWVAR_INT16,
+ VIEWVAR_INT32,
+};
+
+enum {
+ VIEWVAR_DISPLAY_BOOL,
+ VIEWVAR_DISPLAY_UNSIGNED,
+ VIEWVAR_DISPLAY_SIGNED,
+};
+
+struct DeveloperMenu {
+ void (*State)();
+ int Selection;
+ int SubSelection;
+ int ScrollPos;
+ int SubScrollPos;
+ int Timer;
+ bool Windowed;
+ int SceneState;
+ int ListPos;
+ int WindowScale;
+ int WindowAspect;
+ bool ModsChanged;
+ int PlayerListPos;
+};
+struct ViewableVariable {
+ char Name[0x10];
+ void* Value;
+ int Type;
+ int Size;
+ int Min;
+ int Max;
+};
+
+#define VIEWABLEVARIABLE_COUNT 64
+
#define DEFAULT_TARGET_FRAMERATE 60
#define MAX_TARGET_FRAMERATE 240
diff --git a/source/Engine/InputManager.cpp b/source/Engine/InputManager.cpp
index 76dd4129..f9d162b2 100644
--- a/source/Engine/InputManager.cpp
+++ b/source/Engine/InputManager.cpp
@@ -772,6 +772,51 @@ bool InputManager::IsAnyActionReleased(unsigned playerID, unsigned device) {
return player.IsAnyInputReleased(device);
}
+bool InputManager::IsActionHeldByAny(unsigned actionID) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputHeld(actionID)) return true;
+ }
+ return false;
+}
+bool InputManager::IsActionPressedByAny(unsigned actionID) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputPressed(actionID)) return true;
+ }
+ return false;
+}
+bool InputManager::IsActionReleasedByAny(unsigned actionID) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputReleased(actionID)) return true;
+ }
+ return false;
+}
+bool InputManager::IsActionHeldByAny(unsigned actionID, unsigned device) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputHeld(actionID, device)) return true;
+ }
+
+ return false;
+}
+bool InputManager::IsActionPressedByAny(unsigned actionID, unsigned device) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputPressed(actionID, device)) return true;
+ }
+
+ return false;
+}
+bool InputManager::IsActionReleasedByAny(unsigned actionID, unsigned device) {
+ for (unsigned playerID = 0; playerID <= Players.size() - 1; playerID++) {
+ InputPlayer& player = Players[playerID];
+ if (player.IsInputReleased(actionID, device)) return true;
+ }
+
+ return false;
+}
bool InputManager::IsPlayerUsingDevice(unsigned playerID, unsigned device) {
if (playerID >= Players.size() || device >= InputDevice_MAX)
return false;
diff --git a/source/Engine/Math/Math.cpp b/source/Engine/Math/Math.cpp
index d5589328..64f8cb10 100644
--- a/source/Engine/Math/Math.cpp
+++ b/source/Engine/Math/Math.cpp
@@ -16,7 +16,7 @@ int Tan256LookupTable[0x100];
int ASin256LookupTable[0x100];
int ACos256LookupTable[0x100];
-int ArcTan256LookupTable[0x100 * 0x100];
+unsigned int ArcTan256LookupTable[0x100 * 0x100];
int randSeed = 0;
@@ -123,6 +123,15 @@ void Math::CalculateTrigAngles() {
ASin256LookupTable[i] = (int)((asinf(i / 255.0) * 128.0) / R_PI);
ACos256LookupTable[i] = (int)((acosf(i / 255.0) * 128.0) / R_PI);
}
+
+ for (int y = 0; y < 0x100; y++) {
+ unsigned int* arcTan = (unsigned int*)&ArcTan256LookupTable[y];
+
+ for (int x = 0; x < 0x100; x++) {
+ *arcTan = (int)(float)((float)atan2((float)y, x) * 40.743664f);
+ arcTan += 0x100;
+ }
+ }
}
int Math::Sin1024(int angle) {
return Sin1024LookupTable[angle & 0x3FF];
@@ -193,6 +202,33 @@ int Math::ACos256(int angle) {
return -ACos256LookupTable[-angle];
return ACos256LookupTable[angle];
}
+unsigned int Math::ArcTanLookup(int X, int Y) {
+ int x = abs(X);
+ int y = abs(Y);
+
+ if (x <= y) {
+ while (y > 0xFF) {
+ x >>= 4;
+ y >>= 4;
+ }
+ }
+ else {
+ while (x > 0xFF) {
+ x >>= 4;
+ y >>= 4;
+ }
+ }
+ if (X <= 0) {
+ if (Y <= 0)
+ return ArcTan256LookupTable[(x << 8) + y] + 0x80;
+ else
+ return 0x80 - ArcTan256LookupTable[(x << 8) + y];
+ }
+ else if (Y <= 0)
+ return -ArcTan256LookupTable[(x << 8) + y];
+ else
+ return ArcTan256LookupTable[(x << 8) + y];
+}
// help
int Math::CeilPOT(int n) {
diff --git a/source/Engine/ResourceTypes/SceneFormats/HatchSceneReader.cpp b/source/Engine/ResourceTypes/SceneFormats/HatchSceneReader.cpp
index 3a749e1e..c018901a 100644
--- a/source/Engine/ResourceTypes/SceneFormats/HatchSceneReader.cpp
+++ b/source/Engine/ResourceTypes/SceneFormats/HatchSceneReader.cpp
@@ -67,7 +67,7 @@ bool HatchSceneReader::Read(Stream* r, const char* parentFolder) {
if (verPatch >= 1)
r->ReadByte(); // ?
- // Unused (number of kits)
+ // Unused (number of kits)
r->ReadByte();
Scene::PriorityPerLayer = Scene::BasePriorityPerLayer;
@@ -202,7 +202,7 @@ void HatchSceneReader::ReadScrollData(Stream* r, SceneLayer layer) {
info->ConstantParallax = r->ReadInt16();
info->CanDeform = r->ReadByte();
- r->ReadByte(); // ?
+ r->ReadByte(); // unused value
info->Position = 0;
info->Offset = 0;
@@ -424,6 +424,7 @@ void HatchSceneReader::ReadEntities(Stream *r) {
obj->InitialX = posX;
obj->InitialY = posY;
obj->List = objectList;
+ obj->SlotID = (int)i + Application::ReservedSlotIDs;
Scene::AddStatic(objectList, obj);
// Add "filter" property
diff --git a/source/Engine/ResourceTypes/SceneFormats/RSDKSceneReader.cpp b/source/Engine/ResourceTypes/SceneFormats/RSDKSceneReader.cpp
index fbf3ba9b..7a4a0065 100644
--- a/source/Engine/ResourceTypes/SceneFormats/RSDKSceneReader.cpp
+++ b/source/Engine/ResourceTypes/SceneFormats/RSDKSceneReader.cpp
@@ -382,7 +382,7 @@ bool RSDKSceneReader::ReadObjectDefinition(Stream* r, Entity** objSlots, const i
obj->InitialX = obj->X;
obj->InitialY = obj->Y;
obj->List = objectList;
- obj->SlotID = SlotID;
+ obj->SlotID = SlotID + Application::ReservedSlotIDs;
// HACK: This is so Player ends up in the current SlotID,
// since this currently cannot be changed during runtime.
diff --git a/source/Engine/ResourceTypes/SoundFormats/OGG.cpp b/source/Engine/ResourceTypes/SoundFormats/OGG.cpp
index 4449937b..d185fdab 100644
--- a/source/Engine/ResourceTypes/SoundFormats/OGG.cpp
+++ b/source/Engine/ResourceTypes/SoundFormats/OGG.cpp
@@ -249,7 +249,7 @@ SoundFormat* OGG::Load(const char* filename) {
}
ogg = NULL;
-OGG_Load_SUCCESS:
+ OGG_Load_SUCCESS:
if (stream)
stream->Close();
return ogg;
diff --git a/source/Engine/Scene.cpp b/source/Engine/Scene.cpp
index 62da3673..26bc75d0 100644
--- a/source/Engine/Scene.cpp
+++ b/source/Engine/Scene.cpp
@@ -105,7 +105,7 @@ int Scene::Milliseconds = 0;
int Scene::Seconds = 0;
int Scene::Minutes = 0;
-int Scene::Filter = 0xFF;
+int Scene::Filter = 0;
// Scene list variables
int Scene::CurrentSceneInList;
@@ -135,7 +135,7 @@ bool DEV_NoObjectRender = false;
int ViewRenderList[MAX_SCENE_VIEWS];
-#define COLLISION_OFFSET 4.0
+#define COLLISION_OFFSET 4
// Collision variables
float Scene::CollisionTolerance = 0.0;
@@ -151,7 +151,6 @@ float Scene::HighCollisionTolerance = 14.0;
int Scene::FloorAngleTolerance = 0x20;
int Scene::WallAngleTolerance = 0x20;
int Scene::RoofAngleTolerance = 0x20;
-bool Scene::ShowHitboxes = false;
int Scene::DebugHitboxCount = 0;
DebugHitboxInfo Scene::DebugHitboxList[DEBUG_HITBOX_COUNT];
@@ -238,7 +237,7 @@ void UpdateObject(Entity* ent) {
switch (ent->Activity) {
default:
- break;
+ case ACTIVE_DISABLED: break;
case ACTIVE_NEVER:
case ACTIVE_PAUSED:
@@ -537,6 +536,7 @@ void Scene::SetInfoFromCurrentID() {
strcpy(Scene::CurrentFolder, scene.Folder);
strcpy(Scene::CurrentID, scene.ID);
strcpy(Scene::CurrentResourceFolder, scene.ResourceFolder);
+ Scene::Filter = scene.Filter;
strcpy(Scene::CurrentCategory, category.Name);
Scene::CurrentSceneInList = entryID;
@@ -612,7 +612,9 @@ void Scene::ResetPerf() {
});
}
}
+
void Scene::Update() {
+ DebugHitboxCount = 0;
// Animate tiles
Scene::RunTileAnimations();
@@ -964,7 +966,7 @@ void Scene::RenderView(int viewIndex, bool doPerf) {
Graphics::FillRectangle(entX1, entY1, entX2 - entX1, entY2 - entY1);
}
- if ((ent->ViewRenderFlag & viewRenderFlag) == 0)
+ if ((ent->ViewRenderFlag & viewRenderFlag) == 0 || !ent->Visible)
continue;
if ((ent->ViewOverrideFlag & viewRenderFlag) == 0 && (Scene::ObjectViewRenderFlag & viewRenderFlag) == 0)
continue;
@@ -1024,6 +1026,96 @@ void Scene::RenderView(int viewIndex, bool doPerf) {
}
Graphics::TextureBlend = texBlend;
}
+
+ if (Application::DevShowHitboxes) {
+ bool storeBlend = Graphics::TextureBlend;
+ Graphics::TextureBlend = true;
+ for (int i = 0; i < DebugHitboxCount; ++i) {
+ DebugHitboxInfo* info = &DebugHitboxList[i];
+ int x = info->x + info->hitbox.Left;
+ int y = info->y + info->hitbox.Top;
+ int w = abs((info->x + info->hitbox.Right) - x);
+ int h = abs((info->y + info->hitbox.Bottom) - y);
+
+ switch (info->type) {
+ case H_TYPE_TOUCH: {
+ int hex = info->collision ? 0x808000 : 0xFF0000;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ Graphics::FillRectangle(x, y, w, h);
+ break;
+ }
+
+ case H_TYPE_CIRCLE: {
+ int hex = info->collision ? 0x808000 : 0xFF0000;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ Graphics::FillCircle(info->x, info->y, info->hitbox.Left);
+ break;
+ }
+
+ case H_TYPE_BOX: {
+ int hex = 0x0000FF;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ Graphics::FillRectangle(x, y, w, h);
+
+ hex = 0xFFFF00;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ if (info->collision & 1)
+ Graphics::FillRectangle(x, y, w, 1);
+
+ if (info->collision & 8)
+ Graphics::FillRectangle(x, y + h, w, 1);
+
+ if (info->collision & 2) {
+ int sy = y;
+ int sh = h;
+
+ if (info->collision & 1) {
+ sy += 1;
+ sh -= 1;
+ }
+
+ if (info->collision * 8)
+ sh -= 1;
+
+ Graphics::FillRectangle(x, sy, 1, sh);
+ }
+
+ if (info->collision & 4) {
+ int sy = y;
+ int sh = h;
+
+ if (info->collision & 1) {
+ sy += 1;
+ sh -= 1;
+ }
+
+ if (info->collision * 8)
+ sh -= 1;
+
+ Graphics::FillRectangle(x + w, sy, 1, sh);
+ }
+ break;
+ }
+
+ case H_TYPE_PLAT: {
+ int hex = 0x00FF00;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ Graphics::FillRectangle(x, y, w, h);
+
+ hex = 0xFFFF00;
+ Graphics::SetBlendColor((hex >> 16 & 0xFF) / 255.f, (hex >> 8 & 0xFF) / 255.f, (hex & 0xFF) / 255.f, 0.375f);
+ if (info->collision & 1)
+ Graphics::FillRectangle(x, y, w, 1);
+
+ if (info->collision * 8)
+ Graphics::FillRectangle(x, y + h, w, 1);
+ break;
+ }
+ }
+ }
+ Graphics::TextureBlend = storeBlend;
+ }
+
if (viewPerf)
viewPerf->ObjectRenderTime = objectTimeTotal;
@@ -1044,6 +1136,14 @@ void Scene::RenderView(int viewIndex, bool doPerf) {
Scene::CurrentDrawGroup = -1;
PERF_END(ObjectRenderLateTime);
+ if (Application::DevMenuActivated && viewIndex == 0) {
+ // Poll for inputs, since the frame did not run
+ InputManager::Poll();
+
+ if (Application::DevMenu.State)
+ Application::DevMenu.State();
+ }
+
PERF_START(RenderFinishTime);
if (useDrawTarget && currentView->Software)
Graphics::SoftwareEnd();
@@ -1267,6 +1367,9 @@ void Scene::Restart() {
Scene::SetTileCount(Scene::BaseTileCount);
}
+ Application::DeveloperDarkFont = Application::LoadDevFont("Sprites/UI/DarkFont.bin");
+ Application::DeveloperLightFont = Application::LoadDevFont("Sprites/UI/SmallFont.bin");
+
// Restart tile animations
for (Tileset& tileset : Scene::Tilesets)
tileset.RestartAnimations();
@@ -2890,7 +2993,7 @@ bool Scene::CheckObjectCollisionTouch(Entity* thisEntity, CollisionBox* thisHitb
otherHitbox->Bottom = store;
}
- if (ShowHitboxes) {
+ if (Application::DevShowHitboxes) {
int thisHitboxID = AddDebugHitbox(H_TYPE_TOUCH, thisEntity->Direction, thisEntity, thisHitbox);
int otherHitboxID = AddDebugHitbox(H_TYPE_TOUCH, thisEntity->Direction, otherEntity, otherHitbox);
@@ -2908,7 +3011,7 @@ bool Scene::CheckObjectCollisionCircle(Entity* thisEntity, float thisRadius, Ent
float y = thisEntity->Y - otherEntity->Y;
float r = thisRadius + otherRadius;
- if (ShowHitboxes) {
+ if (Application::DevShowHitboxes) {
bool collided = x * x + y * y < r * r;
CollisionBox thisHitbox;
CollisionBox otherHitbox;
@@ -3108,7 +3211,7 @@ bool Scene::CheckObjectCollisionBox(Entity* thisEntity, CollisionBox* thisHitbox
}
}
- if (ShowHitboxes) {
+ if (Application::DevShowHitboxes) {
int thisHitboxID = AddDebugHitbox(H_TYPE_BOX, thisEntity->Direction, thisEntity, thisHitbox);
int otherHitboxID = AddDebugHitbox(H_TYPE_BOX, thisEntity->Direction, otherEntity, otherHitbox);
@@ -3208,7 +3311,7 @@ bool Scene::CheckObjectCollisionPlatform(Entity* thisEntity, CollisionBox* thisH
otherHitbox->Bottom = store;
}
- if (ShowHitboxes) {
+ if (Application::DevShowHitboxes) {
int thisHitboxID = AddDebugHitbox(H_TYPE_PLAT, thisEntity->Direction, thisEntity, thisHitbox);
int otherHitboxID = AddDebugHitbox(H_TYPE_PLAT, thisEntity->Direction, otherEntity, otherHitbox);
if (otherEntity->TileCollisions == TILECOLLISION_UP) {
@@ -3434,7 +3537,7 @@ bool Scene::ObjectTileCollision(Entity* entity, int cLayers, int cMode, int cPla
}
}
-bool Scene::ObjectTileGrip(Entity* entity, int cLayers, int cMode, int cPlane, float xOffset, float yOffset, float tolerance) {
+bool Scene::ObjectTileGrip(Entity* entity, int cLayers, int cMode, int cPlane, int xOffset, int yOffset, float tolerance) {
int layerID = 1;
bool collided = false;
int posX = xOffset + entity->X;
diff --git a/source/Engine/Scene/SceneConfig.h b/source/Engine/Scene/SceneConfig.h
index eb113fd4..6169eb16 100644
--- a/source/Engine/Scene/SceneConfig.h
+++ b/source/Engine/Scene/SceneConfig.h
@@ -19,6 +19,7 @@ struct SceneListEntry {
char* ID = nullptr;
char* ResourceFolder = nullptr;
char* Filetype = nullptr;
+ int Filter = 0;
size_t ParentCategoryID;
size_t CategoryPos;
diff --git a/source/Engine/Scene/SceneInfo.cpp b/source/Engine/Scene/SceneInfo.cpp
index c4f8c2c5..bace22e6 100644
--- a/source/Engine/Scene/SceneInfo.cpp
+++ b/source/Engine/Scene/SceneInfo.cpp
@@ -116,7 +116,7 @@ string SceneInfo::GetParentPath(int entryID) {
snprintf(filePath, sizeof(filePath), "Stages/%s/", entry.Folder);
}
else {
- if (entry.Folder == nullptr)
+ if (!strcmp(entry.Folder, "Unknown"))
snprintf(filePath, sizeof(filePath), "Scenes/");
else
snprintf(filePath, sizeof(filePath), "Scenes/%s/", entry.Folder);
@@ -134,6 +134,7 @@ string SceneInfo::GetFilename(int entryID) {
char filePath[4096];
if (!strcmp(scene.Filetype, "bin")) {
+ snprintf(filePath, sizeof(filePath), "Scene%s.%s", id, scene.Filetype);
if (scene.Folder == nullptr) {
if (scene.Filetype == nullptr)
snprintf(filePath, sizeof(filePath), "Scene%s", id);
@@ -144,7 +145,7 @@ string SceneInfo::GetFilename(int entryID) {
snprintf(filePath, sizeof(filePath), "Scene%s.%s", id, scene.Filetype);
}
else {
- if (scene.Folder == nullptr) {
+ if (!strcmp(scene.Folder, "Unknown")) {
if (scene.Filetype == nullptr)
snprintf(filePath, sizeof(filePath), "%s", id);
else
@@ -239,6 +240,8 @@ bool SceneInfo::Load(XMLNode* node) {
// Folder
if (stgElement->attributes.Exists("folder"))
entry.Folder = XMLParser::TokenToString(stgElement->attributes.Get("folder"));
+ else
+ entry.Folder = StringUtils::Duplicate("Unknown");
// ID
if (stgElement->attributes.Exists("id"))
@@ -252,16 +255,20 @@ bool SceneInfo::Load(XMLNode* node) {
// Resource folder
if (stgElement->attributes.Exists("resourceFolder"))
entry.ResourceFolder = XMLParser::TokenToString(stgElement->attributes.Get("resourceFolder"));
+ else
+ entry.ResourceFolder = StringUtils::Duplicate(entry.Folder);
- // Sprite folder (backwards compat)
- if (stgElement->attributes.Exists("spriteFolder"))
- entry.ResourceFolder = XMLParser::TokenToString(stgElement->attributes.Get("spriteFolder"));
+ // Filter
+ if (stgElement->attributes.Exists("filter"))
+ entry.Filter = (int)XMLParser::TokenToNumber(stgElement->attributes.Get("filter"));
+ else
+ entry.Filter = 0;
// Filetype
- if (stgElement->attributes.Exists("fileExtension"))
- entry.Filetype = XMLParser::TokenToString(stgElement->attributes.Get("fileExtension"));
- else if (stgElement->attributes.Exists("type"))
+ if (stgElement->attributes.Exists("type"))
entry.Filetype = XMLParser::TokenToString(stgElement->attributes.Get("type"));
+ else
+ entry.Name = StringUtils::Duplicate("tmx");
entry.ParentCategoryID = Categories.size();
entry.CategoryPos = category.Count;
@@ -272,7 +279,6 @@ bool SceneInfo::Load(XMLNode* node) {
entry.Properties->Put("folder", entry.Folder);
entry.Properties->Put("id", entry.ID);
entry.Properties->Put("resourceFolder", entry.ResourceFolder);
- entry.Properties->Put("spriteFolder", entry.ResourceFolder); // backwards compat
entry.Properties->Put("fileExtension", entry.Filetype);
FillAttributesHashMap(&stgElement->attributes, entry.Properties);
diff --git a/source/Engine/Types/Entity.cpp b/source/Engine/Types/Entity.cpp
index ccf8e2d5..7420f7ad 100644
--- a/source/Engine/Types/Entity.cpp
+++ b/source/Engine/Types/Entity.cpp
@@ -68,6 +68,7 @@ void Entity::ResetAnimation(int animation, int frame) {
if (frame < 0 || (size_t)frame >= sprite->Animations[animation].Frames.size())
return;
+ PrevAnimation = CurrentAnimation;
CurrentAnimation = animation;
AnimationTimer = 0.0;
CurrentFrame = frame;
@@ -75,6 +76,7 @@ void Entity::ResetAnimation(int animation, int frame) {
AnimationFrameDuration = sprite->Animations[CurrentAnimation].Frames[CurrentFrame].Duration;
AnimationSpeed = sprite->Animations[CurrentAnimation].AnimationSpeed;
AnimationLoopIndex = sprite->Animations[CurrentAnimation].FrameToLoop;
+ RotationStyle = sprite->Animations[CurrentAnimation].Flags;
}
bool Entity::BasicCollideWithObject(Entity* other) {
float otherHitboxW = other->Hitbox.Width;
@@ -352,6 +354,7 @@ void Entity::CopyFields(Entity* other) {
COPY(OnScreenRegionBottom);
COPY(ViewRenderFlag);
COPY(ViewOverrideFlag);
+ COPY(Visible);
COPY(RenderRegionW);
COPY(RenderRegionH);
COPY(RenderRegionTop);
@@ -381,11 +384,13 @@ void Entity::CopyFields(Entity* other) {
COPY(CurrentFrameCount);
COPY(AnimationSpeedMult);
COPY(AnimationSpeedAdd);
+ COPY(PrevAnimation);
COPY(AutoAnimate);
COPY(AnimationSpeed);
COPY(AnimationTimer);
COPY(AnimationFrameDuration);
COPY(AnimationLoopIndex);
+ COPY(RotationStyle);
COPY(Hitbox);
COPY(FlipFlag);
diff --git a/source/Engine/Types/EntityTypes.h b/source/Engine/Types/EntityTypes.h
index 74efeb26..9b75b016 100644
--- a/source/Engine/Types/EntityTypes.h
+++ b/source/Engine/Types/EntityTypes.h
@@ -10,10 +10,10 @@ enum {
};
enum {
- HitboxSide_LEFT = 0,
- HitboxSide_TOP = 1,
- HitboxSide_RIGHT = 2,
- HitboxSide_BOTTOM = 3
+ HITBOX_LEFT = 0,
+ HITBOX_TOP = 1,
+ HITBOX_RIGHT = 2,
+ HITBOX_BOTTOM = 3
};
enum {
@@ -24,7 +24,8 @@ enum {
ACTIVE_BOUNDS = 4, // Updates only when the object is within bounds
ACTIVE_XBOUNDS = 5, // Updates within an x bound (not accounting for y bound)
ACTIVE_YBOUNDS = 6, // Updates within a y bound (not accounting for x bound)
- ACTIVE_RBOUNDS = 7 // Updates within a radius (UpdateRegionW)
+ ACTIVE_RBOUNDS = 7, // Updates within a radius (UpdateRegionW)
+ ACTIVE_DISABLED = 0xFF, // For stopping entities from even checking for an update in some cases
};
namespace CollideSide {