From c0120068d3ad895df7a29a474bacbc458e78ce90 Mon Sep 17 00:00:00 2001
From: Clownacy <Clownacy@users.noreply.github.com>
Date: Wed, 6 Feb 2019 20:02:53 +0000
Subject: [PATCH] Added more NPCs, and the TAM TSC command

---
 src/CommonDefines.h |   4 +-
 src/NpcAct.h        |   3 +
 src/NpcAct160.cpp   | 391 ++++++++++++++++++++++++++++++++++++++++++++
 src/NpcTbl.cpp      |   6 +-
 src/TextScr.cpp     |   8 +
 5 files changed, 407 insertions(+), 5 deletions(-)

diff --git a/src/CommonDefines.h b/src/CommonDefines.h
index 2a135b90..ecf6dece 100644
--- a/src/CommonDefines.h
+++ b/src/CommonDefines.h
@@ -1,5 +1,5 @@
 #pragma once
 #define PATH_LENGTH 260 //Pixel had the path size locked to 260 (dangerously low), if you tried to open the executable in a path with more than around 220 characters, it'd crash.
 
-#define WINDOW_WIDTH 320
-#define WINDOW_HEIGHT 240
+#define WINDOW_WIDTH ((320*16)/9)
+#define WINDOW_HEIGHT 320
diff --git a/src/NpcAct.h b/src/NpcAct.h
index 35989f3f..374a988c 100644
--- a/src/NpcAct.h
+++ b/src/NpcAct.h
@@ -170,6 +170,9 @@ void ActNpc164(NPCHAR *npc);
 void ActNpc165(NPCHAR *npc);
 void ActNpc166(NPCHAR *npc);
 void ActNpc167(NPCHAR *npc);
+void ActNpc168(NPCHAR *npc);
+void ActNpc169(NPCHAR *npc);
+void ActNpc170(NPCHAR *npc);
 
 void ActNpc173(NPCHAR *npc);
 void ActNpc174(NPCHAR *npc);
diff --git a/src/NpcAct160.cpp b/src/NpcAct160.cpp
index 8482b4e7..78274ad7 100644
--- a/src/NpcAct160.cpp
+++ b/src/NpcAct160.cpp
@@ -10,6 +10,7 @@
 #include "Triangle.h"
 #include "Frame.h"
 #include "Caret.h"
+#include "MycParam.h"
 
 //Puu Black
 void ActNpc160(NPCHAR *npc)
@@ -516,6 +517,396 @@ void ActNpc167(NPCHAR *npc)
 	npc->rect = rect[npc->ani_no];
 }
 
+//Boulder
+void ActNpc168(NPCHAR *npc)
+{
+	RECT rect[1];
+
+	rect[0] = {264, 56, 320, 96};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->act_wait = 0;
+			npc->tgt_x = npc->x;
+			// Fallthrough
+		case 11:
+			++npc->act_wait;
+			npc->x = npc->tgt_x;
+
+			if (npc->act_wait / 3 % 2)
+				npc->x += 0x200;
+
+			break;
+
+		case 20:
+			npc->act_no = 21;
+			npc->act_wait = 0;
+			npc->ym = -0x400;
+			npc->xm = 0x100;
+			PlaySoundObject(25, 1);
+			// Fallthrough
+		case 21:
+			npc->ym += 0x10;
+
+			npc->x += npc->xm;
+			npc->y += npc->ym;
+
+			if (npc->act_wait && npc->flag & 8)
+			{
+				PlaySoundObject(35, 1);
+				SetQuake(40);
+				npc->act_no = 0;
+			}
+
+			if (npc->act_wait == 0)
+				++npc->act_wait;
+
+			break;
+	}
+
+	npc->rect = rect[0];
+}
+
+//Balrog (missile)
+void ActNpc169(NPCHAR *npc)
+{
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->act_wait = 30;
+
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+			// Fallthrough
+		case 1:
+			if (--npc->act_wait == 0)
+			{
+				npc->act_no = 2;
+				++npc->count1;
+			}
+
+			break;
+
+		case 2:
+			npc->act_no = 3;
+			npc->act_wait = 0;
+			npc->ani_no = 1;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 3:
+			if (++npc->ani_wait > 3)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+
+				if (npc->ani_no == 2 || npc->ani_no == 4)
+					PlaySoundObject(23, 1);
+			}
+
+			if (npc->ani_no > 4)
+				npc->ani_no = 1;
+
+			if (npc->direct == 0)
+				npc->xm -= 0x20;
+			else
+				npc->xm += 0x20;
+
+			if (npc->act_wait >= 8 && gMC.x > npc->x - 0x1800 && gMC.x < npc->x + 0x1800 && gMC.y > npc->y - 0x1800 && gMC.y < npc->y + 0x1000)
+			{
+				npc->act_no = 10;
+				npc->ani_no = 5;
+				gMC.cond |= 2;
+				DamageMyChar(5);
+			}
+			else
+			{
+				if (++npc->act_wait > 75)
+				{
+					npc->act_no = 9;
+					npc->ani_no = 0;
+				}
+				else
+				{
+					if (npc->flag & 5)
+					{
+						if (npc->count2 < 5)
+						{
+							++npc->count2;
+						}
+						else
+						{
+							npc->act_no = 4;
+							npc->act_wait = 0;
+							npc->ani_no = 7;
+							npc->ym = -0x5FF;
+						}
+					}
+					else
+					{
+						npc->count2 = 0;
+					}
+
+					if (npc->count1 % 2 == 0 && npc->act_wait > 25)
+					{
+						npc->act_no = 4;
+						npc->act_wait = 0;
+						npc->ani_no = 7;
+						npc->ym = -0x5FF;
+					}
+				}
+			}
+
+			break;
+
+		case 4:
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			++npc->act_wait;
+
+			if (npc->act_wait < 30 && npc->act_wait % 6 == 1)
+			{
+				PlaySoundObject(39, 1);
+				SetNpChar(170, npc->x, npc->y, 0, 0, npc->direct, 0, 0x100);
+			}
+
+			if (npc->flag & 8)
+			{
+				npc->act_no = 9;
+				npc->ani_no = 8;
+				SetQuake(30);
+				PlaySoundObject(26, 1);
+			}
+
+			if (npc->act_wait >= 8 && gMC.x > npc->x - 0x1800 && gMC.x < npc->x + 0x1800 && gMC.y > npc->y - 0x1800 && gMC.y < npc->y + 0x1000)
+			{
+				npc->act_no = 10;
+				npc->ani_no = 5;
+				gMC.cond |= 2;
+				DamageMyChar(10);
+			}
+
+			break;
+
+		case 9:
+			npc->xm = 4 * npc->xm / 5;
+
+			if (npc->xm == 0)
+				npc->act_no = 0;
+
+			break;
+
+		case 10:
+			gMC.x = npc->x;
+			gMC.y = npc->y;
+
+			npc->xm = 4 * npc->xm / 5;
+
+			if (npc->xm == 0)
+			{
+				npc->act_no = 11;
+				npc->act_wait = 0;
+				npc->ani_no = 5;
+				npc->ani_wait = 0;
+			}
+
+			break;
+
+		case 11:
+			gMC.x = npc->x;
+			gMC.y = npc->y;
+
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 6)
+				npc->ani_no = 5;
+
+			if (++npc->act_wait > 100)
+				npc->act_no = 20;
+
+			break;
+
+		case 20:
+			PlaySoundObject(25, 1);
+			gMC.cond &= ~2;
+
+			if (npc->direct == 0)
+			{
+				gMC.x += 0x800;
+				gMC.y -= 0x1000;
+				gMC.xm = 0x5FF;
+				gMC.ym = -0x200;
+				gMC.direct = 2;
+				npc->direct = 2;
+			}
+			else
+			{
+				gMC.x -= 0x800;
+				gMC.y -= 0x1000;
+				gMC.xm = -0x5FF;
+				gMC.ym = -0x200;
+				gMC.direct = 0;
+				npc->direct = 0;
+			}
+
+			npc->act_no = 21;
+			npc->act_wait = 0;
+			npc->ani_no = 7;
+			// Fallthrough
+		case 21:
+			if (++npc->act_wait >= 50)
+				npc->act_no = 0;
+
+			break;
+	}
+
+	npc->ym += 0x20;
+
+	if (npc->xm < -0x300)
+		npc->xm = -0x300;
+	if (npc->xm > 0x300)
+		npc->xm = 0x300;
+
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	RECT rect_left[9];
+	RECT rect_right[9];
+
+	rect_left[0] = {0, 0, 40, 24};
+	rect_left[1] = {0, 48, 40, 72};
+	rect_left[2] = {0, 0, 40, 24};
+	rect_left[3] = {40, 48, 80, 72};
+	rect_left[4] = {0, 0, 40, 24};
+	rect_left[5] = {80, 48, 120, 72};
+	rect_left[6] = {120, 48, 160, 72};
+	rect_left[7] = {120, 0, 160, 24};
+	rect_left[8] = {80, 0, 120, 24};
+
+	rect_right[0] = {0, 24, 40, 48};
+	rect_right[1] = {0, 72, 40, 96};
+	rect_right[2] = {0, 24, 40, 48};
+	rect_right[3] = {40, 72, 80, 96};
+	rect_right[4] = {0, 24, 40, 48};
+	rect_right[5] = {80, 72, 120, 96};
+	rect_right[6] = {120, 72, 160, 96};
+	rect_right[7] = {120, 24, 160, 48};
+	rect_right[8] = {80, 24, 120, 48};
+
+	if (npc->direct == 0)
+		npc->rect = rect_left[npc->ani_no];
+	else
+		npc->rect = rect_right[npc->ani_no];
+}
+
+//Balrog missile
+void ActNpc170(NPCHAR *npc)
+{
+	RECT rcLeft[2];
+	RECT rcRight[2];
+
+	rcLeft[0] = {112, 96, 128, 104};
+	rcLeft[1] = {128, 96, 144, 104};
+
+	rcRight[0] = {112, 104, 128, 112};
+	rcRight[1] = {128, 104, 144, 112};
+
+	bool bHit = false;
+
+	if (npc->direct == 0 && npc->flag & 1)
+		bHit = true;
+	if (npc->direct == 2 && npc->flag & 4)
+		bHit = true;
+
+	if (bHit)
+	{
+		PlaySoundObject(44, 1);
+		SetDestroyNpChar(npc->x, npc->y, 0, 3);
+		VanishNpChar(npc);
+		return;
+	}
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+
+			if (npc->direct == 0)
+				npc->xm = Random(1, 2) * 0x200;
+			else
+				npc->xm = Random(-2, -1) * 0x200;
+
+			npc->ym = Random(-2, 0) * 0x200;
+			// Fallthrough
+		case 1:
+			++npc->count1;
+
+			if (npc->direct == 0)
+			{
+				npc->xm -= 0x20;
+
+				if (npc->count1 % 3 == 1)
+					SetCaret(npc->x + 0x1000, npc->y, 7, 2);
+			}
+			else
+			{
+				npc->xm += 0x20;
+
+				if (npc->count1 % 3 == 1)
+					SetCaret(npc->x - 0x1000, npc->y, 7, 0);
+			}
+
+			if (npc->count1 >= 50)
+			{
+				npc->ym = 0;
+			}
+			else
+			{
+				if (gMC.y > npc->y)
+					npc->ym += 0x20;
+				else
+					npc->ym -= 0x20;
+			}
+
+			if (++npc->ani_no > 1)
+				npc->ani_no = 0;
+
+			break;
+	}
+
+	if (npc->xm < -0x400)
+		npc->xm = -0x600;
+	if (npc->xm > 0x400)
+		npc->xm = 0x600;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
 //Gaudi (armoured)
 void ActNpc173(NPCHAR *npc)
 {
diff --git a/src/NpcTbl.cpp b/src/NpcTbl.cpp
index 58648c78..90b45d6f 100644
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -224,9 +224,9 @@ NPCFUNCTION gpNpcFuncTbl[361] =
 	ActNpc165,
 	ActNpc166,
 	ActNpc167,
-	nullptr,
-	nullptr,
-	nullptr,
+	ActNpc168,
+	ActNpc169,
+	ActNpc170,
 	nullptr,
 	nullptr,
 	ActNpc173,
diff --git a/src/TextScr.cpp b/src/TextScr.cpp
index 44fcf4e1..2bdaac91 100644
--- a/src/TextScr.cpp
+++ b/src/TextScr.cpp
@@ -673,6 +673,14 @@ int TextScriptProc()
 						SubArmsData(z);
 						gTS.p_read += 8;
 					}
+					else if (IS_COMMAND('T','A','M'))
+					{
+						x = GetTextScriptNo(gTS.p_read + 4);
+						y = GetTextScriptNo(gTS.p_read + 9);
+						z = GetTextScriptNo(gTS.p_read + 14);
+						TradeArms(x, y, z);
+						gTS.p_read += 18;
+					}
 					else if (IS_COMMAND('P','S','+'))
 					{
 						x = GetTextScriptNo(gTS.p_read + 4);