shithub: cstory

Download patch

ref: 26bcbdbef7fdfbe83d9d63f6daff81a44a588ad6
parent: 88947cd016699382cd99d7cbf306e18cb6a5fb50
author: Clownacy <[email protected]>
date: Fri Feb 8 16:30:08 EST 2019

Added more NPCs

Now with Muscle Doctor

--- a/src/NpcAct.h
+++ b/src/NpcAct.h
@@ -258,11 +258,21 @@
 void ActNpc253(NPCHAR *npc);
 void ActNpc254(NPCHAR *npc);
 void ActNpc255(NPCHAR *npc);
-
+void ActNpc256(NPCHAR *npc);
+void ActNpc257(NPCHAR *npc);
+void ActNpc258(NPCHAR *npc);
 void ActNpc259(NPCHAR *npc);
-
+void ActNpc260(NPCHAR *npc);
+void ActNpc261(NPCHAR *npc);
+void ActNpc262(NPCHAR *npc);
+void ActNpc263(NPCHAR *npc);
+void ActNpc264(NPCHAR *npc);
+void ActNpc265(NPCHAR *npc);
+void ActNpc266(NPCHAR *npc);
+void ActNpc267(NPCHAR *npc);
 void ActNpc268(NPCHAR *npc);
-
+void ActNpc269(NPCHAR *npc);
+void ActNpc270(NPCHAR *npc);
 void ActNpc271(NPCHAR *npc);
 void ActNpc272(NPCHAR *npc);
 void ActNpc273(NPCHAR *npc);
--- a/src/NpcAct240.cpp
+++ b/src/NpcAct240.cpp
@@ -1193,6 +1193,167 @@
 		npc->rect = rcRight[npc->ani_no];
 }
 
+//Doctor (facing away)
+void ActNpc256(NPCHAR *npc)
+{
+	RECT rcLeft[6];
+
+	rcLeft[0] = {48, 160, 72, 192};
+	rcLeft[1] = {72, 160, 96, 192};
+	rcLeft[2] = {0, 128, 24, 160};
+	rcLeft[3] = {24, 128, 48, 160};
+	rcLeft[4] = {0, 160, 24, 192};
+	rcLeft[5] = {24, 160, 48, 192};
+
+	switch ( npc->act_no )
+	{
+		case 0:
+			gSuperXpos = 0;
+			npc->act_no = 1;
+			npc->y -= 0x1000;
+			// Fallthrough
+		case 1:
+			npc->ani_no = 0;
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->ani_wait = 0;
+			npc->ani_no = 0;
+			npc->count1 = 0;
+			// Fallthrough
+		case 11:
+			if (++npc->ani_wait > 5)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 1)
+			{
+				npc->ani_no = 0;
+				++npc->count1;
+			}
+
+			if (npc->count1 > 5)
+				npc->act_no = 1;
+
+			break;
+
+		case 20:
+			npc->act_no = 21;
+			// Fallthrough
+		case 21:
+			npc->ani_no = 2;
+			break;
+
+		case 40:
+			npc->act_no = 41;
+			SetNpChar(257, npc->x - 0x1C00, npc->y - 0x2000, 0, 0, 0, 0, 0x100);
+			SetNpChar(257, npc->x - 0x1C00, npc->y - 0x2000, 0, 0, 2, 0, 0xAA);
+			// Fallthrough
+		case 41:
+			npc->ani_no = 4;
+			break;
+
+		case 50:
+			npc->act_no = 51;
+			npc->ani_wait = 0;
+			npc->ani_no = 4;
+			npc->count1 = 0;
+			// Fallthrough
+		case 51:
+			if (++npc->ani_wait > 5)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 5)
+			{
+				npc->ani_no = 4;
+				++npc->count1;
+			}
+
+			if (npc->count1 > 5)
+				npc->act_no = 41;
+
+			break;
+	}
+
+	npc->rect = rcLeft[npc->ani_no];
+}
+
+//Red crystal
+void ActNpc257(NPCHAR *npc)
+{
+	RECT rc[3];
+
+	rc[0] = {176, 32, 184, 48};
+	rc[1] = {184, 32, 192, 48};
+	rc[2] = {0, 0, 0, 0};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			// Fallthrough
+		case 1:
+			if (gSuperXpos)
+				npc->act_no = 10;
+
+			break;
+
+		case 10:
+			if (npc->x < gSuperXpos)
+				npc->xm += 0x55;
+			if (npc->x > gSuperXpos)
+				npc->xm -= 0x55;
+
+			if (npc->y < gSuperYpos)
+				npc->ym += 0x55;
+			if (npc->y > gSuperYpos)
+				npc->ym -= 0x55;
+
+			if (npc->xm > 0x400)
+				npc->xm = 0x400;
+			if (npc->xm < -0x400)
+				npc->xm = -0x400;
+
+			if (npc->ym > 0x400)
+				npc->ym = 0x400;
+			if (npc->ym < -0x400)
+				npc->ym = -0x400;
+
+			npc->x += npc->xm;
+			npc->y += npc->ym;
+			break;
+	}
+
+	if (++npc->ani_wait > 3)
+	{
+		npc->ani_wait = 0;
+		++npc->ani_no;
+	}
+
+	if (npc->ani_no > 1)
+		npc->ani_no = 0;
+
+	if (npc->direct == 0 && npc->xm > 0)
+		npc->ani_no = 2;
+	if (npc->direct == 2 && npc->xm < 0)
+		npc->ani_no = 2;
+
+	npc->rect = rc[npc->ani_no];
+}
+
+//Mimiga (sleeping)
+void ActNpc258(NPCHAR *npc)
+{
+	RECT rc = {48, 32, 64, 48};
+	npc->rect = rc;
+}
+
 //Curly (carried and unconcious)
 void ActNpc259(NPCHAR *npc)
 {
--- a/src/NpcAct260.cpp
+++ b/src/NpcAct260.cpp
@@ -11,7 +11,1099 @@
 #include "Caret.h"
 #include "Map.h"
 #include "Frame.h"
+#include "MycParam.h"
 
+//Shovel Brigade (caged)
+void ActNpc260(NPCHAR *npc)
+{
+	RECT rcLeft[3];
+	RECT rcRight[3];
+
+	rcLeft[0] = {128, 64, 144, 80};
+	rcLeft[1] = {144, 64, 160, 80};
+	rcLeft[2] = {224, 64, 240, 80};
+
+	rcRight[0] = {128, 80, 144, 96};
+	rcRight[1] = {144, 80, 160, 96};
+	rcRight[2] = {224, 80, 240, 96};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->x += 0x200;
+			npc->y -= 0x400;
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 160) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 12)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 10:
+			npc->act_no = 11;
+			npc->ani_no = 2;
+			SetNpChar(87, npc->x, npc->y - 0x2000, 0, 0, 0, 0, 0x100);
+
+			break;
+	}
+
+	if (gMC.x < npc->x)
+		npc->direct = 0;
+	else
+		npc->direct = 2;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//Chie (caged)
+void ActNpc261(NPCHAR *npc)
+{
+	RECT rcLeft[2];
+	RECT rcRight[2];
+
+	rcLeft[0] = {112, 32, 128, 48};
+	rcLeft[1] = {128, 32, 144, 48};
+
+	rcRight[0] = {112, 48, 128, 64};
+	rcRight[1] = {128, 48, 144, 64};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->x -= 0x200;
+			npc->y -= 0x400;
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 160) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 12 )
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+	}
+
+	if (gMC.x < npc->x)
+		npc->direct = 0;
+	else
+		npc->direct = 2;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//Chaco (caged)
+void ActNpc262(NPCHAR *npc)
+{
+	RECT rcLeft[2];
+	RECT rcRight[2];
+
+	rcLeft[0] = {128, 0, 144, 16};
+	rcLeft[1] = {144, 0, 160, 16};
+
+	rcRight[0] = {128, 16, 144, 32};
+	rcRight[1] = {144, 16, 160, 32};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->x -= 0x200;
+			npc->y -= 0x400;
+			npc->act_no = 1;
+			npc->ani_no = 0;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 1:
+			if (Random(0, 160) == 1)
+			{
+				npc->act_no = 2;
+				npc->act_wait = 0;
+				npc->ani_no = 1;
+			}
+
+			break;
+
+		case 2:
+			if (++npc->act_wait > 12)
+			{
+				npc->act_no = 1;
+				npc->ani_no = 0;
+			}
+
+			break;
+	}
+
+	if (gMC.x < npc->x)
+		npc->direct = 0;
+	else
+		npc->direct = 2;
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//Doctor (boss)
+void ActNpc263(NPCHAR *npc)
+{
+	RECT rcLeft[9];
+	RECT rcRight[9];
+
+	rcLeft[0] = {0, 0, 24, 32};
+	rcLeft[1] = {24, 0, 48, 32};
+	rcLeft[2] = {48, 0, 72, 32};
+	rcLeft[3] = {0, 0, 0, 0};
+	rcLeft[4] = {72, 0, 96, 32};
+	rcLeft[5] = {96, 0, 120, 32};
+	rcLeft[6] = {120, 0, 144, 32};
+	rcLeft[7] = {144, 0, 168, 32};
+	rcLeft[8] = {264, 0, 288, 32};
+
+	rcRight[0] = {0, 32, 24, 64};
+	rcRight[1] = {24, 32, 48, 64};
+	rcRight[2] = {48, 32, 72, 64};
+	rcRight[3] = {0, 0, 0, 0};
+	rcRight[4] = {72, 32, 96, 64};
+	rcRight[5] = {96, 32, 120, 64};
+	rcRight[6] = {120, 32, 144, 64};
+	rcRight[7] = {144, 32, 168, 64};
+	rcRight[8] = {264, 32, 288, 64};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->y += 0x1000;
+			npc->ani_no = 3;
+			break;
+
+		case 2:
+			if (++npc->act_wait / 2 & 1)
+				npc->ani_no = 0;
+			else
+				npc->ani_no = 3;
+
+			if (npc->act_wait > 50)
+				npc->act_no = 10;
+
+			break;
+
+		case 10:
+			npc->ym += 0x80;
+			npc->bits |= 0x20;
+			npc->damage = 3;
+
+			if (npc->flag & 8)
+			{
+				npc->act_no = 20;
+				npc->act_wait = 0;
+				npc->ani_no = 0;
+				npc->count2 = npc->life;
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+			}
+
+			break;
+
+		case 20:
+			if (++npc->act_wait < 50 && npc->life < npc->count2 - 20)
+				npc->act_wait = 50;
+
+			if (npc->act_wait == 50)
+			{
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+
+				npc->ani_no = 4;
+			}
+
+			if (npc->act_wait == 80)
+			{
+				npc->ani_no = 5;
+				PlaySoundObject(25, 1);
+
+				if (npc->direct == 0)
+				{
+					SetNpChar(264, npc->x - 0x2000, npc->y, 0, 0, 0, 0, 0x100);
+					SetNpChar(264, npc->x - 0x2000, npc->y, 0, 0, 0x400, 0, 0x100);
+				}
+				else
+				{
+					SetNpChar(264, npc->x + 0x2000, npc->y, 0, 0, 2, 0, 0x100);
+					SetNpChar(264, npc->x + 0x2000, npc->y, 0, 0, 2 + 0x400, 0, 0x100);
+				}
+			}
+
+			if (npc->act_wait == 120)
+				npc->ani_no = 0;
+
+			if (npc->act_wait > 130 && npc->life < npc->count2 - 50)
+				npc->act_wait = 161;
+
+			if (npc->act_wait > 160)
+			{
+				npc->act_no = 100;
+				npc->ani_no = 0;
+			}
+
+			break;
+
+		case 30:
+			npc->act_no = 31;
+			npc->act_wait = 0;
+			npc->ani_no = 6;
+			npc->tgt_x = npc->x;
+			npc->bits |= 0x20;
+			// Fallthrough
+		case 31:
+			if (++npc->act_wait / 2 & 1)
+				npc->x = npc->tgt_x;
+			else
+				npc->x = npc->tgt_x + 0x200;
+
+			if (npc->act_wait > 50)
+			{
+				npc->act_no = 32;
+				npc->act_wait = 0;
+				npc->ani_no = 7;
+				PlaySoundObject(101, 1);
+
+				for (int deg = 8; deg < 0x100; deg += 0x10)
+				{
+					const int xm = 2 * GetCos(deg);
+					const int ym = 2 * GetSin(deg);
+					SetNpChar(266, npc->x, npc->y, xm, ym, 0, 0, 0x100);
+				}
+			}
+
+			break;
+
+		case 32:
+			if (++npc->act_wait > 50)
+				npc->act_no = 100;
+
+			break;
+
+		case 100:
+			npc->act_no = 101;
+			npc->bits &= ~0x20;
+			npc->damage = 0;
+			npc->act_wait = 0;
+			PlaySoundObject(29, 1);
+			// Fallthrough
+		case 101:
+			npc->act_wait += 2;
+
+			if (npc->act_wait > 16)
+			{
+				npc->act_no = 102;
+				npc->act_wait = 0;
+				npc->ani_no = 3;
+				npc->tgt_x = Random(5, 35) * 0x2000;
+				npc->tgt_y = Random(5, 7) * 0x2000;
+			}
+
+			break;
+
+		case 102:
+			if (++npc->act_wait > 40 )
+			{
+				npc->act_no = 103;
+				npc->act_wait = 16;
+				npc->ani_no = 2;
+				npc->ym = 0;
+				npc->x = npc->tgt_x;
+				npc->y = npc->tgt_y;
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+			}
+
+			break;
+
+		case 103:
+			npc->act_wait -= 2;
+
+			if ( npc->act_wait <= 0 )
+			{
+				npc->bits |= 0x20;
+				npc->damage = 3;
+
+				if (npc->count1 < 3)
+				{
+					++npc->count1;
+					npc->act_no = 10;
+				}
+				else
+				{
+					npc->count1 = 0;
+					npc->act_no = 30;
+				}
+			}
+
+			break;
+
+		case 500:
+			npc->bits &= ~0x20;
+			npc->ani_no = 6;
+			npc->ym += 0x10;
+
+			if (npc->flag & 8)
+			{
+				npc->act_no = 501;
+				npc->act_wait = 0;
+				npc->tgt_x = npc->x;
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+			}
+
+			break;
+
+		case 501:
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			npc->ani_no = 8;
+
+			if (++npc->act_wait / 2 & 1)
+				npc->x = npc->tgt_x;
+			else
+				npc->x = npc->tgt_x + 0x200;
+
+			break;
+	}
+
+	if (npc->act_no >= 10)
+	{
+		if (npc->act_no == 102)
+		{
+			gSuperXpos = npc->tgt_x;
+			gSuperYpos = npc->tgt_y;
+		}
+		else
+		{
+			gSuperXpos = npc->x;
+			gSuperYpos = npc->y;
+		}
+	}
+
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	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];
+
+	if (npc->act_no == 101 || npc->act_no == 103)
+	{
+		npc->rect.top += npc->act_wait;
+		npc->rect.bottom -= npc->act_wait;
+		npc->view.top = (16 - npc->act_wait) << 9;
+	}
+	else
+	{
+		npc->view.top = 0x2000;
+	}
+}
+
+//Doctor red wave (projectile)
+void ActNpc264(NPCHAR *npc)
+{
+	RECT rc = {288, 0, 304, 16};
+
+	if (npc->x < 0 || npc->x > gMap.width * 0x2000)
+	{
+		VanishNpChar(npc);
+		return;
+	}
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->tgt_x = npc->x;
+			npc->tgt_y = npc->y;
+			npc->count1 = npc->direct / 8;
+			npc->direct &= 7;
+			// Fallthrough
+		case 1:
+			npc->count1 += 6;
+			npc->count1 &= 0xFF;
+			const unsigned char deg = npc->count1;
+
+			if (npc->act_wait < 128)
+				++npc->act_wait;
+
+			if (npc->direct == 0)
+				npc->xm -= 21;
+			else
+				npc->xm += 21;
+
+			npc->tgt_x += npc->xm;
+
+			npc->x = npc->tgt_x + npc->act_wait * GetCos(deg) / 8;
+			npc->y = npc->tgt_y + npc->act_wait * GetSin(deg) / 2;
+
+			SetNpChar(265, npc->x, npc->y, 0, 0, 0, 0, 0x100);
+
+			break;
+	}
+
+	npc->rect = rc;
+}
+
+//Doctor red ball projectile
+void ActNpc265(NPCHAR *npc)
+{
+	RECT rc[3];
+
+	rc[0] = {288, 16, 304, 32};
+	rc[1] = {288, 32, 304, 48};
+	rc[2] = {288, 48, 304, 64};
+
+	if (++npc->ani_wait > 3)
+	{
+		npc->ani_wait = 0;
+		++npc->ani_no;
+	}
+
+	if (npc->ani_no > 2)
+		npc->cond = 0;
+	else
+		npc->rect = rc[npc->ani_no];
+}
+
+//Doctor red ball projectile (bouncing)
+void ActNpc266(NPCHAR *npc)
+{
+	RECT rc[2];
+
+	rc[0] = {304, 16, 320, 32};
+	rc[1] = {304, 32, 320, 48};
+
+	if (npc->flag & 1)
+		npc->xm = -npc->xm;
+	if (npc->flag & 4)
+		npc->xm = -npc->xm;
+
+	if (npc->flag & 2)
+		npc->ym = 0x200;
+	if (npc->flag & 8)
+		npc->ym = -0x200;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (++npc->ani_no > 1)
+		npc->ani_no = 0;
+
+	npc->rect = rc[npc->ani_no];
+
+	if (++npc->act_wait % 4 == 1)
+		SetNpChar(265, npc->x, npc->y, 0, 0, 0, 0, 0x100);
+
+	if (npc->act_wait > 250)
+		VanishNpChar(npc);
+}
+
+//Muscle Doctor
+void ActNpc267(NPCHAR *npc)
+{
+	RECT rcLeft[10];
+	RECT rcRight[10];
+
+	rcLeft[0] = {0, 0, 0, 0};
+	rcLeft[1] = {0, 64, 40, 112};
+	rcLeft[2] = {40, 64, 80, 112};
+	rcLeft[3] = {80, 64, 120, 112};
+	rcLeft[4] = {120, 64, 160, 112};
+	rcLeft[5] = {160, 64, 200, 112};
+	rcLeft[6] = {200, 64, 240, 112};
+	rcLeft[7] = {240, 64, 280, 112};
+	rcLeft[8] = {280, 64, 320, 112};
+	rcLeft[9] = {0, 160, 40, 208};
+
+	rcRight[0] = {0, 0, 0, 0};
+	rcRight[1] = {0, 112, 40, 160};
+	rcRight[2] = {40, 112, 80, 160};
+	rcRight[3] = {80, 112, 120, 160};
+	rcRight[4] = {120, 112, 160, 160};
+	rcRight[5] = {160, 112, 200, 160};
+	rcRight[6] = {200, 112, 240, 160};
+	rcRight[7] = {240, 112, 280, 160};
+	rcRight[8] = {280, 112, 320, 160};
+	rcRight[9] = {40, 160, 80, 208};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			if (gMC.x < gSuperXpos)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			if (npc->direct == 0)
+				npc->x = gSuperXpos - 0xC00;
+			else
+				npc->x = gSuperXpos + 0xC00;
+
+			npc->y = gSuperYpos;
+			// Fallthrough
+		case 1:
+			npc->act_no = 2;
+			// Fallthrough
+		case 2:
+			npc->ym += 0x80;
+
+			if (++npc->act_wait / 2 % 2)
+				npc->ani_no = 0;
+			else
+				npc->ani_no = 3;
+
+			break;
+
+		case 5:
+			npc->act_no = 6;
+			npc->ani_no = 1;
+			npc->ani_wait = 0;
+			// Fallthrough
+		case 6:
+			npc->ym += 0x80;
+
+			if (++npc->ani_wait > 40)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 2)
+				npc->ani_no = 1;
+
+			break;
+
+		case 7:
+			npc->act_no = 8;
+			npc->act_wait = 0;
+			npc->ani_no = 3;
+			// Fallthrough
+		case 8:
+			npc->ym += 0x40;
+
+			if (++npc->act_wait > 40)
+				npc->act_no = 10;
+
+			break;
+
+		case 10:
+			npc->bits |= 4;
+			npc->xm = 0;
+			npc->act_no = 11;
+			npc->act_wait = 0;
+			npc->ani_no = 1;
+			npc->ani_wait = 0;
+			npc->count2 = npc->life;
+			// Fallthrough
+		case 11:
+			npc->ym += 0x80;
+
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			if (npc->flag & 8)
+			{
+				if (npc->life >= npc->count2 - 20)
+				{
+					if (++npc->ani_wait > 10)
+					{
+						npc->ani_wait = 0;
+
+						if (++npc->ani_no > 2)
+							npc->ani_no = 1;
+					}
+				}
+				else if (gMC.flag & 8 && gMC.x > npc->x - 0x6000 && gMC.x < npc->x + 0x6000 && npc->ani_no != 6)
+				{
+					npc->ani_no = 6;
+					DamageMyChar(5);
+					SetQuake(10);
+					PlaySoundObject(26, 1);
+					gMC.ym = -0x400;
+
+					if (gMC.x < npc->x)
+						gMC.xm = -0x5FF;
+					else
+						gMC.xm = 0x5FF;
+
+					for (int i = 0; i < 100; ++i)
+						SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y + (Random(-0x10, 0x10) * 0x200), 3 * Random(-0x200, 0x200), 3 * Random(-0x200, 0x200), 3, 0, 0xAA);
+				}
+			}
+			else
+			{
+				npc->ani_no = 4;
+			}
+
+			if (++npc->act_wait > 30 || npc->life < npc->count2 - 20)
+			{
+				if (++npc->count1 > 10)
+					npc->count1 = 0;
+
+				switch (npc->count1)
+				{
+					case 8:
+						npc->act_no = 20;
+						break;
+					case 2:
+					case 7:
+						npc->act_no = 100;
+						break;
+					case 3:
+					case 6:
+						npc->act_no = 30;
+						break;
+					case 1:
+					case 9:
+						npc->act_no = 40;
+						break;
+					default:
+						npc->act_no = 15;
+						npc->act_wait = 0;
+						break;
+				}
+			}
+
+			break;
+
+		case 15:
+			npc->ani_no = 3;
+			++npc->act_wait;
+
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			if (npc->act_wait > 20)
+			{
+				npc->act_no = 16;
+				npc->ani_no = 4;
+				npc->ani_wait = 0;
+				npc->ym = -0x600;
+
+				if (npc->direct == 0)
+					npc->xm = -0x400;
+				else
+					npc->xm = 0x400;
+			}
+
+			break;
+
+		case 16:
+			npc->ym += 0x40;
+
+			if (++npc->ani_wait > 1)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 5)
+				npc->ani_no = 4;
+
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			if (npc->ym > 0 && npc->flag & 8)
+				npc->act_no = 17;
+
+			break;
+
+		case 17:
+			npc->act_no = 18;
+			npc->act_wait = 0;
+			SetQuake(10);
+			PlaySoundObject(26, 1);
+			// Fallthrough
+		case 18:
+			npc->ani_no = 3;
+			++npc->act_wait;
+
+			npc->xm = 7 * npc->xm / 8;
+			npc->ym += 0x80;
+
+			if (npc->act_wait > 10)
+				npc->act_no = 10;
+
+			break;
+
+		case 20:
+			npc->act_no = 21;
+			npc->act_wait = 0;
+			// Fallthrough
+		case 21:
+			++npc->act_wait;
+			npc->ani_no = 6;
+
+			if (npc->act_wait > 20 && npc->act_wait % 3 == 1)
+			{
+				const int ym = Random(-0x200u, 0x200);
+				const int xm = 4 * Random(0x100, 0x200);
+
+				if (npc->direct == 0)
+					SetNpChar(269, npc->x - 0x1000, npc->y - 0x800, -xm, ym, 0, 0, 0x100);
+				else
+					SetNpChar(269, npc->x + 0x1000, npc->y - 0x800, xm, ym, 2, 0, 0x100);
+
+				PlaySoundObject(39, 1);
+			}
+
+			if ( npc->act_wait > 90 )
+				npc->act_no = 10;
+
+			break;
+
+		case 30:
+			npc->act_no = 31;
+			npc->act_wait = 0;
+			npc->bits |= 1;
+			npc->bits &= ~0x20;
+			// Fallthrough
+		case 31:
+			npc->ani_no = 3;
+
+			if (++npc->act_wait > 20)
+			{
+				npc->act_no = 32;
+				npc->act_wait = 0;
+				npc->ani_no = 7;
+				npc->bits |= 0x80;
+				npc->damage = 10;
+				PlaySoundObject(25, 1);
+
+				if (npc->direct == 0)
+					npc->xm = -0x5FF;
+				else
+					npc->xm = 0x5FF;
+			}
+
+			break;
+
+		case 32:
+			++npc->act_wait;
+			npc->ym = 0;
+
+			if (npc->act_wait / 2 % 2)
+				npc->ani_no = 7;
+			else
+				npc->ani_no = 8;
+
+			if (npc->act_wait > 30)
+			{
+				npc->act_wait = 0;
+				npc->act_no = 18;
+				npc->damage = 5;
+				npc->bits &= ~0x81;
+				npc->bits |= 0x20;
+			}
+
+			if (npc->flag & 1 || npc->flag & 4)
+			{
+				npc->act_no = 15;
+				npc->act_wait = 0;
+				npc->damage = 5;
+				npc->bits &= ~0x81;
+				npc->bits |= 0x20;
+			}
+
+			break;
+
+		case 40:
+			npc->ani_no = 3;
+			++npc->act_wait;
+
+			if (gMC.x < npc->x)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+
+			if (npc->act_wait > 20)
+			{
+				npc->act_no = 41;
+				npc->ani_no = 4;
+				npc->ani_wait = 0;
+				npc->ym = -0x800;
+
+				if (npc->direct == 0)
+					npc->xm = -0x400;
+				else
+					npc->xm = 0x400;
+			}
+
+			break;
+
+		case 41:
+			npc->ym += 0x40;
+
+			if (++npc->ani_wait > 1)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 5)
+				npc->ani_no = 4;
+
+			if (gMC.y > npc->y && gMC.x > npc->x - 0x1000 && gMC.x < npc->x + 0x1000)
+			{
+				npc->act_no = 16;
+				npc->ym = 0x5FF;
+				npc->xm = 0;
+			}
+
+			if (npc->ym > 0 && npc->flag & 8)
+				npc->act_no = 17;
+
+			break;
+
+		case 100:
+			npc->act_no = 101;
+			npc->act_wait = 0;
+			npc->bits &= ~0x24;
+			npc->damage = 0;
+			PlaySoundObject(29, 1);
+			// Fallthrough
+		case 101:
+			npc->act_wait += 2;
+
+			if (npc->act_wait > 28)
+			{
+				npc->act_no = 102;
+				npc->act_wait = 0;
+				npc->ani_no = 0;
+
+				npc->tgt_x = gMC.x;
+				npc->tgt_y = gMC.y - 0x4000;
+
+				if ( npc->tgt_y < 0x8000 )
+					npc->tgt_y = 0x8000;
+
+				if ( npc->tgt_x < 0x8000 )
+					npc->tgt_x = 0x8000;
+				if ( npc->tgt_x > 0x48000 )
+					npc->tgt_x = 0x48000;
+			}
+
+			break;
+
+		case 102:
+			if (++npc->act_wait > 40)
+			{
+				npc->act_no = 103;
+				npc->act_wait = 28;
+				npc->ani_no = 4;
+				npc->ym = 0;
+				npc->x = npc->tgt_x;
+				npc->y = npc->tgt_y;
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+			}
+
+			break;
+
+		case 103:
+			npc->act_wait -= 2;
+
+			if (npc->act_wait <= 0)
+			{
+				npc->bits |= 0x24;
+				npc->damage = 5;
+				npc->act_no = 16;
+				npc->ym = -0x200;
+				npc->xm = 0;
+			}
+
+			break;
+
+		case 500:
+			DeleteNpCharCode(269, 1);
+			npc->bits &= ~0x20;
+			npc->ani_no = 4;
+			npc->ym += 0x20;
+			npc->xm = 0;
+
+			if (npc->flag & 8)
+			{
+				npc->act_no = 501;
+				npc->act_wait = 0;
+				npc->tgt_x = npc->x;
+
+				if (gMC.x < npc->x)
+					npc->direct = 0;
+				else
+					npc->direct = 2;
+			}
+
+			break;
+
+		case 501:
+			npc->ani_no = 9;
+
+			if (++npc->act_wait / 2 % 2)
+				npc->x = npc->tgt_x;
+			else
+				npc->x = npc->tgt_x + 0x200;
+
+			break;
+
+		case 510:
+			npc->act_no = 511;
+			npc->act_wait = 0;
+			npc->ani_no = 9;
+			npc->tgt_x = npc->x;
+			npc->y += 0x2000;
+			npc->bits |= 8;
+			// Fallthrough
+		case 511:
+			SetQuake(2);
+
+			if (++npc->act_wait % 6 == 3)
+				PlaySoundObject(25, 1);
+
+			if (npc->act_wait / 2 % 2)
+				npc->x = npc->tgt_x;
+			else
+				npc->x = npc->tgt_x + 0x200;
+
+			if (npc->act_wait > 352)
+			{
+				npc->ani_no = 0;
+				npc->act_no = 0x200;
+			}
+
+			break;
+
+		case 520:
+			npc->damage = 0;
+			gSuperYpos = -0x4000;
+			break;
+	}
+
+	if (npc->act_no >= 11 && npc->act_no < 501)
+	{
+		if (npc->act_no == 102)
+		{
+			gSuperXpos = npc->tgt_x;
+			gSuperYpos = npc->tgt_y;
+		}
+		else
+		{
+			gSuperXpos = npc->x;
+			gSuperYpos = npc->y;
+		}
+	}
+
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+
+	if (npc->act_no < 512)
+	{
+		if (npc->act_no >= 510)
+		{
+			SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - (((336 - npc->act_wait) / 8) * 0x200), Random(-0x200, 0x200), 2 * Random(-0x200, 0), 3, 0, 0xAA);
+			SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - ((336 - npc->act_wait) / 8 * 0x200), Random(-0x200, 0x200), 2 * Random(-0x200, 0), 3, 0, 0xAA);
+			SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - ((336 - npc->act_wait) / 8 * 0x200), 0, 2 * Random(-0x200, 0), 3, 0, 0xAA);
+			SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y - ((336 - npc->act_wait) / 8 * 0x200), 0, 2 * Random(-0x200, 0), 3, 0, 0xAA);
+		}
+		else if (npc->act_no != 102 && npc->act_no != 103 && Random(0, 3) == 2)
+		{
+			SetNpChar(270, npc->x + (Random(-0x10, 0x10) * 0x200), npc->y + (Random(-8, 4) * 0x200), npc->xm, 0, 3, 0, 0x100);
+		}
+	}
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+
+	if (npc->act_no == 511)
+	{
+		npc->rect.top += npc->act_wait / 8;
+		npc->view.top = (44 - npc->act_wait / 8) * 0x200;
+		npc->view.bottom = 0x800;
+	}
+	else if (npc->act_no == 101 || npc->act_no == 103)
+	{
+		npc->rect.top += npc->act_wait;
+		npc->rect.bottom -= npc->act_wait;
+		npc->view.top = (28 - npc->act_wait) * 0x200;
+	}
+	else
+	{
+		npc->view.top = 0x3800;
+	}
+}
+
 //Igor (enemy)
 void ActNpc268(NPCHAR *npc)
 {
@@ -209,6 +1301,138 @@
 		npc->rect = rcLeft[npc->ani_no];
 	else
 		npc->rect = rcRight[npc->ani_no];
+}
+
+//Red Bat (bouncing)
+void ActNpc269(NPCHAR *npc)
+{
+	RECT rcLeft[3];
+	RECT rcRight[3];
+
+	rcLeft[0] = {232, 0, 248, 16};
+	rcLeft[1] = {248, 0, 264, 16};
+	rcLeft[2] = {248, 16, 264, 32};
+
+	rcRight[0] = {232, 32, 248, 48};
+	rcRight[1] = {248, 32, 264, 48};
+	rcRight[2] = {248, 48, 264, 64};
+
+	switch (npc->act_no)
+	{
+		case 0:
+			npc->act_no = 1;
+			npc->xm2 = npc->xm;
+			npc->ym2 = npc->ym;
+			// Fallthrough
+		case 1:
+			if (npc->xm2 < 0 && npc->flag & 1)
+			{
+				npc->direct = 2;
+				npc->xm2 = -npc->xm2;
+			}
+			else if (npc->xm2 > 0 && npc->flag & 4)
+			{
+				npc->direct = 0;
+				npc->xm2 = -npc->xm2;
+			}
+			else if (npc->ym2 < 0 && npc->flag & 2)
+			{
+				npc->ym2 = -npc->ym2;
+			}
+			else if (npc->ym2 > 0 && npc->flag & 8)
+			{
+				npc->ym2 = -npc->ym2;
+			}
+
+			npc->x += npc->xm2;
+			npc->y += npc->ym2;
+
+			if (++npc->ani_wait > 2)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+
+			if (npc->ani_no > 2)
+				npc->ani_no = 0;
+
+			break;
+	}
+
+	if (npc->direct == 0)
+		npc->rect = rcLeft[npc->ani_no];
+	else
+		npc->rect = rcRight[npc->ani_no];
+}
+
+//Doctor's blood (or """"red energy"""")
+void ActNpc270(NPCHAR *npc)
+{
+	RECT rc[2];
+
+	rc[0] = {170, 34, 174, 38};
+	rc[1] = {170, 42, 174, 46};
+
+	if (npc->direct == 3 || npc->direct == 1)
+	{
+		if (npc->direct == 3)
+			npc->ym += 0x40;
+		if (npc->direct == 1)
+			npc->ym -= 0x40;
+
+		++npc->act_wait;
+
+		if (npc->ym > 0x5FF)
+			npc->ym = 0x5FF;
+
+		npc->x += npc->xm;
+		npc->y += npc->ym;
+
+		if (npc->act_wait > 50)
+			npc->cond = 0;
+
+		if (npc->flag & 0xFF)
+			npc->cond = 0;
+	}
+	else if ( npc->direct == 2 )
+	{
+		if (npc->act_no == 0)
+		{
+			npc->act_no = 1;
+			npc->bits |= 8;
+
+			npc->xm = 3 * Random(-0x200, 0x200);
+			npc->ym = 3 * Random(-0x200, 0x200);
+
+			npc->count1 = Random(0x10, 0x33);
+			npc->count2 = Random(0x80, 0x100);
+		}
+
+		if (npc->x < npc->pNpc->x)
+			npc->xm += 0x200 / npc->count1;
+		if (npc->x > npc->pNpc->x)
+			npc->xm -= 0x200 / npc->count1;
+
+		if (npc->y < npc->pNpc->y)
+			npc->ym += 0x200 / npc->count1;
+		if (npc->y > npc->pNpc->y)
+			npc->ym -= 0x200 / npc->count1;
+
+		if (npc->xm > 2 * npc->count2)
+			npc->xm = 2 * npc->count2;
+		if (npc->xm < -2 * npc->count2)
+			npc->xm = -2 * npc->count2;
+
+		if (npc->ym > 3 * npc->count2)
+			npc->ym = 3 * npc->count2;
+		if (npc->ym < -3 * npc->count2)
+			npc->ym = -3 * npc->count2;
+
+		npc->x += npc->xm;
+		npc->y += npc->ym;
+	}
+
+	npc->rect = rc[Random(0, 1)];
 }
 
 // Ironhead block
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -312,21 +312,21 @@
 	ActNpc253,
 	ActNpc254,
 	ActNpc255,
-	nullptr,
-	nullptr,
-	nullptr,
+	ActNpc256,
+	ActNpc257,
+	ActNpc258,
 	ActNpc259,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
+	ActNpc260,
+	ActNpc261,
+	ActNpc262,
+	ActNpc263,
+	ActNpc264,
+	ActNpc265,
+	ActNpc266,
+	ActNpc267,
 	ActNpc268,
-	nullptr,
-	nullptr,
+	ActNpc269,
+	ActNpc270,
 	ActNpc271,
 	ActNpc272,
 	ActNpc273,