User:ChouxZi3
public static class TtcMain
{
public static void FindIdealReentryManipulation()
{
TtcSaveState saveState = new TtcSaveState();
int startingFrame = MupenUtilities.GetFrameCount();
List<List<int>> dustFramesLists = GetDustFrameLists(startingFrame + 2, 25, 25);
Config.Print("START FindIdealReentryManipulation");
foreach (List<int> dustFrames in dustFramesLists)
{
TtcSimulation simulation = new TtcSimulation(saveState, startingFrame, dustFrames);
simulation.FindIdealReentryManipulationGivenDustFrames(dustFrames);
}
Config.Print("END FindIdealReentryManipulation");
}
}
public class TtcSimulation
{
private readonly TtcRng _rng;
private readonly List<TtcObject> _rngObjects;
private readonly int _startingFrame;
private int _currentFrame;
public TtcSimulation(TtcSaveState saveState, int startingFrame, List<int> dustFrames)
{
(_rng, _rngObjects) = TtcUtilities.CreateRngObjectsFromSaveState(saveState);
_startingFrame = startingFrame;
_currentFrame = _startingFrame;
AddDustFrames(dustFrames);
}
public TtcSaveState GetSaveState()
{
return new TtcSaveState(_rng.GetRng(), _rngObjects);
}
// Given dust, goes forward and spawns height swings to investigate
public void FindIdealReentryManipulationGivenDustFrames(List<int> dustFrames)
{
int phase1Limit = 1000;
int maxDustFrame = dustFrames.Count == 0 ? 0 : dustFrames.Max();
int counter = 0;
int frame = _startingFrame;
while (frame < _startingFrame + phase1Limit)
{
counter++;
frame++;
foreach (TtcObject rngObject in _rngObjects)
{
rngObject.SetFrame(frame);
rngObject.Update();
}
// Check if pendulum will do height swing after all dust has been made
TtcPendulum pendulum = GetReentryPendulum();
if (frame > maxDustFrame &&
pendulum._accelerationDirection == -1 &&
pendulum._accelerationMagnitude == 13 &&
pendulum._angularVelocity == 0 &&
pendulum._waitingTimer == 0 &&
pendulum._angle == 42748)
{
TtcSimulation simulation = new TtcSimulation(GetSaveState(), frame, new List<int>());
simulation.FindIdealReentryManipulationGivenFrame1(dustFrames, frame);
}
}
}
// Given frame 1, goes forward and spawns wall push swings to investigate
// Frame 1 is the frame at the start of the pendulum swing that lets Mario get the right height
public void FindIdealReentryManipulationGivenFrame1(List<int> dustFrames, int frame1)
{
//Config.Print("TRY\t{0}\t{1}", frame1, "[" + string.Join(",", dustFrames) + "]");
int phase2Limit = 1000;
TtcPendulum pendulum = GetReentryPendulum();
TtcBobomb firstBobomb = GetFirstBobomb();
TtcBobomb secondBobomb = GetSecondBobomb();
TtcBobomb thirdBobomb = null;
TtcBobomb fourthBobomb = null;
int counter = 0;
int frame = _startingFrame;
while (frame < _startingFrame + phase2Limit)
{
counter++;
frame++;
foreach (TtcObject rngObject in _rngObjects)
{
// coin for bobomb 1
if (counter == 162 && rngObject == firstBobomb)
{
_rng.PollRNG(3);
}
// coin for bobomb 2
if (counter == 258 && rngObject == secondBobomb)
{
_rng.PollRNG(3);
}
rngObject.SetFrame(frame);
rngObject.Update();
}
// bob-omb 2 start
if (counter == 19)
{
secondBobomb.SetWithinMarioRange(1);
}
// bob-omb 2 end, bob-omb 4 start
if (counter == 258)
{
_rngObjects.Remove(secondBobomb);
fourthBobomb = new TtcBobomb(_rng, 0, 0); // starts outside range
_rngObjects.Insert(68, fourthBobomb);
}
// bob-omb 1 start
if (counter == 154)
{
firstBobomb.SetWithinMarioRange(1);
}
// bob-omb 1 end, bob-omb 3 start
if (counter == 162)
{
_rngObjects.Remove(firstBobomb);
thirdBobomb = new TtcBobomb(_rng, 0, 1); // starts inside range
_rngObjects.Insert(68, thirdBobomb);
}
// bob-omb 3 exiting range
if (counter == 363)
{
thirdBobomb.SetWithinMarioRange(0);
}
// dust frames
if (counter >= 84 && counter <= 95 && counter != 93)
{
_rng.PollRNG(4);
}
// bob-omb 2 fuse smoke
if ((counter >= 99 && counter <= 211 && counter % 8 == 3) ||
(counter >= 219 && counter <= 257 && counter % 2 == 1))
{
_rng.PollRNG(3);
}
// bob-omb 1 fuse smoke
if (counter >= 156 && counter <= 162 && counter % 2 == 0)
{
_rng.PollRNG(3);
}
// pendulum must have enough waiting frames
if (counter == 162)
{
bool pendulumQualifies = pendulum._waitingTimer >= 18;
if (!pendulumQualifies) return;
}
// Check if pendulum will do wall push swing
if (counter > 363 + 15 &&
pendulum._accelerationDirection == -1 &&
pendulum._accelerationMagnitude == 42 &&
pendulum._angularVelocity == 0 &&
pendulum._waitingTimer == 0 &&
pendulum._angle == 42748)
{
TtcSimulation simulation = new TtcSimulation(GetSaveState(), frame, new List<int>());
simulation.FindIdealReentryManipulationGivenFrame2(dustFrames, frame1, frame);
}
//Config.Print(frame + "\t" + _rng.GetIndex() + "\t" + GetSaveState());
}
}
// Investigates a wall push swing to see if it qualifies
// Frame 2 is the frame at the start of the pendulum swing that lets Mario get wall displacement
public void FindIdealReentryManipulationGivenFrame2(List<int> dustFrames, int frame1, int frame2)
{
//Config.Print("ATTEMPT\t{0}\t{1}\t{2}", frame1, frame2, "[" + string.Join(",", dustFrames) + "]");
int counter = 0;
int frame = _startingFrame;
while (true)
{
counter++;
frame++;
foreach (TtcObject rngObject in _rngObjects)
{
rngObject.SetFrame(frame);
rngObject.Update();
}
// bob-omb 1 is in range
if (counter == 63)
{
GetFirstBobomb().SetWithinMarioRange(1);
}
// collecting star particles
if (counter == 66)
{
_rng.PollRNG(80);
}
// bob-omb 2 is in range
if (counter == 70)
{
GetSecondBobomb().SetWithinMarioRange(1);
}
// hand is in position
if (counter == 77)
{
TtcHand hand = GetLowerHand();
int min = 36700;
int max = 39400;
bool handQualifies = hand._angle >= min && hand._angle <= max;
if (!handQualifies) return;
}
// spinner is in position
if (counter == 122)
{
TtcSpinner spinner = GetLowestSpinner();
int min = 12600;
int max = 14700;
bool spinnerAngleQualifies =
(spinner._angle >= min && spinner._angle <= max) ||
(spinner._angle >= min + 32768 && spinner._angle <= max + 32768);
bool spinnerDirectionQualifies = spinner._direction == -1;
bool spinnerQualifies = spinnerAngleQualifies && spinnerDirectionQualifies;
if (!spinnerQualifies) return;
List<int> inputDustFrames = dustFrames.ConvertAll(dustFrame => dustFrame - 2);
Config.Print("SUCCESS\t{0}\t{1}\t{2}\t", frame1, frame2, "[" + string.Join(",", inputDustFrames) + "]");
return;
}
}
}
}
public class PendulumSwingTable
{
public struct PendulumSwingReference
{
public int Amplitude;
public int Index;
public override int GetHashCode()
{
return Amplitude;
}
}
Dictionary<int, PendulumSwingReference> _amplitudeDictionary = new Dictionary<int, PendulumSwingReference>();
Dictionary<int, PendulumSwingReference> _indexDictionary = new Dictionary<int, PendulumSwingReference>();
Dictionary<int, string> _extendedAmplitudeDictionary = new Dictionary<int, string>();
public PendulumSwingTable()
{
}
public void Add(PendulumSwingReference pendulumSwingRef)
{
_amplitudeDictionary.Add(pendulumSwingRef.Amplitude, pendulumSwingRef);
_indexDictionary.Add(pendulumSwingRef.Index, pendulumSwingRef);
_extendedAmplitudeDictionary.Add(pendulumSwingRef.Amplitude, pendulumSwingRef.Index.ToString());
}
public int? GetPendulumSwingIndex(int amplitude)
{
if (_amplitudeDictionary.ContainsKey(amplitude))
return _amplitudeDictionary[amplitude].Index;
// Short circuit this case, otherwise Math.Abs throws an exception
if (amplitude == Int32.MinValue)
return null;
// Check for pendulum swings beyond the standard indexes
int absAmplitude = Math.Abs(amplitude);
int tenativeFrames = (int)((-21 + Math.Sqrt(441 + 84 * absAmplitude)) / 42);
int tentativeAmplitude = tenativeFrames * (tenativeFrames + 1) * 21;
if (absAmplitude == tentativeAmplitude && absAmplitude > 7182)
{
if ((amplitude > 0) == (tenativeFrames % 2 == 0)) // beyond forward indexes
{
return tenativeFrames + 270;
}
else // beyond backward indexes
{
return -1 * tenativeFrames - 363;
}
}
return null;
}
public int GetPendulumAmplitude(int index)
{
if (_indexDictionary.ContainsKey(index)) return _indexDictionary[index].Amplitude;
int beyondIndex = index > 288 ? index - 288 : -381 - index;
int amplitudeMagnitude = 7182 + 777 * beyondIndex + 21 * (beyondIndex * beyondIndex);
int sign = index % 2 == 0 ? 1 : -1;
return amplitudeMagnitude * sign;
}
public string GetPendulumSwingIndexExtended(int amplitude)
{
int? pendulumIndex = GetPendulumSwingIndex(amplitude);
if (pendulumIndex.HasValue)
return pendulumIndex.Value.ToString();
if (_extendedAmplitudeDictionary.ContainsKey(amplitude))
return _extendedAmplitudeDictionary[amplitude];
return Double.NaN.ToString();
}
public (int, int)? GetPendulumSwingIndexExtendedPair(int amplitude)
{
string index = GetPendulumSwingIndexExtended(amplitude);
if (index == Double.NaN.ToString()) return null;
int hyphenIndex = index.LastIndexOf('-');
int? primaryIndex, secondaryIndex;
if (hyphenIndex == -1 || hyphenIndex == 0)
{
primaryIndex = ParsingUtilities.ParseIntNullable(index);
secondaryIndex = 0;
}
else
{
primaryIndex = ParsingUtilities.ParseIntNullable(index.Substring(0, hyphenIndex));
secondaryIndex = ParsingUtilities.ParseIntNullable(index.Substring(hyphenIndex + 1));
}
if (primaryIndex == null || secondaryIndex == null) return null;
return (primaryIndex.Value, secondaryIndex.Value);
}
public void FillInExtended()
{
int range = 100; // 2000;
List<int> startingIndexes = new List<int>();
for (int i = 0; i < range; i++)
{
startingIndexes.Add(289 + i);
}
for (int i = 0; i < range; i++)
{
startingIndexes.Add(-382 - i);
}
List<PendulumSwing> startingSwings = startingIndexes.ConvertAll(
index => new PendulumSwing(GetPendulumAmplitude(index), 0, null, index, 0));
Queue<PendulumSwing> queue = new Queue<PendulumSwing>();
foreach (PendulumSwing swing in startingSwings)
{
List<PendulumSwing> successors = swing.GetSuccessors();
successors.ForEach(successor => queue.Enqueue(successor));
}
while (queue.Count > 0)
{
PendulumSwing dequeue = queue.Dequeue();
if (GetPendulumSwingIndexExtended(dequeue.Amplitude) != Double.NaN.ToString())
continue;
if (dequeue.SecondaryIndex > range)
continue;
string extendedIndex = dequeue.PrimaryIndex + "-" + dequeue.SecondaryIndex;
_extendedAmplitudeDictionary[dequeue.Amplitude] = extendedIndex;
List<PendulumSwing> successors = dequeue.GetSuccessors();
successors.ForEach(successor => queue.Enqueue(successor));
}
}
public class PendulumSwing
{
public readonly int Amplitude;
public readonly int Acceleration;
public readonly PendulumSwing Predecessor;
public readonly int PrimaryIndex;
public readonly int SecondaryIndex;
public PendulumSwing(
int amplitude,
int acceleration,
PendulumSwing predecessor,
int primaryIndex,
int secondaryIndex)
{
Amplitude = amplitude;
Acceleration = acceleration;
Predecessor = predecessor;
PrimaryIndex = primaryIndex;
SecondaryIndex = secondaryIndex;
}
public List<PendulumSwing> GetSuccessors()
{
return new List<PendulumSwing>()
{
new PendulumSwing((int)WatchVariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 13), 13, this, PrimaryIndex, SecondaryIndex + 1),
new PendulumSwing((int)WatchVariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 42), 42, this, PrimaryIndex, SecondaryIndex + 1),
};
}
public override string ToString()
{
string predecessorString = Predecessor?.ToString() ?? "";
return predecessorString + " =>" + Acceleration + "=> " + Amplitude;
}
}
}
public static class CalculatorMain
{
public static void CalculateMovementForTtmHolp()
{
float startX = 1094.12268066406f;
float startY = -476.171997070313f;
float startZ = -3675.9716796875f;
float startXSpeed = -6.70571994781494f;
float startYSpeed = -52f;
float startZSpeed = -0.628647029399872f;
float startHSpeed = -6.70173645019531f;
ushort marioAngle = 16455;
Dictionary<int, ushort> cameraAngles =
new Dictionary<int, ushort>()
{
[0] = 28563,
[1] = 28552,
[2] = 28548,
[3] = 28533,
[4] = 28524,
[5] = 28514,
[6] = 28500,
};
float goalX = 1060.860229f;
float goalY = -5001.017029f;
float goalZ = -3678.57666f;
int xInput = 56;
int zInput = 22;
int xRadius = 5;
int zRadius = 5;
MarioState startState = new MarioState(
startX,
startY,
startZ,
startXSpeed,
startYSpeed,
startZSpeed,
startHSpeed,
marioAngle,
cameraAngles[0],
null,
null,
0);
int lastIndex = -1;
List<Input> inputs = CalculatorUtilities.GetInputRange(xInput - xRadius, xInput + xRadius, zInput - zRadius, zInput + zRadius);
float bestDiff = float.MaxValue;
MarioState bestState = null;
Queue<MarioState> queue = new Queue<MarioState>();
HashSet<MarioState> alreadySeen = new HashSet<MarioState>();
queue.Enqueue(startState);
alreadySeen.Add(startState);
while (queue.Count != 0)
{
MarioState dequeue = queue.Dequeue();
List<MarioState> nextStates = inputs.ConvertAll(input => AirMovementCalculator.ApplyInput(dequeue, input));
nextStates = nextStates.ConvertAll(state => state.WithCameraAngle(cameraAngles[state.Index]));
foreach (MarioState state in nextStates)
{
if (alreadySeen.Contains(state)) continue;
if (state.Index > 4) continue;
if (state.Index != lastIndex)
{
lastIndex = state.Index;
System.Diagnostics.Trace.WriteLine("Now at index " + lastIndex);
}
if (state.Index == 4)
{
float diff = (float)MoreMath.GetDistanceBetween(state.X, state.Z, goalX, goalZ);
if (diff > 1 ? diff < bestDiff * 0.5 : diff < bestDiff)
{
bestDiff = diff;
bestState = state;
System.Diagnostics.Trace.WriteLine("Diff of " + bestDiff + " is: " + bestState.GetLineage());
}
}
alreadySeen.Add(state);
queue.Enqueue(state);
}
}
System.Diagnostics.Trace.WriteLine("Done");
}
public static List<(float, float)> GetSuccessFloatPositions()
{
// initial
float startX = -1378.91674804688f;
float startY = -2434f;
float startZ = -1423.35168457031f;
float startXSpeed = 0f;
float startYSpeed = 20f;
float startZSpeed = 0f;
float startHSpeed = 0f;
// after all 4 q steps (no wall displacement)
float endX = -1376.13940429688f;
float endY = -2414f;
float endZ = -1423.66223144531f;
float endXSpeed = 2.7774920463562f;
float endYSpeed = 16f;
float endZSpeed = -0.310500144958496f;
float endHSpeed = -1.45670866966248f;
// after 1 q step (no wall displacement)
float qstepX = -1378.22241210938f;
float qstepY = -2429f;
float qstepZ = -1423.42932128906f;
float qstepXSpeed = 2.7774920463562f;
float qstepYSpeed = -4f;
float qstepZSpeed = -0.310500144958496f;
float qstepHSpeed = -1.45670866966248f;
// after 1 q step and wall displacement
float displacedX = -1307.73107910156f;
float displacedY = -2429f;
float displacedZ = -1353.11071777344f;
float displacedXSpeed = 0f;
float displacedYSpeed = -4f;
float displacedZSpeed = 0f;
float displacedHSpeed = 0f;
// closest starting position that works
float closestX = -1378.91381835938f;
float closestY = -2434f;
float closestZ = -1423.34875488281f;
float closestXSpeed = -3.67686033248901f;
float closestYSpeed = 0f;
float closestZSpeed = -4.74138116836548f;
float closestHSpeed = 6f;
// farthest starting position that is within range (doesn't work)
float farthestX = -1379.22241210938f;
float farthestY = -2434f;
float farthestZ = -1423.65734863281f;
float farthestXSpeed = 0f;
float farthestYSpeed = 0f;
float farthestZSpeed = 0f;
float farthestHSpeed = 0f;
ushort marioAngle = 39655;
ushort cameraAngle = 7142;
TriangleDataModel tri = new TriangleDataModel(0x8015F910);
List<(float, float)> successPositions = new List<(float, float)>();
int numAttempts = 0;
int numSuccesses = 0;
for (float lineX = closestX, lineZ = closestZ; lineX >= farthestX; lineX -= 0.0001f, lineZ -= 0.0001f)
{
List<float> pointXs = new List<float>();
float temp = lineX;
pointXs.Add(temp);
temp = lineX;
for (int i = 0; i < 10; i++)
{
temp -= 0.0001f;
pointXs.Add(temp);
}
temp = lineX;
for (int i = 0; i < 10; i++)
{
temp += 0.0001f;
pointXs.Add(temp);
}
float pointZ = lineZ;
foreach (float pointX in pointXs)
{
MarioState pointState = new MarioState(
pointX,
startY,
pointZ,
startXSpeed,
startYSpeed,
startZSpeed,
startHSpeed,
marioAngle,
cameraAngle,
null,
null,
0);
Input input = new Input(32, -124);
MarioState movedState = AirMovementCalculator.ApplyInput(pointState, input, 1);
(float dispX, float dispZ) = WallDisplacementCalculator.HandleWallDisplacement(
movedState.X, movedState.Y, movedState.Z, tri, 50, 150);
bool match = dispX == displacedX && dispZ == displacedZ;
if (match)
{
successPositions.Add((pointX, pointZ));
/*
Config.Print(
"({0},{1}) => ({2},{3}) match={4}",
(double)pointX, (double)pointZ, (double)dispX, (double)dispZ, match);
*/
}
numAttempts++;
if (match) numSuccesses++;
}
}
/*
Config.Print("numAttempts = " + numAttempts);
Config.Print("numSuccesses = " + numSuccesses);
*/
successPositions.Sort((a, b) => Math.Sign(a.Item1 - b.Item1));
return successPositions;
}
public static void TestWalkingCode()
{
float startX = -7390.01953125f;
float startY = -3153f;
float startZ = 3936.21435546875f;
float startXSpeed = 7.88103151321411f;
float startYSpeed = 0f;
float startZSpeed = -15.0203580856323f;
float startHSpeed = 16.9623641967773f;
ushort startMarioAngle = 27738;
ushort startCameraAngle = 0;
MarioState marioState = new MarioState(
startX, startY, startZ,
startXSpeed, startYSpeed, startZSpeed, startHSpeed,
startMarioAngle, startCameraAngle, null, null, 0);
Input input = new Input(23, 26);
for (int i = 0; i < 10; i++)
{
Config.Print(i + ": " + marioState);
marioState = GroundMovementCalculator.ApplyInput(marioState, input);
}
}
public static void TestGetRelativePosition()
{
float marioX = -1431.61889648438f;
float marioY = -4003f;
float marioZ = -1318.10009765625f;
ushort marioAngle = 53906;
(float x, float y, float z) = ObjectCalculator.GetRelativePosition(
marioX, marioY, marioZ, marioAngle, 0, 60, 100);
Config.Print("{0},{1},{2}", (double)x, (double)y, (double)z);
}
public static void TestGetObjectDisplacement()
{
float marioX = -1462.44079589844f;
float marioY = -4003f;
float marioZ = -1196.89099121094f;
float marioRadius = 37;
float bobombX = -1538.07922363281f;
float bobombY = -4003f;
float bobombZ = -1257.61840820313f;
float bobombRadius = 65 * 1.2f;
float padding = -5;
(float x, float z) = ObjectCalculator.GetObjectDisplacement(
marioX, marioZ, marioRadius, 0, bobombX, bobombZ, bobombRadius, padding);
Config.Print("{0},{1}", (double)x, (double)z);
}
public static void TestCombined()
{
float marioX = -918.42724609375f;
float marioY = -2434f;
float marioZ = -1730.48791503906f;
float marioXSpeed = 1.16657888889313f;
float marioYSpeed = 0f;
float marioZSpeed = 5.46906852722168f;
float marioHSpeed = 5.59210300445557f;
ushort marioAngle = 2206;
ushort cameraAngle = 4132;
float objX = -897.566040039063f;
float objZ = -1632.68811035156f;
int inputX = -14;
int inputY = -48;
MarioState marioState = new MarioState(
marioX, marioY, marioZ,
marioXSpeed, marioYSpeed, marioZSpeed, marioHSpeed,
marioAngle, cameraAngle, null, null, 0);
Input input = new Input(inputX, inputY);
// walking
MarioState afterWalkingTemp = GroundMovementCalculator.ApplyInput(marioState, input);
MarioState afterWalking = afterWalkingTemp.WithPosition(marioState.X, marioState.Y, marioState.Z);
// displacement
(float afterDisplacementX, float afterDisplacementZ) =
ObjectCalculator.GetObjectDisplacement(
afterWalking.X, afterWalking.Z, 37, afterWalking.MarioAngle,
objX, objZ, 65 * 1.2f, -5);
// relative position
(float relX, float relY, float relZ) = ObjectCalculator.GetRelativePosition(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.MarioAngle, 0, 60, 100);
MarioState finalState = new MarioState(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.XSpeed, afterWalking.YSpeed, afterWalking.ZSpeed, afterWalking.HSpeed,
afterWalking.MarioAngle, cameraAngle, null, null, 0);
Config.Print(finalState);
Config.Print("{0},{1},{2}", (double)relX, (double)relY, (double)relZ);
}
public static void TestMovementTowardsSpot()
{
float startX = -1323.72937011719f;
float startY = -2434f;
float startZ = -1579.7392578125f;
float startXSpeed = 2.64395904541016f;
float startYSpeed = 0f;
float startZSpeed = -11.6073894500732f;
float startHSpeed = 11.9047050476074f;
ushort startAngle = 30442;
List<ushort> cameraAngles = new List<ushort>()
{
7997,
8089,
8185,
8276,
8364,
8454,
8546,
8640,
8704,
8983,
9007,
9007,
9007,
9050,
9138,
9225,
9249,
9249,
9249,
9249,
9249,
9249,
9249,
};
int INDEX_START = 0;
float objStartX = -1301.52001953125f;
float objStartZ = -1677.24182128906f;
int inputX = 127;
int inputY = 87;
MarioState marioState = new MarioState(
startX, startY, startZ,
startXSpeed, startYSpeed, startZSpeed, startHSpeed,
startAngle, cameraAngles[INDEX_START], null, null, 0);
MarioBobombState marioBobombState = new MarioBobombState(
marioState, objStartX, objStartZ);
Input input = new Input(inputX, inputY);
MarioBobombState prevMarioBobombState = null;
for (int i = INDEX_START + 1; i < 9; i++)
{
ushort nextCameraAngle = cameraAngles[i];
prevMarioBobombState = marioBobombState;
marioBobombState = ApplyInputToMarioBobombState(marioBobombState, input, nextCameraAngle);
}
Config.Print(marioBobombState);
MarioState m = prevMarioBobombState.MarioState;
(float holpX, float holpY, float holpZ) = HolpCalculator.GetHolp(58, m.X, m.Y, m.Z, m.MarioAngle);
MarioState m2 = marioBobombState.MarioState;
float marioX = m2.X;
float marioY = m2.Y;
float marioZ = m2.Z;
ushort marioAngle = m2.MarioAngle;
float marioRadius = 37;
float bobombX = holpX;
float bobombY = holpY;
float bobombZ = holpZ;
float padding = -5;
for (int i = 1; i <= 4; i++)
{
if (i == 2)
{
ushort bobombAngle = m.MarioAngle;
float delX = 5 * InGameTrigUtilities.InGameSine(bobombAngle);
float delZ = 5 * InGameTrigUtilities.InGameCosine(bobombAngle);
bobombX += delX;
bobombZ += delZ;
}
float bobombRadius = 65 * (1f + 0.2f * i);
(marioX, marioZ) = ObjectCalculator.GetObjectDisplacement(
marioX, marioZ, marioRadius, 0, bobombX, bobombZ, bobombRadius, padding);
Config.Print("{0}: ({1},{2})", i, (double)marioX, (double)marioZ);
}
}
public static bool IsInSortedPositions(
List<(float, float)> positions, (float, float) position)
{
return IsInSortedPositions(positions, position, 0, positions.Count - 1);
}
public static bool IsInSortedPositions(
List<(float, float)> positions, (float, float) position, int startIndex, int endIndex)
{
if (startIndex > endIndex) return false;
int midIndex = (startIndex + endIndex) / 2;
(float midValue1, float midValue2) = positions[midIndex];
if (position.Item1 > midValue1)
{
return IsInSortedPositions(positions, position, midIndex + 1, endIndex);
}
else if (position.Item1 < midValue1)
{
return IsInSortedPositions(positions, position, startIndex, midIndex - 1);
}
else
{
return position.Item2 == midValue2;
}
}
public static float IsInSortedPositions2(
List<(float, float)> positions, (float, float) position)
{
return IsInSortedPositions2(positions, position, 0, positions.Count - 1);
}
public static float IsInSortedPositions2(
List<(float, float)> positions, (float, float) position, int startIndex, int endIndex)
{
if (startIndex > endIndex) return float.MaxValue;
int midIndex = (startIndex + endIndex) / 2;
(float midValue1, float midValue2) = positions[midIndex];
if (position.Item1 > midValue1)
{
return IsInSortedPositions2(positions, position, midIndex + 1, endIndex);
}
else if (position.Item1 < midValue1)
{
return IsInSortedPositions2(positions, position, startIndex, midIndex - 1);
}
else
{
return Math.Abs(position.Item2 - midValue2);
}
}
public static List<List<int>> GetAngleDiffsList(int length, int mid, int range)
{
List<int> angleDiffs = new List<int>();
for (int i = -1 * range; i <= range; i++)
{
int angleDiff = mid + i * 16;
angleDiffs.Add(angleDiff);
}
List<List<int>> output = new List<List<int>>();
GetAngleDiffsListRecursion(output, new List<int>(), length, angleDiffs);
return output;
}
public static void GetAngleDiffsListRecursion(
List<List<int>> output, List<int> state, int length, List<int> values)
{
if (state.Count == length)
{
List<int> temp = new List<int>(state);
output.Add(temp);
return;
}
foreach (int value in values)
{
state.Add(value);
GetAngleDiffsListRecursion(output, state, length, values);
state.RemoveAt(state.Count - 1);
}
}
public static void TestBruteForceMovingToSpot()
{
Config.Print("START BRUTE FORCE");
List<(float, float)> successPositions = GetSuccessFloatPositions();
bool boolValue = IsInSortedPositions(
successPositions, (-1379.0001f, 0f));
List<List<int>> angleDiffsList = GetAngleDiffsList(7, 96, 5);
angleDiffsList.ForEach(list => list.Add(0));
// List<int> angleDiffs = new List<int>() { 89, 92, 96, 91, 88, 90, 92, 2048 };
//float minDiff = float.MaxValue;
for (int i = 0; i < angleDiffsList.Count; i++)
{
List<int> angleDiffs = angleDiffsList[i];
(float x, float z) = MoveIntoSpot(angleDiffs);
float diff = IsInSortedPositions2(successPositions, (x, z));
if (diff < 0.0002f)
{
Config.Print("{0}: [{1}] ({2},{3})", i, (double)diff, (double)x, (double)z);
MoveIntoSpot(angleDiffs, true);
Config.Print();
}
}
Config.Print("END BRUTE FORCE");
}
public static (float x, float z) MoveIntoSpot(List<int> angleDiffs, bool print = false)
{
float startX = -1323.72937011719f;
float startY = -2434f;
float startZ = -1579.7392578125f;
float startXSpeed = 2.64395904541016f;
float startYSpeed = 0f;
float startZSpeed = -11.6073894500732f;
float startHSpeed = 11.9047050476074f;
ushort startAngle = 30442;
float objStartX = -1301.52001953125f;
float objStartZ = -1677.24182128906f;
MarioState marioState = new MarioState(
startX, startY, startZ,
startXSpeed, startYSpeed, startZSpeed, startHSpeed,
startAngle, 0, null, null, 0);
MarioBobombState marioBobombState = new MarioBobombState(
marioState, objStartX, objStartZ);
MarioBobombState prevMarioBobombState = null;
for (int i = 0; i < 8; i++)
{
prevMarioBobombState = marioBobombState;
marioBobombState = ApplyInputToMarioBobombState(marioBobombState, angleDiffs[i]);
if (print)
{
//Config.Print((43226 + i) + ": " + marioBobombState);
Config.Print(
"{0} {1} {2} {3} {4}",
(43227 + i),
(double)marioBobombState.MarioState.X,
(double)marioBobombState.MarioState.Y,
(double)marioBobombState.MarioState.Z,
(double)marioBobombState.MarioState.MarioAngle);
}
}
//Config.Print(marioBobombState);
MarioState m = prevMarioBobombState.MarioState;
(float holpX, float holpY, float holpZ) = HolpCalculator.GetHolp(58, m.X, m.Y, m.Z, m.MarioAngle);
MarioState m2 = marioBobombState.MarioState;
float marioX = m2.X;
float marioY = m2.Y;
float marioZ = m2.Z;
ushort marioAngle = m2.MarioAngle;
float marioRadius = 37;
float bobombX = holpX;
float bobombY = holpY;
float bobombZ = holpZ;
float padding = -5;
for (int i = 1; i <= 4; i++)
{
if (i == 2)
{
ushort bobombAngle = m.MarioAngle;
float delX = 5 * InGameTrigUtilities.InGameSine(bobombAngle);
float delZ = 5 * InGameTrigUtilities.InGameCosine(bobombAngle);
bobombX += delX;
bobombZ += delZ;
}
float bobombRadius = 65 * (1f + 0.2f * i);
(marioX, marioZ) = ObjectCalculator.GetObjectDisplacement(
marioX, marioZ, marioRadius, 0, bobombX, bobombZ, bobombRadius, padding);
//Config.Print("{0}: ({1},{2})", i, (double)marioX, (double)marioZ);
if (print)
{
if (i == 1)
{
for (int j = 0; j < 4; j++)
{
Config.Print(
"{0} {1} {2} {3} {4}",
43235 + j,
(double)marioX,
(double)m2.Y,
(double)marioZ,
(double)m2.MarioAngle);
}
}
else
{
Config.Print(
"{0} {1} {2} {3} {4}",
43237 + i,
(double)marioX,
(double)m2.Y,
(double)marioZ,
(double)m2.MarioAngle);
}
}
}
return (marioX, marioZ);
}
public class MarioBobombState
{
public readonly MarioState MarioState;
public readonly float ObjX;
public readonly float ObjZ;
public MarioBobombState(MarioState marioState, float objX, float objZ)
{
MarioState = marioState;
ObjX = objX;
ObjZ = objZ;
}
public override string ToString()
{
return String.Format("{0} obj=({1},{2})", MarioState, (double)ObjX, (double)ObjZ);
}
}
public static MarioBobombState ApplyInputToMarioBobombState(
MarioBobombState initialState, Input input, ushort nextCameraAngle)
{
// get vars
MarioState marioState = initialState.MarioState;
float objX = initialState.ObjX;
float objZ = initialState.ObjZ;
// walking
MarioState afterWalkingTemp = GroundMovementCalculator.ApplyInput(marioState, input);
// doesn't move due to ceiling
MarioState afterWalking = afterWalkingTemp.WithPosition(marioState.X, marioState.Y, marioState.Z);
// displacement
(float afterDisplacementX, float afterDisplacementZ) =
ObjectCalculator.GetObjectDisplacement(
afterWalking.X, afterWalking.Z, 37, afterWalking.MarioAngle,
objX, objZ, 65 * 1.2f, -5);
// relative position
(float relX, float relY, float relZ) = ObjectCalculator.GetRelativePosition(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.MarioAngle, 0, 60, 100);
MarioState finalMarioState = new MarioState(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.XSpeed, afterWalking.YSpeed, afterWalking.ZSpeed, afterWalking.HSpeed,
afterWalking.MarioAngle, nextCameraAngle, null, null, 0);
MarioBobombState finalMarioBobombState = new MarioBobombState(finalMarioState, relX, relZ);
return finalMarioBobombState;
}
public static MarioBobombState ApplyInputToMarioBobombState(
MarioBobombState initialState, int angleDiff)
{
// get vars
MarioState marioState = initialState.MarioState;
float objX = initialState.ObjX;
float objZ = initialState.ObjZ;
// walking
MarioState afterWalkingTemp = GroundMovementCalculator.ApplyInput(marioState, angleDiff);
// doesn't move due to ceiling
MarioState afterWalking = afterWalkingTemp.WithPosition(marioState.X, marioState.Y, marioState.Z);
// displacement
(float afterDisplacementX, float afterDisplacementZ) =
ObjectCalculator.GetObjectDisplacement(
afterWalking.X, afterWalking.Z, 37, afterWalking.MarioAngle,
objX, objZ, 65 * 1.2f, -5);
// relative position
(float relX, float relY, float relZ) = ObjectCalculator.GetRelativePosition(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.MarioAngle, 0, 60, 100);
MarioState finalMarioState = new MarioState(
afterDisplacementX, afterWalking.Y, afterDisplacementZ,
afterWalking.XSpeed, afterWalking.YSpeed, afterWalking.ZSpeed, afterWalking.HSpeed,
afterWalking.MarioAngle, 0, null, null, 0);
MarioBobombState finalMarioBobombState = new MarioBobombState(finalMarioState, relX, relZ);
return finalMarioBobombState;
}
}
public static class AirMovementCalculator
{
public static MarioState ApplyInput(MarioState marioState, Input input, int numQSteps = 4)
{
MarioState withHSpeed = ComputeAirHSpeed(marioState, input);
MarioState moved = AirMove(withHSpeed, numQSteps);
MarioState withYSpeed = ComputeAirYSpeed(moved);
return withYSpeed;
}
public static MarioState AirMove(MarioState initialState, int numQSteps = 4)
{
float newX = initialState.X;
float newY = initialState.Y;
float newZ = initialState.Z;
for (int i = 0; i < numQSteps; i++)
{
newX += initialState.XSpeed / 4;
newY += initialState.YSpeed / 4;
newZ += initialState.ZSpeed / 4;
}
return new MarioState(
newX,
newY,
newZ,
initialState.XSpeed,
initialState.YSpeed,
initialState.ZSpeed,
initialState.HSpeed,
initialState.MarioAngle,
initialState.CameraAngle,
initialState.PreviousState,
initialState.LastInput,
initialState.Index);
}
// update_air_without_turn
private static MarioState ComputeAirHSpeed(MarioState initialState, Input input)
{
bool longJump = false;
int maxSpeed = longJump ? 48 : 32;
ushort marioAngle = initialState.MarioAngle;
ushort yawIntended = MoreMath.CalculateAngleFromInputs(input.X, input.Y, initialState.CameraAngle);
int deltaAngleIntendedFacing = yawIntended - marioAngle;
float inputScaledMagnitude = input.GetScaledMagnitude();
float perpSpeed = 0;
float newHSpeed = ApproachHSpeed(initialState.HSpeed, 0, 0.35f, 0.35f);
if (inputScaledMagnitude > 0)
{
newHSpeed += (inputScaledMagnitude / 32) * 1.5f * InGameTrigUtilities.InGameCosine(deltaAngleIntendedFacing);
perpSpeed = InGameTrigUtilities.InGameSine(deltaAngleIntendedFacing) * (inputScaledMagnitude / 32) * 10;
}
if (newHSpeed > maxSpeed) newHSpeed -= 1;
if (newHSpeed < -16) newHSpeed += 2;
float newSlidingXSpeed = InGameTrigUtilities.InGameSine(marioAngle) * newHSpeed;
float newSlidingZSpeed = InGameTrigUtilities.InGameCosine(marioAngle) * newHSpeed;
newSlidingXSpeed += perpSpeed * InGameTrigUtilities.InGameSine(marioAngle + 0x4000);
newSlidingZSpeed += perpSpeed * InGameTrigUtilities.InGameCosine(marioAngle + 0x4000);
float newXSpeed = newSlidingXSpeed;
float newZSpeed = newSlidingZSpeed;
return new MarioState(
initialState.X,
initialState.Y,
initialState.Z,
newXSpeed,
initialState.YSpeed,
newZSpeed,
newHSpeed,
initialState.MarioAngle,
initialState.CameraAngle,
initialState,
input,
initialState.Index + 1);
}
private static float ComputeAirHSpeed(float initialHSpeed)
{
int maxSpeed = 32;
float newHSpeed = ApproachHSpeed(initialHSpeed, 0, 0.35f, 0.35f);
if (newHSpeed > maxSpeed) newHSpeed -= 1;
if (newHSpeed < -16) newHSpeed += 2;
return newHSpeed;
}
public static float ComputePosition(float position, float hSpeed, int frames)
{
for (int i = 0; i < frames; i++)
{
hSpeed = ComputeAirHSpeed(hSpeed);
position += hSpeed;
}
return position;
}
private static MarioState ComputeAirYSpeed(MarioState initialState)
{
float newYSpeed = Math.Max(initialState.YSpeed - 4, -75);
return new MarioState(
initialState.X,
initialState.Y,
initialState.Z,
initialState.XSpeed,
newYSpeed,
initialState.ZSpeed,
initialState.HSpeed,
initialState.MarioAngle,
initialState.CameraAngle,
initialState.PreviousState,
initialState.LastInput,
initialState.Index);
}
private static float ApproachHSpeed(float speed, float maxSpeed, float increase, float decrease)
{
if (speed < maxSpeed)
return Math.Min(maxSpeed, speed + increase);
else
return Math.Max(maxSpeed, speed - decrease);
}
}
public static class GroundMovementCalculator
{
// act_hold_walking
public static MarioState ApplyInput(MarioState initialState, Input input)
{
MutableMarioState mutableMarioState = initialState.GetMutableMarioState(input);
mutableMarioState.IntendedMagnitude *= 0.4f;
UpdateWalkingSpeed(mutableMarioState);
PerformGroundStep(mutableMarioState);
MarioState finalState = mutableMarioState.GetMarioState(initialState, input);
return finalState;
}
public static MarioState ApplyInput(MarioState initialState, int angleDiff)
{
MutableMarioState mutableMarioState = initialState.GetMutableMarioState(angleDiff);
mutableMarioState.IntendedMagnitude *= 0.4f;
UpdateWalkingSpeed(mutableMarioState);
PerformGroundStep(mutableMarioState);
MarioState finalState = mutableMarioState.GetMarioState(initialState, null);
return finalState;
}
// update_walking_speed
private static void UpdateWalkingSpeed(MutableMarioState marioState)
{
float maxTargetSpeed;
float targetSpeed;
bool slowSurface = false;
if (slowSurface)
maxTargetSpeed = 24.0f;
else
maxTargetSpeed = 32.0f;
targetSpeed = marioState.IntendedMagnitude < maxTargetSpeed ? marioState.IntendedMagnitude : maxTargetSpeed;
if (marioState.HSpeed <= 0.0f)
marioState.HSpeed += 1.1f;
else if (marioState.HSpeed <= targetSpeed)
marioState.HSpeed += 1.1f - marioState.HSpeed / 43.0f;
else
marioState.HSpeed -= 1.0f;
if (marioState.HSpeed > 48.0f)
marioState.HSpeed = 48.0f;
marioState.MarioAngle = MoreMath.NormalizeAngleUshort(
marioState.IntendedAngle - CalculatorUtilities.ApproachInt(
MoreMath.NormalizeAngleShort(marioState.IntendedAngle - marioState.MarioAngle), 0, 0x800, 0x800));
ApplySlopeAccel(marioState);
}
// apply_slope_accel
private static void ApplySlopeAccel(MutableMarioState marioState)
{
marioState.XSpeed = marioState.HSpeed * InGameTrigUtilities.InGameSine(marioState.MarioAngle);
marioState.YSpeed = 0.0f;
marioState.ZSpeed = marioState.HSpeed * InGameTrigUtilities.InGameCosine(marioState.MarioAngle);
}
// perform_ground_step
private static void PerformGroundStep(MutableMarioState marioState)
{
for (int i = 0; i < 4; i++)
{
marioState.X = marioState.X + marioState.XSpeed / 4.0f;
marioState.Z = marioState.Z + marioState.ZSpeed / 4.0f;
}
}
}
public static class ObjectCalculator
{
public static (float newMarioX, float newMarioZ) GetObjectDisplacement(
float marioX, float marioZ, float marioRadius, ushort marioAngle,
float objectX, float objectZ, float objectRadius, float padding)
{
float minDistance = objectRadius + marioRadius + padding;
float offsetX = marioX - objectX;
float offsetZ = marioZ - objectZ;
float distance = (float)Math.Sqrt(offsetX * offsetX + offsetZ * offsetZ);
if (distance < minDistance)
{
short pushAngle;
float newMarioX;
float newMarioZ;
if (distance == 0.0f)
pushAngle = (short)marioAngle;
else
pushAngle = (short)InGameTrigUtilities.InGameATan(offsetZ, offsetX);
newMarioX = objectX + minDistance * InGameTrigUtilities.InGameSine(pushAngle);
newMarioZ = objectZ + minDistance * InGameTrigUtilities.InGameCosine(pushAngle);
return (newMarioX, newMarioZ);
}
return (marioX, marioZ);
}
public static (float objectX, float objectY, float objectZ) GetRelativePosition(
float marioX, float marioY, float marioZ, ushort marioAngle,
float dleft, float dy, float dforward)
{
float facingZ = InGameTrigUtilities.InGameCosine(marioAngle);
float facingX = InGameTrigUtilities.InGameSine(marioAngle);
float dz = dforward * facingZ - dleft * facingX;
float dx = dforward * facingX + dleft * facingZ;
return (marioX + dx, marioY + dy, marioZ + dz);
}
}
public static class WallDisplacementCalculator
{
public static (float newMarioX, float newMarioZ) HandleWallDisplacement(
float marioX, float marioY, float marioZ, TriangleDataModel surf, float radius, float offsetY)
{
return HandleWallDisplacement(marioX, marioY, marioZ, new List<TriangleDataModel>() { surf }, radius, offsetY);
}
public static (float newMarioX, float newMarioZ) HandleWallDisplacement(
float marioX, float marioY, float marioZ, List<TriangleDataModel> surfs, float radius, float offsetY)
{
float offset;
float x = marioX;
float y = marioY + offsetY;
float z = marioZ;
float px, pz;
float w1, w2, w3;
float y1, y2, y3;
// Max collision radius = 200
if (radius > 200.0f) radius = 200.0f;
foreach (TriangleDataModel surf in surfs)
{
if (y < surf.YMinMinus5 || y > surf.YMaxPlus5)
continue;
offset = surf.NormX * x + surf.NormY * y + surf.NormZ * z + surf.NormOffset;
if (offset < -radius || offset > radius)
continue;
px = x;
pz = z;
if (surf.XProjection)
{
w1 = -surf.Z1;
w2 = -surf.Z2;
w3 = -surf.Z3;
y1 = surf.Y1;
y2 = surf.Y2;
y3 = surf.Y3;
if (surf.NormX > 0.0f)
{
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) > 0.0f) continue;
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) > 0.0f) continue;
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) > 0.0f) continue;
}
else
{
if ((y1 - y) * (w2 - w1) - (w1 - -pz) * (y2 - y1) < 0.0f) continue;
if ((y2 - y) * (w3 - w2) - (w2 - -pz) * (y3 - y2) < 0.0f) continue;
if ((y3 - y) * (w1 - w3) - (w3 - -pz) * (y1 - y3) < 0.0f) continue;
}
}
else
{
w1 = surf.X1;
w2 = surf.X2;
w3 = surf.X3;
y1 = surf.Y1;
y2 = surf.Y2;
y3 = surf.Y3;
if (surf.NormZ > 0.0f)
{
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) > 0.0f) continue;
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) > 0.0f) continue;
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) > 0.0f) continue;
}
else
{
if ((y1 - y) * (w2 - w1) - (w1 - px) * (y2 - y1) < 0.0f) continue;
if ((y2 - y) * (w3 - w2) - (w2 - px) * (y3 - y2) < 0.0f) continue;
if ((y3 - y) * (w1 - w3) - (w3 - px) * (y1 - y3) < 0.0f) continue;
}
}
marioX += surf.NormX * (radius - offset);
marioZ += surf.NormZ * (radius - offset);
}
return (marioX, marioZ);
}
}
public static class HolpCalculator
{
private static List<(int, double, double, double)> _data = new List<(int, double, double, double)>()
{
(0,-13.852560043335,82.7928466796875,43.2764892578125),
(1,-13.8603839874268,84.1005249023438,43.2064208984375),
(2,-13.8159141540527,84.2417602539063,43.1217041015625),
(3,-13.8067932128906,84.3388061523438,43.032958984375),
(4,-13.8156032562256,84.4673461914063,42.8843994140625),
(5,-13.8143367767334,84.3573608398438,42.7357177734375),
(6,-13.8485641479492,84.4801635742188,42.5528564453125),
(7,-13.913293838501,84.3718872070313,42.3017578125),
(8,-13.9324378967285,84.2554931640625,42.12255859375),
(9,-14.0344524383545,83.8282470703125,41.887451171875),
(10,-14.1320991516113,83.65185546875,41.6539306640625),
(11,-14.2047386169434,83.2032470703125,41.481689453125),
(12,-14.3437423706055,82.9824829101563,41.230224609375),
(13,-14.4278945922852,82.4707641601563,41.1116943359375),
(14,-14.6146621704102,81.8866577148438,40.9158935546875),
(15,-14.7635688781738,81.2904663085938,40.7923583984375),
(16,-14.983922958374,80.6292724609375,40.6275634765625),
(17,-15.2353763580322,79.8695678710938,40.525634765625),
(18,-15.4751510620117,79.0504760742188,40.5074462890625),
(19,-15.7339839935303,78.1624145507813,40.528564453125),
(20,-16.0744380950928,77.209716796875,40.4693603515625),
(21,-16.350076675415,76.2724609375,40.4874267578125),
(22,-16.6590099334717,75.2498779296875,40.524169921875),
(23,-16.9654483795166,74.2208862304688,40.5496826171875),
(24,-17.286901473999,73.1162719726563,40.60302734375),
(25,-17.5732021331787,72.0418090820313,40.662109375),
(26,-17.8684062957764,70.9493408203125,40.6968994140625),
(27,-18.1436023712158,70.1430053710938,40.7091064453125),
(28,-18.4258403778076,69.06982421875,40.7000732421875),
(29,-18.6577587127686,68.073974609375,40.6951904296875),
(30,-18.8827457427979,66.8560180664063,40.662353515625),
(31,-19.0599193572998,65.9683227539063,40.640380859375),
(32,-19.2313365936279,65.8605346679688,40.594970703125),
(33,-19.3553791046143,66.3665161132813,40.5447998046875),
(34,-19.4837818145752,67.1422729492188,40.4661865234375),
(35,-19.5892887115479,67.9154052734375,40.43017578125),
(36,-19.659029006958,69.2606811523438,40.4078369140625),
(37,-19.7250804901123,70.356201171875,40.3907470703125),
(38,-19.7577571868896,71.4926147460938,40.40869140625),
(39,-19.7571697235107,72.4199829101563,40.462158203125),
(40,-19.7728824615479,73.1315307617188,40.45849609375),
(41,-19.7376079559326,73.8190307617188,40.5723876953125),
(42,-19.7122821807861,74.5830078125,40.6121826171875),
(43,-19.6650981903076,75.282958984375,40.739013671875),
(44,-19.57346534729,75.8268432617188,40.88525390625),
(45,-19.4797077178955,76.1210327148438,41.033203125),
(46,-19.3439426422119,76.4605102539063,41.2265625),
(47,-19.2333011627197,76.2872314453125,41.37890625),
(48,-19.0889110565186,76.1022338867188,41.597900390625),
(49,-18.9064617156982,75.9515380859375,41.857421875),
(50,-18.7486705780029,75.5679321289063,42.0560302734375),
(51,-18.5583438873291,75.1459350585938,42.33203125),
(52,-18.3875865936279,74.7825317382813,42.52978515625),
(53,-18.1501483917236,74.1698608398438,42.83203125),
(54,-17.9086894989014,73.806396484375,43.1324462890625),
(55,-17.7250003814697,73.1712646484375,43.34814453125),
(56,-17.4643001556396,72.8579711914063,43.6300048828125),
(57,-17.1985988616943,72.2935791015625,43.9110107421875),
(58,-16.9619617462158,71.688720703125,44.1668701171875),
(59,-16.7159366607666,71.3931274414063,44.3900146484375),
(60,-16.4704761505127,70.817626953125,44.6248779296875),
(61,-16.1780300140381,70.2903442382813,44.8857421875),
(62,-15.9158897399902,70.0347900390625,45.0811767578125),
(63,-15.6951370239258,69.4375,45.2755126953125),
(64,-15.4251079559326,69.2108764648438,45.447509765625),
(65,-15.1985931396484,68.4242553710938,45.596435546875),
(66,-14.9584121704102,67.7183227539063,45.701416015625),
(67,-14.7734146118164,67.4125366210938,45.7999267578125),
(68,-14.5395526885986,68.2246704101563,45.871826171875),
(69,-14.385705947876,70.1324462890625,45.7674560546875),
(70,-14.2014904022217,72.6931762695313,45.574951171875),
(71,-14.1282138824463,75.119140625,45.1312255859375),
(72,-13.9819869995117,77.0831298828125,44.716552734375),
(73,-13.9631118774414,78.2352905273438,44.156494140625),
(74,-13.8647117614746,79.316162109375,43.736083984375),
(75,-13.8919486999512,80.1707763671875,43.3465576171875),
};
private static Dictionary<int, (double, double, double)> _dictionary;
static HolpCalculator()
{
_dictionary = new Dictionary<int, (double, double, double)>();
foreach ((int index, double x, double y, double z) in _data)
{
_dictionary[index] = (x, y, z);
}
}
public static (float x, float y, float z) GetHolp(int index)
{
if (!_dictionary.ContainsKey(index)) return (float.NaN, float.NaN, float.NaN);
(double xOffset, double yOffset, double zOffset) = _dictionary[index];
return ((float)xOffset, (float)yOffset, (float)zOffset);
}
public static (float x, float y, float z) GetHolp(
int index, float marioX, float marioY, float marioZ, ushort marioAngle)
{
if (!_dictionary.ContainsKey(index)) return (float.NaN, float.NaN, float.NaN);
(double xOffset, double yOffset, double zOffset) = _dictionary[index];
double vectorMagnitude = MoreMath.GetHypotenuse(xOffset, zOffset);
double vectorAngle = MoreMath.AngleTo_AngleUnits(xOffset, zOffset);
double rotatedAngle = vectorAngle + MoreMath.NormalizeAngleTruncated(marioAngle);
(double rotatedX, double rotatedZ) = MoreMath.GetComponentsFromVector(vectorMagnitude, rotatedAngle);
double offsetX = rotatedX + marioX;
double offsetY = yOffset + marioY;
double offsetZ = rotatedZ + marioZ;
return ((float)offsetX, (float)offsetY, (float)offsetZ);
}
}
public static class CalculatorUtilities
{
public static List<Input> GetAllInputs()
{
return GetInputRange(-128, 127, -128, 127);
}
public static List<Input> GetInputRange(int minX, int maxX, int minZ, int maxZ)
{
List<Input> output = new List<Input>();
for (int x = minX; x <= maxX; x++)
{
if (MoreMath.InputIsInDeadZone(x)) continue;
for (int z = minZ; z <= maxZ; z++)
{
if (MoreMath.InputIsInDeadZone(z)) continue;
output.Add(new Input(x, z));
}
}
return output;
}
public static int ApproachInt(int current, int target, int inc, int dec)
{
if (current < target)
{
current += inc;
if (current > target)
current = target;
}
else
{
current -= dec;
if (current < target)
current = target;
}
return current;
}
}
public class MarioState
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public readonly float XSpeed;
public readonly float YSpeed;
public readonly float ZSpeed;
public readonly float HSpeed;
public readonly ushort MarioAngle;
public readonly ushort CameraAngle;
public readonly MarioState PreviousState;
public readonly Input LastInput;
public readonly int Index;
public MarioState(
float x, float y, float z,
float xSpeed, float ySpeed, float zSpeed, float hSpeed,
ushort marioAngle, ushort cameraAngle,
MarioState previousState, Input lastInput, int index)
{
X = x;
Y = y;
Z = z;
XSpeed = xSpeed;
YSpeed = ySpeed;
ZSpeed = zSpeed;
HSpeed = hSpeed;
MarioAngle = marioAngle;
CameraAngle = cameraAngle;
PreviousState = previousState;
LastInput = lastInput;
Index = index;
}
public MutableMarioState GetMutableMarioState(Input input)
{
return new MutableMarioState(
X, Y, Z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, CameraAngle, input);
}
public MutableMarioState GetMutableMarioState(int angleDiff)
{
return new MutableMarioState(
X, Y, Z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, angleDiff);
}
public override string ToString()
{
return String.Format(
"pos=({0},{1},{2}) spd=({3},{4},{5}) hspd={6} angle={7}",
(double)X, (double)Y, (double)Z,
(double)XSpeed, (double)YSpeed, (double)ZSpeed, (double)HSpeed, MarioAngle);
}
public string ToStringWithInput()
{
string inputString = LastInput != null ? LastInput + " to " : "";
return inputString + ToString();
}
private List<object> GetFields()
{
return new List<object>()
{
X, Y, Z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, CameraAngle,
};
}
public override bool Equals(object obj)
{
if (!(obj is MarioState)) return false;
MarioState other = obj as MarioState;
return Enumerable.SequenceEqual(
GetFields(), other.GetFields());
}
public override int GetHashCode()
{
return GetFields().GetHashCode();
}
public string GetLineage()
{
if (PreviousState == null)
{
return ToStringWithInput();
}
else
{
return PreviousState.GetLineage() + "\r\n" + ToStringWithInput();
}
}
public MarioState WithCameraAngle(ushort cameraAngle)
{
return new MarioState(
X, Y, Z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, cameraAngle,
PreviousState, LastInput, Index);
}
public MarioState WithPosition(float x, float y, float z)
{
return new MarioState(
x, y, z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, CameraAngle,
PreviousState, LastInput, Index);
}
}
public class MutableMarioState
{
public float X;
public float Y;
public float Z;
public float XSpeed;
public float YSpeed;
public float ZSpeed;
public float HSpeed;
public ushort MarioAngle;
public ushort IntendedAngle;
public float IntendedMagnitude;
public MutableMarioState(
float x,
float y,
float z,
float xSpeed,
float ySpeed,
float zSpeed,
float hSpeed,
ushort marioAngle,
ushort cameraAngle,
Input input)
{
X = x;
Y = y;
Z = z;
XSpeed = xSpeed;
YSpeed = ySpeed;
ZSpeed = zSpeed;
HSpeed = hSpeed;
MarioAngle = marioAngle;
IntendedAngle = MoreMath.CalculateAngleFromInputs(input.X, input.Y, cameraAngle);
IntendedMagnitude = input.GetScaledMagnitude();
}
public MutableMarioState(
float x,
float y,
float z,
float xSpeed,
float ySpeed,
float zSpeed,
float hSpeed,
ushort marioAngle,
int angleDiff)
{
X = x;
Y = y;
Z = z;
XSpeed = xSpeed;
YSpeed = ySpeed;
ZSpeed = zSpeed;
HSpeed = hSpeed;
MarioAngle = marioAngle;
IntendedAngle = MoreMath.NormalizeAngleUshort(marioAngle + angleDiff);
IntendedMagnitude = 32;
}
public MarioState GetMarioState(MarioState previousState, Input lastInput)
{
return new MarioState(
X, Y, Z,
XSpeed, YSpeed, ZSpeed, HSpeed,
MarioAngle, previousState.CameraAngle,
previousState, lastInput, previousState.Index + 1);
}
}
// Y value is inputted and stored in sm64 convention
// Y value is displayed in mupen convention
public class Input
{
public readonly int X;
public readonly int Y;
public Input(int x, int y)
{
X = x;
Y = y;
}
public float GetScaledMagnitude()
{
return MoreMath.GetScaledInputMagnitude(X, Y, false);
}
public override string ToString()
{
return String.Format("({0},{1})", X, -1 * Y);
}
}