From 1f0b17457f3e3b144a0f52be1423e84d72a868a8 Mon Sep 17 00:00:00 2001
From: xan1242 <8014093+xan1242@users.noreply.github.com>
Date: Tue, 22 Nov 2022 08:13:07 +0100
Subject: [PATCH] add PathfinderPlayer to repo
---
PathfinderPlayer/Form1.Designer.cs | 299 ++++++++
PathfinderPlayer/Form1.cs | 877 +++++++++++++++++++++++
PathfinderPlayer/Form1.resx | 72 ++
PathfinderPlayer/PathfinderPlayer.csproj | 15 +
PathfinderPlayer/PathfinderPlayer.sln | 25 +
PathfinderPlayer/Program.cs | 17 +
PathfinderPlayer/README.md | 39 +
7 files changed, 1344 insertions(+)
create mode 100644 PathfinderPlayer/Form1.Designer.cs
create mode 100644 PathfinderPlayer/Form1.cs
create mode 100644 PathfinderPlayer/Form1.resx
create mode 100644 PathfinderPlayer/PathfinderPlayer.csproj
create mode 100644 PathfinderPlayer/PathfinderPlayer.sln
create mode 100644 PathfinderPlayer/Program.cs
create mode 100644 PathfinderPlayer/README.md
diff --git a/PathfinderPlayer/Form1.Designer.cs b/PathfinderPlayer/Form1.Designer.cs
new file mode 100644
index 0000000..ea244c6
--- /dev/null
+++ b/PathfinderPlayer/Form1.Designer.cs
@@ -0,0 +1,299 @@
+namespace WinFormsApp1
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.button1 = new System.Windows.Forms.Button();
+ this.button2 = new System.Windows.Forms.Button();
+ this.label1 = new System.Windows.Forms.Label();
+ this.timer1 = new System.Windows.Forms.Timer(this.components);
+ this.label2 = new System.Windows.Forms.Label();
+ this.button3 = new System.Windows.Forms.Button();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.textBox2 = new System.Windows.Forms.TextBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.button4 = new System.Windows.Forms.Button();
+ this.button5 = new System.Windows.Forms.Button();
+ this.label6 = new System.Windows.Forms.Label();
+ this.menuStrip1 = new System.Windows.Forms.MenuStrip();
+ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
+ this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
+ this.sampleFolderDialog = new System.Windows.Forms.OpenFileDialog();
+ this.label7 = new System.Windows.Forms.Label();
+ this.menuStrip1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // button1
+ //
+ this.button1.Location = new System.Drawing.Point(12, 27);
+ this.button1.Name = "button1";
+ this.button1.Size = new System.Drawing.Size(75, 23);
+ this.button1.TabIndex = 0;
+ this.button1.Text = "Play";
+ this.button1.UseVisualStyleBackColor = true;
+ this.button1.Click += new System.EventHandler(this.button1_Click);
+ //
+ // button2
+ //
+ this.button2.Location = new System.Drawing.Point(93, 27);
+ this.button2.Name = "button2";
+ this.button2.Size = new System.Drawing.Size(75, 23);
+ this.button2.TabIndex = 1;
+ this.button2.Text = "Pause";
+ this.button2.UseVisualStyleBackColor = true;
+ this.button2.Click += new System.EventHandler(this.button2_Click);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(12, 83);
+ this.label1.Margin = new System.Windows.Forms.Padding(5);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(36, 15);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Time:";
+ //
+ // timer1
+ //
+ this.timer1.Enabled = true;
+ this.timer1.Interval = 1;
+ this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(12, 133);
+ this.label2.Margin = new System.Windows.Forms.Padding(5);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(87, 15);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Pushing status:";
+ //
+ // button3
+ //
+ this.button3.Location = new System.Drawing.Point(174, 27);
+ this.button3.Name = "button3";
+ this.button3.Size = new System.Drawing.Size(75, 23);
+ this.button3.TabIndex = 4;
+ this.button3.Text = "Stop";
+ this.button3.UseVisualStyleBackColor = true;
+ this.button3.Click += new System.EventHandler(this.button3_Click);
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(12, 158);
+ this.label3.Margin = new System.Windows.Forms.Padding(5);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(28, 15);
+ this.label3.TabIndex = 5;
+ this.label3.Text = "File:";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(12, 108);
+ this.label4.Margin = new System.Windows.Forms.Padding(5);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(52, 15);
+ this.label4.TabIndex = 6;
+ this.label4.Text = "Queued:";
+ //
+ // textBox1
+ //
+ this.textBox1.Location = new System.Drawing.Point(110, 208);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(100, 23);
+ this.textBox1.TabIndex = 0;
+ this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
+ //
+ // textBox2
+ //
+ this.textBox2.Location = new System.Drawing.Point(110, 180);
+ this.textBox2.Name = "textBox2";
+ this.textBox2.Size = new System.Drawing.Size(100, 23);
+ this.textBox2.TabIndex = 7;
+ this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged);
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(12, 183);
+ this.label5.Margin = new System.Windows.Forms.Padding(5, 5, 3, 0);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(58, 15);
+ this.label5.TabIndex = 8;
+ this.label5.Text = "Intensity: ";
+ //
+ // button4
+ //
+ this.button4.Location = new System.Drawing.Point(216, 179);
+ this.button4.Name = "button4";
+ this.button4.Size = new System.Drawing.Size(75, 23);
+ this.button4.TabIndex = 9;
+ this.button4.Text = "Apply";
+ this.button4.UseVisualStyleBackColor = true;
+ this.button4.Click += new System.EventHandler(this.button4_Click);
+ //
+ // button5
+ //
+ this.button5.Location = new System.Drawing.Point(216, 207);
+ this.button5.Name = "button5";
+ this.button5.Size = new System.Drawing.Size(75, 23);
+ this.button5.TabIndex = 10;
+ this.button5.Text = "Apply";
+ this.button5.UseVisualStyleBackColor = true;
+ this.button5.Click += new System.EventHandler(this.button5_Click);
+ //
+ // label6
+ //
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(12, 211);
+ this.label6.Margin = new System.Windows.Forms.Padding(5, 5, 3, 0);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(68, 15);
+ this.label6.TabIndex = 11;
+ this.label6.Text = "Next node: ";
+ //
+ // menuStrip1
+ //
+ this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.toolStripMenuItem1});
+ this.menuStrip1.Location = new System.Drawing.Point(0, 0);
+ this.menuStrip1.Name = "menuStrip1";
+ this.menuStrip1.Size = new System.Drawing.Size(365, 24);
+ this.menuStrip1.TabIndex = 12;
+ this.menuStrip1.Text = "menuStrip1";
+ //
+ // toolStripMenuItem1
+ //
+ this.toolStripMenuItem1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.openToolStripMenuItem,
+ this.exitToolStripMenuItem});
+ this.toolStripMenuItem1.Name = "toolStripMenuItem1";
+ this.toolStripMenuItem1.Size = new System.Drawing.Size(37, 20);
+ this.toolStripMenuItem1.Text = "File";
+ //
+ // openToolStripMenuItem
+ //
+ this.openToolStripMenuItem.Name = "openToolStripMenuItem";
+ this.openToolStripMenuItem.Size = new System.Drawing.Size(112, 22);
+ this.openToolStripMenuItem.Text = "Open...";
+ this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click);
+ //
+ // exitToolStripMenuItem
+ //
+ this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
+ this.exitToolStripMenuItem.Size = new System.Drawing.Size(112, 22);
+ this.exitToolStripMenuItem.Text = "Exit";
+ this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
+ //
+ // openFileDialog1
+ //
+ this.openFileDialog1.DefaultExt = "txt";
+ this.openFileDialog1.Filter = "Pathfinder Map File Source|*.txt|All files|*.*";
+ this.openFileDialog1.Title = "Open a decompiled MPF (map file)...";
+ //
+ // sampleFolderDialog
+ //
+ this.sampleFolderDialog.Filter = "WAV files|*.wav|OGG Vorbis files|*.ogg|MP3 files|*.mp3";
+ this.sampleFolderDialog.Title = "Open the folder containing samples (select any file within folder)...";
+ //
+ // label7
+ //
+ this.label7.AutoSize = true;
+ this.label7.Location = new System.Drawing.Point(12, 58);
+ this.label7.Margin = new System.Windows.Forms.Padding(5);
+ this.label7.Name = "label7";
+ this.label7.Size = new System.Drawing.Size(104, 15);
+ this.label7.TabIndex = 13;
+ this.label7.Text = "Playback: Stopped";
+ //
+ // Form1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(365, 243);
+ this.Controls.Add(this.label7);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.button5);
+ this.Controls.Add(this.button4);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.textBox2);
+ this.Controls.Add(this.textBox1);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.button3);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.button2);
+ this.Controls.Add(this.button1);
+ this.Controls.Add(this.menuStrip1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.MainMenuStrip = this.menuStrip1;
+ this.MaximizeBox = false;
+ this.Name = "Form1";
+ this.Text = "Pathfinder Player";
+ this.Load += new System.EventHandler(this.Form1_Load);
+ this.menuStrip1.ResumeLayout(false);
+ this.menuStrip1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private Button button1;
+ private Button button2;
+ private Label label1;
+ private System.Windows.Forms.Timer timer1;
+ private Label label2;
+ private Button button3;
+ private Label label3;
+ private Label label4;
+ private TextBox textBox1;
+ private TextBox textBox2;
+ private Label label5;
+ private Button button4;
+ private Button button5;
+ private Label label6;
+ private MenuStrip menuStrip1;
+ private ToolStripMenuItem toolStripMenuItem1;
+ private ToolStripMenuItem openToolStripMenuItem;
+ private ToolStripMenuItem exitToolStripMenuItem;
+ private OpenFileDialog openFileDialog1;
+ private OpenFileDialog sampleFolderDialog;
+ private Label label7;
+ }
+}
\ No newline at end of file
diff --git a/PathfinderPlayer/Form1.cs b/PathfinderPlayer/Form1.cs
new file mode 100644
index 0000000..545c974
--- /dev/null
+++ b/PathfinderPlayer/Form1.cs
@@ -0,0 +1,877 @@
+using ManagedBass;
+using System;
+using System.Globalization;
+using System.Linq;
+using static System.Windows.Forms.VisualStyles.VisualStyleElement.TreeView;
+
+namespace WinFormsApp1
+{
+
+ public struct PATHFINDHEADER
+ {
+ /* 0x0000 */ int id;
+ /* 0x0004 */ byte majorRev;
+ /* 0x0005 */ byte minorRev;
+ /* 0x0006 */ byte release;
+ /* 0x0007 */ byte prerelease;
+ /* 0x0008 */ short saveIncrement;
+ /* 0x000a */ short generateID;
+ /* 0x000c */ byte projectID;
+ /* 0x000d */ byte numtracks;
+ /* 0x000e */ byte numsections;
+ /* 0x000f */ byte numevents;
+ /* 0x0010 */ byte numrouters;
+ /* 0x0011 */ byte numnamedvars;
+ /* 0x0012 */ short numnodes;
+ /* 0x0014 */ uint nodeoffsets;
+ /* 0x0018 */ uint nodedata;
+ /* 0x001c */ uint eventoffsets;
+ /* 0x0020 */ uint eventdata;
+ /* 0x0024 */ uint namedvars;
+ /* 0x0028 */ uint noderouters;
+ /* 0x002c */ uint trackoffsets;
+ /* 0x0030 */ uint trackinfos;
+ /* 0x0034 */ uint sampleoffsets;
+ /* 0x0038 */ uint mapfilelen;
+ /* 0x003c */ //uint v40reserve[];
+ }; /* size: 0x0048 */
+
+ public enum PATHACTIONTYPE
+ {
+ PATHACTION_NONE = 0,
+ PATHACTION_CONDITION = 1,
+ PATHACTION_WAITTIME = 2,
+ PATHACTION_WAITBEAT = 3,
+ PATHACTION_BRANCHTO = 4,
+ PATHACTION_FADE = 5,
+ PATHACTION_DRYLEVELFADE = 6,
+ PATHACTION_SFXFADE = 7,
+ PATHACTION_SETVALUE = 8,
+ PATHACTION_EVENT = 9,
+ PATHACTION_FILTER_ON = 10,
+ PATHACTION_FILTER_OFF = 11,
+ PATHACTION_FILTER_CLEAR = 12,
+ PATHACTION_CALLBACK = 13,
+ PATHACTION_CALC = 14,
+ PATHACTION_PAUSE = 15,
+ PATHACTION_LOADBANK = 16,
+ PATHACTION_PITCHFADE = 17,
+ PATHACTION_STRETCHFADE = 18,
+ PATHACTION_MAX = 19,
+ };
+
+ public enum PATHVALUETYPE
+ {
+ PATH_VALUE_BADTYPE = 0,
+ PATH_VALUE_SPECIAL = 1,
+ PATH_VALUE_VARIABLE = 2,
+ PATH_VALUE_INTEGER = 3,
+ PATH_VALUE_MAXTYPES = 4,
+ };
+
+ public enum PATHFADEWHAT
+ {
+ PATH_FADE_INVALID = 0,
+ PATH_FADE_VOLUME = 1,
+ PATH_FADE_SFXSENDLEVEL = 2,
+ PATH_FADE_DRYLEVEL = 3,
+ PATH_FADE_PITCHMULT = 4,
+ PATH_FADE_STRETCHMULT = 5,
+ PATH_FADE_CHANNELVOL = 6,
+ PATH_FADE_PANANGLE = 7,
+ PATH_FADE_PANDISTANCE = 8,
+ PATH_FADE_PANSIZE = 9,
+ PATH_FADE_PANTWIST = 10,
+ PATH_FADE_MAXTYPES = 11,
+ };
+
+ public enum PATHSPECIALVALUETYPE
+ {
+ PATH_SPECIALVALUE_BAD = 0,
+ PATH_CONTROLLER = 1,
+ PATH_CURRENTNODE = 2,
+ PATH_CURRENTPART = 3,
+ PATH_CURRENTSECTION = 4,
+ PATH_EVENTEXPIRY = 5,
+ PATH_EVENTPRIORITY = 6,
+ PATH_FXBUS = 7,
+ PATH_FXDRYLEVEL = 8,
+ PATH_FXSENDLEVEL = 9,
+ PATH_MAINVOICE = 10,
+ PATH_NEXTNODE = 11,
+ PATH_NOBRANCHING = 12,
+ PATH_NODEDURATION = 13,
+ PATH_PAUSE = 14,
+ PATH_PITCHMULT = 15,
+ PATH_PLAYINGNODE = 16,
+ PATH_PLAYSTATUS = 17,
+ PATH_RANDOMSHORT = 18,
+ PATH_TIMENOW = 19,
+ PATH_TIMETONEXTBEAT = 20,
+ PATH_TIMETONEXTBAR = 21,
+ PATH_TIMETONEXTNODE = 22,
+ PATH_VOLUME = 23,
+ PATH_TIMESTRETCH = 24,
+ PATH_BARDURATION = 25,
+ PATH_BEATDURATION = 26,
+ PATH_CURRENTCHANNELSET = 27,
+ PATH_PLAYINGCHANNELSET = 28,
+ PATH_SPECIALVALUE_MAX = 29,
+ };
+
+ public enum PATHOPERATOR
+ {
+ PATH_OPERATOR_INVALID = 0,
+ PATH_OPERATOR_ADD = 1,
+ PATH_OPERATOR_SUB = 2,
+ PATH_OPERATOR_MULT = 3,
+ PATH_OPERATOR_DIV = 4,
+ PATH_OPERATOR_MOD = 5,
+ PATH_OPERATOR_MAX = 6,
+ };
+
+ public enum PATHCOMPARE
+ {
+ PATH_COMPARE_INVALID = 0,
+ PATH_COMPARE_EQUALS = 1,
+ PATH_COMPARE_NOT_EQUAL = 2,
+ PATH_COMPARE_GREATER_THAN = 3,
+ PATH_COMPARE_LESS_THAN = 4,
+ PATH_COMPARE_GREATER_OR_EQUAL = 5,
+ PATH_COMPARE_LESS_OR_EQUAL = 6,
+ PATH_COMPARE_MAX = 7,
+ };
+
+ public struct PATHNODEEVENT
+ {
+ public uint eventID;
+ }
+
+ public struct PATHFINDNODE
+ {
+
+ public int index; /* bit position: 16 */
+ public uint trackID; /* bit position: 11 */
+ public uint sectionID; /* bit position: 5 */
+ public int repeat; /* bit position: 0 */
+ public int routerID; /* bit position: 20 */
+ public uint numbranches; /* bit position: 15 */
+ public uint controller; /* bit position: 12 */
+ public uint beats; /* bit position: 8 */
+ public uint bars; /* bit position: 0 */
+ public uint partID; /* bit position: 16 */
+ public uint synchevery; /* bit position: 12 */
+ public uint synchoffset; /* bit position: 8 */
+ public uint notes; /* bit position: 4 */
+ public uint synch; /* bit position: 2 */
+ public uint channelbranching; /* bit position: 1 */
+ };
+
+ public struct PATHNAMEDVAR
+ {
+ public string name;
+ public int value;
+ };
+
+ struct PATHFINDBRANCH
+ {
+ public int controlmin;
+ public int controlmax;
+ public ushort dstnode;
+ }
+ public struct PATHACTCONDITION
+ {
+ public int value;
+ public int comparevalue;
+ };
+
+ public struct PATHACTFADE
+ {
+ public uint tovol;
+ public int id;
+ public uint flip;
+ public uint ms;
+ };
+
+ public struct PATHACTWAITTIME
+ {
+ public int millisecs;
+ public int lowest;
+ };
+
+ public struct PATHACTBRANCHTO
+ {
+ public int node;
+ public int ofsection;
+ public int immediate;
+ };
+
+ public struct PATHACTSETVALUE
+ {
+ public int towhat;
+ public uint setwhat;
+ };
+
+ public struct PATHACTEVENT
+ {
+ public uint eventID;
+ }
+
+ public struct PATHACTCALC
+ {
+ public uint value;
+ public uint op;
+ public int by;
+ }
+ public struct PATHACT
+ {
+ public PATHACTCONDITION only;
+ public PATHACTWAITTIME waittime;
+ //public PATHACTWAITBEAT waitbeat;
+ public PATHACTBRANCHTO branch;
+ public PATHACTFADE fade;
+ // public PATHACTSFXFADE sfxfade;
+ //public PATHACTDRYFADE dryfade;
+ // public PATHACTPITCHFADE pitchfade;
+ // public PATHACTSTRETCHFADE stretchfade;
+ public PATHACTSETVALUE setval;
+ public PATHACTEVENT evt;
+ // public PATHACTCALLBACK callback;
+ public PATHACTCALC calc;
+ // public PATHACTPAUSE pause;
+ // public PATHLOADBANK loadbank;
+ }
+ public struct PATHACTION
+ {
+ public int track;
+ public int sectionID;
+ public uint type;
+ public uint done;
+ public uint leftvaluetype;
+ public uint rightvaluetype;
+ public uint assess;
+ public uint comparison;
+ public uint indent;
+ public PATHACT act;
+ }
+
+ struct PATHEVENT
+ {
+ /* 0x0000 */ public uint queued;
+ /* 0x0004 */ public uint expiry;
+ /* 0x0008 */ public uint lastact;
+ /* 0x000c */ public uint eventID; /* bit position: 8 */
+ // struct /* bitfield */
+ // {
+ /* 0x000c */ public uint numactions; /* bit position: 0 */
+ /* 0x0010 */ public uint currentaction; /* bit position: 24 */
+ /* 0x0010 */ public uint voices; /* bit position: 20 */
+ /* 0x0010 */ public int priority; /* bit position: 16 */
+ /* 0x0010 */ public uint bumplower; /* bit position: 15 */
+ /* 0x0010 */ public uint beingFiltered; /* bit position: 14 */
+ /* 0x0010 */ public int project; /* bit position: 11 */
+ //}; /* bitfield */
+ /* 0x0010 */ public int unused; /* bit position: 0 */
+ }; /* size: 0x0014 */
+
+ struct prsNODE
+ {
+ public PATHFINDNODE node;
+ public List branches;
+ public int index;
+ }
+
+ struct prsPATHEVENT
+ {
+ public PATHEVENT evt;
+ public List actions;
+ }
+
+ enum PATHASSESS
+ {
+ PATHASSESS_NONE,
+ PATHASSESS_IF,
+ PATHASSESS_ELIF,
+ PATHASSESS_ELSE,
+ PATHASSESS_ENDIF,
+ PATHASSESS_MAX
+ };
+
+
+ public partial class Form1 : Form
+ {
+ int music;
+ byte[] pushbuffer;
+ int counter;
+
+ int intensity_controller = 0;
+ int cur_node = 0;
+ int cur_sample = 0;
+ int cur_eventid = 0;
+ int next_branchto = 0;
+ int next_sample = 0;
+
+ int next_intensity = 0;
+ int initial_node = 0;
+
+ bool bReadyToQueue = false;
+ string queued_file;
+
+ string sample_folder;
+ string sample_ext;
+
+ bool bPausedPlayback = false;
+
+ //PATHNAMEDVAR[] namedvars;
+ //List namedvars = new List();
+ List nodes = new List();
+ //List prsEvents = new List();
+
+ string[] ActionStrings =
+ {
+ "NONE",
+ "Condition",
+ "Wait",
+ "WaitBeat",
+ "Branch",
+ "Fade",
+ "DryFade",
+ "SFXFade",
+ "Set",
+ "Event",
+ "Filter ON",
+ "Filter OFF",
+ "Filter CLEAR",
+ "Callback",
+ "Calc",
+ "Pause",
+ "LoadBank",
+ "PitchFade",
+ "StretchFade",
+ };
+
+ string[] paAssessments =
+ {
+ "None",
+ "If",
+ "Elif",
+ "Else",
+ "Endif"
+ };
+
+ PATHASSESS GetPATHASSESS(string name)
+ {
+ for (int i = 0; i < (int)PATHASSESS.PATHASSESS_MAX; i++)
+ {
+ if (name.Contains(paAssessments[i]))
+ {
+ return (PATHASSESS)i;
+ }
+ }
+
+ return PATHASSESS.PATHASSESS_NONE;
+ }
+
+ PATHACTIONTYPE GetPATHACTIONTYPE(string name)
+ {
+ for (int i = 0; i < (int)PATHACTIONTYPE.PATHACTION_MAX; i++)
+ {
+ if (name.Contains(ActionStrings[i]))
+ {
+ return (PATHACTIONTYPE)i;
+ }
+
+ if (GetPATHASSESS(name) != PATHASSESS.PATHASSESS_NONE)
+ return PATHACTIONTYPE.PATHACTION_CONDITION;
+ }
+
+ return PATHACTIONTYPE.PATHACTION_NONE;
+ }
+
+ enum cmpPathNodeParser
+ {
+ cmpPNP_NULL,
+ cmpPNP_Wave,
+ cmpPNP_Track,
+ cmpPNP_Section,
+ cmpPNP_Part,
+ cmpPNP_Router,
+ cmpPNP_Controller,
+ cmpPNP_Beats,
+ cmpPNP_Bars,
+ cmpPNP_SynchEvery,
+ cmpPNP_SynchOffset,
+ cmpPNP_Notes,
+ cmpPNP_Synch,
+ cmpPNP_ChannelBranching,
+ cmpPNP_Repeat,
+ cmpPNP_Branches,
+ cmpPNP_Event,
+ cmpPNP_MAX
+ };
+
+ public string[] cmpPathNodeStrings =
+ {
+ "NULL",
+ "Wave",
+ "Track",
+ "Section",
+ "Part",
+ "Router",
+ "Controller",
+ "Beats",
+ "Bars",
+ "SynchEvery",
+ "SynchOffset",
+ "Notes",
+ "Synch",
+ "ChannelBranching",
+ "Repeat",
+ "Branches",
+ "Event",
+ };
+
+ cmpPathNodeParser cmpGetPathNodeParserType(string line)
+ {
+ for (int i = 0; i < (int)cmpPathNodeParser.cmpPNP_MAX; i++)
+ {
+ if (line.Contains(cmpPathNodeStrings[i]))
+ {
+ return (cmpPathNodeParser)i;
+ }
+ }
+
+ return cmpPathNodeParser.cmpPNP_NULL;
+ }
+
+ void ParseMapFile(string fname)
+ {
+ StreamReader reader = File.OpenText(fname);
+ string line;
+
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (!line.StartsWith('#'))
+ {
+ //if (line.Contains("Var"))
+ //{
+ // PATHNAMEDVAR var = new PATHNAMEDVAR();
+ // reader.ReadLine();
+ // line = reader.ReadLine();
+ // //line.Replace("\t", "");
+ // line.Trim();
+ // string[] items = line.Split(' ');
+ // var.name = items[0];
+ // var.value = int.Parse(items[2]);
+ // namedvars.Add(var);
+ //}
+ if (line.Contains("Node"))
+ {
+ prsNODE node = new prsNODE();
+
+ string[] items = line.Split(' ');
+ node.index = int.Parse(items[1]);
+
+ cmpPathNodeParser nodetype;
+ reader.ReadLine();
+ do
+ {
+ line = reader.ReadLine();
+ if (line.Contains("}"))
+ break;
+
+ nodetype = cmpGetPathNodeParserType(line);
+ items = line.Split(' ');
+
+ switch (nodetype)
+ {
+ case cmpPathNodeParser.cmpPNP_Wave:
+ node.node.index = int.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Track:
+ node.node.trackID = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Section:
+ node.node.sectionID = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Part:
+ node.node.partID = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Router:
+ node.node.routerID = int.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Controller:
+ node.node.controller = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Beats:
+ node.node.beats = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Bars:
+ node.node.bars = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_SynchEvery:
+ node.node.synchevery = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_SynchOffset:
+ node.node.synchoffset = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Notes:
+ node.node.notes = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Synch:
+ node.node.synch = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_ChannelBranching:
+ node.node.channelbranching = uint.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Repeat:
+ node.node.repeat = int.Parse(items[1]);
+ break;
+ case cmpPathNodeParser.cmpPNP_Branches:
+ // branches
+ node.branches = new();
+ reader.ReadLine();
+ node.node.numbranches = 0;
+ do
+ {
+ line = reader.ReadLine();
+
+ if (line.Contains("Control"))
+ {
+ PATHFINDBRANCH newbranch = new PATHFINDBRANCH();
+ line.Trim();
+ items = line.Split(' ');
+ string[] items2 = items[1].Split(',');
+ newbranch.controlmin = int.Parse(items2[0]);
+ newbranch.controlmax = int.Parse(items2[1]);
+ newbranch.dstnode = ushort.Parse(items[3]);
+
+ node.branches.Add(newbranch);
+ node.node.numbranches = (uint)node.branches.Count();
+ }
+ } while (!line.Contains("}"));
+ break;
+
+ default:
+ break;
+ }
+ } while (!line.Contains("}"));
+ nodes.Add(node);
+ }
+
+ //if (line.Contains("Event"))
+ //{
+ // prsPATHEVENT evt = new prsPATHEVENT();
+ // evt.actions = new List();
+ //
+ // line.Trim();
+ // string[] items = line.Split(' ');
+ // items[1] = items[1].Trim();
+ // items[1] = items[1].Remove(0, 2);
+ // evt.evt.eventID = uint.Parse(items[1], NumberStyles.HexNumber);
+ //
+ // // actions
+ // reader.ReadLine();
+ // line = reader.ReadLine();
+ // if (line.Contains("Actions"))
+ // {
+ // reader.ReadLine();
+ // do
+ // {
+ //
+ // PATHACTION action = new PATHACTION();
+ // PATHACTIONTYPE type;
+ //
+ // line = reader.ReadLine();
+ // if (line.Contains('}'))
+ // break;
+ //
+ // items = line.Split('\t');
+ // string[] items2 = items[0].Split(',');
+ // items2[0] = items2[0].Remove(0, 1);
+ // items2[1] = items2[1].Trim();
+ // items2[1] = items2[1].Replace(")", "");
+ //
+ // action.track = int.Parse(items2[0]);
+ // action.sectionID = int.Parse(items2[1]);
+ //
+ // type = GetPATHACTIONTYPE(items[1]);
+ // action.type = (uint)type;
+ //
+ // switch (type)
+ // {
+ // case PATHACTIONTYPE.PATHACTION_BRANCHTO:
+ // //PATHACTBRANCHTO branch = new();
+ // items2 = items[1].Split(' ');
+ //
+ // action.act.branch.node = int.Parse(items2[1]);
+ //
+ // string[] items3 = items2[2].Split(',');
+ // items3[0] = items3[0].Remove(0, 1);
+ // items3[1] = items3[1].Trim();
+ // items3[1] = items3[1].Replace(")", "");
+ //
+ // action.act.branch.ofsection = int.Parse(items3[0]);
+ // action.act.branch.immediate = int.Parse(items3[1]);
+ //
+ // break;
+ //
+ // default:
+ // break;
+ // }
+ //
+ // evt.actions.Add(action);
+ // } while (!line.Contains("}"));
+ //
+ // }
+ //
+ // prsEvents.Add(evt);
+ //}
+ }
+ }
+ }
+
+ int DecodeData(string FilePath)
+ {
+ int decoder = Bass.CreateStream(FilePath, 0, 0, BassFlags.Decode);
+ int DecodeSize = (int)Bass.ChannelGetLength(decoder, PositionFlags.Bytes);
+ pushbuffer = new byte[DecodeSize];
+ Bass.ChannelGetData(decoder, pushbuffer, DecodeSize);
+ float DecodedSampleRate = 0.0f;
+ Bass.ChannelGetAttribute(decoder, ChannelAttribute.Frequency, out DecodedSampleRate);
+ Bass.ChannelSetAttribute(music, ChannelAttribute.Frequency, DecodedSampleRate);
+ Bass.StreamFree(decoder);
+
+ return DecodeSize;
+ }
+ void PushFile(string FilePath, int hHandle)
+ {
+ int DecodeSize = DecodeData(FilePath);
+ Bass.StreamPutData(hHandle, pushbuffer, (int)DecodeSize);
+ }
+ void CreateStreamPushHandle()
+ {
+ if (music == 0)
+ music = Bass.CreateStream(44100, 2, 0, StreamProcedureType.Push);
+ }
+
+
+
+ void QueueNode(int node)
+ {
+ short shnode = (short)node;
+ node = shnode;
+
+ if (node < 0)
+ {
+ node = cur_node + node;
+ }
+
+ prsNODE nd = nodes.ElementAt(node);
+ bool bFoundBranch = false;
+
+ //if (nd.node.index <= -1)
+ //{
+ // return;
+ //}
+
+ next_sample = -1;
+ next_branchto = -1;
+
+ //if (nd.node.index > 0)
+ next_sample = nd.node.index;
+
+ for (int i = 0; i < nd.node.numbranches; i++)
+ {
+ if ((intensity_controller >= nd.branches.ElementAt(i).controlmin) && (intensity_controller <= nd.branches.ElementAt(i).controlmax))
+ {
+ next_branchto = nd.branches.ElementAt(i).dstnode;
+ bFoundBranch = true;
+ }
+ }
+ if ((!bFoundBranch) && (nd.node.numbranches > 0))
+ {
+ next_branchto = nd.branches.ElementAt(0).dstnode;
+ }
+ cur_node = node;
+ }
+
+ void HandlePushing()
+ {
+ long remaining = 0;
+
+ remaining = Bass.StreamPutData(music, (byte[])null, 0);
+ double time = Bass.ChannelBytes2Seconds(music, remaining);
+
+ label1.Text = "Time: " + time.ToString("0.00") + " (bytes: " + remaining.ToString() + ")";
+ label2.Text = "Pushing status: ";
+ if ((time - 0.1) <= 0)
+ {
+ //string fname = String.Format("E:\\Need for Speed Most Wanted\\InteractiveMusic_ps2\\MW_Music.mus_{0}.asf.wav", counter);
+
+ label2.Text += "Pushing";
+ label3.Text = "File: " + queued_file;
+ bReadyToQueue = true;
+
+
+ //PushFile(fname, music);
+ //counter++;
+ }
+ else
+ {
+ label2.Text += "Not pushing";
+ }
+
+
+ }
+ void HandlePathfinderPlayback()
+ {
+ HandlePushing();
+
+ if (next_branchto >= 0 && bReadyToQueue)
+ {
+ label4.Text = String.Format("Queued: {0}", next_branchto);
+ QueueNode(next_branchto);
+
+ if (next_sample > 0)
+ {
+ if (music != 0)
+ {
+ queued_file = String.Format("{0}\\{1}{2}", sample_folder, next_sample, sample_ext);
+ PushFile(queued_file, music);
+ }
+ }
+ bReadyToQueue = false;
+ }
+ }
+
+
+ public Form1()
+ {
+ InitializeComponent();
+ }
+
+ private void Form1_Load(object sender, EventArgs e)
+ {
+ music = 0;
+
+ // 10ms update period
+ Bass.UpdatePeriod = 10;
+
+ if (!Bass.Init(-1, 44100, DeviceInitFlags.Latency))
+ {
+ MessageBox.Show("Can't initialize device");
+ }
+ }
+
+ private void timer1_Tick(object sender, EventArgs e)
+ {
+ if (music != 0 && (next_branchto >= 0) && !bPausedPlayback)
+ HandlePathfinderPlayback();
+
+ if (music != 0)
+ {
+ label7.Text = "Playback: ";
+ switch (Bass.ChannelIsActive(music))
+ {
+ case PlaybackState.Stalled:
+ label7.Text += "Stalled";
+ break;
+ case PlaybackState.Stopped:
+ label7.Text += "Stopped";
+ break;
+ case PlaybackState.Paused:
+ label7.Text += "Paused";
+ break;
+ case PlaybackState.Playing:
+ label7.Text += "Playing";
+ break;
+ default:
+ break;
+ }
+ label5.Text = "Intensity: " + intensity_controller;
+ label6.Text = "Next node: " + next_branchto;
+ }
+ }
+
+ private void button3_Click(object sender, EventArgs e)
+ {
+ if (music != 0)
+ {
+ Bass.ChannelStop(music);
+ Bass.StreamFree(music);
+ music = 0;
+ }
+ }
+
+ private void button1_Click(object sender, EventArgs e)
+ {
+ //music = Bass.CreateStream("C:\\Temp\\MW_Music.mus_0.asf.wav", 0, 0, BassFlags.Default);
+ //ParseMapFile("D:\\Temp\\mpfmastertest\\MW_Music_decomp.txt");
+ if (nodes.Count > 0)
+ {
+ bPausedPlayback = false;
+ if (music == 0)
+ {
+ next_branchto = initial_node;
+ CreateStreamPushHandle();
+ }
+ Bass.ChannelPlay(music, false);
+ }
+ }
+
+ private void button2_Click(object sender, EventArgs e)
+ {
+ if (music != 0)
+ {
+ if (Bass.ChannelIsActive(music) == PlaybackState.Playing)
+ {
+ Bass.ChannelPause(music);
+ bPausedPlayback = true;
+ }
+ }
+ }
+
+ private void textBox2_TextChanged(object sender, EventArgs e)
+ {
+ int.TryParse(textBox2.Text, out next_intensity);
+ }
+
+ private void button4_Click(object sender, EventArgs e)
+ {
+ intensity_controller = next_intensity;
+ label5.Text = "Intensity: " + intensity_controller;
+ }
+
+ private void textBox1_TextChanged(object sender, EventArgs e)
+ {
+ int.TryParse(textBox1.Text, out initial_node);
+ }
+
+ private void button5_Click(object sender, EventArgs e)
+ {
+ next_branchto = initial_node;
+ label6.Text = "Next node: " + next_branchto;
+ }
+
+ private void openToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if (openFileDialog1.ShowDialog() == DialogResult.OK)
+ {
+ if (sampleFolderDialog.ShowDialog() == DialogResult.OK)
+ {
+ nodes.Clear();
+
+ sample_folder = Path.GetDirectoryName(sampleFolderDialog.FileName);
+ sample_ext = Path.GetExtension(sampleFolderDialog.FileName);
+ ParseMapFile(openFileDialog1.FileName);
+ }
+ }
+ }
+
+ private void exitToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/PathfinderPlayer/Form1.resx b/PathfinderPlayer/Form1.resx
new file mode 100644
index 0000000..d0d8547
--- /dev/null
+++ b/PathfinderPlayer/Form1.resx
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 104, 17
+
+
+ 219, 17
+
+
+ 359, 17
+
+
\ No newline at end of file
diff --git a/PathfinderPlayer/PathfinderPlayer.csproj b/PathfinderPlayer/PathfinderPlayer.csproj
new file mode 100644
index 0000000..c3f390c
--- /dev/null
+++ b/PathfinderPlayer/PathfinderPlayer.csproj
@@ -0,0 +1,15 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PathfinderPlayer/PathfinderPlayer.sln b/PathfinderPlayer/PathfinderPlayer.sln
new file mode 100644
index 0000000..db200d3
--- /dev/null
+++ b/PathfinderPlayer/PathfinderPlayer.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33103.184
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PathfinderPlayer", "PathfinderPlayer.csproj", "{E75A71A4-FFD3-4C8C-AC89-B549D3AFEC53}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E75A71A4-FFD3-4C8C-AC89-B549D3AFEC53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E75A71A4-FFD3-4C8C-AC89-B549D3AFEC53}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E75A71A4-FFD3-4C8C-AC89-B549D3AFEC53}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E75A71A4-FFD3-4C8C-AC89-B549D3AFEC53}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {497AABF3-D40B-493E-BE84-3257D82B294E}
+ EndGlobalSection
+EndGlobal
diff --git a/PathfinderPlayer/Program.cs b/PathfinderPlayer/Program.cs
new file mode 100644
index 0000000..1e39c2a
--- /dev/null
+++ b/PathfinderPlayer/Program.cs
@@ -0,0 +1,17 @@
+namespace WinFormsApp1
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new Form1());
+ }
+ }
+}
\ No newline at end of file
diff --git a/PathfinderPlayer/README.md b/PathfinderPlayer/README.md
new file mode 100644
index 0000000..00ced5e
--- /dev/null
+++ b/PathfinderPlayer/README.md
@@ -0,0 +1,39 @@
+# Pathfinder Player
+
+This is an extremely basic player.
+
+Currently it doesn't support any advanced actions (looping, event actions, variables, routers, etc).
+
+It only does basic branching with a single controller.
+
+You can use this tool to preview what each node will sound like without having to test in the game itself.
+
+## Usage
+
+1. Open the Pathfinder map file source (decompiled with MPFmaster)
+
+2. Open a folder with samples in a supported format by BASS (WAV, MP3, OGG) - convert your samples if you have to
+
+3. Type in your desired node in the "Next node" box and apply it (optional)
+
+4. Press "Play"
+
+5. Fiddle around with the "Intensity" controller as the player is running. You should be able to observe different behavior in real time.
+
+## Status
+
+It is currently very limited and buggy.
+
+It currently has a basic node parser and nothing much more.
+
+It does not exit out of branches and can get stuck if the branches lead nowhere.
+
+It's also limited to 44.1kHz output as I did not write up a configuration dialog for setting up BASS and actually having a config file.
+
+# Credits
+
+[Un4seen Developments Ltd.](http://www.un4seen.com/) (Ian Luck) - BASS library
+
+[ManagedBass wrapper for .NET](https://github.com/ManagedBass/ManagedBass)
+
+