Special case kickbox autogen added. GameState now has a member for passing args from the theme to the autogen, only used by kickbox for kick recovery time.

This commit is contained in:
Kyzentun
2015-01-26 19:43:15 -07:00
parent b6e9d188c3
commit c69cf1ef4e
5 changed files with 233 additions and 2 deletions
+168
View File
@@ -781,6 +781,174 @@ void NoteDataUtil::LoadTransformedLightsFromTwo( const NoteData &marquee, const
NoteDataUtil::RemoveMines( out );
}
// This kickbox_limb enum should not be used anywhere outside the
// Autogenkickbox function. -Kyz
enum kickbox_limb
{
left_foot, left_fist, right_fist, right_foot, num_kickbox_limbs, invalid_limb= -1
};
void NoteDataUtil::AutogenKickbox(const NoteData& in, NoteData& out, const TimingData& timing, StepsType out_type, int nonrandom_seed)
{
// Each limb has its own list of tracks it is used for. This allows
// abstract handling of the different styles.
// By convention, the lower panels are pushed first. This gives the upper
// panels a higher index, which is mnemonically useful.
vector<vector<int> > limb_tracks(num_kickbox_limbs);
bool have_feet= true;
switch(out_type)
{
case StepsType_kickbox_human:
out.SetNumTracks(4);
limb_tracks[left_foot].push_back(0);
limb_tracks[left_fist].push_back(1);
limb_tracks[right_fist].push_back(2);
limb_tracks[right_foot].push_back(3);
break;
case StepsType_kickbox_quadarm:
out.SetNumTracks(4);
have_feet= false;
limb_tracks[left_fist].push_back(1);
limb_tracks[left_fist].push_back(0);
limb_tracks[right_fist].push_back(2);
limb_tracks[right_fist].push_back(3);
break;
case StepsType_kickbox_insect:
out.SetNumTracks(6);
limb_tracks[left_foot].push_back(0);
limb_tracks[left_fist].push_back(2);
limb_tracks[left_fist].push_back(1);
limb_tracks[right_fist].push_back(3);
limb_tracks[right_fist].push_back(4);
limb_tracks[right_foot].push_back(5);
break;
case StepsType_kickbox_arachnid:
out.SetNumTracks(8);
limb_tracks[left_foot].push_back(0);
limb_tracks[left_foot].push_back(1);
limb_tracks[left_fist].push_back(3);
limb_tracks[left_fist].push_back(2);
limb_tracks[right_fist].push_back(4);
limb_tracks[right_fist].push_back(5);
limb_tracks[right_foot].push_back(7);
limb_tracks[right_foot].push_back(6);
break;
DEFAULT_FAIL(out_type);
}
// prev_limb_panels keeps track of which panel in the track list the limb
// hit last.
vector<size_t> prev_limb_panels(num_kickbox_limbs, 0);
vector<int> panel_repeat_counts(num_kickbox_limbs, 0);
vector<int> panel_repeat_goals(num_kickbox_limbs, 0);
RandomGen rnd(nonrandom_seed);
kickbox_limb prev_limb_used= invalid_limb;
// Kicks are only allowed if there is enough setup/recovery time.
float kick_recover_time= GAMESTATE->GetAutoGenFarg(0);
if(kick_recover_time <= 0.0f)
{
kick_recover_time= .25f;
}
float prev_note_time= -1.0f;
int rows_done= 0;
#define RAND_FIST ((rnd() % 2) ? left_fist : right_fist)
#define RAND_FOOT ((rnd() % 2) ? left_foot : right_foot)
FOREACH_NONEMPTY_ROW_ALL_TRACKS(in, r)
{
// Arbitrary: Drop everything except taps and hold heads out entirely,
// convert holds to tap just the head.
bool has_valid_tapnote= false;
for(int t= 0; t < in.GetNumTracks(); ++t)
{
const TapNote& tn= in.GetTapNote(t, r);
if(tn.type == TapNoteType_Tap || tn.type == TapNoteType_HoldHead)
{
has_valid_tapnote= true;
break;
}
}
if(!has_valid_tapnote) { continue; }
int next_row= r;
bool next_has_valid= false;
while(!next_has_valid)
{
if(!in.GetNextTapNoteRowForAllTracks(next_row))
{
next_row= -1;
next_has_valid= true;
}
else
{
for(int t= 0; t < in.GetNumTracks(); ++t)
{
const TapNote& tn= in.GetTapNote(t, next_row);
if(tn.type == TapNoteType_Tap || tn.type == TapNoteType_HoldHead)
{
next_has_valid= true;
break;
}
}
}
}
float this_note_time= timing.GetElapsedTimeFromBeat(NoteRowToBeat(r));
float next_note_time= timing.GetElapsedTimeFromBeat(NoteRowToBeat(next_row));
kickbox_limb this_limb= invalid_limb;
switch(prev_limb_used)
{
case invalid_limb:
// First limb is arbitrarily always a fist.
this_limb= RAND_FIST;
break;
case left_foot:
case right_foot:
// Multiple kicks in a row are allowed if they're on the same foot.
// Allow the last note to be a kick.
// Switch feet if there's enough time.
if(next_note_time - this_note_time > kick_recover_time * 2.0f)
{
this_limb= prev_limb_used == left_foot ? right_foot : left_foot;
}
else if((next_note_time - this_note_time > kick_recover_time * .5f ||
next_note_time < 0.0f) && (rnd() % 2))
{
this_limb= prev_limb_used;
}
else
{
this_limb= RAND_FIST;
}
break;
case left_fist:
case right_fist:
if(this_note_time - prev_note_time > kick_recover_time &&
(next_note_time - this_note_time > kick_recover_time ||
next_note_time < 0.0f) && have_feet)
{
this_limb= RAND_FOOT;
}
else
{
// Alternate fists.
this_limb= prev_limb_used == left_fist ? right_fist : left_fist;
}
break;
}
size_t this_panel= prev_limb_panels[this_limb];
if(panel_repeat_counts[this_limb] + 1 > panel_repeat_goals[this_limb])
{
// Use a different panel.
this_panel= (this_panel + 1) % limb_tracks[this_limb].size();
panel_repeat_counts[this_limb]= 0;
panel_repeat_goals[this_limb]= (rnd() % 8) + 1;
}
out.SetTapNote(limb_tracks[this_limb][this_panel], r, TAP_ORIGINAL_TAP);
++panel_repeat_counts[this_limb];
prev_limb_panels[this_limb]= this_panel;
prev_note_time= this_note_time;
prev_limb_used= this_limb;
++rows_done;
}
out.RevalidateATIs(vector<int>(), false);
}
RadarStats CalculateRadarStatsFast( const NoteData &in, RadarStats &out )
{
out.taps = 0;