diff --git a/.gitignore b/.gitignore
index 8e5f8f11d1..8dd550c2a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,7 @@ GtkModule.so
# StepMania Specific
*.smzip
ver.cpp
+gitversion.h
Cache/
Save/
Logs/
@@ -126,6 +127,7 @@ Utils/temp*
Program/StepMania*.lib
# Unknown File Types
+*.dia
.deps
*.rej
tests/*.err
diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt
index 49c0335c11..3da66d0f3f 100644
--- a/Docs/Changelog_sm5.txt
+++ b/Docs/Changelog_sm5.txt
@@ -4,6 +4,62 @@ The StepMania 5 Changelog covers all post-sm-ssc changes. For a list of changes
from StepMania 4 alpha 5 to sm-ssc v1.2.5, see Changelog_sm-ssc.txt.
________________________________________________________________________________
+2015/01/20
+----------
+* [ScreenSelect] ChoiceNames can be a lua command that is evaluated to get a
+ list of the gamecommands. The main use of this is to get rid of the huge
+ list of metrics that ScreenSelectStyle requires. A single lua function
+ instead of a metric for every style for every game type. [kyzentun]
+* [ScreenSelectMaster] IconChoicePosFunction metric added. This metric is
+ optional, if it's set, it must be set to a function that returns a table
+ of positions. Each position is a table of the form "{x, y, z}", where x,
+ y, and z are numbers and any that is not a number defaults to 0.
+ The function is passed the number of choices for the screen.
+ IconChoiceOnCommand and IconChoiceOffCommand metrics added so each choice
+ doesn't require its own On/OffCommand pair. These are also optional, but
+ if they are set, they will override the individual commands if they exist.
+ (If "IconChoiceCactusOnCommand" and "IconChoiceOnCommand" both exist,
+ "IconChoiceOnCommand" will be used.) [kyzentun]
+ Example:
+ # in metrics.ini
+ IconChoicePosFunction=choice_positions
+ -- In a file in Scripts/
+ function choice_positions(count)
+ local ret= {}
+ for i= 1, ret do ret[i]= {i*24, i*48} end
+ return ret
+ end
+
+2015/01/16
+----------
+* [ScreenSelectMusic] HardCommentMeter metric added. Sets the meter that
+ will trigger the "select music comment hard" announcer sound. [kyzentun]
+
+2015/01/12
+----------
+* [ScreenOptions] GetNumRows function added. [kyzentun]
+
+2015/01/09
+----------
+* [Sprite] SetStateProperties function added. [kyzentun]
+
+2015/01/06
+----------
+* [ActorMultiVertex] GetSpline and SetVertsFromSplines functions added.
+ [kyzentun]
+* [NoteColumnRenderer] Functions for fetching the spline handlers for the
+ column added. [kyzentun]
+* [NCSplineHandler] New class for setting various parameters of a spline used
+ by a NoteColumnRenderer and containing the spline. [kyzentun]
+* [CubicSplineN] New class that provides spline functionality. [kyzentun]
+
+2014/12/26
+----------
+* [NoteField] Columns turned into actors that can be fetched with
+ get_column_actors. [kyzentun]
+ Tiny boost in fps when there is a large number of notes on screen.
+* [NoteColumnRenderer] New class for controlling one column. [kyzentun]
+
2014/12/20
----------
* [Preferences] AllowMultipleHighScoreWithSameName, ComboContinuesBetweenSongs
@@ -29,6 +85,34 @@ ________________________________________________________________________________
* [Player] "ComboBreakOnImmediateHoldLetGo" theme metric added. [sillybear]
* [PlayerState] ApplyPreferredOptionsToOtherLevels function added. [kyzentun]
+2014/12/07
+----------
+* [Game] GetSeparateStyles function added. Use this to detect whether a game
+ allows the players to play different styles. [kyzentun] (used by kickbox)
+* [GameManager] Lua Scripts/ folders are now reloaded when the Game mode is
+ changed. [kyzentun]
+* [GameState] CanSafelyEnterGameplay function added. [kyzentun]
+ In kickbox game mode, players can have different styles set, pass a
+ PlayerNumber when using SetCurrentStyle or GetCurrentStyle.
+* [kickbox] New game mode with 4 styles. [kyzentun]
+* [ScreenGameplay] Notefield positioning is handled a bit differently now.
+ See comments in _fallback/metrics.ini above the [ScreenGameplay]
+ MarginFunction metric. Basically, you can define a lua function that
+ returns the space you want at the edges and in the center instead of
+ setting position metrics. Do NOT use Style:GetWidth to calculate the
+ margins your function returns.
+ ScreenGameplay now handles zooming the notefield to fit in the space
+ instead of using the NeedsZoomOutWith2Players flag in the style.
+ If the notefield doesn't fit in the space between the margins, and there is
+ only one player, the player will be centered even if the Center1Player pref
+ is false. [kyzentun]
+* [Style] NeedsZoomOutWith2Players decapitated. Always returns false now.
+ GetWidth added. [kyzentun]
+* [techno] Techno game mode no longer has special column width for versus.
+ Techno was the only game mode that used the NeedsZoomOutWith2Players flag,
+ and the zoom factor it applied was 0.6, and the special versus column width
+ was 0.6*normal, so this should make no difference. [kyzentun]
+
2014/12/03
----------
* [command line arg] --game command line arg added for setting the game type
@@ -82,6 +166,10 @@ ________________________________________________________________________________
----------
* [RollingNumbers] Cropping and color during tweens fixed. [kyzentun]
+2014/10/27
+----------
+* [Changelog] Vospi read the release notes.
+
2014/10/23
----------
* [Global] approach, multiapproach, lerp, and lerp_color lua functions added. [kyzentun]
diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml
index 53d2d79fd4..beeca21152 100644
--- a/Docs/Luadoc/Lua.xml
+++ b/Docs/Luadoc/Lua.xml
@@ -272,6 +272,7 @@
+
@@ -301,6 +302,7 @@
+
@@ -494,6 +496,7 @@
+
@@ -504,6 +507,7 @@
+
@@ -676,6 +680,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -702,6 +731,7 @@
+
@@ -750,6 +780,7 @@
+
@@ -965,15 +996,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -1396,6 +1444,7 @@
+
@@ -1581,6 +1630,7 @@
+
@@ -1660,6 +1710,7 @@
+
@@ -2212,6 +2263,11 @@
+
+
+
+
+
diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml
index fa8011dbe4..23eaa72ec0 100644
--- a/Docs/Luadoc/LuaDocumentation.xml
+++ b/Docs/Luadoc/LuaDocumentation.xml
@@ -112,6 +112,9 @@ save yourself some time, copy this for undocumented things:
Tries to connect to the server at sAddress.
+
+ Creates a CubicSplineN for you to use. Make sure you destroy the CubicSplineN when you're done with it, or you will have a memory leak.
+
[02 Colors.lua]
@@ -831,6 +834,12 @@ save yourself some time, copy this for undocumented things:
Returns the Actor's parent, or nil if it doesn't have one.
+
+ Returns the Actor's fake parent, or nil if it doesn't have one.
+
+
+ Sets the Actor's fake parent to p, or clears it if p is nil.
+
Returns the Actor's visibility.
@@ -1515,6 +1524,22 @@ save yourself some time, copy this for undocumented things:
Sets multiple vertices at once. The elements of vertices should themselves be tables, of the form provided to SetVertex. If vertices is the first argument it will start from vertex 1. If an integer is provided before vertices it will start from that vertex. It will add vertices as necessary.
Example: self:SetVertices( { { { x1, y1, z1 } , { r1,g1,b1,a1 } , { tcx1,tcy1 } }; { { x2, y2, z2 } , { r2,g2,b2,a2 } , { tcx2,tcy2 } } } )
+
+ Sets all the drawn verts of the ActorMultiVertex by evaluating the splines.
+ ("all the drawn verts" means all the verts between FirstToDraw and NumToDraw, the verts that are set to draw in the current tween state.)
+ The parts of the ActorMultiVertex are evenly spaced along the spline in terms of t value.
+ The exact behavior depends on the draw mode.
+ DrawMode_Quads uses all 4 splines, one for each corner.
+ DrawMode_QuadStrip and DrawMode_Strip use 2 splines, one for each edge of the strip.
+ DrawMode_Fan uses one spline, for the edge verts of the fan. The first vert is not touched because it is the center.
+ DrawMode_Triangles uses 3 splines, one for each corner.
+ DrawMode_SymmetricQuadStrip uses 3 splines, one on each edge and one in the center.
+ DrawMode_LineStrip uses 1 spline.
+
+
+ Returns the requested spline. Spline indices range from 1 to 4.
+ ActorMultiVertex splines are not inside the tween state, and will not change the verts until you call SetVertsFromSplines.
+
Sets the number of vertices.
@@ -2056,6 +2081,92 @@ save yourself some time, copy this for undocumented things:
Returns the SHA-1 hash for s.
+
+
+ All functions in this class have camel case equivalents, use whichever naming style you prefer.
+ This spline implementation is a cubic spline.
+ A spline is a line calculated from a small set of points with mathematical smooting applied.
+ Splines can have any number of dimensions, but splines owned by actors (the ones inside NCSplineHandler and ActorMultiVertex) always have 3 dimensions.
+
+
+ Solves the spline, setting the coefficients.
+
+
+ Evaluates the spline at the given t value, returning a table of the results for each dimension of the spline.
+ t can range from 0 to the value returned by get_max_t().
+ A normal spline will return its starting point for any t value less than 0 and its end point for any t value greater than the max.
+ A looped spline adjust the t value to be within the its range by adding or subtracting the max t as needed. (so if the max t is 4 and you evaluate at 5, it will return the same as if you evaluated at 1.)
+
+
+ Evaluates the derivative at t.
+
+
+ Evaluates the second derivative at t.
+
+
+ Evaluates the third derivative at t.
+ Second and third derivative functions exist because they're possible, not because they're expected to be useful. The fourth derivative would be 0 because the equation for evaluating the spline is "a + (b*t) + (c*t^2) + (d*t^3)".
+
+
+ Sets point i of the spline to the position specified by the table p.
+
+
+ Sets the coefficients of the spline at point i.
+ Each table must contain a value for each dimension of the spline.
+ Solving the spline normally should cover all normal usage, this is for people that want a spline with an abnormal behavior, so if you set the coefficients directly, expect to end up with an unsmooth shape.
+
+
+ Returns a table containing the tables of coefficients for the point i.
+
+
+ Sets the spatial extent of dimension d of the spline to e.
+ The spatial extent exists to handle numbers that exist in a finite looped space, instead of the flat infinite space.
+ To put it more concretely, spatial extent exists to allow a spline to control rotation with wrapping behavior at 0.0 and 2pi, instead of suddenly jerking from 2pi to 0.0.
+
+
+ Returns the spatial extent of dimension d of the spline.
+
+
+ Returns the max t value the spline extends to. For a normal spline, this will be size()-1. For a looped spline, this will be size().
+
+
+ Sets the number of points in the spline. You must set the number of points before trying to set the position of any point.
+
+
+ Returns the number of points in the spline.
+
+
+ Sets the number of dimensions the spline has.
+ Splines that are owned by actors (the ones inside ActorMultiVertex and NCSplineHandler) cannot have their number of dimensions changed because the actors require them to have 3 dimensions.
+
+
+ Returns the number of dimensions the spline has.
+
+
+ Returns true of the spline has zero points, or false if it has more than zero points.
+
+
+ Sets whether the spline is looped. A looped spline is one where the end point is connected to the start point.
+
+
+ Returns whether the spline is looped.
+
+
+ Sets whether the spline is polygonal. If the spline is polygonal, then it will have straight lines between the points instead of curves.
+
+
+ Returns whether the spline is polygonal.
+
+
+ Sets whether the spline is dirty. A dirty spline is one that has been changed in some way that affects its shape. When solve() is called, the spline will only be solved if it is dirty. The dirty flag is automatically set by everything, so you should never have to call this function.
+
+
+ Returns whether the spline is currently dirty.
+
+
+ Destroys the spline, freeing the memory allocated for it. This can only be called on splines created with create_spline().
+
+
Sets the DifficultyIcon's state from the difficulty passed in.
@@ -2131,6 +2242,9 @@ save yourself some time, copy this for undocumented things:
Returns the name of the game such as "dance" or "pump".
+
+ Returns whether this game allows the players to have separate styles.
+
@@ -2270,6 +2384,16 @@ save yourself some time, copy this for undocumented things:
The second argument is optional. Apply the GameCommand represented by sCommand
for pn, if given. See .
+
+ Checks various things to determine whether the game will crash when gameplay starts. Returns false and a string if gameplay cannot be entered safely.
+ Might not work in all cases, but will catch things like a player not having
+ steps set or no current song or style. Mainly exists for people with a custom ScreenSelectMusic replacement.
+ Example:
+ local can, reason= GAMESTATE:CanSafelyEnterGameplay()
+ if not can then
+ lua.ReportScriptError("Cannot safely enter gameplay: " .. tostring(reason))
+ end
+
Removes any stage modifiers that are illegal for course play.
@@ -2944,41 +3068,102 @@ save yourself some time, copy this for undocumented things:
Returns a table of noteskin names for the current gametype.
+
+
+ All functions in this class have camel case equivalents, use whichever naming style you prefer.
+ The spline handler holds info on how the spline is used by the engine.
+ Each get/set pair of functions in this class is for a different aspect of the spline's behavior.
+
+
+ Returns the spline for this handler.
+
+
+ Returns the beats per t value of the spline. If the beats_per_t is 4, then a note must be on screen for 4 beats to traverse from one point on the spline to the next.
+
+
+ Sets the beats per t value for the spline.
+
+
+ Returns the t value that receptors are evaluated at.
+
+
+ the t value that receptors are evaluated at.
+
+
+ Returns the mode the spline is set to.
+ "NoteColumnSplineMode_Disabled" means the spline will not affect the notes or receptors at all.
+ "NoteColumnSplineMode_Offset" means the spline will added to the effects from the mods.
+ "NoteColumnSplineMode_Position" means only the spline affect the notes and mods will be ignored. (but only mods that affect the same aspect of the note as the spline will be disabled. So a rotation spline won't disable Mini or Tiny, but a zoom spline will, and a zoom spline won't disable Dizzy, Twirl, or Roll, but a rotation spline will.)
+
+
+ Sets the current spline mode for this handler.
+
+
+ Returns whether the current song beat is subtracted from a note's beat when calculating the t value to use on the spline.
+
+
+ Sets whether the current song beat is subtracted from a note's beat when calculating the t value to use on the spline.
+
+
+
+
+ All functions in this class have camel case equivalents, use whichever naming style you prefer.
+ Position, rotation, and zoom each have separate spline handlers to allow them to have separate independent behavior.
+ It is important to note that the spline handlers are inside the tween state, so whenever you start a new tween on the actor, you need to refetch the spline handlers.
+
+
+ Returns the handler for the position spline.
+
+
+ Returns the handler for the rotation spline.
+ The rotation applied by the rotation spline is in radians.
+ For convenience, the spatial extent of the rotation spline defaults to 2pi.
+
+
+ Returns the handler for the zoom spline.
+
+
-
+
+ All functions in this class have camel case equivalents, use whichever naming style you prefer.
+
+
Makes the NoteField act as if a hold note was hit in the column, with the given score and bright setting.
- The callback for DidHoldNote will not be called.
+ The callback for did_hold_note will not be called.
-
+
Makes the NoteField act as if a tap note was hit in the column, with the given score and bright setting.
- The callback for DidTapNote will not be called.
+ The callback for did_tap_note will not be called.
-
+
+ Returns a table of the actors for the columns. This means that each column is an actor, so you can move it around or animate it like an actor. See the NoteColumnRenderer class for a list of special functions for the column's actor.
+
+
Same as SetDidTapNoteCallback, but for hold notes. Uses HoldNoteScore instead of TapNoteScore.
-
+
Sets the function that the NoteField will call whenever a tap note is hit.
The callback function is passed the column, the TapNoteScore, and whether the explosion will be bright.
The callback function can return changed values for the NoteField to use instead of the ones that were passed.
Pass nil instead of a function to clear the callback.
-
+
Makes the NoteField act as if a press occurred in the column.
- The callback for SetPressed will not be called.
+ The callback for set_pressed will not be called.
-
+
Sets the function that the NoteField will call whenever a press occurs.
The callback function is passed the column for the press.
The callback function can return changed values for the NoteField to use instead of the ones that were passed.
Pass nil instead of a function to clear the callback.
-
+
Sets the function that the NoteField will call whenever a step occurs.
The callback function is passed the column and the TapNoteScore for the step.
The callback function can return changed values for the NoteField to use instead of the ones that were passed.
Pass nil instead of a function to clear the callback.
-
+
Makes the NoteField act as if a step occurred in the column with the given score.
The callback for Step will not be called.
@@ -4013,6 +4198,9 @@ save yourself some time, copy this for undocumented things:
Returns the current row that player pn is on. (Was previously GetCurrentRow.)
+
+ Returns the number of rows on the screen.
+
Returns the specified OptionRow.
@@ -4511,6 +4699,21 @@ save yourself some time, copy this for undocumented things:
Sets the number of seconds into the animation to fSeconds.
+
+ Sets the properties of the states of the sprite. The properties table is identical to the "Frames" table that can be put in the sprite when calling Def.Sprite.
+ Example:
+ {{Frame= 0, Delay= .016, {0, 0}, {.25, .25}},
+ {Frame= 1, Delay= .016, {0, 0}, {.25, .25}},
+ {Frame= 2, Delay= .016, {0, 0}, {.25, .25}},
+ {Frame= 3, Delay= .016, {0, 0}, {.25, .25}},
+ }
+ Frame is optional, defaulting to 0.
+ Delay is optional, defaulting to 0.
+ The two tables are optional upper left and lower right corners of the fraction of the frame to use. The example makes the sprite only use the upper left corner of each frame.
+ Simpler example:
+ {{Frame= 0, Delay= .016}, {Frame= 1, Delay= .016}, {Frame= 2, Delay= .016}, {Frame= 3, Delay= .016}}
+ This example makes the sprite use the whole of each frame.
+
Set the texture to texture.
@@ -4719,11 +4922,14 @@ save yourself some time, copy this for undocumented things:
Returns the draw order of the column.
+
+ Returns the width of the notefield for the given player with this style.
+
Returns true if this style locks the difficulty for both players.
- Returns true if the Style needs to be zoomed out with two players.
+ Deprecated. Always returns false.
diff --git a/Makefile.am b/Makefile.am
index 271f0346ed..408a11fa6f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,12 +3,6 @@ AUTOMAKE_OPTIONS = 1.7 foreign
SUBDIRS = bundle src
ACLOCAL_AMFLAGS = -I autoconf/m4
-## Black magic (read: sed) for getting the product ID as defined in code, not by the autotools.
-## Quotes are making vim's highlighting of this even worse, so just escape everything,
-## including the escapes. Make it lowercase to match ArchHooks::MountInitialFileSystems().
-## Replace space with - so package build tools won't choke on the installation directory.
-productID := $(shell sed -nr /define\\s+PRODUCT_ID_BARE/\{s/.*define\\s+PRODUCT_ID_BARE\\s+\(.+\)/\\1/\;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ\ /abcdefghijklmnopqrstuvwxyz-/\;p\;q\} $(srcdir)/src/ProductInfo.h)
-
installFiles = src/stepmania
if HAVE_GTK
installFiles += src/GtkModule.so
@@ -27,14 +21,14 @@ dist-hook: SMData
cp -r -t "$(distdir)" $(installFiles)
install-exec-hook:
- mkdir -p "$(DESTDIR)$(prefix)/$(productID)"
- $(INSTALL) $(installFiles) "$(DESTDIR)$(prefix)/$(productID)"
+ mkdir -p "$(DESTDIR)$(prefix)/stepmania-$(VERSION)"
+ $(INSTALL) $(installFiles) "$(DESTDIR)$(prefix)/stepmania-$(VERSION)"
install-data-local:
- mkdir -p "$(DESTDIR)$(prefix)/$(productID)/Songs"
- cp -r -t "$(DESTDIR)$(prefix)/$(productID)" $(installData)
+ mkdir -p "$(DESTDIR)$(prefix)/stepmania-$(VERSION)/Songs"
+ cp -r -t "$(DESTDIR)$(prefix)/stepmania-$(VERSION)" $(installData)
uninstall-hook:
- rm -f "$(DESTDIR)$(prefix)/$(productID)/stepmania"
- rm -f "$(DESTDIR)$(prefix)/$(productID)/GtkModule.so"
+ rm -f "$(DESTDIR)$(prefix)/stepmania-$(VERSION)/stepmania"
+ rm -f "$(DESTDIR)$(prefix)/stepmania-$(VERSION)/GtkModule.so"
# todo: properly remove data
diff --git a/NoteSkins/beat/default/_Tap Lead-in Receptor.lua b/NoteSkins/beat/default/_Tap Lead-in Receptor.lua
index c9e14e9bc3..223d184854 100644
--- a/NoteSkins/beat/default/_Tap Lead-in Receptor.lua
+++ b/NoteSkins/beat/default/_Tap Lead-in Receptor.lua
@@ -11,7 +11,7 @@ return Def.ActorFrame {
LoadActor( "_Tap Receptor", NOTESKIN:LoadActor(Var "Button", "Go Receptor") ) .. {
Frame0000=0;
- Delay0000=0;
+ Delay0000=1;
InitCommand=cmd(playcommand, "Set");
GameplayLeadInChangedMessageCommand=cmd(playcommand,"Set");
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Explosion.lua b/NoteSkins/kickbox/default/AnyLeftFist Explosion.lua
new file mode 100644
index 0000000000..091a5748b8
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Explosion.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFist Explosion") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..f8d38093cc
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..ee11ba1f7e
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..6c13aab879
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold Head Active.lua b/NoteSkins/kickbox/default/AnyLeftFist Hold Head Active.lua
new file mode 100644
index 0000000000..6860d80e16
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/AnyLeftFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..1f7b9e7ae8
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Receptor.lua b/NoteSkins/kickbox/default/AnyLeftFist Receptor.lua
new file mode 100644
index 0000000000..02c21a986a
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Receptor.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFist Receptor") .. {
+ InitCommand=cmd(zoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..a72adc84c0
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..1c1c24ac56
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..d37a6f7922
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..97a53f1339
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll Head Active.lua b/NoteSkins/kickbox/default/AnyLeftFist Roll Head Active.lua
new file mode 100644
index 0000000000..3c7a58b5c4
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/AnyLeftFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..f78715a86b
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFist Tap Lift.lua b/NoteSkins/kickbox/default/AnyLeftFist Tap Lift.lua
new file mode 100644
index 0000000000..69436f46e1
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist Tap Lift.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFist Tap Lift") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFist tap note.lua b/NoteSkins/kickbox/default/AnyLeftFist tap note.lua
new file mode 100644
index 0000000000..2b684618ac
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFist tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFist tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Explosion.lua b/NoteSkins/kickbox/default/AnyLeftFoot Explosion.lua
new file mode 100644
index 0000000000..d5a4101423
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Explosion.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFoot Explosion") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..c6d425f298
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..14494e82c4
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..66949fc088
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..f88bc86cfa
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Active.lua b/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Active.lua
new file mode 100644
index 0000000000..c1d9bb879a
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Inactive.lua b/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Inactive.lua
new file mode 100644
index 0000000000..6e40567184
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Receptor.lua b/NoteSkins/kickbox/default/AnyLeftFoot Receptor.lua
new file mode 100644
index 0000000000..9ea311f4bb
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Receptor.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFoot Receptor") .. {
+ InitCommand=cmd(zoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..b001771a70
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..c6fb7b60f7
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..268a56e789
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..b361a4a42d
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyLeftFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Active.lua b/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Active.lua
new file mode 100644
index 0000000000..f5254f25ce
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..048ce0d90b
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot Tap Lift.lua b/NoteSkins/kickbox/default/AnyLeftFoot Tap Lift.lua
new file mode 100644
index 0000000000..2adf78c28b
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot Tap Lift.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFoot Tap Lift") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyLeftFoot tap note.lua b/NoteSkins/kickbox/default/AnyLeftFoot tap note.lua
new file mode 100644
index 0000000000..c3cb6b2b34
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyLeftFoot tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("AnyRightFoot tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFist Explosion.lua b/NoteSkins/kickbox/default/AnyRightFist Explosion.lua
new file mode 100644
index 0000000000..1c4a2c1c90
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Explosion.lua
@@ -0,0 +1,29 @@
+local t = Def.ActorFrame {
+ LoadActor( "_AnyRightFist Hold Explosion" ) .. {
+ HoldingOnCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "HoldingOnCommand");
+ HoldingOffCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "HoldingOffCommand");
+ InitCommand=cmd(playcommand,"HoldingOff";finishtweening);
+ };
+ LoadActor( "_AnyRightFist Roll Explosion" ) .. {
+ RollOnCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "RollOnCommand");
+ RollOffCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "RollOffCommand");
+ InitCommand=cmd(playcommand,"RollOff";finishtweening);
+ };
+ LoadActor( "_AnyRightFist Tap Explosion Dim" ) .. {
+ InitCommand=cmd(diffusealpha,0);
+ W5Command=NOTESKIN:GetMetricA("GhostArrowDim", "W5Command");
+ W4Command=NOTESKIN:GetMetricA("GhostArrowDim", "W4Command");
+ W3Command=NOTESKIN:GetMetricA("GhostArrowDim", "W3Command");
+ W2Command=NOTESKIN:GetMetricA("GhostArrowDim", "W2Command");
+ W1Command=NOTESKIN:GetMetricA("GhostArrowDim", "W1Command");
+ HeldCommand=NOTESKIN:GetMetricA("GhostArrowDim", "HeldCommand");
+ JudgmentCommand=cmd(finishtweening);
+ BrightCommand=cmd(visible,false);
+ DimCommand=cmd(visible,true);
+ };
+ LoadActor( "AnyRightFist HitMine Explosion" ) .. {
+ InitCommand=cmd(blend,"BlendMode_Add";diffusealpha,0);
+ HitMineCommand=NOTESKIN:GetMetricA("GhostArrowBright", "HitMineCommand");
+ };
+}
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFist HitMine Explosion.redir b/NoteSkins/kickbox/default/AnyRightFist HitMine Explosion.redir
new file mode 100644
index 0000000000..42966e5ea3
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist HitMine Explosion.redir
@@ -0,0 +1 @@
+Fallback HitMine Explosion
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..f8d38093cc
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..9f7bef91a6
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..48b7f39d65
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold Head Active.redir b/NoteSkins/kickbox/default/AnyRightFist Hold Head Active.redir
new file mode 100644
index 0000000000..4b94e621e2
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Hold Head Active.redir
@@ -0,0 +1 @@
+AnyRightFist tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/AnyRightFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..1da889831b
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFist Receptor.lua b/NoteSkins/kickbox/default/AnyRightFist Receptor.lua
new file mode 100644
index 0000000000..b02bcff4bf
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Receptor.lua
@@ -0,0 +1,19 @@
+local t = Def.ActorFrame {
+ Def.Sprite {
+ Texture="_AnyRightFist receptor underlay";
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand');
+ NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
+ };
+ Def.Sprite {
+ Texture="_AnyRightFist receptor frame";
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand');
+ PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand');
+ LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand');
+ NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
+ };
+};
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..6357ddf13e
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..7018cca581
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..0fc3e30726
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..7e2ba13d7a
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll Head Active.redir b/NoteSkins/kickbox/default/AnyRightFist Roll Head Active.redir
new file mode 100644
index 0000000000..4b94e621e2
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Roll Head Active.redir
@@ -0,0 +1 @@
+AnyRightFist tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/AnyRightFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..1da889831b
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFist','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFist Tap Lift.lua b/NoteSkins/kickbox/default/AnyRightFist Tap Lift.lua
new file mode 100644
index 0000000000..df2bf160a9
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFist Tap Lift.lua
@@ -0,0 +1,10 @@
+local t = Def.ActorFrame {
+ InitCommand=cmd(pulse;effectclock,'beat';effectmagnitude,1,1.2,1);
+ Def.Sprite {
+ Texture=NOTESKIN:GetPath( '_AnyRightFist', 'tap lift' );
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=cmd(diffuseramp;effectclock,'beat';effectcolor1,color("1,1,1,1");effectcolor2,color("1,1,1,0.5"));
+ };
+};
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFist tap Note (doubleres).png b/NoteSkins/kickbox/default/AnyRightFist tap Note (doubleres).png
new file mode 100644
index 0000000000..c973d2d61a
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFist tap Note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Explosion.lua b/NoteSkins/kickbox/default/AnyRightFoot Explosion.lua
new file mode 100644
index 0000000000..d6626a9543
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Explosion.lua
@@ -0,0 +1,29 @@
+local t = Def.ActorFrame {
+ LoadActor( "_AnyRightFoot Hold Explosion" ) .. {
+ HoldingOnCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "HoldingOnCommand");
+ HoldingOffCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "HoldingOffCommand");
+ InitCommand=cmd(playcommand,"HoldingOff";finishtweening);
+ };
+ LoadActor( "_AnyRightFoot Roll Explosion" ) .. {
+ RollOnCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "RollOnCommand");
+ RollOffCommand=NOTESKIN:GetMetricA("HoldGhostArrow", "RollOffCommand");
+ InitCommand=cmd(playcommand,"RollOff";finishtweening);
+ };
+ LoadActor( "_AnyRightFoot Tap Explosion Dim" ) .. {
+ InitCommand=cmd(diffusealpha,0);
+ W5Command=NOTESKIN:GetMetricA("GhostArrowDim", "W5Command");
+ W4Command=NOTESKIN:GetMetricA("GhostArrowDim", "W4Command");
+ W3Command=NOTESKIN:GetMetricA("GhostArrowDim", "W3Command");
+ W2Command=NOTESKIN:GetMetricA("GhostArrowDim", "W2Command");
+ W1Command=NOTESKIN:GetMetricA("GhostArrowDim", "W1Command");
+ HeldCommand=NOTESKIN:GetMetricA("GhostArrowDim", "HeldCommand");
+ JudgmentCommand=cmd(finishtweening);
+ BrightCommand=cmd(visible,false);
+ DimCommand=cmd(visible,true);
+ };
+ LoadActor( "AnyRightFoot HitMine Explosion" ) .. {
+ InitCommand=cmd(blend,"BlendMode_Add";diffusealpha,0);
+ HitMineCommand=NOTESKIN:GetMetricA("GhostArrowBright", "HitMineCommand");
+ };
+}
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFoot HitMine Explosion.redir b/NoteSkins/kickbox/default/AnyRightFoot HitMine Explosion.redir
new file mode 100644
index 0000000000..42966e5ea3
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot HitMine Explosion.redir
@@ -0,0 +1 @@
+Fallback HitMine Explosion
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..2edfc9edcc
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..e0ce58df3f
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..ff1c84141d
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..59a3396f10
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold Head Active.redir b/NoteSkins/kickbox/default/AnyRightFoot Hold Head Active.redir
new file mode 100644
index 0000000000..7b3cc70420
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Hold Head Active.redir
@@ -0,0 +1 @@
+AnyRightFoot tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Hold Head Inactive.redir b/NoteSkins/kickbox/default/AnyRightFoot Hold Head Inactive.redir
new file mode 100644
index 0000000000..7b3cc70420
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Hold Head Inactive.redir
@@ -0,0 +1 @@
+AnyRightFoot tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Receptor.lua b/NoteSkins/kickbox/default/AnyRightFoot Receptor.lua
new file mode 100644
index 0000000000..e22d359884
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Receptor.lua
@@ -0,0 +1,19 @@
+local t = Def.ActorFrame {
+ Def.Sprite {
+ Texture="_AnyRightFoot receptor underlay";
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'InitCommand');
+ NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
+ };
+ Def.Sprite {
+ Texture="_AnyRightFoot receptor frame";
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'InitCommand');
+ PressCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'PressCommand');
+ LiftCommand=NOTESKIN:GetMetricA('ReceptorOverlay', 'LiftCommand');
+ NoneCommand=NOTESKIN:GetMetricA('ReceptorArrow', 'NoneCommand');
+ };
+};
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..442a9af6d5
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..62d6829cd3
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..1f9213caca
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..4c215082a6
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll Head Active.redir b/NoteSkins/kickbox/default/AnyRightFoot Roll Head Active.redir
new file mode 100644
index 0000000000..7b3cc70420
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Roll Head Active.redir
@@ -0,0 +1 @@
+AnyRightFoot tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/AnyRightFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..ef274ab9f3
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('AnyRightFoot','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/AnyRightFoot Tap Lift.lua b/NoteSkins/kickbox/default/AnyRightFoot Tap Lift.lua
new file mode 100644
index 0000000000..af6974d334
--- /dev/null
+++ b/NoteSkins/kickbox/default/AnyRightFoot Tap Lift.lua
@@ -0,0 +1,10 @@
+local t = Def.ActorFrame {
+ InitCommand=cmd(pulse;effectclock,'beat';effectmagnitude,1,1.2,1);
+ Def.Sprite {
+ Texture=NOTESKIN:GetPath( '_AnyRightFoot', 'tap lift' );
+ Frame0000=0;
+ Delay0000=1;
+ InitCommand=cmd(diffuseramp;effectclock,'beat';effectcolor1,color("1,1,1,1");effectcolor2,color("1,1,1,0.5"));
+ };
+};
+return t;
diff --git a/NoteSkins/kickbox/default/AnyRightFoot tap note (doubleres).png b/NoteSkins/kickbox/default/AnyRightFoot tap note (doubleres).png
new file mode 100644
index 0000000000..6cc60d40d3
Binary files /dev/null and b/NoteSkins/kickbox/default/AnyRightFoot tap note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..db01049885
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..3972aee3e0
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..6c13aab879
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold Head Active.lua b/NoteSkins/kickbox/default/DownLeftFist Hold Head Active.lua
new file mode 100644
index 0000000000..546daeca87
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFist Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/DownLeftFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..58b947ade3
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..80a697aaa0
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..1c1c24ac56
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..5fbd74b81e
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..97a53f1339
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll Head Active.lua b/NoteSkins/kickbox/default/DownLeftFist Roll Head Active.lua
new file mode 100644
index 0000000000..ffc18da6b2
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFist Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/DownLeftFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..dd9179c9d5
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFist tap note.lua b/NoteSkins/kickbox/default/DownLeftFist tap note.lua
new file mode 100644
index 0000000000..0da60031f1
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFist tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("DownRightFist tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..df3691df3e
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..14494e82c4
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..46e135de94
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..f88bc86cfa
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold Head Active.lua b/NoteSkins/kickbox/default/DownLeftFoot Hold Head Active.lua
new file mode 100644
index 0000000000..c54e0cb61e
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFoot Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Hold Head Inactive.lua b/NoteSkins/kickbox/default/DownLeftFoot Hold Head Inactive.lua
new file mode 100644
index 0000000000..fc85fe577e
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFoot Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..0ab2d0ae31
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..c6fb7b60f7
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..0360109f8a
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..b361a4a42d
Binary files /dev/null and b/NoteSkins/kickbox/default/DownLeftFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll Head Active.lua b/NoteSkins/kickbox/default/DownLeftFoot Roll Head Active.lua
new file mode 100644
index 0000000000..9ced3372f7
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFoot Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/DownLeftFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..baab4167b6
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownLeftFoot tap note.lua b/NoteSkins/kickbox/default/DownLeftFoot tap note.lua
new file mode 100644
index 0000000000..7befd52196
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownLeftFoot tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("DownRightfoot tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..db01049885
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..7ce3ea8918
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..48b7f39d65
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold Head Active.redir b/NoteSkins/kickbox/default/DownRightFist Hold Head Active.redir
new file mode 100644
index 0000000000..f75ddace0e
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFist Hold Head Active.redir
@@ -0,0 +1 @@
+DownRightFist Tap Note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/DownRightFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..9421a85389
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Hold Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..7d8e6e4eb0
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..7018cca581
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..b49d74be20
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..7e2ba13d7a
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll Head Active.redir b/NoteSkins/kickbox/default/DownRightFist Roll Head Active.redir
new file mode 100644
index 0000000000..f75ddace0e
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFist Roll Head Active.redir
@@ -0,0 +1 @@
+DownRightFist Tap Note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/DownRightFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..e932453fbf
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFist','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFist Tap Note (doubleres).png b/NoteSkins/kickbox/default/DownRightFist Tap Note (doubleres).png
new file mode 100644
index 0000000000..4910ff6934
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFist Tap Note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..e33823e061
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..e0ce58df3f
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..0ea451be10
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..59a3396f10
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold Head Active.redir b/NoteSkins/kickbox/default/DownRightFoot Hold Head Active.redir
new file mode 100644
index 0000000000..cfce5762a3
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFoot Hold Head Active.redir
@@ -0,0 +1 @@
+DownRightFoot Tap Note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFoot Hold Head Inactive.lua b/NoteSkins/kickbox/default/DownRightFoot Hold Head Inactive.lua
new file mode 100644
index 0000000000..3da4bc208f
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFoot Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Hold Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..4a5053ae40
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..62d6829cd3
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..452664de64
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..4c215082a6
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll Head Active.redir b/NoteSkins/kickbox/default/DownRightFoot Roll Head Active.redir
new file mode 100644
index 0000000000..cfce5762a3
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFoot Roll Head Active.redir
@@ -0,0 +1 @@
+DownRightFoot Tap Note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/DownRightFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..1a8e3831e1
--- /dev/null
+++ b/NoteSkins/kickbox/default/DownRightFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('DownRightFoot','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/DownRightFoot tap note (doubleres).png b/NoteSkins/kickbox/default/DownRightFoot tap note (doubleres).png
new file mode 100644
index 0000000000..03175feae6
Binary files /dev/null and b/NoteSkins/kickbox/default/DownRightFoot tap note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/Fallback HitMine Explosion.png b/NoteSkins/kickbox/default/Fallback HitMine Explosion.png
new file mode 100644
index 0000000000..34c26623b2
Binary files /dev/null and b/NoteSkins/kickbox/default/Fallback HitMine Explosion.png differ
diff --git a/NoteSkins/kickbox/default/NoteSkin.lua b/NoteSkins/kickbox/default/NoteSkin.lua
new file mode 100644
index 0000000000..36d13e337a
--- /dev/null
+++ b/NoteSkins/kickbox/default/NoteSkin.lua
@@ -0,0 +1,77 @@
+local ret = ... or {};
+
+local pn = Var "Player"
+
+local OldRedir = ret.Redir;
+ret.Redir = function(sButton, sElement)
+ -- Replace all receptors with genericized ones
+ if string.find(sButton,"RightFoot") and string.find(sElement, "Receptor") then
+ return "AnyRightFoot", "Receptor"
+ end
+ if string.find(sButton,"LeftFoot") and string.find(sElement, "Receptor") then
+ return "AnyLeftFoot", "Receptor"
+ end
+ if string.find(sButton,"RightFist") and string.find(sElement, "Receptor") then
+ return "AnyRightFist", "Receptor"
+ end
+ if string.find(sButton,"LeftFist") and string.find(sElement, "Receptor") then
+ return "AnyLeftFist", "Receptor"
+ end
+
+ -- Replace all Lifts with genericized ones
+ if string.find(sButton,"RightFoot") and string.find(sElement, "Tap Lift") then
+ return "AnyRightFoot", "Tap Lift"
+ end
+ if string.find(sButton,"LeftFoot") and string.find(sElement, "Tap Lift") then
+ return "AnyLeftFoot", "Tap Lift"
+ end
+ if string.find(sButton,"RightFist") and string.find(sElement, "Tap Lift") then
+ return "AnyRightFist", "Tap Lift"
+ end
+ if string.find(sButton,"LeftFist") and string.find(sElement, "Tap Lift") then
+ return "AnyLeftFist", "Tap Lift"
+ end
+
+ -- Replace all explosions with AnyRight* or AnyLeft*. Is there a better way to do this?
+ if string.find(sButton,"RightFoot") and string.find(sElement, "Explosion") then
+ return "AnyRightFoot", "Explosion"
+ end
+ if string.find(sButton,"LeftFoot") and string.find(sElement, "Explosion") then
+ return "AnyLeftFoot", "Explosion"
+ end
+ if string.find(sButton,"RightFist") and string.find(sElement, "Explosion") then
+ return "AnyRightFist", "Explosion"
+ end
+ if string.find(sButton,"LeftFist") and string.find(sElement, "Explosion") then
+ return "AnyLeftFist", "Explosion"
+ end
+
+ if (GAMESTATE:GetCurrentStyle(pn):GetStepsType() == "StepsType_Kickbox_Human") then
+ if string.find(sButton, "LeftFoot") then
+ sButton = "AnyLeftFoot"
+ end
+ if string.find(sButton, "RightFoot") then
+ sButton = "AnyRightFoot"
+ end
+ --
+ if string.find(sButton, "LeftFist") then
+ sButton = "AnyLeftFist"
+ end
+ if string.find(sButton, "RightFist") then
+ sButton = "AnyRightFist"
+ end
+ end
+
+ if (GAMESTATE:GetCurrentStyle(pn):GetStepsType() == "StepsType_Kickbox_Insect") then
+ if string.find(sButton, "LeftFoot") then
+ sButton = "AnyLeftFoot"
+ end
+ if string.find(sButton, "RightFoot") then
+ sButton = "AnyRightFoot"
+ end
+ end
+ -- return OldRedir(sButton, sElement);
+ return sButton, sElement
+end
+
+return ret
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..45cc937c45
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..cedaa8d60c
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..6c13aab879
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold Head Active.lua b/NoteSkins/kickbox/default/UpLeftFist Hold Head Active.lua
new file mode 100644
index 0000000000..fc9b4d75fb
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFist Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/UpLeftFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..843b85ee6f
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..2b1ba16fdc
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..1c1c24ac56
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..29c99b9ceb
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..97a53f1339
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll Head Active.lua b/NoteSkins/kickbox/default/UpLeftFist Roll Head Active.lua
new file mode 100644
index 0000000000..130785536e
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFist Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/UpLeftFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..5a4f6740e1
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFist tap note.lua b/NoteSkins/kickbox/default/UpLeftFist tap note.lua
new file mode 100644
index 0000000000..19354e02ef
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFist tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("UpRightFist tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..04df3ae21f
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..14494e82c4
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..ad57537f3b
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..f88bc86cfa
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold Head Active.lua b/NoteSkins/kickbox/default/UpLeftFoot Hold Head Active.lua
new file mode 100644
index 0000000000..61146282f1
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFoot Hold Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Hold Head Inactive.lua b/NoteSkins/kickbox/default/UpLeftFoot Hold Head Inactive.lua
new file mode 100644
index 0000000000..c5a6822b3a
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFoot Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Hold Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..73aa60a8bb
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..c6fb7b60f7
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..34196a23cc
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..b361a4a42d
Binary files /dev/null and b/NoteSkins/kickbox/default/UpLeftFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll Head Active.lua b/NoteSkins/kickbox/default/UpLeftFoot Roll Head Active.lua
new file mode 100644
index 0000000000..dde3793531
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFoot Roll Head Active.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1);
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/UpLeftFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..e6cf005901
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Roll Head Active');
+ InitCommand=cmd(basezoomx,-1;diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpLeftFoot tap note.lua b/NoteSkins/kickbox/default/UpLeftFoot tap note.lua
new file mode 100644
index 0000000000..b5a0ee700a
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpLeftFoot tap note.lua
@@ -0,0 +1,5 @@
+local t = LoadActor("UpRightFoot tap Note") .. {
+ InitCommand=cmd(basezoomx,-1);
+}
+
+return t;
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..45cc937c45
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..27a16473b5
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..ca71791d1f
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..48b7f39d65
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold Head Active.redir b/NoteSkins/kickbox/default/UpRightFist Hold Head Active.redir
new file mode 100644
index 0000000000..dd2524567c
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFist Hold Head Active.redir
@@ -0,0 +1 @@
+UpRightFist tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFist Hold Head Inactive.lua b/NoteSkins/kickbox/default/UpRightFist Hold Head Inactive.lua
new file mode 100644
index 0000000000..6ee636e5ae
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFist Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Hold Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..6340cd7e48
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..7018cca581
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..b4347051f9
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..7e2ba13d7a
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll Head Active.redir b/NoteSkins/kickbox/default/UpRightFist Roll Head Active.redir
new file mode 100644
index 0000000000..dd2524567c
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFist Roll Head Active.redir
@@ -0,0 +1 @@
+UpRightFist tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFist Roll Head Inactive.lua b/NoteSkins/kickbox/default/UpRightFist Roll Head Inactive.lua
new file mode 100644
index 0000000000..8224fb70dc
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFist Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFist','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFist Tap Note (doubleres).png b/NoteSkins/kickbox/default/UpRightFist Tap Note (doubleres).png
new file mode 100644
index 0000000000..691ed89bd8
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFist Tap Note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold Body Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Hold Body Active (doubleres).png
new file mode 100644
index 0000000000..2d23d94c70
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Hold Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Hold Body Inactive (doubleres).png
new file mode 100644
index 0000000000..e0ce58df3f
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Hold Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..5dc1b546fa
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..59a3396f10
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Hold BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold Head Active.redir b/NoteSkins/kickbox/default/UpRightFoot Hold Head Active.redir
new file mode 100644
index 0000000000..173d519124
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFoot Hold Head Active.redir
@@ -0,0 +1 @@
+UpRightFoot tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFoot Hold Head Inactive.lua b/NoteSkins/kickbox/default/UpRightFoot Hold Head Inactive.lua
new file mode 100644
index 0000000000..f6ece95dcf
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFoot Hold Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Hold Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll Body Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Roll Body Active (doubleres).png
new file mode 100644
index 0000000000..11558f0025
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Roll Body Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll Body Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Roll Body Inactive (doubleres).png
new file mode 100644
index 0000000000..62d6829cd3
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Roll Body Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Active (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Active (doubleres).png
new file mode 100644
index 0000000000..dd7770fd1b
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Active (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Inactive (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Inactive (doubleres).png
new file mode 100644
index 0000000000..4c215082a6
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot Roll BottomCap Inactive (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll Head Active.redir b/NoteSkins/kickbox/default/UpRightFoot Roll Head Active.redir
new file mode 100644
index 0000000000..173d519124
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFoot Roll Head Active.redir
@@ -0,0 +1 @@
+UpRightFoot tap note
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFoot Roll Head Inactive.lua b/NoteSkins/kickbox/default/UpRightFoot Roll Head Inactive.lua
new file mode 100644
index 0000000000..8c1e64442a
--- /dev/null
+++ b/NoteSkins/kickbox/default/UpRightFoot Roll Head Inactive.lua
@@ -0,0 +1,4 @@
+return Def.Sprite {
+ Texture=NOTESKIN:GetPath('UpRightFoot','Roll Head Active');
+ InitCommand=cmd(diffuse,color("0.5,0.5,0.5,1"));
+};
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/UpRightFoot tap note (doubleres).png b/NoteSkins/kickbox/default/UpRightFoot tap note (doubleres).png
new file mode 100644
index 0000000000..3b7b2103c6
Binary files /dev/null and b/NoteSkins/kickbox/default/UpRightFoot tap note (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFist Hold Explosion.redir b/NoteSkins/kickbox/default/_AnyRightFist Hold Explosion.redir
new file mode 100644
index 0000000000..da0637f259
--- /dev/null
+++ b/NoteSkins/kickbox/default/_AnyRightFist Hold Explosion.redir
@@ -0,0 +1 @@
+_AnyRightFist Tap explosion dim
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/_AnyRightFist Roll Explosion.redir b/NoteSkins/kickbox/default/_AnyRightFist Roll Explosion.redir
new file mode 100644
index 0000000000..da0637f259
--- /dev/null
+++ b/NoteSkins/kickbox/default/_AnyRightFist Roll Explosion.redir
@@ -0,0 +1 @@
+_AnyRightFist Tap explosion dim
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/_AnyRightFist Tap Explosion Dim (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFist Tap Explosion Dim (doubleres).png
new file mode 100644
index 0000000000..7072601112
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFist Tap Explosion Dim (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFist Tap Lift (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFist Tap Lift (doubleres).png
new file mode 100644
index 0000000000..8bf71144a5
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFist Tap Lift (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFist receptor frame (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFist receptor frame (doubleres).png
new file mode 100644
index 0000000000..8e5c28506e
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFist receptor frame (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFist receptor underlay (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFist receptor underlay (doubleres).png
new file mode 100644
index 0000000000..067dbeebff
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFist receptor underlay (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot Hold Explosion.redir b/NoteSkins/kickbox/default/_AnyRightFoot Hold Explosion.redir
new file mode 100644
index 0000000000..92395ce391
--- /dev/null
+++ b/NoteSkins/kickbox/default/_AnyRightFoot Hold Explosion.redir
@@ -0,0 +1 @@
+_AnyRightFoot Tap explosion dim
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot Roll Explosion.redir b/NoteSkins/kickbox/default/_AnyRightFoot Roll Explosion.redir
new file mode 100644
index 0000000000..92395ce391
--- /dev/null
+++ b/NoteSkins/kickbox/default/_AnyRightFoot Roll Explosion.redir
@@ -0,0 +1 @@
+_AnyRightFoot Tap explosion dim
\ No newline at end of file
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot Tap Explosion Dim (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFoot Tap Explosion Dim (doubleres).png
new file mode 100644
index 0000000000..ac8b969e48
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFoot Tap Explosion Dim (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot Tap Lift (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFoot Tap Lift (doubleres).png
new file mode 100644
index 0000000000..25f1ef1f6b
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFoot Tap Lift (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot receptor frame (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFoot receptor frame (doubleres).png
new file mode 100644
index 0000000000..8c930452e1
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFoot receptor frame (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/_AnyRightFoot receptor underlay (doubleres).png b/NoteSkins/kickbox/default/_AnyRightFoot receptor underlay (doubleres).png
new file mode 100644
index 0000000000..539556d338
Binary files /dev/null and b/NoteSkins/kickbox/default/_AnyRightFoot receptor underlay (doubleres).png differ
diff --git a/NoteSkins/kickbox/default/metrics.ini b/NoteSkins/kickbox/default/metrics.ini
new file mode 100644
index 0000000000..a9376cb03c
--- /dev/null
+++ b/NoteSkins/kickbox/default/metrics.ini
@@ -0,0 +1,57 @@
+[Global]
+FallbackNoteSkin=common
+
+[NoteDisplay]
+StartDrawingHoldBodyOffsetFromHead=-12
+StopDrawingHoldBodyOffsetFromTail=-32 // top of tail
+
+FlipHeadAndTailWhenReverse=0
+FlipHoldBodyWhenReverse=0
+
+[GhostArrowDim]
+HitMineCommand=blend,"BlendMode_Add";diffuse,1,1,1,1;zoom,1;rotationz,0;linear,0.3;rotationz,90;linear,0.3;rotationz,180;diffusealpha,0
+W5Command=diffuse,0.8,0.0,0.6,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W4Command=diffuse,0.3,0.8,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W3Command=diffuse,0.0,1.0,0.4,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W2Command=diffuse,1.0,1.0,0.3,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W1Command=diffuse,1.0,1.0,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+HeldCommand=diffuse,1.0,1.0,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+
+[GhostArrowBright]
+NoneCommand=
+HitMineCommand=blend,"BlendMode_Add";diffuse,1,1,1,1;zoom,1;rotationz,0;linear,0.3;rotationz,90;linear,0.3;rotationz,180;diffusealpha,0
+AvoidMineCommand=
+MissCommand=
+W5Command=diffuse,0.8,0.0,0.6,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W4Command=diffuse,0.3,0.8,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W3Command=diffuse,0.0,1.0,0.4,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W2Command=diffuse,1.0,1.0,0.3,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+W1Command=diffuse,1.0,1.0,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+HeldCommand=diffuse,1.0,1.0,1.0,1;zoom,1;linear,0.06;zoom,1.1;linear,0.06;diffusealpha,0
+
+[HoldGhostArrow]
+HoldingOnCommand=visible,true;pulse;effectmagnitude,1,1.1,1;effectclock,'beat';effectperiod,0.125
+HoldingOffCommand=visible,false;stopeffect;
+RollOnCommand=visible,true;pulse;effectmagnitude,1,1.1,1;effectclock,'beat';effectperiod,0.125
+RollOffCommand=visible,false;stopeffect;
+
+[ReceptorArrow]
+InitCommand=effectclock,'beat';glowramp;effectcolor1,color("1,1,1,0");effectcolor2,color("1,1,1,0.5");
+# By default, always step. Individual game skins can override this.
+NoneCommand=
+HitMineCommand=
+AvoidMineCommand=
+MissCommand=
+W5Command=
+W4Command=
+W3Command=
+W2Command=
+W1Command=
+PressCommand=stoptweening;bounceend,0.05;zoom,0.75
+LiftCommand=stoptweening;decelerate,0.1;zoom,1
+
+[ReceptorOverlay]
+InitCommand=
+PressCommand=stoptweening;bounceend,0.05;zoom,0.75
+LiftCommand=stoptweening;decelerate,0.1;zoom,1
+NoneCommand=
\ No newline at end of file
diff --git a/NoteSkins/pump/default/UpLeft Receptor.lua b/NoteSkins/pump/default/UpLeft Receptor.lua
index 6b36007723..ebe2fbc70c 100644
--- a/NoteSkins/pump/default/UpLeft Receptor.lua
+++ b/NoteSkins/pump/default/UpLeft Receptor.lua
@@ -37,14 +37,14 @@ return Def.ActorFrame {
NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{
Name="Base";
Frames={
- { Frame = 0, Delay = 0 }
+ { Frame = 0 }
};
PressCommand=cmd(finishtweening;linear,0.05;zoom,0.9;linear,0.1;zoom,1);
};
NOTESKIN:LoadActor(Var "Button", "Ready Receptor")..{
Name="Glow";
Frames= {
- { Frame = 1, Delay = 0 }
+ { Frame = 1 }
};
InitCommand=cmd(blend,'BlendMode_Add');
PressCommand=cmd(finishtweening;linear,0.05;zoom,0.9;linear,0.1;zoom,1);
diff --git a/Themes/_Installer/Languages/pl.ini b/Themes/_Installer/Languages/pl.ini
new file mode 100644
index 0000000000..868173bc5c
--- /dev/null
+++ b/Themes/_Installer/Languages/pl.ini
@@ -0,0 +1,36 @@
+[Installer Sections]
+TEXT_IO_CHECK_FOR_UPDATES=SprawdŸ aktualizacje
+TEXT_IO_RUN=${PRODUCT_DISPLAY}
+TEXT_IO_RUN_WITHOUT_SSE2=${PRODUCT_DISPLAY} (non-SSE2)
+TEXT_IO_OPEN_PROGRAM_FOLDER=Otwórz ${PRODUCT_ID} Folder Programu
+TEXT_IO_OPEN_SETTINGS_FOLDER=Otwórz ${PRODUCT_ID} Ustawienia Programu
+TEXT_IO_MANUAL=${PRODUCT_ID} Obs³uga
+TEXT_IO_TOOLS=${PRODUCT_ID} Narzêdzia
+TEXT_IO_WEB_SITE=${PRODUCT_ID} Strona WWW
+TEXT_IO_UNINSTALL=Usuñ ${PRODUCT_DISPLAY}
+TEXT_IO_VIEW_STATISTICS=Poka¿ Statystyki
+TEXT_IO_REMOVE_ONLY=${PRODUCT_DISPLAY} (tylko usuñ)
+TEXT_IO_SMZIP_PACKAGE=Paczka SMZIP
+TEXT_IO_FATAL_ERROR_COPYING_PCK =B³¹d krytyczny kopiowania pliku pck.
+TEXT_IO_FATAL_ERROR_INSTALL=B³¹d krytyczny podczas instalacji.
+TEXT_IO_LAUNCH_THE_GAME=Uruchom StepMania
+TEXT_IO_TEXTURE_FONT_GENERATOR=Generator Tekstur Czcionek
+
+[Installer Functions]
+TEXT_IO_TITLE=${PRODUCT_DISPLAY}
+TEXT_IO_SUBTITLE=
+TEXT_IO_INSTALL=Instaluj
+TEXT_IO_PLAY=Graj
+TEXT_IO_REINSTALL=Zainstaluj ponownie
+
+[Leave Autorun]
+TEXT_IO_COULD_NOT_EXECUTE=Nie mo¿na uruchomiæ $INSTDIR\Program\${PRODUCT_FAMILY}.exe
+
+[PreInstall]
+TEXT_IO_UNINSTALL_PREVIOUS=Wczeœniejsza wersja ${PRODUCT_ID} musi zostaæ usuniêta przed kontynuowaniem.\nCzy chcesz kontynuowaæ?
+TEXT_IO_DIRECTX_VISIT_MICROSOFT=Zdecydowanie zaleca siê najnowsz¹ wersjê DirectX (8.1 lub wy¿szej).\nCzy chcesz odwiedziæ stronê Microsoftu teraz?
+TEXT_IO_UNINSTALL_FAILED_INSTALL_ANYWAY=Dezinstalacja nie powiod³a siê. Zainstalowaæ mimo wszystko?
+TEXT_IO_INSTALL_DIRECTX=Wymagana jest najnowsza wersja DirectX (8.1 lub wy¿szej).\nCzy chcesz zainstalowaæ teraz DirectX 8.1?
+TEXT_IO_FULL_INSTALL_NOT_FOUND=${PRODUCT_ID} nie wydaje siê byæ zainstalowany.\nCzy chcesz kontynuowaæ?
+[Uninstall]
+TEXT_IO_FATAL_ERROR_UNINSTALL=B³¹d krytyczny podczas odinstalowywania.
\ No newline at end of file
diff --git a/Themes/_fallback/BGAnimations/ScreenSystemLayer error.lua b/Themes/_fallback/BGAnimations/ScreenSystemLayer error.lua
index 6772731280..b30fc7429f 100644
--- a/Themes/_fallback/BGAnimations/ScreenSystemLayer error.lua
+++ b/Themes/_fallback/BGAnimations/ScreenSystemLayer error.lua
@@ -3,6 +3,10 @@
-- If you include this file in your theme, you will not benefit from any improvements in error reporting.
-- If you want to adjust how long errors stay on screen for, call the "SetErrorMessageTime" function. (see usage notes in comments above that function)
+if PREFSMAN:GetPreference("IgnoredDialogs") ~= "" then
+ return Def.Actor{}
+end
+
local line_height= 12 -- A good line height for Common Normal at .5 zoom.
local min_message_time= {show= 1, hide= .03125}
diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini
index 73c6291100..10505b2a40 100644
--- a/Themes/_fallback/Languages/en.ini
+++ b/Themes/_fallback/Languages/en.ini
@@ -100,6 +100,10 @@ Practice=Practice
[EditMenu]
Blank=Blank
+No Group Selected.=No Group Selected.
+No StepsType selected.=No StepsType selected.
+No Steps selected.=No Steps selected.
+No valid action.=No valid action.
[EditMenuRow]
Action=Action
@@ -170,6 +174,14 @@ Right Blue=Right Blue
Right Green=Right Green
Right Yellow=Right Yellow
Right White=Right White
+DownLeftFoot=Down Left Foot
+UpLeftFoot=Up Left Foot
+UpLeftFist=Up Left Fist
+DownLeftFist=Down Left Fist
+DownRightFoot=Down Right Foot
+UpRightFoot=Up Right Foot
+UpRightFist=Up Right Fist
+DownRightFist=Down Right Fist
[GameCommand]
Could not launch web browser.=Could not launch web browser.
@@ -1533,6 +1545,7 @@ ExplanationSteps=Choose the steps you want to edit.\nSelect "New Edit" to create
ExplanationStepsType=Choose the type of steps that you want to edit.
ExplanationSourceSteps=Choose the steps you want to fill into a new edit.
ExplanationSourceStepsType=Choose the type of steps that you want to use fill into a new edit.\nChoose "Blank" to create a new edit with no initial steps.
+One of the selected things is invalid. Pick something valid instead.=One of the selected things is invalid. Pick something valid instead.
Profile name cannot be blank.=Profile name can not be blank.
The name you chose conflicts with another profile. Please use a different name.=The name you chose conflicts with another profile. Please use a different name.
These steps are produced by autogen. You do not need to delete them.=These steps are produced by autogen. You do not need to delete them.
@@ -2050,6 +2063,10 @@ Pnm_Nine=9 Button
Guitar_Five=5 Frets
Karaoke=Karaoke
Lights_Cabinet=Lights
+Kickbox_Human=Human
+Kickbox_Quadarm=Quadarm
+Kickbox_Insect=Insect
+Kickbox_Arachnid=Arachnid
[StyleType]
StyleType_OnePlayerOneSide=1 Player
@@ -2623,6 +2640,10 @@ Pump_Halfdouble=Half-Double
Pump_Couple=Couple
Pump_Routine=Routine
Kb7_Single=KB7
+Kickbox_Human=Human
+Kickbox_Quadarm=Quadarm
+Kickbox_Insect=Insect
+Kickbox_Arachnid=Arachnid
Ez2_Single=Single
Ez2_Double=Double
Ez2_Real=Real
@@ -2658,6 +2679,10 @@ Pump_Halfdouble=Half-Double
Pump_Couple=Couple
Pump_Routine=Routine
Kb7_Single=KB7
+Kickbox_Human=Human
+Kickbox_Quadarm=Quadarm
+Kickbox_Insect=Insect
+Kickbox_Arachnid=Arachnid
Ez2_Single=Single
Ez2_Double=Double
Ez2_Real=Real
diff --git a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc
index 0a5b0994d9..ac2e351e4a 100644
--- a/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc
+++ b/Themes/_fallback/Other/ScreenGameplaySyncMachine music.ssc
@@ -1305,4 +1305,85 @@
000000001
100000000
000000001
-;
\ No newline at end of file
+;
+
+//---------------kickbox-quadarm - blank----------------
+#NOTEDATA:;
+#CHARTNAME:Syncer;
+#STEPSTYPE:kickbox-quadarm;
+#DESCRIPTION:Sync the Game;
+#CHARTSTYLE:;
+#DIFFICULTY:Beginner;
+#METER:1;
+#RADARVALUES:0.414,0.379,0.000,0.000,0.000,49.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.414,0.379,0.000,0.000,0.000,49.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000;
+#CREDIT:blank;
+#NOTES:
+0000
+0000
+0000
+0000
+,
+0000
+0000
+0000
+0000
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0001
+1000
+0001
+1000
+0001
+1000
+0001
+,
+1000
+0000
+0000
+0000
+;
diff --git a/Themes/_fallback/Scripts/00 init.lua b/Themes/_fallback/Scripts/00 init.lua
index 64062f0efb..a3c353f946 100644
--- a/Themes/_fallback/Scripts/00 init.lua
+++ b/Themes/_fallback/Scripts/00 init.lua
@@ -43,6 +43,30 @@ function math.round(n)
end
end
+function split(delimiter, text)
+ local list = {}
+ local pos = 1
+ while 1 do
+ local first,last = string.find(text, delimiter, pos)
+ if first then
+ table.insert(list, string.sub(text, pos, first-1))
+ pos = last+1
+ else
+ table.insert(list, string.sub(text, pos))
+ break
+ end
+ end
+ return list
+end
+
+function join(delimiter, list)
+ local ret = list[1]
+ for i = 2,table.getn(list) do
+ ret = ret .. delimiter .. list[i]
+ end
+ return ret or ""
+end
+
-- (c) 2006 Glenn Maynard
-- All rights reserved.
--
diff --git a/Themes/_fallback/Scripts/01 alias.lua b/Themes/_fallback/Scripts/01 alias.lua
index f482a4c03e..65a527fcb6 100644
--- a/Themes/_fallback/Scripts/01 alias.lua
+++ b/Themes/_fallback/Scripts/01 alias.lua
@@ -24,6 +24,65 @@ _safe = {
--[[ compatibility aliases ]]
+function alias_one(class, main_name, alt_name)
+ if type(main_name) ~= "string" then
+ lua.ReportScriptError("Name of function to make an alias for must be a string.")
+ return
+ end
+ if type(alt_name) ~= "string" then
+ lua.ReportScriptError("Alias name of function must be a string.")
+ return
+ end
+ if class[alt_name] then return end
+ class[alt_name]= class[main_name]
+end
+
+function alias_set(class, set)
+ assert(type(class) == "table" and type(set) == "table",
+ "alias_set must be passed a class and a set of names to make alieases.")
+ for i, fun in ipairs(set) do
+ if type(fun) == "table" then
+ local main_name= fun[1]
+ if type(set[2]) == "table" then
+ for n, alt_name in ipairs(set[2]) do
+ alias_one(class, main_name, alt_name)
+ end
+ elseif type(set[2]) == "string" then
+ alias_one(class, main_name, set[2])
+ end
+ else
+ lua.ReportScriptError("alias entry " .. i .. " in set passed to " ..
+ "alias_set is not a table.")
+ end
+ end
+end
+
+function make_camel_aliases(class)
+ local name_list= {}
+ for name, fun in pairs(class) do
+ if type(fun) == "function" and type(name) == "string" then
+ name_list[#name_list+1]= name
+ end
+ end
+ for i, name in ipairs(name_list) do
+ local words= split("_", name)
+ for o, w in ipairs(words) do
+ words[o]= w:sub(1,1):upper() .. w:sub(2)
+ end
+ local camel_name= join("", words)
+ if name ~= camel_name then
+ alias_one(class, name, camel_name)
+ end
+ end
+end
+
+local to_camel_list= {
+ CubicSplineN, NCSplineHandler, NoteColumnRenderer, NoteField}
+
+for i, class in ipairs(to_camel_list) do
+ make_camel_aliases(class)
+end
+
--[[ ActorScroller: all of these got renamed, so alias the lowercase ones if
themes are going to look for them. ]]
ActorScroller.getsecondtodestination = ActorScroller.GetSecondsToDestination
diff --git a/Themes/_fallback/Scripts/02 Branches.lua b/Themes/_fallback/Scripts/02 Branches.lua
index 3ea2c399fe..e15372fd8c 100644
--- a/Themes/_fallback/Scripts/02 Branches.lua
+++ b/Themes/_fallback/Scripts/02 Branches.lua
@@ -34,11 +34,6 @@ function GameOverOrContinue()
end
end
--- functions used for Routine mode
-function IsRoutine()
- return GAMESTATE:GetCurrentStyle() and GAMESTATE:GetCurrentStyle():GetStyleType() == "StyleType_TwoPlayersSharedSides"
-end
-
Branch = {
Init = function() return "ScreenInit" end,
AfterInit = function()
diff --git a/Themes/_fallback/Scripts/02 Utilities.lua b/Themes/_fallback/Scripts/02 Utilities.lua
index 53a3acf534..602a33f508 100644
--- a/Themes/_fallback/Scripts/02 Utilities.lua
+++ b/Themes/_fallback/Scripts/02 Utilities.lua
@@ -29,30 +29,6 @@ function TableStringLookup(t, group)
return ret
end
-function split(delimiter, text)
- local list = {}
- local pos = 1
- while 1 do
- local first,last = string.find(text, delimiter, pos)
- if first then
- table.insert(list, string.sub(text, pos, first-1))
- pos = last+1
- else
- table.insert(list, string.sub(text, pos))
- break
- end
- end
- return list
-end
-
-function join(delimiter, list)
- local ret = list[1]
- for i = 2,table.getn(list) do
- ret = ret .. delimiter .. list[i]
- end
- return ret or ""
-end
-
function wrap(val,n)
local x = val
Trace( "wrap "..x.." "..n )
@@ -238,12 +214,10 @@ function Center1Player()
end
function IsRoutine()
- local styleType = GAMESTATE:GetCurrentStyle():GetStyleType()
-
- if styleType == "StyleType_TwoPlayersSharedSides" then
+ local style= GAMESTATE:GetCurrentStyle()
+ if style and style:GetStyleType() == "StyleType_TwoPlayersSharedSides" then
return true
end
-
return false
end
@@ -304,8 +278,9 @@ function getenv(name) return envTable[name] end
-- tobool(v)
-- Converts v to a boolean.
function tobool(v)
- if getmetatable(v) and (getmetatable(v))["__tobool"] and type((getmetatable(v))["__tobool"])=="function" then
- return (getmetatable(v))["__tobool"](v)
+ local meta= getmetatable(v)
+ if meta and type(meta.__tobool) == "function" then
+ return meta.__tobool(v)
elseif type(v) == "string" then
local cmp = string.lower(v)
if cmp == "true" or cmp == "t" then
@@ -319,7 +294,10 @@ function tobool(v)
else
return true
end
+ elseif type(v) == "boolean" then
+ return v
end
+ return nil
end
-- GetPlayerOrMachineProfile(pn)
diff --git a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua
index 707595f7aa..f044e8db5a 100644
--- a/Themes/_fallback/Scripts/03 CustomSpeedMods.lua
+++ b/Themes/_fallback/Scripts/03 CustomSpeedMods.lua
@@ -341,6 +341,23 @@ function SpeedModIncLarge()
return ret
end
+function GetSpeedModeAndValueFromPoptions(pn)
+ local poptions= GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Preferred")
+ local speed= nil
+ local mode= nil
+ if poptions:MaxScrollBPM() > 0 then
+ mode= "m"
+ speed= math.round(poptions:MaxScrollBPM())
+ elseif poptions:TimeSpacing() > 0 then
+ mode= "C"
+ speed= math.round(poptions:ScrollBPM())
+ else
+ mode= "x"
+ speed= math.round(poptions:ScrollSpeed() * 100)
+ end
+ return speed, mode
+end
+
function ArbitrarySpeedMods()
-- If players are allowed to join while this option row is active, problems will probably occur.
local increment= get_speed_increment()
@@ -400,6 +417,7 @@ function ArbitrarySpeedMods()
val.mode= ({"x", "C", "m"})[real_choice - 4]
end
self:GenChoices()
+ MESSAGEMAN:Broadcast("SpeedChoiceChanged", {pn= pn, mode= val.mode, speed= val.speed})
return true
end,
GenChoices= function(self)
@@ -440,19 +458,7 @@ function ArbitrarySpeedMods()
}
for i, pn in ipairs(GAMESTATE:GetEnabledPlayers()) do
if GAMESTATE:IsHumanPlayer(pn) then
- local poptions= GAMESTATE:GetPlayerState(pn):GetPlayerOptions("ModsLevel_Preferred")
- local speed= nil
- local mode= nil
- if poptions:MaxScrollBPM() > 0 then
- mode= "m"
- speed= math.round(poptions:MaxScrollBPM())
- elseif poptions:TimeSpacing() > 0 then
- mode= "C"
- speed= math.round(poptions:ScrollBPM())
- else
- mode= "x"
- speed= math.round(poptions:ScrollSpeed() * 100)
- end
+ local speed, mode= GetSpeedModeAndValueFromPoptions(pn)
ret.CurValues[pn]= {mode= mode, speed= speed}
ret.NumPlayers= ret.NumPlayers + 1
end
diff --git a/Themes/_fallback/Scripts/03 Gameplay.lua b/Themes/_fallback/Scripts/03 Gameplay.lua
index 4d893f91c4..4c5fcaacb1 100644
--- a/Themes/_fallback/Scripts/03 Gameplay.lua
+++ b/Themes/_fallback/Scripts/03 Gameplay.lua
@@ -22,10 +22,60 @@ function GetExtraColorThreshold()
para = 10,
techno = 10,
lights = 10, -- lights shouldn't be playable
+ kickbox= 100, -- extra color is lame
}
return Modes[CurGameName()] or 10
end
+-- GameplayMargins exists to provide a layer of backwards compatibility for
+-- people using the X position metrics to set where the notefields are.
+-- This makes it somewhat complex.
+-- Rather than trying to understand how it works, you can simply do this:
+-- (example values in parentheses)
+-- 1. Decide how much space you want in the center between notefields. (80)
+-- 2. Decide how much space you want on each side. (40)
+-- 3. Write a simple function that just returns those numbers:
+-- function GameplayMargins() return 40, 80, 40 end
+-- Then the engine does the work of figuring out where each notefield should
+-- be centered.
+function GameplayMargins(enabled_players, styletype)
+ local other= {[PLAYER_1]= PLAYER_2, [PLAYER_2]= PLAYER_1}
+ local margins= {[PLAYER_1]= {40, 40}, [PLAYER_2]= {40, 40}}
+ -- Use a fake style width because calculating the real style width throws off
+ -- the code in the engine.
+ local fake_style_width= 272
+ -- Handle the case of a single player that is centered first because it's
+ -- simpler.
+ if Center1Player() then
+ local pn= enabled_players[1]
+ fake_style_width= 544
+ local center= _screen.cx
+ local left= center - (fake_style_width / 2)
+ local right= _screen.w - center - (fake_style_width / 2)
+ -- center margin width will be ignored.
+ return left, 80, right
+ end
+ local half_screen= _screen.w / 2
+ local left= {[PLAYER_1]= 0, [PLAYER_2]= half_screen}
+ for i, pn in ipairs(enabled_players) do
+ local edge= left[pn]
+ local center= THEME:GetMetric("ScreenGameplay",
+ "Player"..ToEnumShortString(pn)..ToEnumShortString(styletype).."X")
+ -- Adjust for the p2 center being on the right side.
+ center= center - edge
+ margins[pn][1]= center - (fake_style_width / 2)
+ margins[pn][2]= half_screen - center - (fake_style_width / 2)
+ if #enabled_players == 1 then
+ margins[other[pn]][1]= margins[pn][2]
+ margins[other[pn]][2]= margins[pn][1]
+ end
+ end
+ local left= margins[PLAYER_1][1]
+ local center= margins[PLAYER_1][2] + margins[PLAYER_2][1]
+ local right= margins[PLAYER_2][2]
+ return left, center, right
+end
+
-- AllowOptionsMenu()
-- [en] returns if you are able to select options
-- on ScreenSelectMusic.
@@ -51,11 +101,68 @@ function GameCompatibleModes()
maniax = "Single,Double,Versus",
-- todo: add versus modes for technomotion
techno = "Single4,Single5,Single8,Double4,Double5,Double8",
- lights = "Single" -- lights shouldn't be playable
+ lights = "Single", -- lights shouldn't be playable
}
return Modes[CurGameName()]
end
+local function upper_first_letter(s)
+ local first_letter= s:match("([a-zA-Z])")
+ return s:gsub(first_letter, first_letter:upper(), 1)
+end
+
+-- No more having a metric for every style for every game mode. -Kyz
+function ScreenSelectStyleChoices()
+ local styles= GAMEMAN:GetStylesForGame(GAMESTATE:GetCurrentGame():GetName())
+ local choices= {}
+ for i, style in ipairs(styles) do
+ local name= style:GetName()
+ local cap_name= upper_first_letter(name)
+ -- couple-edit and threepanel don't seem like they should actually be
+ -- selectable. -Kyz
+ if name ~= "couple-edit" and name ~= "threepanel" then
+ choices[#choices+1]= "name," .. cap_name .. ";style," .. name ..
+ ";text," .. cap_name .. ";screen," .. Branch.AfterSelectStyle()
+ end
+ end
+ return choices
+end
+
+-- No more having an xy for every style for every game mode. -Kyz
+function ScreenSelectStylePositions(count)
+ local poses= {}
+ local columns= 1
+ local choice_height= 96
+ local column_x= {_screen.cx, _screen.cx + 160}
+ if count > 4 then
+ column_x[1]= _screen.cx - 160
+ columns= 2
+ end
+ if count > 8 then
+ column_x[1]= _screen.cx - 240
+ column_x[2]= _screen.cx
+ column_x[3]= _screen.cx + 240
+ columns= 3
+ end
+ local num_per_column= {math.ceil(count/columns), math.floor(count/columns)}
+ if count > 8 then
+ if count % 3 == 0 then
+ num_per_column[3]= count/columns
+ elseif count % 3 == 1 then
+ num_per_column[3]= num_per_column[2]
+ else
+ num_per_column[3]= num_per_column[1]
+ end
+ end
+ for c= 1, columns do
+ local start_y= _screen.cy - (choice_height * ((num_per_column[c] / 2)+.5))
+ for i= 1, num_per_column[c] do
+ poses[#poses+1]= {column_x[c], start_y + (choice_height * i)}
+ end
+ end
+ return poses
+end
+
function SelectProfileKeys()
local sGame = CurGameName()
if sGame == "pump" then
diff --git a/Themes/_fallback/Scripts/04 CreditsHelpers.lua b/Themes/_fallback/Scripts/04 CreditsHelpers.lua
index 50c6103d67..02f121acd9 100644
--- a/Themes/_fallback/Scripts/04 CreditsHelpers.lua
+++ b/Themes/_fallback/Scripts/04 CreditsHelpers.lua
@@ -50,6 +50,7 @@ local stepmania_credits= {
{
name= "Translators",
"John Reactor (Polish)",
+ "Jarosław Pietras (Polish)",
"DHalens (Spanish)",
"@Niler_jp (Japanese)",
"Deamon007 (Dutch)"
diff --git a/Themes/_fallback/Scripts/04 LogDisplay.lua b/Themes/_fallback/Scripts/04 LogDisplay.lua
index f9207d79be..ca1fcc116a 100644
--- a/Themes/_fallback/Scripts/04 LogDisplay.lua
+++ b/Themes/_fallback/Scripts/04 LogDisplay.lua
@@ -144,6 +144,10 @@ local log_display_mt= {
end
end,
[name_mess]= function(subself, mess)
+ if PREFSMAN:GetPreference("IgnoredDialogs") ~= "" then
+ self:visible(false)
+ return
+ end
if not mess.message then return end
if self.messes_since_update > self.max_log then return end
-- Long ago, someone decided that "::" should be an alias for "\n"
diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini
index 91808f5a5e..a5686ff6c9 100644
--- a/Themes/_fallback/metrics.ini
+++ b/Themes/_fallback/metrics.ini
@@ -1130,7 +1130,7 @@ AttackDisplayXOffsetOneSideP2=0
AttackDisplayXOffsetBothSides=0
AttackDisplayY=-70
AttackDisplayYReverse=70
-; HACK: These shouldn't go to the render pipe at all if IsGame("pump")
+# HACK: These shouldn't go to the render pipe at all if IsGame("pump")
HoldJudgmentYStandard=IsGame("pump") and -99999 or -90
HoldJudgmentYReverse=IsGame("pump") and -99999 or 90
BrightGhostComboThreshold=100
@@ -1916,7 +1916,7 @@ LoadEdits=true
Fallback="ScreenWithMenuElements"
Class="ScreenSelectProfile"
#
-ScreenOnCommand=%function(self) self:lockinput(3); end;
+ScreenOnCommand=%function(self) self:lockinput(1); end;
#
NextScreen=Branch.AfterSelectProfile()
PrevScreen=Branch.TitleMenu()
@@ -1944,6 +1944,12 @@ PrevScreen=Branch.TitleMenu()
TimerSeconds=30
#
DefaultChoice="Single"
+# Giant metric list left in for backwards compatibility.
+# A much better way to handle this is:
+# ChoiceNames="lua,ScreenSelectStyleChoices()"
+# That will list all the styles for the current game without needing a huge
+# list of metrics. _fallback still uses the old method to avoid the
+# possibility of breaking themes. -Kyz
ChoiceNames=GameCompatibleModes()
#
OptionOrderAuto="1:2,2:1"
@@ -2085,6 +2091,7 @@ TimerSeconds=120
DoRouletteOnMenuTimer=true
RouletteTimerSeconds=15
IdleCommentSeconds=20
+HardCommentMeter=10
#
DefaultSort=GAMESTATE:IsCourseMode() and "Group" or "AllCourses"
#
@@ -2191,13 +2198,13 @@ FrameX=0
FrameY=0
FrameOnCommand=
FrameLoadCommand=%function(self,param) local bFlip = param.PlayerState and param.PlayerState:GetPlayerNumber() ~= PLAYER_1; self:zoomx(bFlip and -1 or 1); end
-FrameSetCommand=%function(self,param) if param.CustomDifficulty then self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)) end end
+FrameSetCommand=%function(self,param) if param.CustomDifficulty and param.CustomDifficulty ~= "" then self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)) end end
NumTicks=10
MaxTicks=14
TicksX=0
TicksY=0
TicksOnCommand=shadowlength,0;
-TicksSetCommand=%function(self,param) self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)) if param.Meter > 9 then self:glowshift() else self:stopeffect() end end
+TicksSetCommand=%function(self,param) if param.CustomDifficulty and param.CustomDifficulty ~= "" then self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)) if param.Meter > 9 then self:glowshift() else self:stopeffect() end end end
ShowTicks=false
ShowMeter=true
MeterFormatString="%i"
@@ -2205,12 +2212,12 @@ ZeroMeterString="?"
MeterX=30
MeterY=0
MeterOnCommand=shadowlength,0
-MeterSetCommand=%function(self,param) if param.CustomDifficulty then self:diffuse(CustomDifficultyToLightColor(param.CustomDifficulty)); self:strokecolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); end end
+MeterSetCommand=%function(self,param) if param.CustomDifficulty and param.CustomDifficulty ~= "" then self:diffuse(CustomDifficultyToLightColor(param.CustomDifficulty)); self:strokecolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); end end
ShowDescription=true
DescriptionX=-10
DescriptionY=0
DescriptionOnCommand=shadowlength,0;uppercase,true;
-DescriptionSetCommand=%function(self,param) if param.CustomDifficulty then self:diffuse(CustomDifficultyToLightColor(param.CustomDifficulty)); self:strokecolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); end end
+DescriptionSetCommand=%function(self,param) if param.CustomDifficulty and param.CustomDifficulty ~= "" then self:diffuse(CustomDifficultyToLightColor(param.CustomDifficulty)); self:strokecolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); end end
ShowCredit=false
CreditX=0
CreditY=0
@@ -2876,8 +2883,8 @@ AutoDismissSanitySecs=5
#
# The position of the Devices list and its On/Off commands.
DevicesX=SCREEN_CENTER_X
-DevicesY=SCREEN_TOP+24
-DevicesOnCommand=zoom,0.75;draworder,5;strokecolor,color("0,0,0,1")
+DevicesY=SCREEN_TOP+4
+DevicesOnCommand=vertalign,top;maxheight,92;zoom,0.75;draworder,5;strokecolor,color("0,0,0,1")
DevicesOffCommand=
#
# The ListHeader parts are the row that the player's cursor starts on with
@@ -3417,7 +3424,25 @@ MusicFadeOutSeconds=0.5
OutTransitionLength=5
CourseTransitionLength=0.5
BeginFailedDelay=1.0
-#
+# New way to control where the notefields are on gameplay.
+# The MarginFunction will be passed GAMESTATE:EnabledPlayers() and the
+# current styletype. The function must return three values:
+# Left margin width, center margin width, right margin width.
+# The engine will then position the notefields and adjust their size to fit
+# in the space not occupied by the margins. If there is only one player and
+# that player would normally be centered (OnePlayerTwoSides or
+# TwoPlayersSharedSides, or the Center1Player preference), then the center
+# margin value will be ignored.
+# Mods applied to the player may still move the notefield into the margin,
+# this is just for controlling its initial position and size.
+# The purpose of this is to allow the engine more flexibility in styles,
+# for example, one player playing dance-solo while the other plays
+# dance-single.
+MarginFunction=GameplayMargins
+# These X values for each player and styletype are deprecated in favor of
+# writing a MarginFunction that returns the margin sizes you prefer.
+# The MarginFunction supplied by _fallback will use these metrics for
+# backwards compatibility.
PlayerP1OnePlayerOneSideX=math.floor(scale((0.85/3),0,1,SCREEN_LEFT,SCREEN_RIGHT))
PlayerP2OnePlayerOneSideX=math.floor(scale((2.15/3),0,1,SCREEN_LEFT,SCREEN_RIGHT))
PlayerP1TwoPlayersTwoSidesX=math.floor(scale((0.85/3),0,1,SCREEN_LEFT,SCREEN_RIGHT))
diff --git a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua
index e7b9331a3b..c021dca519 100644
--- a/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua
+++ b/Themes/default/BGAnimations/ScreenGameplay decorations/default.lua
@@ -30,13 +30,13 @@ local function CreateSegments(Player)
local firstBeatSecs = song:GetFirstSecond();
local lastBeatSecs = song:GetLastSecond();
- local bpms = timingData:GetBPMsAndTimes();
- local stops = timingData:GetStops();
- local delays = timingData:GetDelays();
- local warps = timingData:GetWarps();
- local fakes = timingData:GetFakes();
- local scrolls = timingData:GetScrolls();
- local speeds = timingData:GetSpeeds();
+ local bpms = timingData:GetBPMsAndTimes(true);
+ local stops = timingData:GetStops(true);
+ local delays = timingData:GetDelays(true);
+ local warps = timingData:GetWarps(true);
+ local fakes = timingData:GetFakes(true);
+ local scrolls = timingData:GetScrolls(true);
+ local speeds = timingData:GetSpeeds(true);
-- we don't want too many segments to be shown.
local sumSegments = #bpms + #stops + #delays + #warps + #fakes + #scrolls + #speeds
diff --git a/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua b/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua
index df6ab760e1..d5f5ccf3c8 100644
--- a/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua
+++ b/Themes/default/BGAnimations/ScreenGameplay underlay/danger.lua
@@ -9,7 +9,7 @@ for pn=1,#players do
self:x(
THEME:GetMetric(
Var "LoadingScreen",
- "Player" .. ToEnumShortString(players[pn]) .. ToEnumShortString(GAMESTATE:GetCurrentStyle():GetStyleType()) .. "X"
+ "Player" .. ToEnumShortString(players[pn]) .. ToEnumShortString(GAMESTATE:GetCurrentStyle(pn):GetStyleType()) .. "X"
)
)
end,
diff --git a/Themes/default/BGAnimations/ScreenPlayerOptions decorations.lua b/Themes/default/BGAnimations/ScreenPlayerOptions decorations.lua
new file mode 100644
index 0000000000..346f4a256c
--- /dev/null
+++ b/Themes/default/BGAnimations/ScreenPlayerOptions decorations.lua
@@ -0,0 +1,15 @@
+local num_players = GAMESTATE:GetHumanPlayers();
+
+local t = LoadFallbackB();
+
+for i=1,#num_players do
+ local metrics_name = "PlayerNameplate" .. ToEnumShortString(num_players[i])
+ t[#t+1] = LoadActor( THEME:GetPathG(Var "LoadingScreen", "PlayerNameplate"), num_players[i] ) .. {
+ InitCommand=function(self)
+ self:name(metrics_name);
+ ActorUtil.LoadAllCommandsAndSetXY(self,Var "LoadingScreen");
+ end
+ }
+end
+
+return t;
\ No newline at end of file
diff --git a/Themes/default/Graphics/ScreenPlayerOptions PlayerNameplate.lua b/Themes/default/Graphics/ScreenPlayerOptions PlayerNameplate.lua
new file mode 100644
index 0000000000..9e5b512a3e
--- /dev/null
+++ b/Themes/default/Graphics/ScreenPlayerOptions PlayerNameplate.lua
@@ -0,0 +1,94 @@
+local PlayerNumber = ...
+assert( PlayerNumber )
+
+local bpm_text_zoom = 0.875
+
+local song_bpms= {}
+local bpm_text= "??? - ???"
+local function format_bpm(bpm)
+ return ("%.0f"):format(bpm)
+end
+
+-- Courses don't have GetDisplayBpms.
+if GAMESTATE:GetCurrentSong() then
+ song_bpms= GAMESTATE:GetCurrentSong():GetDisplayBpms()
+ song_bpms[1]= math.round(song_bpms[1])
+ song_bpms[2]= math.round(song_bpms[2])
+ if song_bpms[1] == song_bpms[2] then
+ bpm_text= format_bpm(song_bpms[1])
+ else
+ bpm_text= format_bpm(song_bpms[1]) .. " - " .. format_bpm(song_bpms[2])
+ end
+end
+
+local t = Def.ActorFrame {
+ LoadActor(THEME:GetPathB("_frame","3x1"),"rounded fill", 192-8) .. {
+ OnCommand=cmd(diffuse,color("#333333");diffusealpha,0.875);
+ };
+ LoadActor(THEME:GetPathB("_frame","3x1"),"rounded gloss", 192-8) .. {
+ OnCommand=cmd(diffusealpha,0.125);
+ };
+ LoadFont("Common Normal") .. {
+ Text=ToEnumShortString(PlayerNumber);
+ Name="PlayerShortName",
+ InitCommand=cmd(x,-104;maxwidth,32),
+ OnCommand=cmd(diffuse,PlayerColor(PlayerNumber);shadowlength,1)
+ },
+ LoadFont("Common Normal") .. {
+ Text=bpm_text;
+ Name="BPMRangeOld",
+ InitCommand=cmd(x,-40;maxwidth,88/bpm_text_zoom),
+ OnCommand=cmd(shadowlength,1;zoom,bpm_text_zoom)
+ },
+ LoadActor(THEME:GetPathG("_StepsDisplayListRow","arrow")) .. {
+ Name="Seperator",
+ InitCommand=cmd(x,14)
+ },
+ LoadFont("Common Normal") .. {
+ Text="100 - 200000";
+ Name="BPMRangeNew",
+ InitCommand= function(self)
+ self:x(68):maxwidth(88/bpm_text_zoom):shadowlength(1):zoom(bpm_text_zoom)
+ local speed, mode= GetSpeedModeAndValueFromPoptions(PlayerNumber)
+ self:playcommand("SpeedChoiceChanged", {pn= PlayerNumber, mode= mode, speed= speed})
+ end,
+ BPMWillNotChangeCommand=cmd(stopeffect),
+ BPMWillChangeCommand=cmd(diffuseshift;effectcolor1,Color.White;effectcolor2,Color.Orange),
+ SpeedChoiceChangedMessageCommand= function(self, param)
+ if param.pn ~= PlayerNumber then return end
+ local text= ""
+ local no_change= true
+ if param.mode == "x" then
+ if not song_bpms[1] then
+ text= "??? - ???"
+ elseif song_bpms[1] == song_bpms[2] then
+ text= format_bpm(song_bpms[1] * param.speed*.01)
+ else
+ text= format_bpm(song_bpms[1] * param.speed*.01) .. " - " ..
+ format_bpm(song_bpms[2] * param.speed*.01)
+ end
+ no_change= param.speed == 100
+ elseif param.mode == "C" then
+ text= param.mode .. param.speed
+ no_change= param.speed == song_bpms[2] and song_bpms[1] == song_bpms[2]
+ else
+ no_change= param.speed == song_bpms[2]
+ if song_bpms[1] == song_bpms[2] then
+ text= param.mode .. param.speed
+ else
+ local factor= song_bpms[1] / song_bpms[2]
+ text= param.mode .. format_bpm(param.speed * factor) .. " - "
+ .. param.mode .. param.speed
+ end
+ end
+ self:settext(text)
+ if no_change then
+ self:queuecommand("BPMWillNotChange")
+ else
+ self:queuecommand("BPMWillChange")
+ end
+ end
+ }
+}
+
+return t
\ No newline at end of file
diff --git a/Themes/default/metrics.ini b/Themes/default/metrics.ini
index dc6b0a6018..f1a18125ff 100644
--- a/Themes/default/metrics.ini
+++ b/Themes/default/metrics.ini
@@ -157,7 +157,7 @@ TitleGainFocusCommand=stoptweening;zoom,0.6375*1.125;bounceend,0.1;diffuse,Color
TitleLoseFocusCommand=diffuse,Color("White");strokecolor,Color("Black");stopeffect;
#
ItemsStartX=SCREEN_CENTER_X-140
-ItemsEndX=SCREEN_CENTER_X+130
+ItemsEndX=SCREEN_CENTER_X+80
ItemsGapX=12
ItemsMinBaseZoom=0.5
ItemsLongRowP1X=SCREEN_CENTER_X-60
@@ -422,7 +422,7 @@ MoveCommand=decelerate,0.05
FrameX=
FrameSetCommand=%function(self,param) \
- if param.CustomDifficulty then \
+ if param.CustomDifficulty and param.CustomDifficulty ~= "" then \
self:diffuse(ColorMidTone( CustomDifficultyToColor(param.CustomDifficulty) )); \
else \
self:diffuse(color('1,1,1,1')); \
@@ -436,7 +436,7 @@ ShowMeter=true
MeterX=56
MeterOnCommand=shadowlength,1;zoom,0.65;textglowmode,'TextGlowMode_Inner';
MeterSetCommand=%function(self,param) \
- if param.CustomDifficulty then \
+ if param.CustomDifficulty and param.CustomDifficulty ~= "" then \
self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)); \
self:shadowcolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); \
end; \
@@ -457,7 +457,7 @@ DescriptionSetCommand=%function(self,param) \
if self:GetText() == "" then \
self:settext("Edit"); \
end; \
- if param.CustomDifficulty then \
+ if param.CustomDifficulty and param.CustomDifficulty ~= "" then \
self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)); \
self:shadowcolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); \
end; \
@@ -771,10 +771,8 @@ FOV=90
PerChoiceScrollElement=false
PerChoiceIconElement=false
#
-Choice7Keys="name,7Keys;style,single7;screen,"..Branch.AfterSelectStyle()
-Choice10Keys="name,10Keys;style,double5;screen,"..Branch.AfterSelectStyle()
-Choice14Keys="name,14Keys;style,double7;screen,"..Branch.AfterSelectStyle()
-ChoiceKB7="name,kb7;style,single;screen,"..Branch.AfterSelectStyle()
+# Having one lua function is so much better than dozens of metrics. -Kyz
+ChoiceNames="lua,ScreenSelectStyleChoices()"
#
ShowScroller=false
ShowIcon=true
@@ -784,65 +782,10 @@ UseIconMetrics=true
IconGainFocusCommand=stoptweening;bounceend,0.05;zoom,1;
IconLoseFocusCommand=stoptweening;decelerate,0.1;zoom,0.8;
#
-IconChoiceSingleX=SCREEN_CENTER_X-160
-IconChoiceSingleY=SCREEN_CENTER_Y-96
-IconChoiceSingleOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceSingleOffCommand=linear,0.05;zoomx,0
+IconChoicePosFunction=ScreenSelectStylePositions
+IconChoiceOnCommand=zoom,0;bounceend,0.35;zoom,1
+IconChoiceOffCommand=linear,0.05;zoomx,0
#
-IconChoiceDoubleX=SCREEN_CENTER_X-160
-IconChoiceDoubleY=SCREEN_CENTER_Y
-IconChoiceDoubleOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceDoubleOffCommand=linear,0.05;zoomx,0
-####
-IconChoiceSoloX=SCREEN_CENTER_X-160
-IconChoiceSoloY=SCREEN_CENTER_Y+96
-IconChoiceSoloOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceSoloOffCommand=linear,0.05;zoomx,0
-#
-IconChoiceHalfDoubleX=SCREEN_CENTER_X-160
-IconChoiceHalfDoubleY=SCREEN_CENTER_Y+96
-IconChoiceHalfDoubleOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceHalfDoubleOffCommand=linear,0.05;zoomx,0
-####
-IconChoiceVersusX=SCREEN_CENTER_X+160
-IconChoiceVersusY=string.find(THEME:GetMetric("ScreenSelectStyle","ChoiceNames"),"Routine") and SCREEN_CENTER_Y-96 or SCREEN_CENTER_Y-48
-IconChoiceVersusOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceVersusOffCommand=linear,0.05;zoomx,0
-#
-IconChoiceCoupleX=SCREEN_CENTER_X+160
-IconChoiceCoupleY=string.find(THEME:GetMetric("ScreenSelectStyle","ChoiceNames"),"Routine") and SCREEN_CENTER_Y or SCREEN_CENTER_Y+48
-IconChoiceCoupleOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceCoupleOffCommand=linear,0.05;zoomx,0
-#
-IconChoiceRoutineX=SCREEN_CENTER_X+160
-IconChoiceRoutineY=SCREEN_CENTER_Y+96
-IconChoiceRoutineOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoiceRoutineOffCommand=linear,0.05;zoomx,0
-#
-IconChoicekb7X=SCREEN_CENTER_X
-IconChoicekb7Y=SCREEN_CENTER_Y
-IconChoicekb7OnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoicekb7OffCommand=linear,0.05;zoomx,0
-#
-IconChoice5KeysX=SCREEN_CENTER_X-160
-IconChoice5KeysY=SCREEN_CENTER_Y-48
-IconChoice5KeysOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoice5KeysOffCommand=linear,0.05;zoomx,0
-#
-IconChoice7KeysX=SCREEN_CENTER_X-160
-IconChoice7KeysY=SCREEN_CENTER_Y+48
-IconChoice7KeysOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoice7KeysOffCommand=linear,0.05;zoomx,0
-#
-IconChoice10KeysX=SCREEN_CENTER_X+160
-IconChoice10KeysY=SCREEN_CENTER_Y-48
-IconChoice10KeysOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoice10KeysOffCommand=linear,0.05;zoomx,0
-#
-IconChoice14KeysX=SCREEN_CENTER_X+160
-IconChoice14KeysY=SCREEN_CENTER_Y+48
-IconChoice14KeysOnCommand=zoom,0;bounceend,0.35;zoom,1
-IconChoice14KeysOffCommand=linear,0.05;zoomx,0
[ScreenSelectPlayMode]
PersistScreens="ScreenSelectPlayMode,ScreenSelectMusic"
@@ -1167,7 +1110,7 @@ MeterX=56-32
MeterY=0
MeterOnCommand=shadowlength,1;textglowmode,'TextGlowMode_Inner'
MeterSetCommand=%function(self,param) \
- if param.CustomDifficulty then \
+ if param.CustomDifficulty and param.CustomDifficulty ~= "" then \
self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)); \
self:shadowcolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); \
end; \
@@ -1193,7 +1136,7 @@ DescriptionSetCommand=%function(self,param) \
if self:GetText() == "" then \
self:settext("Edit"); \
end; \
- if param.CustomDifficulty then \
+ if param.CustomDifficulty and param.CustomDifficulty ~= "" then \
self:diffuse(CustomDifficultyToColor(param.CustomDifficulty)); \
self:shadowcolor(CustomDifficultyToDarkColor(param.CustomDifficulty)); \
end; \
@@ -1427,6 +1370,16 @@ LineSF="lua,OptionRowScreenFilter()"
Line17="lua,OptionRowProTiming()"
Line18="list,Characters"
+PlayerNameplateP1X=SCREEN_CENTER_X * 0.5 + 16
+PlayerNameplateP1Y=SCREEN_CENTER_Y - 176
+PlayerNameplateP1OnCommand=draworder,DrawOrder.Decorations;zoomy,0;addx,-SCREEN_CENTER_X;sleep,0.75;decelerate,0.25;addx,SCREEN_CENTER_X;zoomy,1
+PlayerNameplateP1OffCommand=
+
+PlayerNameplateP2X=SCREEN_CENTER_X * 1.5 - 16
+PlayerNameplateP2Y=SCREEN_CENTER_Y - 176
+PlayerNameplateP2OnCommand=draworder,DrawOrder.Decorations;zoomy,0;addx,SCREEN_CENTER_X;sleep,0.75;decelerate,0.25;addx,-SCREEN_CENTER_X;zoomy,1
+PlayerNameplateP2OffCommand=
+
[ScreenPlayerOptionsRestricted]
[ScreenSplash]
diff --git a/Xcode/Info-StepMania.plist b/Xcode/Info-StepMania.plist
index 184f964ad6..b2ca6994d3 100644
--- a/Xcode/Info-StepMania.plist
+++ b/Xcode/Info-StepMania.plist
@@ -50,9 +50,9 @@
LSApplicationCategoryType
public.app-category.music-games
LSMinimumSystemVersion
- 10.5.10
+ 10.6.8
NSHumanReadableCopyright
- Copyright 2001-2014
+ Copyright 2001-2015
NSPrincipalClass
SMApplication
diff --git a/Xcode/stepmania.xcodeproj/project.pbxproj b/Xcode/stepmania.xcodeproj/project.pbxproj
index c6d55d8caf..64a6d1d13f 100644
--- a/Xcode/stepmania.xcodeproj/project.pbxproj
+++ b/Xcode/stepmania.xcodeproj/project.pbxproj
@@ -182,6 +182,8 @@
36CA53210F9156860063D59D /* ScreenOptionsEditCourse.h in Headers */ = {isa = PBXBuildFile; fileRef = 36CA531F0F9156860063D59D /* ScreenOptionsEditCourse.h */; };
37171EBE1946C9D500E09FC5 /* ActorMultiVertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37171EBC1946C9D500E09FC5 /* ActorMultiVertex.cpp */; };
37171EBF1946C9D500E09FC5 /* ActorMultiVertex.h in Headers */ = {isa = PBXBuildFile; fileRef = 37171EBD1946C9D500E09FC5 /* ActorMultiVertex.h */; };
+ 37EC1B1F1A61C00E008C749C /* CubicSpline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37EC1B1D1A61C00E008C749C /* CubicSpline.cpp */; };
+ 37EC1B201A61C00E008C749C /* CubicSpline.h in Headers */ = {isa = PBXBuildFile; fileRef = 37EC1B1E1A61C00E008C749C /* CubicSpline.h */; };
AA059ABC0B8CCFB5006F8139 /* ActorMultiTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA059ABA0B8CCFB5006F8139 /* ActorMultiTexture.cpp */; };
AA059ABD0B8CCFB5006F8139 /* ActorMultiTexture.h in Headers */ = {isa = PBXBuildFile; fileRef = AA059ABB0B8CCFB5006F8139 /* ActorMultiTexture.h */; };
AA059ABE0B8CCFB5006F8139 /* ActorMultiTexture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA059ABA0B8CCFB5006F8139 /* ActorMultiTexture.cpp */; };
@@ -2066,6 +2068,8 @@
36CA531F0F9156860063D59D /* ScreenOptionsEditCourse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenOptionsEditCourse.h; path = ../src/ScreenOptionsEditCourse.h; sourceTree = SOURCE_ROOT; };
37171EBC1946C9D500E09FC5 /* ActorMultiVertex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ActorMultiVertex.cpp; path = ../src/ActorMultiVertex.cpp; sourceTree = ""; };
37171EBD1946C9D500E09FC5 /* ActorMultiVertex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ActorMultiVertex.h; path = ../src/ActorMultiVertex.h; sourceTree = ""; };
+ 37EC1B1D1A61C00E008C749C /* CubicSpline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CubicSpline.cpp; path = ../src/CubicSpline.cpp; sourceTree = ""; };
+ 37EC1B1E1A61C00E008C749C /* CubicSpline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CubicSpline.h; path = ../src/CubicSpline.h; sourceTree = ""; };
AA059ABA0B8CCFB5006F8139 /* ActorMultiTexture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 8; lastKnownFileType = sourcecode.cpp.cpp; name = ActorMultiTexture.cpp; path = ../src/ActorMultiTexture.cpp; sourceTree = ""; tabWidth = 8; usesTabs = 1; };
AA059ABB0B8CCFB5006F8139 /* ActorMultiTexture.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 8; lastKnownFileType = sourcecode.c.h; name = ActorMultiTexture.h; path = ../src/ActorMultiTexture.h; sourceTree = ""; tabWidth = 8; usesTabs = 1; };
AA059E2A0B8F0C66006F8139 /* libz_link.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libz_link.a; sourceTree = ""; };
@@ -3990,6 +3994,8 @@
AA6EFDBB04770A83005F316C /* Rage */ = {
isa = PBXGroup;
children = (
+ 37EC1B1D1A61C00E008C749C /* CubicSpline.cpp */,
+ 37EC1B1E1A61C00E008C749C /* CubicSpline.h */,
AA6EFD6D04770A7C005F316C /* RageBitmapTexture.cpp */,
AA6EFD6E04770A7C005F316C /* RageBitmapTexture.h */,
AA6EFD6F04770A7C005F316C /* RageDisplay.cpp */,
@@ -5496,6 +5502,7 @@
B75CE3B5137963350076A82D /* SongPosition.h in Headers */,
2B9C2E8E137A138B004C92F3 /* NotesLoaderJson.h in Headers */,
2B9C2E90137A138B004C92F3 /* NotesWriterJson.h in Headers */,
+ 37EC1B201A61C00E008C749C /* CubicSpline.h in Headers */,
2B43509513949F37006FA051 /* TimingSegments.h in Headers */,
B773AE6E140AAB1800C68DDD /* SpecialDirs.h in Headers */,
2B01A79816C881E500D5CFD2 /* RageDisplay_OGL_Helpers.h in Headers */,
@@ -6818,6 +6825,7 @@
AAFBEEED094D807E000029DE /* ScreenOptionsMemoryCard.cpp in Sources */,
AAFBEEEF094D807E000029DE /* ScreenServiceAction.cpp in Sources */,
AA0732900954381800F396C5 /* XmlFileUtil.cpp in Sources */,
+ 37EC1B1F1A61C00E008C749C /* CubicSpline.cpp in Sources */,
AAD5219C095513DA00073D86 /* XmlFile.cpp in Sources */,
AADD1CC5095C233F0088C9DF /* LocalizedString.cpp in Sources */,
AABBFCD309838C3A00F077E2 /* SMMain.mm in Sources */,
@@ -8400,7 +8408,7 @@
MACOSX_DEPLOYMENT_TARGET = 10.6;
ONLY_ACTIVE_ARCH = YES;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
- SDKROOT = macosx;
+ SDKROOT = macosx10.6;
SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)";
STRIP_INSTALLED_PRODUCT = NO;
STRIP_STYLE = "non-global";
@@ -8781,7 +8789,7 @@
LINKER_DISPLAYS_MANGLED_NAMES = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
- SDKROOT = macosx;
+ SDKROOT = macosx10.6;
SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)";
STRIP_STYLE = "non-global";
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../extern/glew-1.5.8/include $(PROJECT_DIR)/../extern/jsoncpp/include $(PROJECT_DIR)/../extern/vorbis";
@@ -9094,7 +9102,7 @@
LINKER_DISPLAYS_MANGLED_NAMES = YES;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES;
- SDKROOT = macosx;
+ SDKROOT = macosx10.6;
SHARED_PRECOMPS_DIR = "/Library/Caches/com.apple.Xcode.$(UID)/SharedPrecompiledHeaders/$(PRODUCT_NAME)/$(CONFIGURATION)";
STRIP_STYLE = "non-global";
USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../extern/glew-1.5.8/include $(PROJECT_DIR)/../extern/jsoncpp/include $(PROJECT_DIR)/../extern/vorbis";
diff --git a/autoconf/m4/video.m4 b/autoconf/m4/video.m4
index db55a2fb74..b48fba1e2a 100644
--- a/autoconf/m4/video.m4
+++ b/autoconf/m4/video.m4
@@ -70,10 +70,16 @@ if test "$with_ffmpeg" = "yes"; then
fi
else
dnl System FFMpeg
+dnl HACK: $prefix is set to NONE if not user specified
+ if test "$prefix" = "NONE"; then
+ our_installdir="/opt"
+ else
+ our_installdir="$prefix"
+ fi
dnl We might as well throw in GPL stuff as we're bound to GPL by libmad anyway.
- FFMPEG_CONFFLAGS="--enable-gpl --disable-programs --disable-doc --disable-avdevice --disable-swresample --disable-postproc --disable-avfilter"
+ FFMPEG_CONFFLAGS="--shlibdir=$our_installdir/stepmania-$VERSION --enable-gpl --disable-programs --disable-doc --disable-avdevice --disable-swresample --disable-postproc --disable-avfilter"
if test "$host_os" = "mingw32"; then
- FFMPEG_CONFFLAGS="$FFMPEG_CONFFLAGS --yasmexe=../yasm-1.2.0-win32.exe --arch=x86"
+ FFMPEG_CONFFLAGS="$FFMPEG_CONFFLAGS --arch=x86"
fi
if test "$enable_lto" = "yes"; then
FFMPEG_CONFFLAGS="$FFMPEG_CONFFLAGS --enable-lto"
diff --git a/bundle/COPYING.yasm b/bundle/COPYING.yasm
deleted file mode 100644
index ddd3c01fa5..0000000000
--- a/bundle/COPYING.yasm
+++ /dev/null
@@ -1,61 +0,0 @@
-Yasm is Copyright (c) 2001-2010 Peter Johnson and other Yasm developers.
-
-Yasm developers and/or contributors include:
- Peter Johnson
- Michael Urman
- Brian Gladman (Visual Studio build files, other fixes)
- Stanislav Karchebny (options parser)
- Mathieu Monnier (SSE4 instruction patches, NASM preprocessor additions)
- Anonymous "NASM64" developer (NASM preprocessor fixes)
- Stephen Polkowski (x86 instruction patches)
- Henryk Richter (Mach-O object format)
- Ben Skeggs (patches, bug reports)
- Alexei Svitkine (GAS preprocessor)
- Samuel Thibault (TASM parser and frontend)
-
------------------------------------
-Yasm licensing overview and summary
------------------------------------
-
-Note: This document does not provide legal advice nor is it the actual
-license of any part of Yasm. See the individual licenses for complete
-details. Consult a lawyer for legal advice.
-
-The primary license of Yasm is the 2-clause BSD license. Please use this
-license if you plan on submitting code to the project.
-
-Yasm has absolutely no warranty; not even for merchantibility or fitness
-for a particular purpose.
-
--------
-Libyasm
--------
-Libyasm is 2-clause or 3-clause BSD licensed, with the exception of
-bitvect, which is triple-licensed under the Artistic license, GPL, and
-LGPL. Libyasm is thus GPL and LGPL compatible. In addition, this also
-means that libyasm is free for binary-only distribution as long as the
-terms of the 3-clause BSD license and Artistic license (as it applies to
-bitvect) are fulfilled.
-
--------
-Modules
--------
-The modules are 2-clause or 3-clause BSD licensed.
-
----------
-Frontends
----------
-The frontends are 2-clause BSD licensed.
-
--------------
-License Texts
--------------
-The full text of all licenses are provided in separate files in the source
-distribution. Each source file may include the entire license (in the case
-of the BSD and Artistic licenses), or may reference the GPL or LGPL license
-file.
-
-BSD.txt - 2-clause and 3-clause BSD licenses
-Artistic.txt - Artistic license
-GNU_GPL-2.0 - GNU General Public License
-GNU_LGPL-2.0 - GNU Library General Public License
diff --git a/bundle/Makefile.am b/bundle/Makefile.am
index 896c503518..bab2301c8a 100644
--- a/bundle/Makefile.am
+++ b/bundle/Makefile.am
@@ -12,6 +12,12 @@ if WINDOWS
rm -f ../*.dll
endif
+install:
+ cd ffmpeg && $(MAKE) install-libs
+
+uninstall:
+ cd ffmpeg && $(MAKE) uninstall-libs
+
clean-local: del-dlls
cd ffmpeg && $(MAKE) clean
diff --git a/configure.ac b/configure.ac
index 230986785f..e875775951 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.59)
-AC_INIT(StepMania 5, beta 0, [https://github.com/stepmania/stepmania], StepMania, [http://stepmania.com])
+AC_INIT(StepMania, 5.0, [https://github.com/stepmania/stepmania], StepMania, [http://stepmania.com])
AC_CONFIG_SRCDIR([src/StepMania.cpp])
AC_CONFIG_AUX_DIR(autoconf)
AC_CANONICAL_TARGET
@@ -202,6 +202,11 @@ if test "$with_prof" = "yes"; then
test "$DEFAULT_LDFLAGS" = "yes" && LDFLAGS="$LDFLAGS -pg"
fi
+dnl Usually in libc, but not always(?)
+if test "$unix" = "yes"; then
+ AC_SEARCH_LIBS(clock_gettime, rt,, AC_ERROR([clock_gettime() not available?]))
+fi
+
SM_OPENGL
SM_X11
GL_CFLAGS="$GL_CFLAGS $XCFLAGS"
@@ -344,6 +349,7 @@ AM_CONDITIONAL(HAVE_PTHREAD, test "$have_pthread" = "yes")
# Always:
AC_DEFINE(_GNU_SOURCE, 1, [Use GNU extensions])
AC_DEFINE(__STDC_FORMAT_MACROS, 1, [Use PRId64 and similar])
+AC_DEFINE(USE_GITVERSION, 1, [We are generating gitversion.h])
AM_CONDITIONAL(HAVE_ALSA, test x$alsa != xfalse )
AM_CONDITIONAL(HAVE_GTK, test "$enable_gtk2" != "no" )
diff --git a/src/Actor.cpp b/src/Actor.cpp
index 402899c411..9dac9f0454 100644
--- a/src/Actor.cpp
+++ b/src/Actor.cpp
@@ -164,6 +164,7 @@ Actor::Actor()
m_size = RageVector2( 1, 1 );
InitState();
m_pParent = NULL;
+ m_FakeParent= NULL;
m_bFirstUpdate = true;
}
@@ -183,6 +184,7 @@ Actor::Actor( const Actor &cpy ):
#define CPY(x) x = cpy.x
CPY( m_sName );
CPY( m_pParent );
+ CPY( m_FakeParent );
CPY( m_pLuaInstance );
CPY( m_baseRotation );
@@ -279,24 +281,56 @@ void Actor::LoadFromNode( const XNode* pNode )
PlayCommandNoRecurse( Message("Init") );
}
+bool Actor::PartiallyOpaque()
+{
+ return m_pTempState->diffuse[0].a > 0 || m_pTempState->diffuse[1].a > 0 ||
+ m_pTempState->diffuse[2].a > 0 || m_pTempState->diffuse[3].a > 0 ||
+ m_pTempState->glow.a > 0;
+}
+
void Actor::Draw()
{
if( !m_bVisible ||
m_fHibernateSecondsLeft > 0 ||
this->EarlyAbortDraw() )
+ {
return; // early abort
+ }
+ bool fake_parent_partially_opaque= true;
+ if(m_FakeParent)
+ {
+ if(!m_FakeParent->m_bVisible || m_FakeParent->m_fHibernateSecondsLeft > 0
+ || m_FakeParent->EarlyAbortDraw())
+ {
+ return;
+ }
+ m_FakeParent->PreDraw();
+ fake_parent_partially_opaque= m_FakeParent->PartiallyOpaque();
+ }
this->PreDraw();
ASSERT( m_pTempState != NULL );
- if( m_pTempState->diffuse[0].a > 0 || m_pTempState->diffuse[1].a > 0 || m_pTempState->diffuse[2].a > 0 || m_pTempState->diffuse[3].a > 0 || m_pTempState->glow.a > 0 ) // This Actor is not fully transparent
- {
+ if(PartiallyOpaque() && fake_parent_partially_opaque)
+ {
+ if(m_FakeParent)
+ {
+ m_FakeParent->BeginDraw();
+ }
// call the most-derived versions
this->BeginDraw();
this->DrawPrimitives(); // call the most-derived version of DrawPrimitives();
this->EndDraw();
+ if(m_FakeParent)
+ {
+ m_FakeParent->EndDraw();
+ }
}
this->PostDraw();
+ if(m_FakeParent)
+ {
+ m_FakeParent->PostDraw();
+ }
m_pTempState = NULL;
}
@@ -1300,9 +1334,9 @@ void Actor::QueueMessage( const RString& sMessageName )
TI.m_sCommandName = "!" + sMessageName;
}
-void Actor::AddCommand( const RString &sCmdName, apActorCommands apac )
+void Actor::AddCommand( const RString &sCmdName, apActorCommands apac, bool warn )
{
- if( HasCommand(sCmdName) )
+ if( HasCommand(sCmdName) && warn)
{
RString sWarning = GetLineage()+"'s command '"+sCmdName+"' defined twice";
LuaHelpers::ReportScriptError(sWarning, "COMMAND_DEFINED_TWICE");
@@ -1705,6 +1739,32 @@ public:
pParent->PushSelf(L);
return 1;
}
+ static int GetFakeParent(T* p, lua_State *L)
+ {
+ Actor* fake= p->GetFakeParent();
+ if(fake == NULL)
+ {
+ lua_pushnil(L);
+ }
+ else
+ {
+ fake->PushSelf(L);
+ }
+ return 1;
+ }
+ static int SetFakeParent(T* p, lua_State* L)
+ {
+ if(lua_isnoneornil(L, 1))
+ {
+ p->SetFakeParent(NULL);
+ }
+ else
+ {
+ Actor* fake= Luna::check(L, 1);
+ p->SetFakeParent(fake);
+ }
+ COMMON_RETURN_SELF;
+ }
static int Draw( T* p, lua_State *L )
{
LUA->YieldLua();
@@ -1876,6 +1936,8 @@ public:
ADD_METHOD( GetName );
ADD_METHOD( GetParent );
+ ADD_METHOD( GetFakeParent );
+ ADD_METHOD( SetFakeParent );
ADD_METHOD( Draw );
}
diff --git a/src/Actor.h b/src/Actor.h
index 2be5f711bd..7957306409 100644
--- a/src/Actor.h
+++ b/src/Actor.h
@@ -232,6 +232,8 @@ public:
float aux;
};
+ // PartiallyOpaque broken out of Draw for reuse and clarity.
+ bool PartiallyOpaque();
/**
* @brief Calls multiple functions for drawing the Actors.
*
@@ -305,6 +307,9 @@ public:
* @return the Actor's lineage. */
RString GetLineage() const;
+ void SetFakeParent(Actor* mailman) { m_FakeParent= mailman; }
+ Actor* GetFakeParent() { return m_FakeParent; }
+
/**
* @brief Retrieve the Actor's x position.
* @return the Actor's x position. */
@@ -577,7 +582,7 @@ public:
virtual void PushContext( lua_State *L );
// Named commands
- void AddCommand( const RString &sCmdName, apActorCommands apac );
+ void AddCommand( const RString &sCmdName, apActorCommands apac, bool warn= true );
bool HasCommand( const RString &sCmdName ) const;
const apActorCommands *GetCommand( const RString &sCommandName ) const;
void PlayCommand( const RString &sCommandName ) { HandleMessage( Message(sCommandName) ); } // convenience
@@ -607,6 +612,10 @@ protected:
RString m_sName;
/** @brief the current parent of this Actor if it exists. */
Actor *m_pParent;
+ // m_FakeParent exists to provide a way to render the actor inside another's
+ // state without making that actor the parent. It's like having multiple
+ // parents. -Kyz
+ Actor* m_FakeParent;
/** @brief Some general information about the Tween. */
struct TweenInfo
diff --git a/src/ActorMultiVertex.cpp b/src/ActorMultiVertex.cpp
index c569eb3d7a..b3c1102311 100644
--- a/src/ActorMultiVertex.cpp
+++ b/src/ActorMultiVertex.cpp
@@ -7,6 +7,7 @@
#include "RageLog.h"
#include "RageDisplay.h"
#include "RageTexture.h"
+#include "RageTimer.h"
#include "RageUtil.h"
#include "ActorUtil.h"
#include "Foreach.h"
@@ -62,6 +63,12 @@ ActorMultiVertex::ActorMultiVertex()
_EffectMode = EffectMode_Normal;
_TextureMode = TextureMode_Modulate;
+ _splines.resize(num_vert_splines);
+ for(size_t i= 0; i < num_vert_splines; ++i)
+ {
+ _splines[i].redimension(3);
+ _splines[i].m_owned_by_actor= true;
+ }
}
ActorMultiVertex::~ActorMultiVertex()
@@ -78,6 +85,7 @@ ActorMultiVertex::ActorMultiVertex( const ActorMultiVertex &cpy ):
CPY( AMV_start );
CPY( _EffectMode );
CPY( _TextureMode );
+ CPY( _splines );
#undef CPY
if( cpy._Texture != NULL )
@@ -309,6 +317,62 @@ bool ActorMultiVertex::EarlyAbortDraw() const
return false;
}
+void ActorMultiVertex::SetVertsFromSplinesInternal(size_t num_splines, size_t offset)
+{
+ vector& verts= AMV_DestTweenState().vertices;
+ size_t first= AMV_DestTweenState().FirstToDraw + offset;
+ size_t num_verts= AMV_DestTweenState().GetSafeNumToDraw(AMV_DestTweenState()._DrawMode, AMV_DestTweenState().NumToDraw) - offset;
+ vector tper(num_splines, 0.0f);
+ float num_parts= static_cast(num_verts) /
+ static_cast(num_splines);
+ for(size_t i= 0; i < num_splines; ++i)
+ {
+ tper[i]= _splines[i].get_max_t() / num_parts;
+ }
+ for(size_t v= 0; v < num_verts; ++v)
+ {
+ vector pos;
+ const int spi= v%num_splines;
+ float part= static_cast(v/num_splines);
+ _splines[spi].evaluate(part * tper[spi], pos);
+ verts[v+first].p.x= pos[0];
+ verts[v+first].p.y= pos[1];
+ verts[v+first].p.z= pos[2];
+ }
+}
+
+void ActorMultiVertex::SetVertsFromSplines()
+{
+ if(AMV_DestTweenState().vertices.empty()) { return; }
+ switch(AMV_DestTweenState()._DrawMode)
+ {
+ case DrawMode_Quads:
+ SetVertsFromSplinesInternal(4, 0);
+ break;
+ case DrawMode_QuadStrip:
+ case DrawMode_Strip:
+ SetVertsFromSplinesInternal(2, 0);
+ break;
+ case DrawMode_Fan:
+ // Skip the first vert because it is the center of the fan. -Kyz
+ SetVertsFromSplinesInternal(1, 1);
+ break;
+ case DrawMode_Triangles:
+ case DrawMode_SymmetricQuadStrip:
+ SetVertsFromSplinesInternal(3, 0);
+ break;
+ case DrawMode_LineStrip:
+ SetVertsFromSplinesInternal(1, 0);
+ break;
+ }
+}
+
+CubicSplineN* ActorMultiVertex::GetSpline(size_t i)
+{
+ ASSERT(i < num_vert_splines);
+ return &(_splines[i]);
+}
+
void ActorMultiVertex::SetCurrentTweenStart()
{
AMV_start= AMV_current;
@@ -638,6 +702,23 @@ public:
COMMON_RETURN_SELF;
}
+ static int GetSpline(T* p, lua_State* L)
+ {
+ size_t i= static_cast(IArg(1)-1);
+ if(i >= ActorMultiVertex::num_vert_splines)
+ {
+ luaL_error(L, "Spline index must be greater than 0 and less than or equal to %zu.", ActorMultiVertex::num_vert_splines);
+ }
+ p->GetSpline(i)->PushSelf(L);
+ return 1;
+ }
+
+ static int SetVertsFromSplines(T* p, lua_State* L)
+ {
+ p->SetVertsFromSplines();
+ COMMON_RETURN_SELF;
+ }
+
static int SetTexture( T* p, lua_State *L )
{
RageTexture *Texture = Luna::check(L, 1);
@@ -679,6 +760,9 @@ public:
ADD_METHOD( GetCurrFirstToDraw );
ADD_METHOD( GetCurrNumToDraw );
+ ADD_METHOD( GetSpline );
+ ADD_METHOD( SetVertsFromSplines );
+
// Copy from RageTexture
ADD_METHOD( SetTexture );
ADD_METHOD( GetTexture );
diff --git a/src/ActorMultiVertex.h b/src/ActorMultiVertex.h
index 176d2a7cad..5b598cb310 100644
--- a/src/ActorMultiVertex.h
+++ b/src/ActorMultiVertex.h
@@ -1,7 +1,9 @@
/** @brief ActorMultiVertex - A texture created from multiple textures. */
#include "Actor.h"
+#include "CubicSpline.h"
#include "RageDisplay.h"
+#include "RageMath.h"
#include "RageTextureID.h"
enum DrawMode
@@ -26,6 +28,7 @@ class RageTexture;
class ActorMultiVertex: public Actor
{
public:
+ static const size_t num_vert_splines= 4;
ActorMultiVertex();
ActorMultiVertex( const ActorMultiVertex &cpy );
virtual ~ActorMultiVertex();
@@ -35,7 +38,9 @@ public:
struct AMV_TweenState
{
- AMV_TweenState(): _DrawMode(DrawMode_Invalid), FirstToDraw(0), NumToDraw(-1), line_width(1.0f) {}
+ AMV_TweenState(): _DrawMode(DrawMode_Invalid), FirstToDraw(0),
+ NumToDraw(-1), line_width(1.0f)
+ {}
static void MakeWeightedAverage(AMV_TweenState& average_out, const AMV_TweenState& ts1, const AMV_TweenState& ts2, float percent_between);
bool operator==(const AMV_TweenState& other) const;
bool operator!=(const AMV_TweenState& other) const { return !operator==(other); }
@@ -102,6 +107,10 @@ public:
void SetVertexColor( int index , RageColor c );
void SetVertexCoords( int index , float TexCoordX , float TexCoordY );
+ inline void SetVertsFromSplinesInternal(size_t num_splines, size_t start_vert);
+ void SetVertsFromSplines();
+ CubicSplineN* GetSpline(size_t i);
+
virtual void PushSelf( lua_State *L );
private:
@@ -117,6 +126,10 @@ private:
EffectMode _EffectMode;
TextureMode _TextureMode;
+
+ // Four splines for controlling vert positions, because quads drawmode
+ // requires four. -Kyz
+ vector _splines;
};
/**
diff --git a/src/ArrowEffects.cpp b/src/ArrowEffects.cpp
index 76f2a17d94..ae0ee06754 100644
--- a/src/ArrowEffects.cpp
+++ b/src/ArrowEffects.cpp
@@ -82,16 +82,16 @@ namespace
void ArrowEffects::Update()
{
- const Style* pStyle = GAMESTATE->GetCurrentStyle();
-
static float fLastTime = 0;
float fTime = RageTimer::GetTimeSinceStartFast();
FOREACH_EnabledPlayer( pn )
{
+ const Style* pStyle = GAMESTATE->GetCurrentStyle(pn);
const Style::ColumnInfo* pCols = pStyle->m_ColumnInfo[pn];
const SongPosition &position = GAMESTATE->m_bIsUsingStepTiming
? GAMESTATE->m_pPlayerState[pn]->m_Position : GAMESTATE->m_Position;
+ const float field_zoom= GAMESTATE->m_pPlayerState[pn]->m_NotefieldZoom;
PerPlayerData &data = g_EffectData[pn];
@@ -127,8 +127,8 @@ void ArrowEffects::Update()
for( int i=iStartCol; i<=iEndCol; i++ )
{
- data.m_fMinTornadoX[iColNum] = min( data.m_fMinTornadoX[iColNum], pCols[i].fXOffset );
- data.m_fMaxTornadoX[iColNum] = max( data.m_fMaxTornadoX[iColNum], pCols[i].fXOffset );
+ data.m_fMinTornadoX[iColNum] = min( data.m_fMinTornadoX[iColNum], pCols[i].fXOffset * field_zoom );
+ data.m_fMaxTornadoX[iColNum] = max( data.m_fMaxTornadoX[iColNum], pCols[i].fXOffset * field_zoom);
}
}
@@ -439,7 +439,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
{
float fPixelOffsetFromCenter = 0; // fill this in below
- const Style* pStyle = GAMESTATE->GetCurrentStyle();
+ const Style* pStyle = GAMESTATE->GetCurrentStyle(pPlayerState->m_PlayerNumber);
const float* fEffects = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects;
// TODO: Don't index by PlayerNumber.
@@ -448,7 +448,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
if( fEffects[PlayerOptions::EFFECT_TORNADO] != 0 )
{
- const float fRealPixelOffset = pCols[iColNum].fXOffset;
+ const float fRealPixelOffset = pCols[iColNum].fXOffset * pPlayerState->m_NotefieldZoom;
const float fPositionBetween = SCALE( fRealPixelOffset, data.m_fMinTornadoX[iColNum], data.m_fMaxTornadoX[iColNum],
TORNADO_POSITION_SCALE_TO_LOW, TORNADO_POSITION_SCALE_TO_HIGH );
float fRads = acosf( fPositionBetween );
@@ -469,8 +469,8 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
const int iFirstCol = 0;
const int iLastCol = pStyle->m_iColsPerPlayer-1;
const int iNewCol = SCALE( iColNum, iFirstCol, iLastCol, iLastCol, iFirstCol );
- const float fOldPixelOffset = pCols[iColNum].fXOffset;
- const float fNewPixelOffset = pCols[iNewCol].fXOffset;
+ const float fOldPixelOffset = pCols[iColNum].fXOffset * pPlayerState->m_NotefieldZoom;
+ const float fNewPixelOffset = pCols[iNewCol].fXOffset * pPlayerState->m_NotefieldZoom;
const float fDistance = fNewPixelOffset - fOldPixelOffset;
fPixelOffsetFromCenter += fDistance * fEffects[PlayerOptions::EFFECT_FLIP];
}
@@ -515,7 +515,7 @@ float ArrowEffects::GetXPos( const PlayerState* pPlayerState, int iColNum, float
}
}
- fPixelOffsetFromCenter += pCols[iColNum].fXOffset;
+ fPixelOffsetFromCenter += pCols[iColNum].fXOffset * pPlayerState->m_NotefieldZoom;
if( fEffects[PlayerOptions::EFFECT_TINY] != 0 )
{
@@ -764,10 +764,11 @@ bool ArrowEffects::NeedZBuffer( const PlayerState* pPlayerState )
float ArrowEffects::GetZoom( const PlayerState* pPlayerState )
{
float fZoom = 1.0f;
- // FIXME: Move the zoom values into Style
- if( GAMESTATE->GetCurrentStyle()->m_bNeedsZoomOutWith2Players &&
- (GAMESTATE->GetNumSidesJoined()==2 || GAMESTATE->AnyPlayersAreCpu()) )
- fZoom *= 0.6f;
+ // Design change: Instead of having a flag in the style that toggles a
+ // fixed zoom (0.6) that is only applied to the columns, ScreenGameplay now
+ // calculates a zoom factor to apply to the notefield and puts it in the
+ // PlayerState. -Kyz
+ fZoom*= pPlayerState->m_NotefieldZoom;
float fTinyPercent = pPlayerState->m_PlayerOptions.GetCurrent().m_fEffects[PlayerOptions::EFFECT_TINY];
if( fTinyPercent != 0 )
diff --git a/src/ArrowEffects.h b/src/ArrowEffects.h
index 1ee054d333..8629c8bd33 100644
--- a/src/ArrowEffects.h
+++ b/src/ArrowEffects.h
@@ -19,6 +19,14 @@ public:
return GetYOffset( pPlayerState, iCol, fNoteBeat, fThrowAway, bThrowAway, bAbsolute );
}
+ static void GetXYZPos(const PlayerState* player_state, int col, float y_offset, float y_reverse_offset, vector& ret, bool with_reverse= true)
+ {
+ ASSERT(ret.size() == 3);
+ ret[0]= GetXPos(player_state, col, y_offset);
+ ret[1]= GetYPos(player_state, col, y_offset, y_reverse_offset, with_reverse);
+ ret[2]= GetZPos(player_state, col, y_offset);
+ }
+
/**
* @brief Retrieve the actual display position.
*
diff --git a/src/BPMDisplay.cpp b/src/BPMDisplay.cpp
index 3e138d9155..1f10ccbadc 100644
--- a/src/BPMDisplay.cpp
+++ b/src/BPMDisplay.cpp
@@ -213,9 +213,9 @@ void BPMDisplay::SetBpmFromSteps( const Steps* pSteps )
void BPMDisplay::SetBpmFromCourse( const Course* pCourse )
{
ASSERT( pCourse != NULL );
- ASSERT( GAMESTATE->GetCurrentStyle() != NULL );
+ ASSERT( GAMESTATE->GetCurrentStyle(PLAYER_INVALID) != NULL );
- StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType;
+ StepsType st = GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType;
Trail *pTrail = pCourse->GetTrail( st );
// GetTranslitFullTitle because "Crashinfo.txt is garbled because of the ANSI output as usual." -f
ASSERT_M( pTrail != NULL, ssprintf("Course '%s' has no trail for StepsType '%s'", pCourse->GetTranslitFullTitle().c_str(), StringConversion::ToString(st).c_str() ) );
@@ -259,7 +259,7 @@ void BPMDisplay::SetFromGameState()
}
if( GAMESTATE->m_pCurCourse.Get() )
{
- if( GAMESTATE->GetCurrentStyle() == NULL )
+ if( GAMESTATE->GetCurrentStyle(PLAYER_INVALID) == NULL )
; // This is true when backing out from ScreenSelectCourse to ScreenTitleMenu. So, don't call SetBpmFromCourse where an assert will fire.
else
SetBpmFromCourse( GAMESTATE->m_pCurCourse );
diff --git a/src/Background.cpp b/src/Background.cpp
index d607a20122..e70e86e6e9 100644
--- a/src/Background.cpp
+++ b/src/Background.cpp
@@ -205,7 +205,7 @@ void BackgroundImpl::Init()
{
bOneOrMoreChars = true;
// Disable dancing characters if Beginner Helper will be showing.
- if( PREFSMAN->m_bShowBeginnerHelper && BeginnerHelper::CanUse() &&
+ if( PREFSMAN->m_bShowBeginnerHelper && BeginnerHelper::CanUse(p) &&
GAMESTATE->m_pCurSteps[p] && GAMESTATE->m_pCurSteps[p]->GetDifficulty() == Difficulty_Beginner )
bShowingBeginnerHelper = true;
}
diff --git a/src/BeginnerHelper.cpp b/src/BeginnerHelper.cpp
index 5c6f2968ee..f43bf118c1 100644
--- a/src/BeginnerHelper.cpp
+++ b/src/BeginnerHelper.cpp
@@ -78,7 +78,7 @@ BeginnerHelper::~BeginnerHelper()
bool BeginnerHelper::Init( int iDancePadType )
{
ASSERT( !m_bInitialized );
- if( !CanUse() )
+ if( !CanUse(PLAYER_INVALID) )
return false;
// If no players were successfully added, bail.
@@ -200,7 +200,7 @@ void BeginnerHelper::AddPlayer( PlayerNumber pn, const NoteData &ns )
ASSERT( pn >= 0 && pn < NUM_PLAYERS );
ASSERT( GAMESTATE->IsHumanPlayer(pn) );
- if( !CanUse() )
+ if( !CanUse(pn) )
return;
const Character *Character = GAMESTATE->m_pCurCharacters[pn];
@@ -212,13 +212,20 @@ void BeginnerHelper::AddPlayer( PlayerNumber pn, const NoteData &ns )
m_bPlayerEnabled[pn] = true;
}
-bool BeginnerHelper::CanUse()
+bool BeginnerHelper::CanUse(PlayerNumber pn)
{
for (int i=0; iGetCurrentStyle()->m_bCanUseBeginnerHelper;
+ // This does not pass PLAYER_INVALID to GetCurrentStyle because that would
+ // only check the first non-NULL style. Both styles need to be checked. -Kyz
+ if(pn == PLAYER_INVALID)
+ {
+ return GAMESTATE->GetCurrentStyle(PLAYER_1)->m_bCanUseBeginnerHelper ||
+ GAMESTATE->GetCurrentStyle(PLAYER_2)->m_bCanUseBeginnerHelper;
+ }
+ return GAMESTATE->GetCurrentStyle(pn)->m_bCanUseBeginnerHelper;
}
void BeginnerHelper::DrawPrimitives()
diff --git a/src/BeginnerHelper.h b/src/BeginnerHelper.h
index a5941e7e85..38bb8b144a 100644
--- a/src/BeginnerHelper.h
+++ b/src/BeginnerHelper.h
@@ -18,7 +18,7 @@ public:
bool Init( int iDancePadType );
bool IsInitialized() { return m_bInitialized; }
- static bool CanUse();
+ static bool CanUse(PlayerNumber pn);
void AddPlayer( PlayerNumber pn, const NoteData &nd );
void ShowStepCircle( PlayerNumber pn, int CSTEP );
bool m_bShowBackground;
diff --git a/src/CourseUtil.cpp b/src/CourseUtil.cpp
index 44ed9212c4..5c67882ed6 100644
--- a/src/CourseUtil.cpp
+++ b/src/CourseUtil.cpp
@@ -95,14 +95,14 @@ void CourseUtil::SortCoursePointerArrayByDifficulty( vector &vpCoursesI
void CourseUtil::SortCoursePointerArrayByRanking( vector &vpCoursesInOut )
{
for( unsigned i=0; iUpdateCourseStats( GAMESTATE->GetCurrentStyle()->m_StepsType );
+ vpCoursesInOut[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType );
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByRanking );
}
void CourseUtil::SortCoursePointerArrayByTotalDifficulty( vector &vpCoursesInOut )
{
for( unsigned i=0; iUpdateCourseStats( GAMESTATE->GetCurrentStyle()->m_StepsType );
+ vpCoursesInOut[i]->UpdateCourseStats( GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType );
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByTotalDifficulty );
}
@@ -176,7 +176,7 @@ void CourseUtil::SortCoursePointerArrayByAvgDifficulty( vector &vpCours
course_sort_val.clear();
for( unsigned i = 0; i < vpCoursesInOut.size(); ++i )
{
- int iMeter = vpCoursesInOut[i]->GetMeter( GAMESTATE->GetCurrentStyle()->m_StepsType, Difficulty_Medium );
+ int iMeter = vpCoursesInOut[i]->GetMeter( GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType, Difficulty_Medium );
course_sort_val[vpCoursesInOut[i]] = ssprintf( "%06i", iMeter );
}
sort( vpCoursesInOut.begin(), vpCoursesInOut.end(), CompareCoursePointersByTitle );
@@ -448,8 +448,8 @@ bool EditCourseUtil::ValidateEditCourseName( const RString &sAnswer, RString &sE
void EditCourseUtil::UpdateAndSetTrail()
{
- ASSERT( GAMESTATE->m_pCurStyle != NULL );
- StepsType st = GAMESTATE->m_pCurStyle->m_StepsType;
+ ASSERT( GAMESTATE->GetCurrentStyle(PLAYER_INVALID) != NULL );
+ StepsType st = GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType;
Trail *pTrail = NULL;
if( GAMESTATE->m_pCurCourse )
pTrail = GAMESTATE->m_pCurCourse->GetTrailForceRegenCache( st );
diff --git a/src/CubicSpline.cpp b/src/CubicSpline.cpp
new file mode 100644
index 0000000000..142f305aa0
--- /dev/null
+++ b/src/CubicSpline.cpp
@@ -0,0 +1,1037 @@
+#include "global.h"
+#include "CubicSpline.h"
+#include "RageLog.h"
+#include "RageUtil.h"
+#include
+using std::list;
+
+// Spline solving optimization:
+// The tridiagonal part of the system of equations for a spline of size n is
+// the same for all splines of size n. It's not affected by the positions
+// of the points.
+// So spline solving can be split into two parts. Part 1 solves the
+// tridiagonal and stores the result. Part 2 takes the solved tridiagonal
+// and applies it to the positions to find the coefficients.
+// Part 1 only needs to be done when the number of points changes. So this
+// could cut solve time for the same number of points substantially.
+// Further optimization is to cache the part 1 results for the last 16 spline
+// sizes solved, to reduce the cost of using lots of splines with a small
+// number of sizes.
+
+struct SplineSolutionCache
+{
+ struct Entry
+ {
+ vector diagonals;
+ vector multiples;
+ };
+ void solve_diagonals_straight(vector& diagonals, vector& multiples);
+ void solve_diagonals_looped(vector& diagonals, vector& multiples);
+private:
+ void prep_inner(size_t last, vector& out);
+ bool find_in_cache(list& cache, vector& outd, vector& outm);
+ void add_to_cache(list& cache, vector& outd, vector& outm);
+ list straight_diagonals;
+ list looped_diagonals;
+};
+
+const size_t solution_cache_limit= 16;
+
+bool SplineSolutionCache::find_in_cache(list& cache, vector& outd, vector& outm)
+{
+ size_t out_size= outd.size();
+ for(list::iterator entry= cache.begin();
+ entry != cache.end(); ++entry)
+ {
+ if(out_size == entry->diagonals.size())
+ {
+ for(size_t i= 0; i < out_size; ++i)
+ {
+ outd[i]= entry->diagonals[i];
+ }
+ outm.resize(entry->multiples.size());
+ for(size_t i= 0; i < entry->multiples.size(); ++i)
+ {
+ outm[i]= entry->multiples[i];
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void SplineSolutionCache::add_to_cache(list& cache, vector& outd, vector& outm)
+{
+ if(cache.size() >= solution_cache_limit)
+ {
+ cache.pop_back();
+ }
+ cache.push_front(Entry());
+ cache.front().diagonals= outd;
+ cache.front().multiples= outm;
+}
+
+void SplineSolutionCache::prep_inner(size_t last, vector& out)
+{
+ for(size_t i= 1; i < last; ++i)
+ {
+ out[i]= 4.0f;
+ }
+}
+
+void SplineSolutionCache::solve_diagonals_straight(vector& diagonals, vector& multiples)
+{
+ if(find_in_cache(straight_diagonals, diagonals, multiples))
+ {
+ return;
+ }
+
+ // Solution steps:
+ // Two stages: First, work downwards, zeroing the 1s below each diagonal.
+ // | 2 1 0 0 | -> | 2 1 0 0 | -> | 2 1 0 0 | -> | 2 1 0 0 |
+ // | 1 4 1 0 | -> | 0 a 1 0 | -> | 0 d 1 0 | -> | 0 a 1 0 |
+ // | 0 1 4 1 | -> | 0 1 4 1 | -> | 0 0 b 1 | -> | 0 0 b 1 |
+ // | 0 0 1 2 | -> | 0 0 1 2 | -> | 0 0 1 2 | -> | 0 0 0 c |
+ // Second stage: Work upwards, zeroing the 1s above each diagonal.
+ // V
+ // | 2 1 0 0 | -> | 2 1 0 0 | -> | 2 0 0 0 |
+ // | 0 a 1 0 | -> | 0 a 0 0 | -> | 0 a 0 0 |
+ // | 0 0 b 0 | -> | 0 0 b 0 | -> | 0 0 b 0 |
+ // | 0 0 0 c | -> | 0 0 0 c | -> | 0 0 0 c |
+
+ size_t last= diagonals.size();
+ diagonals[0]= 2.0f;
+ prep_inner(last-1, diagonals);
+ diagonals[last-1]= 2.0f;
+
+ // Stage one.
+ // Operation: Add row[0] * -.5 to row[1] to zero [r1][c0].
+ diagonals[1]-= .5f;
+ multiples.push_back(.5f);
+ for(size_t i= 1; i < last-1; ++i)
+ {
+ // Operation: Add row[i] / -[ri][ci] to row[i+1] to zero [ri+1][ci].
+ const float diag_recip= 1.0f / diagonals[i];
+ diagonals[i+1]-= diag_recip;
+ multiples.push_back(diag_recip);
+ }
+ // Stage two.
+ for(size_t i= last-1; i > 0; --i)
+ {
+ // Operation: Add row [i] / -[ri][ci] to row[i-1] to zero [ri-1][ci].
+ multiples.push_back(1.0f / diagonals[i]);
+ }
+ // Solving finished.
+ add_to_cache(straight_diagonals, diagonals, multiples);
+}
+
+void SplineSolutionCache::solve_diagonals_looped(vector& diagonals, vector& multiples)
+{
+ if(find_in_cache(looped_diagonals, diagonals, multiples))
+ {
+ return;
+ }
+
+ // The steps to solve the system of equations look like this:
+ // Stage one: Zero the 1s below the diagonals.
+ // | 4 1 0 0 1 | -> | 4 1 0 0 1 | -> | 4 1 0 0 1 | -> | 4 1 0 0 1 |
+ // | 1 4 1 0 0 | -> | 0 a 1 0 u | -> | 0 a 1 0 u | -> | 0 a 1 0 u |
+ // | 0 1 4 1 0 | -> | 0 1 4 1 0 | -> | 0 0 b 1 v | -> | 0 0 b 1 v |
+ // | 0 0 1 4 1 | -> | 0 0 1 4 1 | -> | 0 0 1 4 1 | -> | 0 0 0 c w |
+ // | 1 0 0 1 4 | -> | 1 0 0 1 4 | -> | 1 0 0 1 4 | -> | 1 0 0 1 4 |
+ // V
+ // | 4 1 0 0 1 |
+ // | 0 a 1 0 u |
+ // | 0 0 b 1 v |
+ // | 0 0 0 c w |
+ // | 1 0 0 0 d |
+ // The top of the right column is left unzeroed because it will be changed
+ // by stage two, nullifying the effect of zeroing it.
+ // V Stage two: Zero the 1s above the diagonals, starting with the second
+ // to last row to avoid carrying effects across the left column.
+ // | 4 1 0 0 1 | -> | 4 1 0 0 1 | -> | 4 0 0 0 z | -> | 4 0 0 0 z |
+ // | 0 a 1 0 u | -> | 0 a 0 0 y | -> | 0 a 0 0 y | -> | 0 a 0 0 y |
+ // | 0 0 b 0 x | -> | 0 0 b 0 x | -> | 0 0 b 0 x | -> | 0 0 b 0 x |
+ // | 0 0 0 c w | -> | 0 0 0 c w | -> | 0 0 0 c w | -> | 0 0 0 c w |
+ // | 1 0 0 0 d | -> | 1 0 0 0 d | -> | 1 0 0 0 d | -> | 0 0 0 0 f |
+ // V Stage three: Zero the right column.
+ // | 4 0 0 0 0 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 |
+ // | 0 a 0 0 y | -> | 0 a 0 0 0 | -> | 0 a 0 0 0 | -> | 0 a 0 0 0 |
+ // | 0 0 b 0 x | -> | 0 0 b 0 x | -> | 0 0 b 0 0 | -> | 0 0 b 0 0 |
+ // | 0 0 0 c w | -> | 0 0 0 c w | -> | 0 0 0 c w | -> | 0 0 0 c 0 |
+ // | 0 0 0 0 f | -> | 0 0 0 0 f | -> | 0 0 0 0 f | -> | 0 0 0 0 f |
+
+ size_t last= diagonals.size();
+ diagonals[0]= 4.0f;
+ prep_inner(last, diagonals);
+ // right_column is sized to not store the diagonal .
+ vector right_column(diagonals.size()-1, 0.0f);
+ right_column[0]= 1.0f;
+ right_column[last-2]= 1.0f;
+
+ // Stage one.
+ for(size_t i= 0; i < last-2; ++i)
+ {
+ // Operation: Add row[i] / -[ri][ci] to row[i+1] to zero [ri+1][ci].
+ const float diag_recip= 1.0f / diagonals[i];
+ diagonals[i+1]-= diag_recip;
+ right_column[i+1]-= right_column[i] * diag_recip;
+ multiples.push_back(diag_recip);
+ }
+ // Last step of stage one needs special handling for right_column.
+ // Operation: Add row[l-2] / [rl-2][cl-2] to row[l-1] to zero [rl-1][cl-2].
+ {
+ const float diag_recip= 1.0f / diagonals[last-2];
+ diagonals[last-1]-= right_column[last-2] * diag_recip;
+ multiples.push_back(diag_recip);
+ }
+ // Stage two.
+ for(size_t i= last-2; i > 0; --i)
+ {
+ // Operation: Add row[i] / -[ri][ci] to row[i-1] to zero [ri-1][ci].
+ const float diag_recip= 1.0f / diagonals[i];
+ right_column[i-1]-= right_column[i] * diag_recip;
+ multiples.push_back(diag_recip);
+ }
+ // Last step of stage two.
+ {
+ // Operation: Add row[0] / [r0][c0] to row[l-1] to zero [rl-1][c0].
+ const float diag_recip= 1.0f / diagonals[0];
+ right_column[0]-= right_column[1] * diag_recip;
+ multiples.push_back(diag_recip);
+ }
+ // Stage three.
+ const size_t end= last-1;
+ for(size_t i= 0; i < end; ++i)
+ {
+ // Operation: Add row[e] * (right_column[i] / [re][ce]) to row[i] to
+ // zero right_column[i].
+ multiples.push_back(right_column[i] / diagonals[end]);
+ }
+
+ // Solving finished.
+ add_to_cache(looped_diagonals, diagonals, multiples);
+}
+
+SplineSolutionCache solution_cache;
+
+// loop_space_difference exists to handle numbers that exist in a finite
+// looped space, instead of the flat infinite space.
+// To put it more concretely, loop_space_difference exists to allow a spline
+// to control rotation with wrapping behavior at 0.0 and 2pi, instead of
+// suddenly jerking from 2pi to 0.0. -Kyz
+float loop_space_difference(float a, float b, float spatial_extent);
+float loop_space_difference(float a, float b, float spatial_extent)
+{
+ const float norm_diff= a - b;
+ if(spatial_extent == 0.0f) { return norm_diff; }
+ const float plus_diff= a - (b + spatial_extent);
+ const float minus_diff= a - (b - spatial_extent);
+ const float abs_norm_diff= abs(norm_diff);
+ const float abs_plus_diff= abs(plus_diff);
+ const float abs_minus_diff= abs(minus_diff);
+ if(abs_norm_diff < abs_plus_diff)
+ {
+ if(abs_norm_diff < abs_minus_diff)
+ {
+ return norm_diff;
+ }
+ if(abs_plus_diff < abs_minus_diff)
+ {
+ return plus_diff;
+ }
+ return minus_diff;
+ }
+ if(abs_plus_diff < abs_minus_diff)
+ {
+ return plus_diff;
+ }
+ return minus_diff;
+}
+
+void CubicSpline::solve_looped()
+{
+ if(check_minimum_size()) { return; }
+ size_t last= m_points.size();
+ vector results(m_points.size());
+ vector diagonals(m_points.size());
+ vector multiples;
+ solution_cache.solve_diagonals_looped(diagonals, multiples);
+ results[0]= 3 * loop_space_difference(
+ m_points[1].a, m_points[last-1].a, m_spatial_extent);
+ prep_inner(last, results);
+ results[last-1]= 3 * loop_space_difference(
+ m_points[0].a, m_points[last-2].a, m_spatial_extent);
+
+ // Steps explained in detail in SplineSolutionCache.
+ // Only the operations on the results column are performed here.
+ // Stage one.
+ // SplineSolutionCache's Stage one loop ends at last-2 because it has to
+ // handle right_column. This does not handle right_column, so the loop
+ // goes to last-1.
+ for(size_t i= 0; i < last-1; ++i)
+ {
+ // Operation: Add row[i] * -multiples[i] to row[i+1].
+ results[i+1]-= results[i] * multiples[i];
+ }
+ size_t next_mult= last-1;
+ // Stage two.
+ for(size_t i= last-2; i > 0; --i)
+ {
+ // Operation: Add row[i] * -multiples[nm] to row[i-1].
+ results[i-1]-= results[i] * multiples[next_mult];
+ ++next_mult;
+ }
+ // Last step of stage two.
+ // Operation: Add row[0] * -multiples[nm] to row[l-1].
+ results[last-1]-= results[0] * multiples[next_mult];
+ ++next_mult;
+ // Stage three.
+ const size_t end= last-1;
+ for(size_t i= 0; i < end; ++i)
+ {
+ // Operation: Add row[e] * -multiples[nm] to row[i].
+ results[i]-= results[end] * multiples[next_mult];
+ ++next_mult;
+ }
+ // Solving finished.
+ set_results(last, diagonals, results);
+}
+
+void CubicSpline::solve_straight()
+{
+ if(check_minimum_size()) { return; }
+ size_t last= m_points.size();
+ vector results(m_points.size());
+ vector diagonals(m_points.size());
+ vector multiples;
+ solution_cache.solve_diagonals_straight(diagonals, multiples);
+ results[0]= 3 * (m_points[1].a - m_points[0].a);
+ prep_inner(last, results);
+ results[last-1]= 3 * loop_space_difference(
+ m_points[last-1].a, m_points[last-2].a, m_spatial_extent);
+
+ // Steps explained in detail in SplineSolutionCache.
+ // Only the operations on the results column are performed here.
+ // Stage one.
+ for(size_t i= 0; i < last-1; ++i)
+ {
+ // Operation: Add row[i] * -multiples[i] to row[i+1].
+ results[i+1]-= results[i] * multiples[i];
+ }
+ size_t next_mult= last-1;
+ // Stage two.
+ for(size_t i= last-1; i > 0; --i)
+ {
+ // Operation: Add row[i] * -multiples[nm] to row [i-1].
+ results[i-1]-= results[i] * multiples[next_mult];
+ ++next_mult;
+ }
+ // Solving finished.
+ set_results(last, diagonals, results);
+}
+
+void CubicSpline::solve_polygonal()
+{
+ if(check_minimum_size()) { return; }
+ size_t last= m_points.size() - 1;
+ for(size_t i= 0; i < last; ++i)
+ {
+ m_points[i].b= loop_space_difference(
+ m_points[i+1].a, m_points[i].a, m_spatial_extent);
+ }
+ m_points[last].b= loop_space_difference(
+ m_points[0].a, m_points[last].a, m_spatial_extent);
+}
+
+bool CubicSpline::check_minimum_size()
+{
+ size_t last= m_points.size();
+ if(last < 2)
+ {
+ m_points[0].b= m_points[0].c= m_points[0].d= 0.0f;
+ return true;
+ }
+ if(last == 2)
+ {
+ m_points[0].b= loop_space_difference(
+ m_points[1].a, m_points[0].a, m_spatial_extent);
+ m_points[0].c= m_points[0].d= 0.0f;
+ // These will be used in the looping case.
+ m_points[1].b= loop_space_difference(
+ m_points[0].a, m_points[1].a, m_spatial_extent);
+ m_points[1].c= m_points[1].d= 0.0f;
+ return true;
+ }
+ float a= m_points[0].a;
+ bool all_points_identical= true;
+ for(size_t i= 0; i < m_points.size(); ++i)
+ {
+ m_points[i].b= m_points[i].c= m_points[i].d= 0.0f;
+ if(m_points[i].a != a) { all_points_identical= false; }
+ }
+ return all_points_identical;
+}
+
+void CubicSpline::prep_inner(size_t last, vector& results)
+{
+ for(size_t i= 1; i < last - 1; ++i)
+ {
+ results[i]= 3 * loop_space_difference(
+ m_points[i+1].a, m_points[i-1].a, m_spatial_extent);
+ }
+}
+
+void CubicSpline::set_results(size_t last, vector& diagonals, vector& results)
+{
+ // No more operations left, everything not a diagonal should be zero now.
+ for(size_t i= 0; i < last; ++i)
+ {
+ results[i]/= diagonals[i];
+ }
+ // Now we can go through and set the b, c, d values of each point.
+ // b, c, d values of the last point are not set because they are unused.
+ for(size_t i= 0; i < last; ++i)
+ {
+ size_t next= (i+1) % last;
+ float diff= loop_space_difference(
+ m_points[next].a, m_points[i].a, m_spatial_extent);
+ m_points[i].b= results[i];
+ m_points[i].c= (3 * diff) - (2 * results[i]) - results[next];
+ m_points[i].d= (2 * -diff) + results[i] + results[next];
+#define UNNAN(n) if(n != n) { n = 0.0f; }
+ UNNAN(m_points[i].b);
+ UNNAN(m_points[i].c);
+ UNNAN(m_points[i].d);
+#undef UNNAN
+ }
+ // Solving is now complete.
+}
+
+void CubicSpline::p_and_tfrac_from_t(float t, bool loop, size_t& p, float& tfrac) const
+{
+ if(loop)
+ {
+ float max_t= static_cast(m_points.size());
+ while(t >= max_t) { t-= max_t; }
+ while(t < 0.0f) { t+= max_t; }
+ p= static_cast(t);
+ tfrac= t - static_cast(p);
+ }
+ else
+ {
+ int flort= static_cast(t);
+ if(flort < 0)
+ {
+ p= 0;
+ tfrac= 0;
+ }
+ else if(static_cast(flort) >= m_points.size() - 1)
+ {
+ p= m_points.size() - 1;
+ tfrac= 0;
+ }
+ else
+ {
+ p= static_cast(flort);
+ tfrac= t - static_cast(p);
+ }
+ }
+}
+
+#define RETURN_IF_EMPTY if(m_points.empty()) { return 0.0f; }
+#define DECLARE_P_AND_TFRAC \
+size_t p= 0; float tfrac= 0.0f; \
+p_and_tfrac_from_t(t, loop, p, tfrac);
+
+float CubicSpline::evaluate(float t, bool loop) const
+{
+ RETURN_IF_EMPTY;
+ DECLARE_P_AND_TFRAC;
+ float tsq= tfrac * tfrac;
+ float tcub= tsq * tfrac;
+ return m_points[p].a + (m_points[p].b * tfrac) +
+ (m_points[p].c * tsq) + (m_points[p].d * tcub);
+}
+
+float CubicSpline::evaluate_derivative(float t, bool loop) const
+{
+ RETURN_IF_EMPTY;
+ DECLARE_P_AND_TFRAC;
+ float tsq= tfrac * tfrac;
+ return m_points[p].b + (2.0f * m_points[p].c * tfrac) +
+ (3.0f * m_points[p].d * tsq);
+}
+
+float CubicSpline::evaluate_second_derivative(float t, bool loop) const
+{
+ RETURN_IF_EMPTY;
+ DECLARE_P_AND_TFRAC;
+ return (2.0f * m_points[p].c) + (6.0f * m_points[p].d * tfrac);
+}
+
+float CubicSpline::evaluate_third_derivative(float t, bool loop) const
+{
+ RETURN_IF_EMPTY;
+ DECLARE_P_AND_TFRAC;
+ return 6.0f * m_points[p].d;
+}
+
+#undef RETURN_IF_EMPTY
+#undef DECLARE_P_AND_TFRAC
+
+void CubicSpline::set_point(size_t i, float v)
+{
+ ASSERT_M(i < m_points.size(), "CubicSpline::set_point requires the index to be less than the number of points.");
+ m_points[i].a= v;
+}
+
+void CubicSpline::set_coefficients(size_t i, float b, float c, float d)
+{
+ ASSERT_M(i < m_points.size(), "CubicSpline: point index must be less than the number of points.");
+ m_points[i].b= b;
+ m_points[i].c= c;
+ m_points[i].d= d;
+}
+
+void CubicSpline::get_coefficients(size_t i, float& b, float& c, float& d) const
+{
+ ASSERT_M(i < m_points.size(), "CubicSpline: point index must be less than the number of points.");
+ b= m_points[i].b;
+ c= m_points[i].c;
+ d= m_points[i].d;
+}
+
+void CubicSpline::set_point_and_coefficients(size_t i, float a, float b,
+ float c, float d)
+{
+ set_coefficients(i, b, c, d);
+ m_points[i].a= a;
+}
+
+void CubicSpline::get_point_and_coefficients(size_t i, float& a, float& b,
+ float& c, float& d) const
+{
+ get_coefficients(i, b, c, d);
+ a= m_points[i].a;
+}
+
+void CubicSpline::resize(size_t s)
+{
+ m_points.resize(s);
+}
+
+size_t CubicSpline::size() const
+{
+ return m_points.size();
+}
+
+bool CubicSpline::empty() const
+{
+ return m_points.empty();
+}
+
+void CubicSplineN::weighted_average(CubicSplineN& out,
+ const CubicSplineN& from, CubicSplineN const& to, float between)
+{
+ ASSERT_M(out.dimension() == from.dimension() &&
+ to.dimension() == from.dimension(),
+ "Cannot tween splines of different dimensions.");
+#define BOOLS_FROM_CLOSEST(closest) \
+ out.set_loop(closest.get_loop()); \
+ out.set_polygonal(closest.get_polygonal());
+ if(between >= 0.5f)
+ {
+ BOOLS_FROM_CLOSEST(to);
+ }
+ else
+ {
+ BOOLS_FROM_CLOSEST(from);
+ }
+#undef BOOLS_FROM_CLOSEST
+ // Behavior for splines of different sizes: Use a size between the two.
+ // Points that exist in both will be averaged.
+ // Points that only exist in one will come only from that one.
+ const size_t from_size= from.size();
+ const size_t to_size= to.size();
+ size_t out_size= to_size;
+ size_t limit= to_size;
+ if(from_size < to_size)
+ {
+ out_size= from_size + static_cast(
+ static_cast(to_size - from_size) * between);
+ }
+ else if(to_size < from_size)
+ {
+ limit= from_size;
+ out_size= to_size + static_cast(
+ static_cast(from_size - to_size) * between);
+ }
+ CLAMP(out_size, 0, limit);
+ out.resize(out_size);
+
+ for(size_t spli= 0; spli < out.m_splines.size(); ++spli)
+ {
+ for(size_t p= 0; p < out_size; ++p)
+ {
+ float fc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ float tc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ if(p < from_size)
+ {
+ from.m_splines[spli].get_point_and_coefficients(p, fc[0], fc[1],
+ fc[2], fc[3]);
+ }
+ if(p < to_size)
+ {
+ to.m_splines[spli].get_point_and_coefficients(p, tc[0], tc[1],
+ tc[2], tc[3]);
+ }
+ else
+ {
+ for(int i= 0; i < 4; ++i)
+ {
+ tc[i]= fc[i];
+ }
+ }
+ if(p >= from_size)
+ {
+ for(int i= 0; i < 4; ++i)
+ {
+ fc[i]= tc[i];
+ }
+ }
+ float oc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ for(int i= 0; i < 4; ++i)
+ {
+ oc[i]= lerp(between, fc[i], tc[i]);
+ }
+ out.m_splines[spli].set_point_and_coefficients(p, oc[0], oc[1], oc[2],
+ oc[3]);
+ }
+ }
+ // The spline is not solved after averaging because my testing showed that
+ // it is unnecessary.
+ // My testing method was this:
+ // Spline A is generated by lerping all points and coefficients.
+ // Spline B is generated by lerping all points then solving.
+ // The coefficients for Spline A and Spline B are identical to 5 to 9
+ // significant digits. Thus, solving is unnecessary.
+ // Additionally, solving would require a mechanism to disable solving for
+ // the people that wish to set their own coefficients instead of solving.
+ // -Kyz
+}
+
+void CubicSplineN::solve()
+{
+ if(!m_dirty) { return; }
+#define SOLVE_LOOP(solvent) \
+ for(spline_cont_t::iterator spline= m_splines.begin(); \
+ spline != m_splines.end(); ++spline) \
+ { \
+ spline->solvent(); \
+ }
+ if(m_polygonal)
+ {
+ SOLVE_LOOP(solve_polygonal);
+ }
+ else
+ {
+ if(m_loop)
+ {
+ SOLVE_LOOP(solve_looped);
+ }
+ else
+ {
+ SOLVE_LOOP(solve_straight);
+ }
+ }
+#undef SOLVE_LOOP
+ m_dirty= false;
+}
+
+#define CSN_EVAL_SOMETHING(something) \
+void CubicSplineN::something(float t, vector& v) const \
+{ \
+ for(spline_cont_t::const_iterator spline= m_splines.begin(); \
+ spline != m_splines.end(); ++spline) \
+ { \
+ v.push_back(spline->something(t, m_loop)); \
+ } \
+}
+
+CSN_EVAL_SOMETHING(evaluate);
+CSN_EVAL_SOMETHING(evaluate_derivative);
+CSN_EVAL_SOMETHING(evaluate_second_derivative);
+CSN_EVAL_SOMETHING(evaluate_third_derivative);
+
+#undef CSN_EVAL_SOMETHING
+
+void CubicSplineN::set_point(size_t i, const vector& v)
+{
+ ASSERT_M(v.size() == m_splines.size(), "CubicSplineN::set_point requires the passed point to be the same dimension as the spline.");
+ for(size_t n= 0; n < m_splines.size(); ++n)
+ {
+ m_splines[n].set_point(i, v[n]);
+ }
+ m_dirty= true;
+}
+
+void CubicSplineN::set_coefficients(size_t i, const vector& b,
+ const vector& c, const vector& d)
+{
+ ASSERT_M(b.size() == c.size() && c.size() == d.size() &&
+ d.size() == m_splines.size(), "CubicSplineN: coefficient vectors must be "
+ "the same dimension as the spline.");
+ for(size_t n= 0; n < m_splines.size(); ++n)
+ {
+ m_splines[n].set_coefficients(i, b[n], c[n], d[n]);
+ }
+ m_dirty= true;
+}
+
+void CubicSplineN::get_coefficients(size_t i, vector& b,
+ vector& c, vector& d)
+{
+ ASSERT_M(b.size() == c.size() && c.size() == d.size() &&
+ d.size() == m_splines.size(), "CubicSplineN: coefficient vectors must be "
+ "the same dimension as the spline.");
+ for(size_t n= 0; n < m_splines.size(); ++n)
+ {
+ m_splines[n].get_coefficients(i, b[n], c[n], d[n]);
+ }
+}
+
+void CubicSplineN::set_spatial_extent(size_t i, float extent)
+{
+ ASSERT_M(i < m_splines.size(), "CubicSplineN: index of spline to set extent"
+ " of is out of range.");
+ m_splines[i].m_spatial_extent= extent;
+ m_dirty= true;
+}
+
+float CubicSplineN::get_spatial_extent(size_t i)
+{
+ ASSERT_M(i < m_splines.size(), "CubicSplineN: index of spline to get extent"
+ " of is out of range.");
+ return m_splines[i].m_spatial_extent;
+}
+
+void CubicSplineN::resize(size_t s)
+{
+ for(spline_cont_t::iterator spline= m_splines.begin();
+ spline != m_splines.end(); ++spline)
+ {
+ spline->resize(s);
+ }
+ m_dirty= true;
+}
+
+size_t CubicSplineN::size() const
+{
+ if(!m_splines.empty())
+ {
+ return m_splines[0].size();
+ }
+ return 0;
+}
+
+bool CubicSplineN::empty() const
+{
+ return m_splines.empty() || m_splines[0].empty();
+}
+
+void CubicSplineN::redimension(size_t d)
+{
+ m_splines.resize(d);
+ m_dirty= true;
+}
+
+size_t CubicSplineN::dimension() const
+{
+ return m_splines.size();
+}
+
+// m_dirty is set before the member so that the set_dirty that is created
+// can actually be used to set the dirty flag. -Kyz
+#define SET_GET_MEM(member, name) \
+void CubicSplineN::set_##name(bool b) \
+{ \
+ m_dirty= true; \
+ member= b; \
+} \
+bool CubicSplineN::get_##name() const \
+{ \
+ return member; \
+}
+
+SET_GET_MEM(m_loop, loop);
+SET_GET_MEM(m_polygonal, polygonal);
+SET_GET_MEM(m_dirty, dirty);
+
+#undef SET_GET_MEM
+
+#include "LuaBinding.h"
+
+struct LunaCubicSplineN : Luna
+{
+ static size_t dimension_index(T* p, lua_State* L, int s)
+ {
+ size_t i= static_cast(IArg(s)-1);
+ if(i >= p->dimension())
+ {
+ luaL_error(L, "Spline dimension index out of range.");
+ }
+ return i;
+ }
+ static size_t point_index(T* p, lua_State* L, int s)
+ {
+ size_t i= static_cast(IArg(s)-1);
+ if(i >= p->size())
+ {
+ luaL_error(L, "Spline point index out of range.");
+ }
+ return i;
+ }
+ static int solve(T* p, lua_State* L)
+ {
+ p->solve();
+ COMMON_RETURN_SELF;
+ }
+#define LCSN_EVAL_SOMETHING(something) \
+ static int something(T* p, lua_State* L) \
+ { \
+ vector pos; \
+ p->something(FArg(1), pos); \
+ lua_createtable(L, pos.size(), 0); \
+ for(size_t i= 0; i < pos.size(); ++i) \
+ { \
+ lua_pushnumber(L, pos[i]); \
+ lua_rawseti(L, -2, i+1); \
+ } \
+ return 1; \
+ }
+ LCSN_EVAL_SOMETHING(evaluate);
+ LCSN_EVAL_SOMETHING(evaluate_derivative);
+ LCSN_EVAL_SOMETHING(evaluate_second_derivative);
+ LCSN_EVAL_SOMETHING(evaluate_third_derivative);
+#undef LCSN_EVAL_SOMETHING
+
+ static void get_element_table_from_stack(T* p, lua_State* L, int s,
+ size_t limit, vector& ret)
+ {
+ size_t elements= lua_objlen(L, s);
+ // Too many elements is not an error because allowing it allows the user
+ // to reuse the same position data set after changing the dimension size.
+ // The same is true for too few elements.
+ for(size_t e= 0; e < elements; ++e)
+ {
+ lua_rawgeti(L, s, e+1);
+ ret.push_back(FArg(-1));
+ }
+ while(ret.size() < limit)
+ {
+ ret.push_back(0.0f);
+ }
+ ret.resize(limit);
+ }
+ static void set_point_from_stack(T* p, lua_State* L, size_t i, int s)
+ {
+ if(!lua_istable(L, s))
+ {
+ luaL_error(L, "Spline point must be a table.");
+ }
+ vector pos;
+ get_element_table_from_stack(p, L, s, p->dimension(), pos);
+ p->set_point(i, pos);
+ }
+ static int set_point(T* p, lua_State* L)
+ {
+ size_t i= point_index(p, L, 1);
+ set_point_from_stack(p, L, i, 2);
+ COMMON_RETURN_SELF;
+ }
+ static void set_coefficients_from_stack(T* p, lua_State* L, size_t i, int s)
+ {
+ if(!lua_istable(L, s) || !lua_istable(L, s+1) || !lua_istable(L, s+2))
+ {
+ luaL_error(L, "Spline coefficient args must be three tables.");
+ }
+ size_t limit= p->dimension();
+ vector b; get_element_table_from_stack(p, L, s, limit, b);
+ vector c; get_element_table_from_stack(p, L, s+1, limit, c);
+ vector d; get_element_table_from_stack(p, L, s+2, limit, d);
+ p->set_coefficients(i, b, c, d);
+ }
+ static int set_coefficients(T* p, lua_State* L)
+ {
+ size_t i= point_index(p, L, 1);
+ set_coefficients_from_stack(p, L, i, 2);
+ COMMON_RETURN_SELF;
+ }
+ static int get_coefficients(T* p, lua_State* L)
+ {
+ size_t i= point_index(p, L, 1);
+ size_t limit= p->dimension();
+ vector > coeff(3);
+ coeff[0].resize(limit);
+ coeff[1].resize(limit);
+ coeff[2].resize(limit);
+ p->get_coefficients(i, coeff[0], coeff[1], coeff[2]);
+ lua_createtable(L, 3, 0);
+ for(size_t co= 0; co < coeff.size(); ++co)
+ {
+ lua_createtable(L, limit, 0);
+ for(size_t v= 0; v < limit; ++v)
+ {
+ lua_pushnumber(L, coeff[co][v]);
+ lua_rawseti(L, -2, v+1);
+ }
+ lua_rawseti(L, -2, co+1);
+ }
+ return 1;
+ }
+ static int set_spatial_extent(T* p, lua_State* L)
+ {
+ size_t i= dimension_index(p, L, 1);
+ p->set_spatial_extent(i, FArg(2));
+ COMMON_RETURN_SELF;
+ }
+ static int get_spatial_extent(T* p, lua_State* L)
+ {
+ size_t i= dimension_index(p, L, 1);
+ lua_pushnumber(L, p->get_spatial_extent(i));
+ return 1;
+ }
+ static int get_max_t(T* p, lua_State* L)
+ {
+ lua_pushnumber(L, p->get_max_t());
+ return 1;
+ }
+ static int set_size(T* p, lua_State* L)
+ {
+ int siz= IArg(1);
+ if(siz < 0)
+ {
+ luaL_error(L, "A spline cannot have less than 0 points.");
+ }
+ p->resize(static_cast(siz));
+ COMMON_RETURN_SELF;
+ }
+ static int get_size(T* p, lua_State* L)
+ {
+ lua_pushnumber(L, p->size());
+ return 1;
+ }
+ static int set_dimension(T* p, lua_State* L)
+ {
+ if(p->m_owned_by_actor)
+ {
+ luaL_error(L, "This spline cannot be redimensioned because it is "
+ "owned by an actor that relies on it having fixed dimensions.");
+ }
+ int dim= IArg(1);
+ if(dim < 0)
+ {
+ luaL_error(L, "A spline cannot have less than 0 dimensions.");
+ }
+ p->redimension(static_cast(dim));
+ COMMON_RETURN_SELF;
+ }
+ static int get_dimension(T* p, lua_State* L)
+ {
+ lua_pushnumber(L, p->dimension());
+ return 1;
+ }
+ static int empty(T* p, lua_State* L)
+ {
+ lua_pushboolean(L, p->empty());
+ return 1;
+ }
+#define SET_GET_LUA(name) \
+ static int set_##name(T* p, lua_State* L) \
+ { \
+ p->set_##name(lua_toboolean(L, 1)); \
+ COMMON_RETURN_SELF; \
+ } \
+ static int get_##name(T* p, lua_State* L) \
+ { \
+ lua_pushboolean(L, p->get_##name()); \
+ return 1; \
+ }
+ SET_GET_LUA(loop);
+ SET_GET_LUA(polygonal);
+ SET_GET_LUA(dirty);
+#undef SET_GET_LUA
+ static int destroy(T* p, lua_State* L)
+ {
+ if(p->m_owned_by_actor)
+ {
+ luaL_error(L, "This spline cannot be destroyed because it is "
+ "owned by an actor that relies on it existing.");
+ }
+ SAFE_DELETE(p);
+ return 0;
+ }
+ LunaCubicSplineN()
+ {
+ ADD_METHOD(solve);
+ ADD_METHOD(evaluate);
+ ADD_METHOD(evaluate_derivative);
+ ADD_METHOD(evaluate_second_derivative);
+ ADD_METHOD(evaluate_third_derivative);
+ ADD_METHOD(set_point);
+ ADD_METHOD(set_coefficients);
+ ADD_METHOD(get_coefficients);
+ ADD_METHOD(set_spatial_extent);
+ ADD_METHOD(get_spatial_extent);
+ ADD_METHOD(get_max_t);
+ ADD_METHOD(set_size);
+ ADD_METHOD(get_size);
+ ADD_METHOD(set_dimension);
+ ADD_METHOD(get_dimension);
+ ADD_METHOD(empty);
+ ADD_METHOD(set_loop);
+ ADD_METHOD(get_loop);
+ ADD_METHOD(set_polygonal);
+ ADD_METHOD(get_polygonal);
+ ADD_METHOD(set_dirty);
+ ADD_METHOD(get_dirty);
+ ADD_METHOD(destroy);
+ }
+};
+LUA_REGISTER_CLASS(CubicSplineN);
+
+int LuaFunc_create_spline(lua_State* L);
+int LuaFunc_create_spline(lua_State* L)
+{
+ CubicSplineN* spline= new CubicSplineN;
+ spline->PushSelf(L);
+ return 1;
+}
+LUAFUNC_REGISTER_COMMON(create_spline);
+
+// Side note: Actually written between 2014/12/26 and 2014/12/28
+/*
+ * Copyright (c) 2014-2015 Eric Reese
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+ * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+ * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/src/CubicSpline.h b/src/CubicSpline.h
new file mode 100644
index 0000000000..aae6e702e9
--- /dev/null
+++ b/src/CubicSpline.h
@@ -0,0 +1,111 @@
+#ifndef CUBIC_SPLINE_H
+#define CUBIC_SPLINE_H
+
+#include
+using std::vector;
+struct lua_State;
+
+struct CubicSpline
+{
+CubicSpline() :m_spatial_extent(0.0f) {}
+ void solve_looped();
+ void solve_straight();
+ void solve_polygonal();
+ void p_and_tfrac_from_t(float t, bool loop, size_t& p, float& tfrac) const;
+ float evaluate(float t, bool loop) const;
+ float evaluate_derivative(float t, bool loop) const;
+ float evaluate_second_derivative(float t, bool loop) const;
+ float evaluate_third_derivative(float t, bool loop) const;
+ void set_point(size_t i, float v);
+ void set_coefficients(size_t i, float b, float c, float d);
+ void get_coefficients(size_t i, float& b, float& c, float& d) const;
+ void set_point_and_coefficients(size_t i, float a, float b, float c, float d);
+ void get_point_and_coefficients(size_t i, float& a, float& b, float& c, float& d) const;
+ void resize(size_t s);
+ size_t size() const;
+ bool empty() const;
+ float m_spatial_extent;
+private:
+ bool check_minimum_size();
+ void prep_inner(size_t last, vector& results);
+ void set_results(size_t last, vector& diagonals, vector& results);
+
+ struct SplinePoint
+ {
+ float a, b, c, d;
+ };
+ vector m_points;
+};
+
+struct CubicSplineN
+{
+ CubicSplineN()
+ :m_owned_by_actor(false), m_loop(false), m_polygonal(false), m_dirty(true)
+ {}
+ static void weighted_average(CubicSplineN& out, const CubicSplineN& from,
+ const CubicSplineN& to, float between);
+ void solve();
+ void evaluate(float t, vector& v) const;
+ void evaluate_derivative(float t, vector& v) const;
+ void evaluate_second_derivative(float t, vector& v) const;
+ void evaluate_third_derivative(float t, vector& v) const;
+ void set_point(size_t i, const vector& v);
+ void set_coefficients(size_t i, const vector& b,
+ const vector& c, const vector& d);
+ void get_coefficients(size_t i, vector& b,
+ vector& c, vector& d);
+ void set_spatial_extent(size_t i, float extent);
+ float get_spatial_extent(size_t i);
+ void resize(size_t s);
+ size_t size() const;
+ void redimension(size_t d);
+ size_t dimension() const;
+ bool empty() const;
+ float get_max_t() const {
+ if(m_loop) { return static_cast(size()); }
+ else { return static_cast(size()-1); }
+ }
+ typedef vector spline_cont_t;
+ void set_loop(bool l);
+ bool get_loop() const;
+ void set_polygonal(bool p);
+ bool get_polygonal() const;
+ void set_dirty(bool d);
+ bool get_dirty() const;
+ bool m_owned_by_actor;
+
+ void PushSelf(lua_State* L);
+private:
+ bool m_loop;
+ bool m_polygonal;
+ bool m_dirty;
+ spline_cont_t m_splines;
+};
+
+#endif
+
+// Side note: Actually written between 2014/12/26 and 2014/12/28
+/*
+ * Copyright (c) 2014-2015 Eric Reese
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, and/or sell copies of the Software, and to permit persons to
+ * whom the Software is furnished to do so, provided that the above
+ * copyright notice(s) and this permission notice appear in all copies of
+ * the Software and that both the above copyright notice(s) and this
+ * permission notice appear in supporting documentation.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+ * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+ * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/src/DifficultyList.cpp b/src/DifficultyList.cpp
index a3ce25a8a9..192931c37e 100644
--- a/src/DifficultyList.cpp
+++ b/src/DifficultyList.cpp
@@ -277,7 +277,7 @@ void StepsDisplayList::SetFromGameState()
FOREACH_CONST( Difficulty, difficulties, d )
{
m_Rows[i].m_dc = *d;
- m_Lines[i].m_Meter.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GAMESTATE->m_pCurStyle->m_StepsType, 0, *d, CourseType_Invalid );
+ m_Lines[i].m_Meter.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType, 0, *d, CourseType_Invalid );
++i;
}
}
diff --git a/src/EditMenu.cpp b/src/EditMenu.cpp
index 2c9e205c49..69c4641b14 100644
--- a/src/EditMenu.cpp
+++ b/src/EditMenu.cpp
@@ -51,6 +51,11 @@ void EditMenu::StripLockedStepsAndDifficulty( vector &v )
void EditMenu::GetSongsToShowForGroup( const RString &sGroup, vector &vpSongsOut )
{
+ if(sGroup == "")
+ {
+ vpSongsOut.clear();
+ return;
+ }
vpSongsOut = SONGMAN->GetSongs( SHOW_GROUPS.GetValue()? sGroup:GROUP_ALL );
EditMode mode = EDIT_MODE.GetValue();
switch( mode )
@@ -189,6 +194,8 @@ void EditMenu::Load( const RString &sType )
void EditMenu::RefreshAll()
{
+ if(!SafeToUse()) { return; }
+
ChangeToRow( GetFirstRow() );
OnRowValueChanged( (EditMenuRow)0 );
@@ -230,6 +237,11 @@ void EditMenu::RefreshAll()
}
}
+bool EditMenu::SafeToUse()
+{
+ return !m_sGroups.empty();
+}
+
bool EditMenu::CanGoUp()
{
return m_SelectedRow != GetFirstRow();
@@ -242,6 +254,10 @@ bool EditMenu::CanGoDown()
bool EditMenu::CanGoLeft()
{
+ if(GetRowSize(m_SelectedRow) <= 0)
+ {
+ return false;
+ }
if( m_SelectedRow == ROW_SONG || m_SelectedRow == ROW_GROUP )
return true; // wraps
return m_iSelection[m_SelectedRow] != 0;
@@ -265,6 +281,10 @@ int EditMenu::GetRowSize( EditMenuRow er ) const
bool EditMenu::CanGoRight()
{
+ if(GetRowSize(m_SelectedRow) <= 0)
+ {
+ return false;
+ }
if( m_SelectedRow == ROW_SONG || m_SelectedRow == ROW_GROUP )
return true; // wraps
return m_iSelection[m_SelectedRow] != GetRowSize(m_SelectedRow)-1;
@@ -358,6 +378,8 @@ void EditMenu::UpdateArrows()
static LocalizedString BLANK ( "EditMenu", "Blank" );
void EditMenu::OnRowValueChanged( EditMenuRow row )
{
+ if(!SafeToUse()) { return; }
+
UpdateArrows();
EditMode mode = EDIT_MODE.GetValue();
@@ -365,69 +387,108 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
switch( row )
{
case ROW_GROUP:
- m_textValue[ROW_GROUP].SetText( SONGMAN->ShortenGroupName(GetSelectedGroup()) );
- if( SHOW_GROUPS.GetValue() )
- {
- m_GroupBanner.LoadFromSongGroup( GetSelectedGroup() );
- m_GroupBanner.PlayCommand("Changed");
- }
m_pSongs.clear();
- if( mode == EditMode_Practice )
+ if(GetSelectedGroup() == "")
{
- m_pSongs.clear();
- vector vtSongs;
- GetSongsToShowForGroup( GetSelectedGroup(), vtSongs );
- // Filter out songs that aren't playable.
- FOREACH( Song*, vtSongs, s )
- if( SongUtil::IsSongPlayable(*s) )
- m_pSongs.push_back(*s);
+ m_textValue[ROW_GROUP].SetText(THEME->GetString(m_sName, "No Group Selected."));
+ if(SHOW_GROUPS.GetValue())
+ {
+ m_GroupBanner.LoadFallback();
+ m_GroupBanner.PlayCommand("Changed");
+ }
}
else
- GetSongsToShowForGroup( GetSelectedGroup(), m_pSongs );
+ {
+ m_textValue[ROW_GROUP].SetText( SONGMAN->ShortenGroupName(GetSelectedGroup()) );
+ if( SHOW_GROUPS.GetValue() )
+ {
+ m_GroupBanner.LoadFromSongGroup(GetSelectedGroup());
+ m_GroupBanner.PlayCommand("Changed");
+ }
+ if( mode == EditMode_Practice )
+ {
+ vector vtSongs;
+ GetSongsToShowForGroup(GetSelectedGroup(), vtSongs);
+ // Filter out songs that aren't playable.
+ FOREACH(Song*, vtSongs, s)
+ {
+ if(SongUtil::IsSongPlayable(*s))
+ {
+ m_pSongs.push_back(*s);
+ }
+ }
+ }
+ else
+ {
+ GetSongsToShowForGroup(GetSelectedGroup(), m_pSongs);
+ }
+ }
m_iSelection[ROW_SONG] = 0;
// fall through
case ROW_SONG:
- m_textValue[ROW_SONG].SetText( "" );
- m_SongBanner.LoadFromSong( GetSelectedSong() );
- m_SongBanner.PlayCommand("Changed");
- m_SongTextBanner.SetFromSong( GetSelectedSong() );
-
- if( mode == EditMode_Practice )
+ if(GetSelectedSong() == NULL)
{
- StepsType orgSel = StepsType_Invalid;
- if( !m_StepsTypes.empty() ) // Not first run
+ m_textValue[ROW_SONG].SetText("");
+ m_SongBanner.LoadFallback();
+ m_SongBanner.PlayCommand("Changed");
+ m_SongTextBanner.SetFromString("", "", "", "", "", "");
+ if(mode == EditMode_Practice)
{
- ASSERT( (int) m_StepsTypes.size() > m_iSelection[ROW_STEPS_TYPE] );
- orgSel = m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]];
+ m_iSelection[ROW_STEPS_TYPE] = 0;
+ m_StepsTypes.clear();
}
-
- // The StepsType selection may no longer be valid. Zero it for now.
- m_iSelection[ROW_STEPS_TYPE] = 0;
- m_StepsTypes.clear();
-
- // Only show StepsTypes for which we have valid Steps.
- vector vSts = CommonMetrics::STEPS_TYPES_TO_SHOW.GetValue();
- FOREACH( StepsType, vSts, st )
+ }
+ else
+ {
+ m_textValue[ROW_SONG].SetText("");
+ m_SongBanner.LoadFromSong(GetSelectedSong());
+ m_SongBanner.PlayCommand("Changed");
+ m_SongTextBanner.SetFromSong(GetSelectedSong());
+
+ if(mode == EditMode_Practice)
{
- if( SongUtil::GetStepsByDifficulty( GetSelectedSong(), *st, Difficulty_Invalid, false) != NULL )
- m_StepsTypes.push_back( *st );
+ StepsType orgSel = StepsType_Invalid;
+ if(!m_StepsTypes.empty()) // Not first run
+ {
+ ASSERT( (int) m_StepsTypes.size() > m_iSelection[ROW_STEPS_TYPE] );
+ orgSel = m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]];
+ }
+
+ // The StepsType selection may no longer be valid. Zero it for now.
+ m_iSelection[ROW_STEPS_TYPE] = 0;
+ m_StepsTypes.clear();
+
+ // Only show StepsTypes for which we have valid Steps.
+ vector vSts = CommonMetrics::STEPS_TYPES_TO_SHOW.GetValue();
+ FOREACH( StepsType, vSts, st )
+ {
+ if(SongUtil::GetStepsByDifficulty( GetSelectedSong(), *st, Difficulty_Invalid, false) != NULL)
+ m_StepsTypes.push_back(*st);
- // Try to preserve the user's StepsType selection.
- if( *st == orgSel )
+ // Try to preserve the user's StepsType selection.
+ if(*st == orgSel)
m_iSelection[ROW_STEPS_TYPE] = m_StepsTypes.size() - 1;
+ }
}
-
}
// fall through
case ROW_STEPS_TYPE:
- m_textValue[ROW_STEPS_TYPE].SetText( GAMEMAN->GetStepsTypeInfo(GetSelectedStepsType()).GetLocalizedString() );
-
+ if(GetSelectedStepsType() == StepsType_Invalid)
{
+ m_textValue[ROW_STEPS_TYPE].SetText(THEME->GetString(m_sName, "No StepsType selected."));
+ m_vpSteps.clear();
+ }
+ else
+ {
+ m_textValue[ROW_STEPS_TYPE].SetText( GAMEMAN->GetStepsTypeInfo(GetSelectedStepsType()).GetLocalizedString() );
+
Difficulty dcOld = Difficulty_Invalid;
- if( !m_vpSteps.empty() )
+ if(!m_vpSteps.empty())
+ {
dcOld = GetSelectedDifficulty();
+ }
m_vpSteps.clear();
@@ -437,60 +498,60 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
{
switch( mode )
{
- case EditMode_Full:
- case EditMode_CourseMods:
- case EditMode_Practice:
- {
- vector v;
- SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedStepsType(), Difficulty_Edit );
- StepsUtil::SortStepsByDescription( v );
- FOREACH_CONST( Steps*, v, p )
- m_vpSteps.push_back( StepsAndDifficulty(*p,dc) );
- }
- break;
- case EditMode_Home:
- // have only "New Edit"
- break;
- default:
- FAIL_M(ssprintf("Invalid edit mode: %i", mode));
+ case EditMode_Full:
+ case EditMode_CourseMods:
+ case EditMode_Practice:
+ {
+ vector v;
+ SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedStepsType(), Difficulty_Edit );
+ StepsUtil::SortStepsByDescription( v );
+ FOREACH_CONST( Steps*, v, p )
+ m_vpSteps.push_back( StepsAndDifficulty(*p,dc) );
+ }
+ break;
+ case EditMode_Home:
+ // have only "New Edit"
+ break;
+ default:
+ FAIL_M(ssprintf("Invalid edit mode: %i", mode));
}
switch( mode )
{
- case EditMode_Practice:
- case EditMode_CourseMods:
- break;
- case EditMode_Home:
- case EditMode_Full:
- m_vpSteps.push_back( StepsAndDifficulty(NULL,dc) ); // "New Edit"
- break;
- default:
- FAIL_M(ssprintf("Invalid edit mode: %i", mode));
+ case EditMode_Practice:
+ case EditMode_CourseMods:
+ break;
+ case EditMode_Home:
+ case EditMode_Full:
+ m_vpSteps.push_back( StepsAndDifficulty(NULL,dc) ); // "New Edit"
+ break;
+ default:
+ FAIL_M(ssprintf("Invalid edit mode: %i", mode));
}
}
else
{
Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedStepsType(), dc );
if( pSteps && UNLOCKMAN->StepsIsLocked( GetSelectedSong(), pSteps ) )
- pSteps = NULL;
+ pSteps = NULL;
switch( mode )
{
- case EditMode_Home:
- // don't allow selecting of non-edits in HomeMode
- break;
- case EditMode_Practice:
- case EditMode_CourseMods:
- // only show this difficulty if steps exist
- if( pSteps )
+ case EditMode_Home:
+ // don't allow selecting of non-edits in HomeMode
+ break;
+ case EditMode_Practice:
+ case EditMode_CourseMods:
+ // only show this difficulty if steps exist
+ if( pSteps )
m_vpSteps.push_back( StepsAndDifficulty(pSteps,dc) );
- break;
- case EditMode_Full:
- // show this difficulty whether or not steps exist.
- m_vpSteps.push_back( StepsAndDifficulty(pSteps,dc) );
- break;
- default:
- FAIL_M(ssprintf("Invalid edit mode: %i", mode));
+ break;
+ case EditMode_Full:
+ // show this difficulty whether or not steps exist.
+ m_vpSteps.push_back( StepsAndDifficulty(pSteps,dc) );
+ break;
+ default:
+ FAIL_M(ssprintf("Invalid edit mode: %i", mode));
}
}
}
@@ -504,51 +565,75 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
break;
}
}
+ CLAMP( m_iSelection[ROW_STEPS], 0, m_vpSteps.size()-1 );
}
-
- CLAMP( m_iSelection[ROW_STEPS], 0, m_vpSteps.size()-1 );
-
// fall through
case ROW_STEPS:
+ if(GetSelectedSteps() == NULL && mode == EditMode_Practice)
+ {
+ m_textValue[ROW_STEPS].SetText(THEME->GetString(m_sName, "No Steps selected."));
+ m_StepsDisplay.Unset();
+ }
+ else
{
RString s = CustomDifficultyToLocalizedString( GetCustomDifficulty( GetSelectedStepsType(), GetSelectedDifficulty(), CourseType_Invalid ) );
m_textValue[ROW_STEPS].SetText( s );
- }
- if( GetSelectedSteps() )
- m_StepsDisplay.SetFromSteps( GetSelectedSteps() );
- else
- m_StepsDisplay.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GetSelectedSourceStepsType(), 0, GetSelectedDifficulty(), CourseType_Invalid );
- // fall through
- case ROW_SOURCE_STEPS_TYPE:
- m_textLabel[ROW_SOURCE_STEPS_TYPE].SetVisible( GetSelectedSteps() ? false : true );
- m_textValue[ROW_SOURCE_STEPS_TYPE].SetVisible( GetSelectedSteps() ? false : true );
- m_textValue[ROW_SOURCE_STEPS_TYPE].SetText( GAMEMAN->GetStepsTypeInfo(GetSelectedSourceStepsType()).GetLocalizedString() );
-
- m_vpSourceSteps.clear();
- m_vpSourceSteps.push_back( StepsAndDifficulty(NULL,Difficulty_Invalid) ); // "blank"
- FOREACH_ENUM( Difficulty, dc )
- {
- // fill in m_vpSourceSteps
- if( dc != Difficulty_Edit )
+ if( GetSelectedSteps() )
{
- Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedSourceStepsType(), dc );
- if( pSteps != NULL )
- m_vpSourceSteps.push_back( StepsAndDifficulty(pSteps,dc) );
+ m_StepsDisplay.SetFromSteps( GetSelectedSteps() );
}
else
{
- vector v;
- SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedSourceStepsType(), dc );
- StepsUtil::SortStepsByDescription( v );
- FOREACH_CONST( Steps*, v, pSteps )
- m_vpSourceSteps.push_back( StepsAndDifficulty(*pSteps,dc) );
+ m_StepsDisplay.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GetSelectedSourceStepsType(), 0, GetSelectedDifficulty(), CourseType_Invalid );
}
}
- StripLockedStepsAndDifficulty( m_vpSteps );
- CLAMP( m_iSelection[ROW_SOURCE_STEPS], 0, m_vpSourceSteps.size()-1 );
+ // fall through
+ case ROW_SOURCE_STEPS_TYPE:
+ if(mode == EditMode_Practice)
+ {
+ m_textLabel[ROW_SOURCE_STEPS_TYPE].SetVisible(false);
+ m_textValue[ROW_SOURCE_STEPS_TYPE].SetVisible(false);
+ }
+ else
+ {
+ m_textLabel[ROW_SOURCE_STEPS_TYPE].SetVisible( GetSelectedSteps() ? false : true );
+ m_textValue[ROW_SOURCE_STEPS_TYPE].SetVisible( GetSelectedSteps() ? false : true );
+ m_textValue[ROW_SOURCE_STEPS_TYPE].SetText( GAMEMAN->GetStepsTypeInfo(GetSelectedSourceStepsType()).GetLocalizedString() );
+ m_vpSourceSteps.clear();
+ m_vpSourceSteps.push_back( StepsAndDifficulty(NULL,Difficulty_Invalid) ); // "blank"
+
+ FOREACH_ENUM( Difficulty, dc )
+ {
+ // fill in m_vpSourceSteps
+ if( dc != Difficulty_Edit )
+ {
+ Steps *pSteps = SongUtil::GetStepsByDifficulty( GetSelectedSong(), GetSelectedSourceStepsType(), dc );
+ if( pSteps != NULL )
+ m_vpSourceSteps.push_back( StepsAndDifficulty(pSteps,dc) );
+ }
+ else
+ {
+ vector v;
+ SongUtil::GetSteps( GetSelectedSong(), v, GetSelectedSourceStepsType(), dc );
+ StepsUtil::SortStepsByDescription( v );
+ FOREACH_CONST( Steps*, v, pSteps )
+ m_vpSourceSteps.push_back( StepsAndDifficulty(*pSteps,dc) );
+ }
+ }
+ StripLockedStepsAndDifficulty( m_vpSteps );
+ CLAMP( m_iSelection[ROW_SOURCE_STEPS], 0, m_vpSourceSteps.size()-1 );
+ }
// fall through
case ROW_SOURCE_STEPS:
+ if(mode == EditMode_Practice)
+ {
+ m_textLabel[ROW_SOURCE_STEPS].SetVisible(false);
+ m_textValue[ROW_SOURCE_STEPS].SetVisible(false);
+ m_Actions.clear();
+ m_Actions.push_back( EditMenuAction_Practice );
+ }
+ else
{
m_textLabel[ROW_SOURCE_STEPS].SetVisible( GetSelectedSteps() ? false : true );
m_textValue[ROW_SOURCE_STEPS].SetVisible( GetSelectedSteps() ? false : true );
@@ -566,11 +651,11 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
}
bool bHideMeter = false;
if( GetSelectedSourceDifficulty() == Difficulty_Invalid )
- bHideMeter = true;
+ bHideMeter = true;
else if( GetSelectedSourceSteps() )
- m_StepsDisplaySource.SetFromSteps( GetSelectedSourceSteps() );
+ m_StepsDisplaySource.SetFromSteps( GetSelectedSourceSteps() );
else
- m_StepsDisplaySource.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GetSelectedSourceStepsType(), 0, GetSelectedSourceDifficulty(), CourseType_Invalid );
+ m_StepsDisplaySource.SetFromStepsTypeAndMeterAndDifficultyAndCourseType( GetSelectedSourceStepsType(), 0, GetSelectedSourceDifficulty(), CourseType_Invalid );
m_StepsDisplaySource.SetVisible( !(bHideMeter || GetSelectedSteps()) );
m_Actions.clear();
@@ -578,17 +663,17 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
{
switch( mode )
{
- case EditMode_Practice:
- case EditMode_CourseMods:
- m_Actions.push_back( EditMenuAction_Practice );
- break;
- case EditMode_Home:
- case EditMode_Full:
- m_Actions.push_back( EditMenuAction_Edit );
- m_Actions.push_back( EditMenuAction_Delete );
- break;
- default:
- FAIL_M(ssprintf("Invalid edit mode: %i", mode));
+ case EditMode_Practice:
+ case EditMode_CourseMods:
+ m_Actions.push_back( EditMenuAction_Practice );
+ break;
+ case EditMode_Home:
+ case EditMode_Full:
+ m_Actions.push_back( EditMenuAction_Edit );
+ m_Actions.push_back( EditMenuAction_Delete );
+ break;
+ default:
+ FAIL_M(ssprintf("Invalid edit mode: %i", mode));
}
}
else
@@ -599,7 +684,14 @@ void EditMenu::OnRowValueChanged( EditMenuRow row )
}
// fall through
case ROW_ACTION:
- m_textValue[ROW_ACTION].SetText( EditMenuActionToLocalizedString(GetSelectedAction()) );
+ if(GetSelectedAction() == EditMenuAction_Invalid)
+ {
+ m_textValue[ROW_ACTION].SetText(THEME->GetString(m_sName, "No valid action."));
+ }
+ else
+ {
+ m_textValue[ROW_ACTION].SetText( EditMenuActionToLocalizedString(GetSelectedAction()) );
+ }
break;
default:
FAIL_M(ssprintf("Invalid EditMenuRow: %i", row));
diff --git a/src/EditMenu.h b/src/EditMenu.h
index dac6767899..a468e34b0c 100644
--- a/src/EditMenu.h
+++ b/src/EditMenu.h
@@ -102,74 +102,86 @@ public:
void RefreshAll();
+ bool SafeToUse();
+
+#define RETURN_IF_INVALID(check, retval) if(check) { return retval; }
+
/** @brief Retrieve the currently selected group.
* @return the current group. */
RString GetSelectedGroup() const
{
if( !SHOW_GROUPS.GetValue() ) return GROUP_ALL;
int groups = static_cast(m_sGroups.size());
- ASSERT_M(m_iSelection[ROW_GROUP] < groups,
- ssprintf("Group selection %d < Number of groups %d",
- m_iSelection[ROW_GROUP],
- groups));
+ RETURN_IF_INVALID(m_iSelection[ROW_GROUP] >= groups, "");
return m_sGroups[m_iSelection[ROW_GROUP]];
}
/** @brief Retrieve the currently selected song.
* @return the current song. */
Song* GetSelectedSong() const
{
- ASSERT(m_iSelection[ROW_SONG] < (int)m_pSongs.size());
+ RETURN_IF_INVALID(m_pSongs.empty() ||
+ m_iSelection[ROW_SONG] >= (int)m_pSongs.size(), NULL);
return m_pSongs[m_iSelection[ROW_SONG]];
}
/** @brief Retrieve the currently selected steps type.
* @return the current steps type. */
StepsType GetSelectedStepsType() const
{
- ASSERT(m_iSelection[ROW_STEPS_TYPE] < (int)m_StepsTypes.size());
+ RETURN_IF_INVALID(m_StepsTypes.empty() ||
+ m_iSelection[ROW_STEPS_TYPE] >= (int)m_StepsTypes.size(), StepsType_Invalid);
return m_StepsTypes[m_iSelection[ROW_STEPS_TYPE]];
}
/** @brief Retrieve the currently selected steps.
* @return the current steps. */
Steps* GetSelectedSteps() const
{
- ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size());
+ RETURN_IF_INVALID(m_vpSteps.empty() ||
+ m_iSelection[ROW_STEPS] >= (int)m_vpSteps.size(), NULL);
return m_vpSteps[m_iSelection[ROW_STEPS]].pSteps;
}
/** @brief Retrieve the currently selected difficulty.
* @return the current difficulty. */
Difficulty GetSelectedDifficulty() const
{
- ASSERT(m_iSelection[ROW_STEPS] < (int)m_vpSteps.size());
+ RETURN_IF_INVALID(m_vpSteps.empty() ||
+ m_iSelection[ROW_STEPS] >= (int)m_vpSteps.size(), Difficulty_Invalid);
return m_vpSteps[m_iSelection[ROW_STEPS]].dc;
}
/** @brief Retrieve the currently selected source steps type.
* @return the current source steps type. */
StepsType GetSelectedSourceStepsType() const
{
- ASSERT(m_iSelection[ROW_SOURCE_STEPS_TYPE] < (int)m_StepsTypes.size());
+ RETURN_IF_INVALID(m_StepsTypes.empty() ||
+ m_iSelection[ROW_SOURCE_STEPS_TYPE] >= (int)m_StepsTypes.size(), StepsType_Invalid);
return m_StepsTypes[m_iSelection[ROW_SOURCE_STEPS_TYPE]];
}
/** @brief Retrieve the currently selected source steps.
* @return the current source steps. */
Steps* GetSelectedSourceSteps() const
{
- ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size());
+ RETURN_IF_INVALID(m_vpSourceSteps.empty() ||
+ m_iSelection[ROW_SOURCE_STEPS] >= (int)m_vpSourceSteps.size(), NULL);
return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].pSteps;
}
/** @brief Retrieve the currently selected difficulty.
* @return the current difficulty. */
Difficulty GetSelectedSourceDifficulty() const
{
- ASSERT(m_iSelection[ROW_SOURCE_STEPS] < (int)m_vpSourceSteps.size());
+ RETURN_IF_INVALID(m_vpSourceSteps.empty() ||
+ m_iSelection[ROW_SOURCE_STEPS] >= (int)m_vpSourceSteps.size(), Difficulty_Invalid);
return m_vpSourceSteps[m_iSelection[ROW_SOURCE_STEPS]].dc;
}
/** @brief Retrieve the currently selected action.
* @return the current action. */
EditMenuAction GetSelectedAction() const
{
- ASSERT(m_iSelection[ROW_ACTION] < (int)m_Actions.size());
+ RETURN_IF_INVALID(m_Actions.empty() ||
+ m_iSelection[ROW_ACTION] >= (int)m_Actions.size(), EditMenuAction_Invalid);
return m_Actions[m_iSelection[ROW_ACTION]];
}
+
+#undef RETURN_IF_INVALID
+
/** @brief Retrieve the currently selected row.
* @return the current row. */
EditMenuRow GetSelectedRow() const { return m_SelectedRow; }
diff --git a/src/Game.cpp b/src/Game.cpp
index 07aac354c4..12763ed4ff 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -62,12 +62,14 @@ public:
static int GetName( T* p, lua_State *L ) { lua_pushstring( L, p->m_szName ); return 1; }
static int CountNotesSeparately( T* p, lua_State *L ) { lua_pushboolean( L, p->m_bCountNotesSeparately ); return 1; }
DEFINE_METHOD( GetMapJudgmentTo, GetMapJudgmentTo(Enum::Check(L, 1)) )
+ DEFINE_METHOD(GetSeparateStyles, m_PlayersHaveSeparateStyles);
LunaGame()
{
ADD_METHOD( GetName );
ADD_METHOD( CountNotesSeparately );
ADD_METHOD( GetMapJudgmentTo );
+ ADD_METHOD( GetSeparateStyles );
}
};
diff --git a/src/Game.h b/src/Game.h
index e3d1eb3e39..2f06b933a7 100644
--- a/src/Game.h
+++ b/src/Game.h
@@ -34,6 +34,7 @@ struct Game
/** @brief Do we count multiple notes in a row as separate notes, or as one note? */
bool m_bCountNotesSeparately;
bool m_bTickHolds;
+ bool m_PlayersHaveSeparateStyles;
InputScheme m_InputScheme;
diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp
index 60d788df96..83da0bb0a5 100644
--- a/src/GameCommand.cpp
+++ b/src/GameCommand.cpp
@@ -84,7 +84,7 @@ bool GameCommand::DescribesCurrentMode( PlayerNumber pn ) const
{
if( m_pm != PlayMode_Invalid && GAMESTATE->m_PlayMode != m_pm )
return false;
- if( m_pStyle && GAMESTATE->GetCurrentStyle() != m_pStyle )
+ if( m_pStyle && GAMESTATE->GetCurrentStyle(pn) != m_pStyle )
return false;
// HACK: don't compare m_dc if m_pSteps is set. This causes problems
// in ScreenSelectOptionsMaster::ImportOptions if m_PreferredDifficulty
@@ -289,7 +289,7 @@ void GameCommand::LoadOne( const Command& cmd )
if( !m_bInvalid )
{
Song *pSong = (m_pSong != NULL)? m_pSong:GAMESTATE->m_pCurSong;
- const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle();
+ const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber());
if( pSong == NULL || pStyle == NULL )
{
MAKE_INVALID("Must set Song and Style to set Steps.");
@@ -327,7 +327,7 @@ void GameCommand::LoadOne( const Command& cmd )
if( !m_bInvalid )
{
Course *pCourse = (m_pCourse != NULL)? m_pCourse:GAMESTATE->m_pCurCourse;
- const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle();
+ const Style *pStyle = m_pStyle ? m_pStyle : GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber());
if( pCourse == NULL || pStyle == NULL )
{
MAKE_INVALID("Must set Course and Style to set Trail.");
@@ -598,7 +598,7 @@ bool GameCommand::IsPlayable( RString *why ) const
if( m_pm != PlayMode_Invalid || m_pStyle != NULL )
{
const PlayMode pm = (m_pm != PlayMode_Invalid) ? m_pm : GAMESTATE->m_PlayMode;
- const Style *style = (m_pStyle != NULL)? m_pStyle: GAMESTATE->GetCurrentStyle();
+ const Style *style = (m_pStyle != NULL)? m_pStyle: GAMESTATE->GetCurrentStyle(GAMESTATE->GetMasterPlayerNumber());
if( !AreStyleAndPlayModeCompatible( style, pm ) )
{
if( why )
@@ -705,7 +705,7 @@ void GameCommand::ApplySelf( const vector &vpns ) const
if( m_pStyle != NULL )
{
- GAMESTATE->SetCurrentStyle( m_pStyle );
+ GAMESTATE->SetCurrentStyle( m_pStyle, GAMESTATE->GetMasterPlayerNumber() );
// It's possible to choose a style that didn't have enough players joined.
// If enough players aren't joined, then we need to subtract credits
diff --git a/src/GameConstantsAndTypes.h b/src/GameConstantsAndTypes.h
index 6180b547cd..900359148a 100644
--- a/src/GameConstantsAndTypes.h
+++ b/src/GameConstantsAndTypes.h
@@ -104,6 +104,10 @@ enum StepsType
StepsType_popn_five,
StepsType_popn_nine,
StepsType_lights_cabinet,
+ StepsType_kickbox_human,
+ StepsType_kickbox_quadarm,
+ StepsType_kickbox_insect,
+ StepsType_kickbox_arachnid,
NUM_StepsType, // leave this at the end
StepsType_Invalid,
};
diff --git a/src/GameInput.h b/src/GameInput.h
index 5a474f0e71..c3ed05ea06 100644
--- a/src/GameInput.h
+++ b/src/GameInput.h
@@ -174,6 +174,16 @@ GameButton StringToGameButton( const InputScheme* pInputs, const RString& s );
#define LIGHTS_BUTTON_BASS_RIGHT GAME_BUTTON_CUSTOM_08
#define NUM_LIGHTS_BUTTONS GAME_BUTTON_CUSTOM_09
+#define KICKBOX_BUTTON_DOWN_LEFT_FOOT GAME_BUTTON_CUSTOM_01
+#define KICKBOX_BUTTON_UP_LEFT_FOOT GAME_BUTTON_CUSTOM_02
+#define KICKBOX_BUTTON_UP_LEFT_FIST GAME_BUTTON_CUSTOM_03
+#define KICKBOX_BUTTON_DOWN_LEFT_FIST GAME_BUTTON_CUSTOM_04
+#define KICKBOX_BUTTON_DOWN_RIGHT_FIST GAME_BUTTON_CUSTOM_05
+#define KICKBOX_BUTTON_UP_RIGHT_FIST GAME_BUTTON_CUSTOM_06
+#define KICKBOX_BUTTON_UP_RIGHT_FOOT GAME_BUTTON_CUSTOM_07
+#define KICKBOX_BUTTON_DOWN_RIGHT_FOOT GAME_BUTTON_CUSTOM_08
+#define NUM_KICKBOX_BUTTONS GAME_BUTTON_CUSTOM_09
+
#define GAME_BUTTON_LEFT GAME_BUTTON_MENULEFT
#define GAME_BUTTON_RIGHT GAME_BUTTON_MENURIGHT
#define GAME_BUTTON_UP GAME_BUTTON_MENUUP
diff --git a/src/GameLoop.cpp b/src/GameLoop.cpp
index 98976a2d91..7b1366e46a 100644
--- a/src/GameLoop.cpp
+++ b/src/GameLoop.cpp
@@ -239,6 +239,7 @@ namespace
* case going from theme to theme, but if it was, it should be fixed
* now. There's probably be a better way to do it, but I'm not sure
* what it'd be. -aj */
+ THEME->UpdateLuaGlobals();
THEME->ReloadMetrics();
g_NewGame= RString();
g_NewTheme= RString();
diff --git a/src/GameManager.cpp b/src/GameManager.cpp
index 7d7a77f12a..95692c90e4 100644
--- a/src/GameManager.cpp
+++ b/src/GameManager.cpp
@@ -93,6 +93,11 @@ static const StepsTypeInfo g_StepsTypeInfos[] = {
{ "pnm-nine", 9, true, StepsTypeCategory_Single }, // called "pnm" for backward compat
// cabinet lights and other fine StepsTypes that don't exist lol
{ "lights-cabinet", NUM_CabinetLight, false, StepsTypeCategory_Single }, // XXX disable lights autogen for now
+ // kickbox mania
+ { "kickbox-human", 4, true, StepsTypeCategory_Single },
+ { "kickbox-quadarm", 4, true, StepsTypeCategory_Single },
+ { "kickbox-insect", 6, true, StepsTypeCategory_Single },
+ { "kickbox-arachnid", 8, true, StepsTypeCategory_Single },
};
@@ -165,7 +170,6 @@ static const Style g_Style_Dance_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0, 1, 2, 3
},
- false, // m_bNeedsZoomOutWith2Players
true, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -201,7 +205,6 @@ static const Style g_Style_Dance_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0, 1, 2, 3
},
- false, // m_bNeedsZoomOutWith2Players
true, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -245,7 +248,6 @@ static const Style g_Style_Dance_Double =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -281,7 +283,6 @@ static const Style g_Style_Dance_Couple =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3
},
- false, // m_bNeedsZoomOutWith2Players
true, // m_bCanUseBeginnerHelper
true, // m_bLockDifficulties
};
@@ -321,7 +322,6 @@ static const Style g_Style_Dance_Solo =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -365,7 +365,6 @@ static const Style g_Style_Dance_Couple_Edit =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -400,7 +399,6 @@ static const Style g_Style_Dance_ThreePanel =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -438,7 +436,6 @@ static const Style g_Style_Dance_Solo_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,5,1,4,2,3 // outside in
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
}; */
@@ -482,10 +479,8 @@ static const Style g_Style_Dance_Routine =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
true, // m_bLockDifficulties
-
};
static const Style *g_apGame_Dance_Styles[] =
@@ -507,6 +502,7 @@ static const Game g_Game_Dance =
g_apGame_Dance_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"dance", // m_szName
NUM_DANCE_BUTTONS, // m_iButtonsPerController
@@ -595,7 +591,6 @@ static const Style g_Style_Pump_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -633,7 +628,6 @@ static const Style g_Style_Pump_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -673,7 +667,6 @@ static const Style g_Style_Pump_HalfDouble =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,3,1,4,0,5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -721,7 +714,6 @@ static const Style g_Style_Pump_Double =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4, 2+5,1+5,3+5,0+5,4+5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -759,7 +751,6 @@ static const Style g_Style_Pump_Couple =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
true, // m_bLockDifficulties
};
@@ -807,7 +798,6 @@ static const Style g_Style_Pump_Couple_Edit =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4, 2+5,1+5,3+5,0+5,4+5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -855,7 +845,6 @@ static const Style g_Style_Pump_Routine =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,1,3,0,4,7,6,8,5,9
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
true, // m_bLockDifficulties
};
@@ -878,6 +867,7 @@ static const Game g_Game_Pump =
g_apGame_Pump_Styles, // m_apStyles
false, // m_bCountNotesSeparately
true, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"pump", // m_szName
NUM_PUMP_BUTTONS, // m_iButtonsPerController
@@ -956,7 +946,6 @@ static const Style g_Style_KB7_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6 // doesn't work?
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1000,7 +989,6 @@ static const Style g_Style_KB7_Small =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6 // doesn't work?
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
}; */
@@ -1042,7 +1030,6 @@ static const Style g_Style_KB7_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6
},
- true, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1061,6 +1048,7 @@ static const Game g_Game_KB7 =
g_apGame_KB7_Styles, // m_apStyles
true, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"kb7", // m_szName
NUM_KB7_BUTTONS, // m_iButtonsPerController
@@ -1129,7 +1117,6 @@ static const Style g_Style_Ez2_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,0,4,1,3 // This should be from back to front: Down, UpLeft, UpRight, Upper Left Hand, Upper Right Hand
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1171,7 +1158,6 @@ static const Style g_Style_Ez2_Real =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
3,0,6,1,5,2,4 // This should be from back to front: Down, UpLeft, UpRight, Lower Left Hand, Lower Right Hand, Upper Left Hand, Upper Right Hand
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1209,7 +1195,6 @@ static const Style g_Style_Ez2_Single_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,0,4,1,3 // This should be from back to front: Down, UpLeft, UpRight, Upper Left Hand, Upper Right Hand
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1251,7 +1236,6 @@ static const Style g_Style_Ez2_Real_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
3,0,6,2,4,1,5 // This should be from back to front: Down, UpLeft, UpRight, Lower Left Hand, Lower Right Hand, Upper Left Hand, Upper Right Hand
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1299,7 +1283,6 @@ static const Style g_Style_Ez2_Double =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,0,4,1,3,7,5,9,6,8 // This should be from back to front: Down, UpLeft, UpRight, Upper Left Hand, Upper Right Hand
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1333,6 +1316,7 @@ static const Game g_Game_Ez2 =
g_apGame_Ez2_Styles, // m_apStyles
true, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"ez2", // m_szName
NUM_EZ2_BUTTONS, // m_iButtonsPerController
@@ -1399,7 +1383,6 @@ static const Style g_Style_Para_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,0,4,1,3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1437,7 +1420,6 @@ static const Style g_Style_Para_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
2,0,4,1,3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1466,6 +1448,7 @@ static const Game g_Game_Para =
g_apGame_Para_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"para", // m_szName
NUM_PARA_BUTTONS, // m_iButtonsPerController
@@ -1533,7 +1516,6 @@ static const Style g_Style_DS3DDX_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1564,6 +1546,7 @@ static const Game g_Game_DS3DDX =
g_apGame_DS3DDX_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"ds3ddx", // m_szName
NUM_DS3DDX_BUTTONS, // m_iButtonsPerController
@@ -1633,7 +1616,6 @@ static const Style g_Style_Beat_Single5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1673,7 +1655,6 @@ static const Style g_Style_Beat_Versus5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1725,7 +1706,6 @@ static const Style g_Style_Beat_Double5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7,8,9,10,11
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1769,7 +1749,6 @@ static const Style g_Style_Beat_Single7 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1813,7 +1792,6 @@ static const Style g_Style_Beat_Versus7 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1874,7 +1852,6 @@ static const Style g_Style_Beat_Double7 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -1910,6 +1887,7 @@ static const Game g_Game_Beat =
g_apGame_Beat_Styles, // m_apStyles
true, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"beat", // m_szName
NUM_BEAT_BUTTONS, // m_iButtonsPerController
@@ -1977,7 +1955,6 @@ static const Style g_Style_Maniax_Single =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0, 1, 2, 3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2013,7 +1990,6 @@ static const Style g_Style_Maniax_Versus =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0, 1, 2, 3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2057,7 +2033,6 @@ static const Style g_Style_Maniax_Double =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2090,6 +2065,7 @@ static const Game g_Game_Maniax =
g_apGame_Maniax_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"maniax", // m_szName
NUM_MANIAX_BUTTONS, // m_iButtonsPerController
@@ -2119,7 +2095,6 @@ static const Game g_Game_Maniax =
//ThemeMetric TECHNO_COL_SPACING ("ColumnSpacing","Techno");
static const int TECHNO_COL_SPACING = 56;
//ThemeMetric TECHNO_VERSUS_COL_SPACING ("ColumnSpacing","TechnoVersus");
-static const int TECHNO_VERSUS_COL_SPACING = 33;
static const Style g_Style_Techno_Single4 =
{ // STYLE_TECHNO_SINGLE4
true, // m_bUsedForGameplay
@@ -2151,7 +2126,6 @@ static const Style g_Style_Techno_Single4 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2191,7 +2165,6 @@ static const Style g_Style_Techno_Single5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2235,7 +2208,6 @@ static const Style g_Style_Techno_Single8 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- true, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2271,7 +2243,6 @@ static const Style g_Style_Techno_Versus4 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2311,7 +2282,6 @@ static const Style g_Style_Techno_Versus5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2328,24 +2298,24 @@ static const Style g_Style_Techno_Versus8 =
8, // m_iColsPerPlayer
{ // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
{ // PLAYER_1
- { TRACK_1, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_2, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_3, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_4, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_5, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_6, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_7, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_8, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
+ { TRACK_1, -TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +TECHNO_COL_SPACING*3.5f, NULL },
},
{ // PLAYER_2
- { TRACK_1, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_2, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_3, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_4, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_5, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_6, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_7, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_8, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
+ { TRACK_1, -TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +TECHNO_COL_SPACING*3.5f, NULL },
},
},
{ // m_iInputColumn[NUM_GameController][NUM_GameButton]
@@ -2357,7 +2327,6 @@ static const Style g_Style_Techno_Versus8 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- true, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2401,7 +2370,6 @@ static const Style g_Style_Techno_Double4 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2461,7 +2429,6 @@ static const Style g_Style_Techno_Double5 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7,8,9
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2478,40 +2445,40 @@ static const Style g_Style_Techno_Double8 =
16, // m_iColsPerPlayer
{ // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
{ // PLAYER_1
- { TRACK_1, -TECHNO_VERSUS_COL_SPACING*7.5f, NULL },
- { TRACK_2, -TECHNO_VERSUS_COL_SPACING*6.5f, NULL },
- { TRACK_3, -TECHNO_VERSUS_COL_SPACING*5.5f, NULL },
- { TRACK_4, -TECHNO_VERSUS_COL_SPACING*4.5f, NULL },
- { TRACK_5, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_6, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_7, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_8, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_9, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_10, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_11, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_12, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_13, +TECHNO_VERSUS_COL_SPACING*4.5f, NULL },
- { TRACK_14, +TECHNO_VERSUS_COL_SPACING*5.5f, NULL },
- { TRACK_15, +TECHNO_VERSUS_COL_SPACING*6.5f, NULL },
- { TRACK_16, +TECHNO_VERSUS_COL_SPACING*7.5f, NULL },
+ { TRACK_1, -TECHNO_COL_SPACING*7.5f, NULL },
+ { TRACK_2, -TECHNO_COL_SPACING*6.5f, NULL },
+ { TRACK_3, -TECHNO_COL_SPACING*5.5f, NULL },
+ { TRACK_4, -TECHNO_COL_SPACING*4.5f, NULL },
+ { TRACK_5, -TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_6, -TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_7, -TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_8, -TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_9, +TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_10, +TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_11, +TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_12, +TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_13, +TECHNO_COL_SPACING*4.5f, NULL },
+ { TRACK_14, +TECHNO_COL_SPACING*5.5f, NULL },
+ { TRACK_15, +TECHNO_COL_SPACING*6.5f, NULL },
+ { TRACK_16, +TECHNO_COL_SPACING*7.5f, NULL },
},
{ // PLAYER_2
- { TRACK_1, -TECHNO_VERSUS_COL_SPACING*7.5f, NULL },
- { TRACK_2, -TECHNO_VERSUS_COL_SPACING*6.5f, NULL },
- { TRACK_3, -TECHNO_VERSUS_COL_SPACING*5.5f, NULL },
- { TRACK_4, -TECHNO_VERSUS_COL_SPACING*4.5f, NULL },
- { TRACK_5, -TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_6, -TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_7, -TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_8, -TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_9, +TECHNO_VERSUS_COL_SPACING*0.5f, NULL },
- { TRACK_10, +TECHNO_VERSUS_COL_SPACING*1.5f, NULL },
- { TRACK_11, +TECHNO_VERSUS_COL_SPACING*2.5f, NULL },
- { TRACK_12, +TECHNO_VERSUS_COL_SPACING*3.5f, NULL },
- { TRACK_13, +TECHNO_VERSUS_COL_SPACING*4.5f, NULL },
- { TRACK_14, +TECHNO_VERSUS_COL_SPACING*5.5f, NULL },
- { TRACK_15, +TECHNO_VERSUS_COL_SPACING*6.5f, NULL },
- { TRACK_16, +TECHNO_VERSUS_COL_SPACING*7.5f, NULL },
+ { TRACK_1, -TECHNO_COL_SPACING*7.5f, NULL },
+ { TRACK_2, -TECHNO_COL_SPACING*6.5f, NULL },
+ { TRACK_3, -TECHNO_COL_SPACING*5.5f, NULL },
+ { TRACK_4, -TECHNO_COL_SPACING*4.5f, NULL },
+ { TRACK_5, -TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_6, -TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_7, -TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_8, -TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_9, +TECHNO_COL_SPACING*0.5f, NULL },
+ { TRACK_10, +TECHNO_COL_SPACING*1.5f, NULL },
+ { TRACK_11, +TECHNO_COL_SPACING*2.5f, NULL },
+ { TRACK_12, +TECHNO_COL_SPACING*3.5f, NULL },
+ { TRACK_13, +TECHNO_COL_SPACING*4.5f, NULL },
+ { TRACK_14, +TECHNO_COL_SPACING*5.5f, NULL },
+ { TRACK_15, +TECHNO_COL_SPACING*6.5f, NULL },
+ { TRACK_16, +TECHNO_COL_SPACING*7.5f, NULL },
},
},
{ // m_iInputColumn[NUM_GameController][NUM_GameButton]
@@ -2521,7 +2488,6 @@ static const Style g_Style_Techno_Double8 =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2570,6 +2536,7 @@ static const Game g_Game_Techno =
g_apGame_Techno_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"techno", // m_szName
NUM_TECHNO_BUTTONS, // m_iButtonsPerController
@@ -2642,7 +2609,6 @@ static const Style g_Style_Popn_Five =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2688,7 +2654,6 @@ static const Style g_Style_Popn_Nine =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7,8
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2721,6 +2686,7 @@ static const Game g_Game_Popn =
g_apGame_Popn_Styles, // m_apStyles
true, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"popn", // m_szName
NUM_POPN_BUTTONS, // m_iButtonsPerController
@@ -2810,7 +2776,6 @@ static const Style g_Style_Lights_Cabinet =
{ // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
0,1,2,3,4,5,6,7
},
- false, // m_bNeedsZoomOutWith2Players
false, // m_bCanUseBeginnerHelper
false, // m_bLockDifficulties
};
@@ -2827,6 +2792,7 @@ static const Game g_Game_Lights =
g_apGame_Lights_Styles, // m_apStyles
false, // m_bCountNotesSeparately
false, // m_bTickHolds
+ false, // m_PlayersHaveSeparateStyles
{ // m_InputScheme
"lights", // m_szName
NUM_LIGHTS_BUTTONS, // m_iButtonsPerController
@@ -2859,6 +2825,393 @@ static const Game g_Game_Lights =
TNS_W5, // m_mapW5To
};
+/** Kickbox mania **********************************************************/
+static const AutoMappings g_AutoKeyMappings_Kickbox = AutoMappings (
+ "", "", "",
+ AutoMappingEntry(0, KEY_Cq, GAME_BUTTON_MENULEFT, false),
+ AutoMappingEntry(0, KEY_Cr, GAME_BUTTON_MENURIGHT, false),
+ AutoMappingEntry(0, KEY_Ce, GAME_BUTTON_MENUUP, false),
+ AutoMappingEntry(0, KEY_Cw, GAME_BUTTON_MENUDOWN, false),
+ AutoMappingEntry(0, KEY_Cz, KICKBOX_BUTTON_DOWN_LEFT_FOOT, false),
+ AutoMappingEntry(0, KEY_Ca, KICKBOX_BUTTON_UP_LEFT_FOOT, false),
+ AutoMappingEntry(0, KEY_Cs, KICKBOX_BUTTON_UP_LEFT_FIST, false),
+ AutoMappingEntry(0, KEY_Cx, KICKBOX_BUTTON_DOWN_LEFT_FIST, false),
+ AutoMappingEntry(0, KEY_Cc, KICKBOX_BUTTON_DOWN_RIGHT_FIST, false),
+ AutoMappingEntry(0, KEY_Cd, KICKBOX_BUTTON_UP_RIGHT_FIST, false),
+ AutoMappingEntry(0, KEY_Cf, KICKBOX_BUTTON_UP_RIGHT_FOOT, false),
+ AutoMappingEntry(0, KEY_Cv, KICKBOX_BUTTON_DOWN_RIGHT_FOOT, false),
+ AutoMappingEntry(0, KEY_Cu, GAME_BUTTON_MENULEFT, true),
+ AutoMappingEntry(0, KEY_Cp, GAME_BUTTON_MENURIGHT, true),
+ AutoMappingEntry(0, KEY_Ci, GAME_BUTTON_MENUUP, true),
+ AutoMappingEntry(0, KEY_Co, GAME_BUTTON_MENUDOWN, true),
+ AutoMappingEntry(0, KEY_Cm, KICKBOX_BUTTON_DOWN_LEFT_FOOT, true),
+ AutoMappingEntry(0, KEY_Cj, KICKBOX_BUTTON_UP_LEFT_FOOT, true),
+ AutoMappingEntry(0, KEY_Ck, KICKBOX_BUTTON_UP_LEFT_FIST, true),
+ AutoMappingEntry(0, KEY_COMMA, KICKBOX_BUTTON_DOWN_LEFT_FIST, true),
+ AutoMappingEntry(0, KEY_PERIOD, KICKBOX_BUTTON_DOWN_RIGHT_FIST, true),
+ AutoMappingEntry(0, KEY_Cl, KICKBOX_BUTTON_UP_RIGHT_FIST, true),
+ AutoMappingEntry(0, KEY_SEMICOLON, KICKBOX_BUTTON_UP_RIGHT_FOOT, true),
+ AutoMappingEntry(0, KEY_SLASH, KICKBOX_BUTTON_DOWN_RIGHT_FOOT, true)
+);
+
+static const int KICKBOX_COL_SPACING= 64;
+
+static const Style g_Style_Kickbox_Human=
+{
+ true, // m_bUsedForGameplay
+ true, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ true, // m_bUsedForHowToPlay
+ "human", // m_szName
+ StepsType_kickbox_human, // m_StepsType
+ StyleType_OnePlayerOneSide, // m_StyleType
+ 4, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 0, 1, 1, 2, 2, 3, 3, Style::END_MAPPING },
+ { 0, 0, 1, 1, 2, 2, 3, 3, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Human_Versus=
+{
+ true, // m_bUsedForGameplay
+ false, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ false, // m_bUsedForHowToPlay
+ "hversus", // m_szName
+ StepsType_kickbox_human, // m_StepsType
+ StyleType_TwoPlayersTwoSides, // m_StyleType
+ 4, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 0, 1, 1, 2, 2, 3, 3, Style::END_MAPPING },
+ { 0, 0, 1, 1, 2, 2, 3, 3, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Quadarm=
+{
+ true, // m_bUsedForGameplay
+ true, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ true, // m_bUsedForHowToPlay
+ "quadarm", // m_szName
+ StepsType_kickbox_quadarm, // m_StepsType
+ StyleType_OnePlayerOneSide, // m_StyleType
+ 4, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { Style::NO_MAPPING, Style::NO_MAPPING, 0, 1, 2, 3, Style::NO_MAPPING, Style::NO_MAPPING, Style::END_MAPPING },
+ { Style::NO_MAPPING, Style::NO_MAPPING, 0, 1, 2, 3, Style::NO_MAPPING, Style::NO_MAPPING, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Quadarm_Versus=
+{
+ true, // m_bUsedForGameplay
+ false, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ false, // m_bUsedForHowToPlay
+ "qversus", // m_szName
+ StepsType_kickbox_quadarm, // m_StepsType
+ StyleType_TwoPlayersTwoSides, // m_StyleType
+ 4, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_3, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*1.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { Style::NO_MAPPING, Style::NO_MAPPING, 0, 1, 2, 3, Style::NO_MAPPING, Style::NO_MAPPING, Style::END_MAPPING },
+ { Style::NO_MAPPING, Style::NO_MAPPING, 0, 1, 2, 3, Style::NO_MAPPING, Style::NO_MAPPING, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Insect=
+{
+ true, // m_bUsedForGameplay
+ true, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ true, // m_bUsedForHowToPlay
+ "insect", // m_szName
+ StepsType_kickbox_insect, // m_StepsType
+ StyleType_OnePlayerOneSide, // m_StyleType
+ 6, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*2.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*2.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 0, 1, 2, 3, 4, 5, 5, Style::END_MAPPING },
+ { 0, 0, 1, 2, 3, 4, 5, 5, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3, 4, 5
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Insect_Versus=
+{
+ true, // m_bUsedForGameplay
+ false, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ false, // m_bUsedForHowToPlay
+ "iversus", // m_szName
+ StepsType_kickbox_insect, // m_StepsType
+ StyleType_TwoPlayersTwoSides, // m_StyleType
+ 6, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*2.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_4, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*2.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 0, 1, 2, 3, 4, 5, 5, Style::END_MAPPING },
+ { 0, 0, 1, 2, 3, 4, 5, 5, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3, 4, 5
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Arachnid=
+{
+ true, // m_bUsedForGameplay
+ true, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ true, // m_bUsedForHowToPlay
+ "arachnid", // m_szName
+ StepsType_kickbox_arachnid, // m_StepsType
+ StyleType_OnePlayerOneSide, // m_StyleType
+ 8, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +KICKBOX_COL_SPACING*3.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +KICKBOX_COL_SPACING*3.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 1, 2, 3, 4, 5, 6, 7, Style::END_MAPPING },
+ { 0, 1, 2, 3, 4, 5, 6, 7, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3, 4, 5, 6, 7
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style g_Style_Kickbox_Arachnid_Versus=
+{
+ true, // m_bUsedForGameplay
+ false, // m_bUsedForEdit
+ true, // m_bUsedForDemonstration
+ false, // m_bUsedForHowToPlay
+ "aversus", // m_szName
+ StepsType_kickbox_arachnid, // m_StepsType
+ StyleType_TwoPlayersTwoSides, // m_StyleType
+ 8, // m_iColsPerPlayer
+ { // m_ColumnInfo[NUM_PLAYERS][MAX_COLS_PER_PLAYER];
+ { // PLAYER_1
+ { TRACK_1, -KICKBOX_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +KICKBOX_COL_SPACING*3.5f, NULL },
+ },
+ { // PLAYER_2
+ { TRACK_1, -KICKBOX_COL_SPACING*3.5f, NULL },
+ { TRACK_2, -KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_3, -KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_4, -KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_5, +KICKBOX_COL_SPACING*0.5f, NULL },
+ { TRACK_6, +KICKBOX_COL_SPACING*1.5f, NULL },
+ { TRACK_7, +KICKBOX_COL_SPACING*2.5f, NULL },
+ { TRACK_8, +KICKBOX_COL_SPACING*3.5f, NULL },
+ },
+ },
+ { // m_iInputColumn[NUM_GameController][NUM_GameButton]
+ { 0, 1, 2, 3, 4, 5, 6, 7, Style::END_MAPPING },
+ { 0, 1, 2, 3, 4, 5, 6, 7, Style::END_MAPPING }
+ },
+ { // m_iColumnDrawOrder[MAX_COLS_PER_PLAYER];
+ 0, 1, 2, 3, 4, 5, 6, 7
+ },
+ false, // m_bCanUseBeginnerHelper
+ false, // m_bLockDifficulties
+};
+
+static const Style* g_apGame_Kickbox_Styles[] =
+{
+ &g_Style_Kickbox_Human,
+ &g_Style_Kickbox_Quadarm,
+ &g_Style_Kickbox_Insect,
+ &g_Style_Kickbox_Arachnid,
+ &g_Style_Kickbox_Human_Versus,
+ &g_Style_Kickbox_Quadarm_Versus,
+ &g_Style_Kickbox_Insect_Versus,
+ &g_Style_Kickbox_Arachnid_Versus,
+ NULL
+};
+
+static const Game g_Game_Kickbox =
+{
+ "kickbox", // m_szName
+ g_apGame_Kickbox_Styles, // m_apStyles
+ true, // m_bCountNotesSeparately
+ false, // m_bTickHolds
+ true, // m_PlayersHaveSeparateStyles
+ { // m_InputScheme
+ "kickbox", // m_szName
+ NUM_KICKBOX_BUTTONS, // m_iButtonsPerController
+ { // m_szButtonNames
+ { "DownLeftFoot", GameButton_Invalid },
+ { "UpLeftFoot", GameButton_Invalid },
+ { "UpLeftFist", GAME_BUTTON_LEFT },
+ { "DownLeftFist", GAME_BUTTON_UP },
+ { "DownRightFist", GAME_BUTTON_DOWN },
+ { "UpRightFist", GAME_BUTTON_RIGHT },
+ { "UpRightFoot", GameButton_Invalid },
+ { "DownRightFoot", GameButton_Invalid },
+ },
+ &g_AutoKeyMappings_Kickbox
+ },
+ {
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ { GameButtonType_Step },
+ },
+ TNS_W1, // m_mapW1To
+ TNS_W2, // m_mapW2To
+ TNS_W3, // m_mapW3To
+ TNS_W4, // m_mapW4To
+ TNS_W5, // m_mapW5To
+};
+
static const Game *g_Games[] =
{
&g_Game_Dance,
@@ -2872,6 +3225,7 @@ static const Game *g_Games[] =
&g_Game_Techno,
&g_Game_Popn,
&g_Game_Lights,
+ &g_Game_Kickbox,
};
GameManager::GameManager()
diff --git a/src/GameState.cpp b/src/GameState.cpp
index 8444616d4a..0253d9dd92 100644
--- a/src/GameState.cpp
+++ b/src/GameState.cpp
@@ -20,6 +20,7 @@
#include "LuaReference.h"
#include "MessageManager.h"
#include "MemoryCardManager.h"
+#include "NoteData.h"
#include "NoteSkinManager.h"
#include "PlayerState.h"
#include "PrefsManager.h"
@@ -136,7 +137,11 @@ GameState::GameState() :
{
g_pImpl = new GameStateImpl;
- SetCurrentStyle( NULL );
+ m_pCurStyle.Set(NULL);
+ FOREACH_PlayerNumber(rpn)
+ {
+ m_SeparatedStyles[rpn]= NULL;
+ }
m_pCurGame.Set( NULL );
m_iCoins.Set( 0 );
@@ -153,12 +158,12 @@ GameState::GameState() :
FOREACH_PlayerNumber( p )
{
m_pPlayerState[p] = new PlayerState;
- m_pPlayerState[p]->m_PlayerNumber = p;
+ m_pPlayerState[p]->SetPlayerNumber(p);
}
FOREACH_MultiPlayer( p )
{
m_pMultiPlayerState[p] = new PlayerState;
- m_pMultiPlayerState[p]->m_PlayerNumber = PLAYER_1;
+ m_pMultiPlayerState[p]->SetPlayerNumber(PLAYER_1);
m_pMultiPlayerState[p]->m_mp = p;
}
@@ -285,7 +290,7 @@ void GameState::Reset()
ASSERT( THEME != NULL );
m_timeGameStarted.SetZero();
- SetCurrentStyle( NULL );
+ SetCurrentStyle( NULL, PLAYER_INVALID );
FOREACH_MultiPlayer( p )
m_MultiPlayerStatus[p] = MultiPlayerStatus_NotJoined;
FOREACH_PlayerNumber( pn )
@@ -391,23 +396,32 @@ void GameState::JoinPlayer( PlayerNumber pn )
}
// Set the current style to something appropriate for the new number of joined players.
- if( ALLOW_LATE_JOIN && m_pCurStyle != NULL )
+ // beat gametype's versus styles use a different stepstype from its single
+ // styles, so when GameCommand tries to join both players for a versus
+ // style, it hits the assert when joining the first player. So if the first
+ // player is being joined and the current styletype is for two players,
+ // assume that the second player will be joined immediately afterwards and
+ // don't try to change the style. -Kyz
+ const Style* cur_style= GetCurrentStyle(PLAYER_INVALID);
+ if( ALLOW_LATE_JOIN && cur_style != NULL && !(pn == PLAYER_1 &&
+ (cur_style->m_StyleType == StyleType_TwoPlayersTwoSides ||
+ cur_style->m_StyleType == StyleType_TwoPlayersSharedSides)))
{
const Style *pStyle;
// Only use one player for StyleType_OnePlayerTwoSides and StepsTypes
// that can only be played by one player (e.g. dance-solo,
// dance-threepanel, popn-nine). -aj
// XXX?: still shows joined player as "Insert Card". May not be an issue? -aj
- if( m_pCurStyle->m_StyleType == StyleType_OnePlayerTwoSides ||
- m_pCurStyle->m_StepsType == StepsType_dance_solo ||
- m_pCurStyle->m_StepsType == StepsType_dance_threepanel ||
- m_pCurStyle->m_StepsType == StepsType_popn_nine )
- pStyle = GAMEMAN->GetFirstCompatibleStyle( m_pCurGame, 1, m_pCurStyle->m_StepsType );
+ if( cur_style->m_StyleType == StyleType_OnePlayerTwoSides ||
+ cur_style->m_StepsType == StepsType_dance_solo ||
+ cur_style->m_StepsType == StepsType_dance_threepanel ||
+ cur_style->m_StepsType == StepsType_popn_nine )
+ pStyle = GAMEMAN->GetFirstCompatibleStyle( m_pCurGame, 1, cur_style->m_StepsType );
else
- pStyle = GAMEMAN->GetFirstCompatibleStyle( m_pCurGame, GetNumSidesJoined(), m_pCurStyle->m_StepsType );
+ pStyle = GAMEMAN->GetFirstCompatibleStyle( m_pCurGame, GetNumSidesJoined(), cur_style->m_StepsType );
// use SetCurrentStyle in case of StyleType_OnePlayerTwoSides
- SetCurrentStyle( pStyle );
+ SetCurrentStyle( pStyle, pn );
}
Message msg( MessageIDToString(Message_PlayerJoined) );
@@ -657,7 +671,7 @@ int GameState::GetNumStagesForCurrentSongAndStepsOrCourse() const
int iNumStagesOfThisSong = 1;
if( m_pCurSong )
{
- const Style *pStyle = m_pCurStyle;
+ const Style *pStyle = GetCurrentStyle(PLAYER_INVALID);
int numSidesJoined = GetNumSidesJoined();
if( pStyle == NULL )
{
@@ -734,7 +748,12 @@ void GameState::BeginStage()
// only do this check with human players, assume CPU players (Rave)
// always have tokens. -aj (this could probably be moved below, even.)
if( !IsEventMode() && !IsCpuPlayer(p) )
- ASSERT( m_iPlayerStageTokens[p] >= m_iNumStagesOfThisSong );
+ {
+ if(m_iPlayerStageTokens[p] < m_iNumStagesOfThisSong)
+ {
+ LuaHelpers::ReportScriptErrorFmt("Player %d only has %d stage tokens, but needs %d.", p, m_iPlayerStageTokens[p], m_iNumStagesOfThisSong);
+ }
+ }
m_iPlayerStageTokens[p] -= m_iNumStagesOfThisSong;
}
FOREACH_HumanPlayer( pn )
@@ -894,6 +913,170 @@ void GameState::SaveCurrentSettingsToProfile( PlayerNumber pn )
pProfile->m_lastCourse.FromCourse( m_pPreferredCourse );
}
+bool GameState::CanSafelyEnterGameplay(RString& reason)
+{
+ if(!IsCourseMode())
+ {
+ Song const* song= m_pCurSong;
+ if(song == NULL)
+ {
+ reason= "Current song is NULL.";
+ return false;
+ }
+ }
+ else
+ {
+ Course const* song= m_pCurCourse;
+ if(song == NULL)
+ {
+ reason= "Current course is NULL.";
+ return false;
+ }
+ }
+ FOREACH_EnabledPlayer(pn)
+ {
+ Style const* style= GetCurrentStyle(pn);
+ if(style == NULL)
+ {
+ reason= ssprintf("Style for player %d is NULL.", pn+1);
+ return false;
+ }
+ if(!IsCourseMode())
+ {
+ Steps const* steps= m_pCurSteps[pn];
+ if(steps == NULL)
+ {
+ reason= ssprintf("Steps for player %d is NULL.", pn+1);
+ return false;
+ }
+ if(steps->m_StepsType != style->m_StepsType)
+ {
+ reason= ssprintf("Player %d StepsType %s for steps does not equal "
+ "StepsType %s for style.", pn+1,
+ GAMEMAN->GetStepsTypeInfo(steps->m_StepsType).szName,
+ GAMEMAN->GetStepsTypeInfo(style->m_StepsType).szName);
+ return false;
+ }
+ if(steps->m_pSong != m_pCurSong)
+ {
+ reason= ssprintf("Steps for player %d are not for the current song.",
+ pn+1);
+ return false;
+ }
+ NoteData ndtemp;
+ steps->GetNoteData(ndtemp);
+ if(ndtemp.GetNumTracks() != style->m_iColsPerPlayer)
+ {
+ reason= ssprintf("Steps for player %d have %d columns, style has %d "
+ "columns.", pn+1, ndtemp.GetNumTracks(), style->m_iColsPerPlayer);
+ return false;
+ }
+ }
+ else
+ {
+ Trail const* steps= m_pCurTrail[pn];
+ if(steps == NULL)
+ {
+ reason= ssprintf("Steps for player %d is NULL.", pn+1);
+ return false;
+ }
+ if(steps->m_StepsType != style->m_StepsType)
+ {
+ reason= ssprintf("Player %d StepsType %s for steps does not equal "
+ "StepsType %s for style.", pn+1,
+ GAMEMAN->GetStepsTypeInfo(steps->m_StepsType).szName,
+ GAMEMAN->GetStepsTypeInfo(style->m_StepsType).szName);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void GameState::SetCompatibleStylesForPlayers()
+{
+ bool style_set= false;
+ if(IsCourseMode())
+ {
+ if(m_pCurCourse != NULL)
+ {
+ const Style* style= m_pCurCourse->GetCourseStyle(m_pCurGame, GetNumSidesJoined());
+ if(style != NULL)
+ {
+ style_set= true;
+ SetCurrentStyle(style, PLAYER_INVALID);
+ }
+ }
+ else if(GetCurrentStyle(PLAYER_INVALID) == NULL)
+ {
+ vector vst;
+ GAMEMAN->GetStepsTypesForGame(m_pCurGame, vst);
+ const Style *style = GAMEMAN->GetFirstCompatibleStyle(
+ m_pCurGame, GetNumSidesJoined(), vst[0]);
+ SetCurrentStyle(style, PLAYER_INVALID);
+ }
+ }
+ if(!style_set)
+ {
+ FOREACH_EnabledPlayer(pn)
+ {
+ StepsType st= StepsType_Invalid;
+ if(m_pCurSteps[pn] != NULL)
+ {
+ st= m_pCurSteps[pn]->m_StepsType;
+ }
+ else if(m_pCurTrail[pn] != NULL)
+ {
+ st= m_pCurTrail[pn]->m_StepsType;
+ }
+ else
+ {
+ vector vst;
+ GAMEMAN->GetStepsTypesForGame(m_pCurGame, vst);
+ st= vst[0];
+ }
+ const Style *style = GAMEMAN->GetFirstCompatibleStyle(
+ m_pCurGame, GetNumSidesJoined(), st);
+ SetCurrentStyle(style, pn);
+ }
+ }
+}
+
+void GameState::ForceSharedSidesMatch()
+{
+ PlayerNumber pn_with_shared= PLAYER_INVALID;
+ const Style* shared_style= NULL;
+ FOREACH_EnabledPlayer(pn)
+ {
+ const Style* style= GetCurrentStyle(pn);
+ ASSERT_M(style != NULL, "Style being null should not be possible.");
+ if(style->m_StyleType == StyleType_TwoPlayersSharedSides)
+ {
+ pn_with_shared= pn;
+ shared_style= style;
+ }
+ }
+ if(pn_with_shared != PLAYER_INVALID)
+ {
+ ASSERT_M(GetNumPlayersEnabled() == 2, "2 players must be enabled for shared sides.");
+ PlayerNumber other_pn= OPPOSITE_PLAYER[pn_with_shared];
+ const Style* other_style= GetCurrentStyle(other_pn);
+ ASSERT_M(other_style != NULL, "Other player's style being null should not be possible.");
+ if(other_style->m_StyleType != StyleType_TwoPlayersSharedSides)
+ {
+ SetCurrentStyle(shared_style, other_pn);
+ if(IsCourseMode())
+ {
+ m_pCurTrail[other_pn].Set(m_pCurTrail[pn_with_shared]);
+ }
+ else
+ {
+ m_pCurSteps[other_pn].Set(m_pCurSteps[pn_with_shared]);
+ }
+ }
+ }
+}
+
void GameState::Update( float fDelta )
{
m_SongOptions.Update( fDelta );
@@ -1197,7 +1380,7 @@ RString GameState::GetPlayerDisplayName( PlayerNumber pn ) const
bool GameState::PlayersCanJoin() const
{
- bool b = GetNumSidesJoined() == 0 || GetCurrentStyle() == NULL; // selecting a style finalizes the players
+ bool b = GetNumSidesJoined() == 0 || GetCurrentStyle(PLAYER_INVALID) == NULL; // selecting a style finalizes the players
if( ALLOW_LATE_JOIN.IsLoaded() && ALLOW_LATE_JOIN )
{
Screen *pScreen = SCREENMAN->GetTopScreen();
@@ -1216,39 +1399,69 @@ int GameState::GetNumSidesJoined() const
return iNumSidesJoined;
}
-const Game* GameState::GetCurrentGame()
+const Game* GameState::GetCurrentGame() const
{
ASSERT( m_pCurGame != NULL ); // the game must be set before calling this
return m_pCurGame;
}
-const Style* GameState::GetCurrentStyle() const
+const Style* GameState::GetCurrentStyle(PlayerNumber pn) const
{
- return m_pCurStyle;
-}
-
-void GameState::SetCurrentStyle( const Style *pStyle )
-{
- m_pCurStyle.Set( pStyle );
- if( INPUTMAPPER )
+ if(GetCurrentGame() == NULL) { return NULL; }
+ if(!GetCurrentGame()->m_PlayersHaveSeparateStyles)
{
- if( GetCurrentStyle() && GetCurrentStyle()->m_StyleType == StyleType_OnePlayerTwoSides )
- INPUTMAPPER->SetJoinControllers( this->GetMasterPlayerNumber() );
- else
- INPUTMAPPER->SetJoinControllers( PLAYER_INVALID );
+ return m_pCurStyle;
+ }
+ else
+ {
+ if(pn >= NUM_PLAYERS)
+ {
+ return m_SeparatedStyles[PLAYER_1] == NULL ? m_SeparatedStyles[PLAYER_2]
+ : m_SeparatedStyles[PLAYER_1];
+ }
+ return m_SeparatedStyles[pn];
}
}
-bool GameState::SetCompatibleStyle(StepsType stype)
+void GameState::SetCurrentStyle(const Style *style, PlayerNumber pn)
+{
+ if(!GetCurrentGame()->m_PlayersHaveSeparateStyles)
+ {
+ m_pCurStyle.Set(style);
+ }
+ else
+ {
+ if(pn == PLAYER_INVALID)
+ {
+ FOREACH_PlayerNumber(rpn)
+ {
+ m_SeparatedStyles[rpn]= style;
+ }
+ }
+ else
+ {
+ m_SeparatedStyles[pn]= style;
+ }
+ }
+ if(INPUTMAPPER)
+ {
+ if(GetCurrentStyle(pn) && GetCurrentStyle(pn)->m_StyleType == StyleType_OnePlayerTwoSides)
+ INPUTMAPPER->SetJoinControllers(this->GetMasterPlayerNumber());
+ else
+ INPUTMAPPER->SetJoinControllers(PLAYER_INVALID);
+ }
+}
+
+bool GameState::SetCompatibleStyle(StepsType stype, PlayerNumber pn)
{
bool style_incompatible= false;
- if(!m_pCurStyle)
+ if(!GetCurrentStyle(pn))
{
style_incompatible= true;
}
else
{
- style_incompatible= stype != m_pCurStyle->m_StepsType;
+ style_incompatible= stype != GetCurrentStyle(pn)->m_StepsType;
}
if(CommonMetrics::AUTO_SET_STYLE && style_incompatible)
{
@@ -1258,9 +1471,9 @@ bool GameState::SetCompatibleStyle(StepsType stype)
{
return false;
}
- SetCurrentStyle(compatible_style);
+ SetCurrentStyle(compatible_style, pn);
}
- return stype == m_pCurStyle->m_StepsType;
+ return stype == GetCurrentStyle(pn)->m_StepsType;
}
bool GameState::IsPlayerEnabled( PlayerNumber pn ) const
@@ -1303,7 +1516,29 @@ bool GameState::IsHumanPlayer( PlayerNumber pn ) const
if( pn == PLAYER_INVALID )
return false;
- if( GetCurrentStyle() == NULL ) // no style chosen
+ if(GetCurrentGame()->m_PlayersHaveSeparateStyles)
+ {
+ if( GetCurrentStyle(pn) == NULL ) // no style chosen
+ {
+ return m_bSideIsJoined[pn];
+ }
+ else
+ {
+ StyleType type = GetCurrentStyle(pn)->m_StyleType;
+ switch( type )
+ {
+ case StyleType_TwoPlayersTwoSides:
+ case StyleType_TwoPlayersSharedSides:
+ return true;
+ case StyleType_OnePlayerOneSide:
+ case StyleType_OnePlayerTwoSides:
+ return pn == this->GetMasterPlayerNumber();
+ default:
+ FAIL_M(ssprintf("Invalid style type: %i", type));
+ }
+ }
+ }
+ if( GetCurrentStyle(pn) == NULL ) // no style chosen
{
if( PlayersCanJoin() )
return m_bSideIsJoined[pn]; // only allow input from sides that have already joined
@@ -1311,7 +1546,7 @@ bool GameState::IsHumanPlayer( PlayerNumber pn ) const
return true; // if we can't join, then we're on a screen like MusicScroll or GameOver
}
- StyleType type = GetCurrentStyle()->m_StyleType;
+ StyleType type = GetCurrentStyle(pn)->m_StyleType;
switch( type )
{
case StyleType_TwoPlayersTwoSides:
@@ -1669,7 +1904,7 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector &asFeatsOu
{
CHECKPOINT;
- StepsType st = GetCurrentStyle()->m_StepsType;
+ StepsType st = GetCurrentStyle(pn)->m_StepsType;
// Find unique Song and Steps combinations that were played.
// We must keep only the unique combination or else we'll double-count
@@ -2012,7 +2247,7 @@ bool GameState::DifficultiesLocked() const
return true;
if( IsCourseMode() )
return PREFSMAN->m_bLockCourseDifficulties;
- if( GetCurrentStyle()->m_bLockDifficulties )
+ if( GetCurrentStyle(PLAYER_INVALID)->m_bLockDifficulties )
return true;
return false;
}
@@ -2099,7 +2334,7 @@ bool GameState::ChangePreferredCourseDifficulty( PlayerNumber pn, int dir )
return false;
if( find(v.begin(),v.end(),cd) == v.end() )
continue; /* not available */
- if( !pCourse || pCourse->GetTrail( GetCurrentStyle()->m_StepsType, cd ) )
+ if( !pCourse || pCourse->GetTrail( GetCurrentStyle(pn)->m_StepsType, cd ) )
break;
}
@@ -2319,13 +2554,21 @@ public:
else { Song *pS = Luna::check( L, 1, true ); p->m_pCurSong.Set( pS ); }
COMMON_RETURN_SELF;
}
- static void SetCompatibleStyleOrError(T* p, lua_State* L, StepsType stype)
+ static int CanSafelyEnterGameplay(T* p, lua_State* L)
{
- if(!p->SetCompatibleStyle(stype))
+ RString reason;
+ bool can= p->CanSafelyEnterGameplay(reason);
+ lua_pushboolean(L, can);
+ LuaHelpers::Push(L, reason);
+ return 2;
+ }
+ static void SetCompatibleStyleOrError(T* p, lua_State* L, StepsType stype, PlayerNumber pn)
+ {
+ if(!p->SetCompatibleStyle(stype, pn))
{
luaL_error(L, "No compatible style for steps/trail.");
}
- if(!p->m_pCurStyle)
+ if(!p->GetCurrentStyle(pn))
{
luaL_error(L, "No style set and AutoSetStyle is false, cannot set steps/trail.");
}
@@ -2348,7 +2591,7 @@ public:
else
{
Steps *pS = Luna::check(L,2);
- SetCompatibleStyleOrError(p, L, pS->m_StepsType);
+ SetCompatibleStyleOrError(p, L, pS->m_StepsType, pn);
p->m_pCurSteps[pn].Set(pS);
}
COMMON_RETURN_SELF;
@@ -2378,7 +2621,7 @@ public:
else
{
Trail *pS = Luna::check(L,2);
- SetCompatibleStyleOrError(p, L, pS->m_StepsType);
+ SetCompatibleStyleOrError(p, L, pS->m_StepsType, pn);
p->m_pCurTrail[pn].Set(pS);
}
COMMON_RETURN_SELF;
@@ -2579,7 +2822,8 @@ public:
}
static int GetCurrentStyle( T* p, lua_State *L )
{
- Style *pStyle = const_cast