shithub: cstory

Download patch

ref: c04092df89cd28cee2240cf75355ae664bed0661
parent: f8791a7d39576f370f1d23d4fda9b1dc8efe40d8
author: cuckydev <cuckydev@users.noreply.github.com>
date: Fri Jan 25 17:38:50 EST 2019

added first 6 npcs, npc map collision, player map collision, fixed huge issue with map drawing, causing there to be 50+% cpu usage. bluh

--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,10 @@
 	Map \
 	MapName \
 	MyChar \
+	MycHit \
+	NpcAct000 \
 	NpChar \
+	NpcHit \
 	NpcTbl \
 	Organya \
 	PixTone \
--- a/src/Back.h
+++ b/src/Back.h
@@ -11,6 +11,7 @@
 	int fx;
 };
 
+extern BACK gBack;
 extern int gWaterY;
 
 bool InitBack(char *fName, int type);
--- a/src/Frame.cpp
+++ b/src/Frame.cpp
@@ -23,9 +23,9 @@
 	if (gFrame.y <= -0x200)
 		gFrame.y = 0;
 	
-	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9);
+	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9)
 		gFrame.x = (((map_w - 1) << 4) - WINDOW_WIDTH) << 9;
-	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9);
+	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9)
 		gFrame.y = (((map_l - 1) << 4) - WINDOW_HEIGHT) << 9;
 
 	//Quake
@@ -74,9 +74,9 @@
 	if (gFrame.y <= -0x200)
 		gFrame.y = 0;
 
-	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9);
+	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9)
 		gFrame.x = (((map_w - 1) << 4) - WINDOW_WIDTH) << 9;
-	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9);
+	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9)
 		gFrame.y = (((map_l - 1) << 4) - WINDOW_HEIGHT) << 9;
 }
 
@@ -89,8 +89,8 @@
 	int16_t map_w, map_l;
 	GetMapData(0, &map_w, &map_l);
 	
-	gFrame.x = mc_x - 81920;
-	gFrame.y = mc_y - 61440;
+	gFrame.x = mc_x - (WINDOW_WIDTH << 9);
+	gFrame.y = mc_y - (WINDOW_HEIGHT << 9);
 	
 	//Keep in bounds
 	if (gFrame.x <= -0x200)
@@ -97,17 +97,17 @@
 		gFrame.x = 0;
 	if (gFrame.y <= -0x200)
 		gFrame.y = 0;
-
-	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9);
+	
+	if (gFrame.x > ((((map_w - 1) << 4) - WINDOW_WIDTH)) << 9)
 		gFrame.x = (((map_w - 1) << 4) - WINDOW_WIDTH) << 9;
-	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9);
+	if (gFrame.y > ((((map_l - 1) << 4) - WINDOW_HEIGHT)) << 9)
 		gFrame.y = (((map_l - 1) << 4) - WINDOW_HEIGHT) << 9;
 }
 
 void SetFrameTargetMyChar(int wait)
 {
-	gFrame.tgt_x = &gMC.x;
-	gFrame.tgt_y = &gMC.y;
+	gFrame.tgt_x = &gMC.tgt_x;
+	gFrame.tgt_y = &gMC.tgt_y;
 	gFrame.wait = wait;
 }
 
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -7,6 +7,7 @@
 #include "Tags.h"
 #include "NpcTbl.h"
 #include "NpChar.h"
+#include "NpcHit.h"
 #include "Generic.h"
 #include "GenericLoad.h"
 #include "TextScr.h"
@@ -16,6 +17,7 @@
 #include "Escape.h"
 #include "Stage.h"
 #include "MyChar.h"
+#include "MycHit.h"
 #include "Caret.h"
 #include "Map.h"
 #include "Main.h"
@@ -132,11 +134,11 @@
 		ActNpChar();
 		//ActBossChar();
 		ActBack();
-		//ResetMyCharFlag();
-		//HitMyCharMap();
+		ResetMyCharFlag();
+		HitMyCharMap();
 		//HitMyCharNpChar();
 		//HitMyCharBoss();
-		//HitNpCharMap();
+		HitNpCharMap();
 		//HitBossMap();
 		//HitBossBullet();
 		//ActCaret();
@@ -321,7 +323,7 @@
 		}
 		
 		//Update carets
-		//ActCaret();
+		ActCaret();
 		
 		//Animate character cursor
 		if ( ++anime >= 40 )
@@ -384,7 +386,7 @@
 		PutBitmap3(&grcGame, 116, char_y, &char_rc, char_surf);
 		
 		//Draw carets
-		//PutCaret(0, 0);
+		PutCaret(0, 0);
 		
 		//if (time_counter)
 		//	PutTimeCounter(16, 8);
@@ -408,6 +410,124 @@
 			return 0;
 	}
 	
+	return 3;
+}
+
+int ModeAction()
+{
+	int frame_x = 0;
+	int frame_y = 0;
+	
+	bool swPlay = true;
+	
+	//Reset stuff
+	gCounter = 0;
+	grcGame.left = 0;
+	g_GameFlags = 3;
+	
+	//Initialize everything
+	InitMyChar();
+	InitNpChar();
+	//InitBullet();
+	InitCaret();
+	//InitStar();
+	InitFade();
+	//InitFlash();
+	//ClearArmsData();
+	//ClearItemData();
+	//ClearPermitStage();
+	//StartMapping();
+	InitFlags();
+	//InitBossLife();
+	
+	TransferStage(2, 94, 5, 6);
+	ChangeMusic(mus_MischievousRobot);
+	SetFrameTargetMyChar(16);
+	SetFrameMyChar();
+	
+	while (true)
+	{
+		//Get pressed keys
+		GetTrg();
+		
+		//Escape menu
+		if (gKey & KEY_ESCAPE)
+		{
+			int escRet = Call_Escape();
+			if (escRet == 0)
+				return 0;
+			if (escRet == 2)
+				return 1;
+		}
+		
+		if (swPlay & 1 && g_GameFlags & 1)
+		{
+			if (g_GameFlags & 2)
+				ActMyChar(true);
+			else
+				ActMyChar(false);
+			
+			//ActStar();
+			ActNpChar();
+			//ActBossChar();
+			//ActValueView();
+			ActBack();
+			ResetMyCharFlag();
+			HitMyCharMap();
+			//HitMyCharNpChar();
+			//HitMyCharBoss();
+			HitNpCharMap();
+			//HitBossMap();
+			//HitBulletMap();
+			//HitNpCharBullet();
+			//HitBossBullet();
+			//if (g_GameFlags & 2)
+			//	ShootBullet();
+			//ActBullet();
+			ActCaret();
+			MoveFrame3();
+			//ActFlash(frame_x, frame_y);
+			
+			if (g_GameFlags & 2)
+				AnimationMyChar(true);
+			else
+				AnimationMyChar(false);
+		}
+		
+		if (g_GameFlags & 8)
+		{
+			ActionCredit();
+			ActionIllust();
+			ActionStripper();
+		}
+		
+		ProcFade();
+		CortBox(&grcFull, 0x000020);
+		GetFramePosition(&frame_x, &frame_y);
+		PutBack(frame_x, frame_y);
+		PutStage_Back(frame_x, frame_y);
+		//PutBossChar(frame_x, frame_y);
+		PutNpChar(frame_x, frame_y);
+		//PutBullet(frame_x, frame_y);
+		PutMyChar(frame_x, frame_y);
+		//PutStar(frame_x, frame_y);
+		PutMapDataVector(frame_x, frame_y);
+		PutStage_Front(frame_x, frame_y);
+		PutFront(frame_x, frame_y);
+		//PutFlash();
+		PutCaret(frame_x, frame_y);
+		//PutValueView(frame_x, frame_y);
+		//PutBossLife();
+		PutFade();
+		
+		PutMapName(false);
+		
+		PutFramePerSecound();
+        if (!Flip_SystemTask())
+          break;
+        ++gCounter;
+	}
+	
 	return 0;
 }
 
@@ -432,8 +552,8 @@
 					mode = ModeOpening();
 				if (mode == 2)
 					mode = ModeTitle();
-				//if (mode == 3)
-				//	mode = ModeAction();
+				if (mode == 3)
+					mode = ModeAction();
 			}
 			
 			EndMapData();
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -132,8 +132,8 @@
 void PutStage_Back(int fx, int fy)
 {
 	//Get range to draw
-	int num_x = WINDOW_WIDTH / 2 + 1;
-	int num_y = WINDOW_HEIGHT / 2 + 1;
+	int num_x = (WINDOW_WIDTH >> 4) + 1;
+	int num_y = (WINDOW_HEIGHT >> 4) + 1;
 	int put_x = (fx / 0x200 + 8) / 16;
 	int put_y = (fy / 0x200 + 8) / 16;
 	
@@ -165,8 +165,8 @@
 	RECT rcSnack = {256, 48, 272, 64};
 	
 	//Get range to draw
-	int num_x = WINDOW_WIDTH / 2 + 1;
-	int num_y = WINDOW_HEIGHT / 2 + 1;
+	int num_x = (WINDOW_WIDTH >> 4) + 1;
+	int num_y = (WINDOW_HEIGHT >> 4) + 1;
 	int put_x = (fx / 0x200 + 8) / 16;
 	int put_y = (fy / 0x200 + 8) / 16;
 	
@@ -199,8 +199,8 @@
 void PutMapDataVector(int fx, int fy)
 {
 	//Get range to draw
-	int num_x = WINDOW_WIDTH / 2 + 1;
-	int num_y = WINDOW_HEIGHT / 2 + 1;
+	int num_x = (WINDOW_WIDTH >> 4) + 1;
+	int num_y = (WINDOW_HEIGHT >> 4) + 1;
 	int put_x = (fx / 0x200 + 8) / 16;
 	int put_y = (fy / 0x200 + 8) / 16;
 	
--- a/src/MyChar.cpp
+++ b/src/MyChar.cpp
@@ -4,9 +4,12 @@
 #include "WindowsWrapper.h"
 
 #include "MyChar.h"
+#include "NpChar.h"
 #include "Draw.h"
 #include "Sound.h"
 #include "KeyControl.h"
+#include "Game.h"
+#include "Caret.h"
 
 MYCHAR gMC;
 
@@ -136,6 +139,577 @@
 		gMC.cond &= ~2;
 	else
 		gMC.cond |= 2;
+}
+
+void PutMyChar(int fx, int fy)
+{
+	if ((gMC.cond & 0x80u) && !(gMC.cond & 2))
+	{
+		//Draw weapon
+		gMC.rect_arms.left = 24 * 0;//(gArmsData[gSelectedArms].code % 13);
+		gMC.rect_arms.right = gMC.rect_arms.left + 24;
+		gMC.rect_arms.top = 96 * 0;//(gArmsData[gSelectedArms].code / 13);
+		gMC.rect_arms.bottom = gMC.rect_arms.top + 16;
+		
+		if (gMC.direct == 2)
+		{
+			gMC.rect_arms.top += 16;
+			gMC.rect_arms.bottom += 16;
+		}
+		
+		int arms_offset_y;
+		if (gMC.up)
+		{
+			arms_offset_y = -4;
+			gMC.rect_arms.top += 32;
+			gMC.rect_arms.bottom += 32;
+		}
+		else if (gMC.down)
+		{
+			arms_offset_y = 4;
+			gMC.rect_arms.top += 64;
+			gMC.rect_arms.bottom += 64;
+		}
+		else
+		{
+			arms_offset_y = 0;
+		}
+		
+		if (gMC.ani_no == 1 || gMC.ani_no == 3 || gMC.ani_no == 6 || gMC.ani_no == 8)
+			++gMC.rect_arms.top;
+		
+		if (gMC.direct)
+			PutBitmap3(
+				&grcGame,
+				(gMC.x - gMC.view.left) / 0x200 - fx / 0x200,
+				arms_offset_y + (gMC.y - gMC.view.top) / 0x200 - fy / 0x200,
+				&gMC.rect_arms,
+				11);
+		else
+			PutBitmap3(
+				&grcGame,
+				(gMC.x - gMC.view.left) / 0x200 - fx / 0x200 - 8,
+				arms_offset_y + (gMC.y - gMC.view.top) / 0x200 - fy / 0x200,
+				&gMC.rect_arms,
+				11);
+		
+		if (!((gMC.shock >> 1) & 1))
+		{
+			//Draw player
+			RECT rect = gMC.rect;
+			if (gMC.equip & 0x40)
+			{
+				rect.top += 32;
+				rect.bottom += 32;
+			}
+			
+			PutBitmap3(&grcGame, (gMC.x - gMC.view.left) / 0x200 - fx / 0x200, (gMC.y - gMC.view.top) / 0x200 - fy / 0x200, &rect, 16);
+			
+			//Draw airtank
+			RECT rcBubble[2];
+			rcBubble[0] = {56, 96, 80, 120};
+			rcBubble[1] = {80, 96, 104, 120};
+			
+			++gMC.bubble;
+			if (gMC.equip & 0x10 && gMC.flag & 0x100)
+				PutBitmap3(&grcGame, gMC.x / 0x200 - 12 - fx / 0x200, gMC.y / 0x200 - 12 - fy / 0x200, &rcBubble[(gMC.bubble >> 1) & 1], 19);
+			else if (gMC.unit == 1)
+				PutBitmap3(&grcGame, gMC.x / 0x200 - 12 - fx / 0x200, gMC.y / 0x200 - 12 - fy / 0x200, &rcBubble[(gMC.bubble >> 1) & 1], 19);
+		}
+	}
+}
+
+void ActMyChar_Normal(bool bKey)
+{
+	if (!(gMC.cond & 2))
+	{
+		//Get speeds and accelerations
+		int max_dash;
+		int gravity1;
+		int gravity2;
+		int jump;
+		int dash1;
+		int dash2;
+		int resist;
+		
+		if (gMC.flag & 0x100)
+		{
+			max_dash = 0x196;
+			gravity1 = 0x28;
+			gravity2 = 0x10;
+			jump = 0x280;
+			dash1 = 0x2A;
+			dash2 = 0x10;
+			resist = 0x19;
+		}
+		else
+		{
+			max_dash = 0x32C;
+			gravity1 = 0x50;
+			gravity2 = 0x20;
+			jump = 0x500;
+			dash1 = 0x55;
+			dash2 = 0x20;
+			resist = 0x33;
+		}
+		
+		//Don't create "?" effect
+		gMC.ques = 0;
+		
+		//If can't control player, stop boosting
+		if (!bKey)
+			gMC.boost_sw = 0;
+		
+		//Movement on the ground
+		if (gMC.flag & 8 || gMC.flag & 0x10 || gMC.flag & 0x20)
+		{
+			//Stop boosting and refuel
+			gMC.boost_sw = 0;
+			
+			if (gMC.equip & 1)
+			{
+				gMC.boost_cnt = 50;
+			}
+			else if (gMC.equip & 0x20)
+			{
+				gMC.boost_cnt = 50;
+			}
+			else
+			{
+				gMC.boost_cnt = 0;
+			}
+			
+			//Move in direction held
+			if (bKey)
+			{
+				if (gKeyTrg != gKeyDown || gKey != gKeyDown || (gMC.cond & 1) || g_GameFlags & 4)
+				{
+					if (gKey != gKeyDown)
+					{
+						if (gKey & gKeyLeft && gMC.xm > -max_dash)
+							gMC.xm -= dash1;
+						if (gKey & gKeyRight && gMC.xm < max_dash)
+							gMC.xm += dash1;
+						
+						if (gKey & gKeyLeft)
+							gMC.direct = 0;
+						if (gKey & gKeyRight)
+							gMC.direct = 2;
+					}
+				}
+				else
+				{
+					gMC.cond |= 1;
+					gMC.ques = 1;
+				}
+			}
+			
+			//Friction
+			if (!(gMC.cond & 0x20))
+			{
+				if (gMC.xm < 0)
+				{
+					if (gMC.xm <= -resist)
+						gMC.xm += resist;
+					else
+						gMC.xm = 0;
+				}
+				if (gMC.xm > 0)
+				{
+					if (gMC.xm >= resist)
+						gMC.xm -= resist;
+					else
+						gMC.xm = 0;
+				}
+			}
+		}
+		else
+		{
+			//Start boosting
+			if (bKey)
+			{
+				if (gMC.equip & 0x21 && gKeyTrg & gKeyJump && gMC.boost_cnt)
+				{
+					//Booster 0.8
+					if (gMC.equip & 1)
+					{
+						gMC.boost_sw = 1;
+						if (gMC.ym > 0x100)
+							gMC.ym /= 2;
+					}
+					
+					//Booster 2.0
+					if (gMC.equip & 0x20)
+					{
+						if (gKey & gKeyUp)
+						{
+							gMC.boost_sw = 2;
+							gMC.xm = 0;
+							gMC.ym = -0x5FF;
+						}
+						else if ( gKey & gKeyLeft )
+						{
+							gMC.boost_sw = 1;
+							gMC.ym = 0;
+							gMC.xm = -0x5FF;
+						}
+						else if ( gKey & gKeyRight )
+						{
+							gMC.boost_sw = 1;
+							gMC.ym = 0;
+							gMC.xm = 0x5FF;
+						}
+						else if ( gKey & gKeyDown )
+						{
+							gMC.boost_sw = 3;
+							gMC.xm = 0;
+							gMC.ym = 0x5FF;
+						}
+						else
+						{
+							gMC.boost_sw = 2;
+							gMC.xm = 0;
+							gMC.ym = -0x5FF;
+						}
+					}
+				}
+				
+				//Move left and right
+				if ( gKey & gKeyLeft && gMC.xm > -max_dash )
+					gMC.xm -= dash2;
+				if ( gKey & gKeyRight && gMC.xm < max_dash )
+					gMC.xm += dash2;
+				
+				if ( gKey & gKeyLeft )
+					gMC.direct = 0;
+				if ( gKey & gKeyRight )
+					gMC.direct = 2;
+			}
+			
+			//Slow down when stopped boosting (Booster 2.0)
+			if (gMC.equip & 0x20 && gMC.boost_sw && (!(gKey & gKeyJump) || !gMC.boost_cnt))
+			{
+				if (gMC.boost_sw == 1)
+					gMC.xm /= 2;
+				else if (gMC.boost_sw == 2)
+					gMC.ym /= 2;
+			}
+			
+			//Stop boosting
+			if (!gMC.boost_cnt || !(gKey & gKeyJump))
+				gMC.boost_sw = 0;
+		}
+		
+		//Jumping
+		if ( bKey )
+		{
+			//Look up and down
+			gMC.up = (gKey & gKeyUp) != 0;
+			gMC.down = gKey & gKeyDown && !(gMC.flag & 8);
+			
+			if (gKeyTrg & gKeyJump
+				&& (gMC.flag & 8 || gMC.flag & 0x10 || gMC.flag & 0x20)
+				&& !(gMC.flag & 0x2000))
+			{
+				gMC.ym = -jump;
+				PlaySoundObject(15, 1);
+			}
+		}
+		
+		//Stop interacting when moved
+		if (bKey && (gKeyShot | gKeyJump | gKeyUp | gKeyRight | gKeyLeft) & gKey)
+			gMC.cond &= ~1;
+		
+		//Booster losing fuel
+		if (gMC.boost_sw && gMC.boost_cnt)
+			--gMC.boost_cnt;
+		
+		//Wind / current forces
+		if (gMC.flag & 0x1000)
+			gMC.xm -= 0x88;
+		if (gMC.flag & 0x2000)
+			gMC.ym -= 0x80;
+		if (gMC.flag & 0x4000)
+			gMC.xm += 0x88;
+		if (gMC.flag & 0x8000)
+			gMC.ym += 0x55;
+		
+		//Booster 2.0 forces and effects
+		if (gMC.equip & 0x20 && gMC.boost_sw)
+		{
+			if (gMC.boost_sw == 1)
+			{
+				//Go up when going into a wall
+				if (gMC.flag & 5)
+					gMC.ym = -0x100;
+				
+				//Move in direction facing
+				if (!gMC.direct)
+					gMC.xm -= 0x20;
+				if (gMC.direct == 2)
+					gMC.xm += 0x20;
+				
+				//Boost particles (and sound)
+				if (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1)
+				{
+					if (!gMC.direct)
+						SetCaret(gMC.x + 0x400, gMC.y + 0x400, 7, 2);
+					if (gMC.direct == 2)
+						SetCaret(gMC.x - 0x400, gMC.y + 0x400, 7, 0);
+					
+					PlaySoundObject(113, 1);
+				}
+			}
+			else if (gMC.boost_sw == 2)
+			{
+				//Move upwards
+				gMC.ym -= 0x20;
+				
+				//Boost particles (and sound)
+				if (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1)
+				{
+					SetCaret(gMC.x, gMC.y + 0xC00, 7, 3);
+					PlaySoundObject(113, 1);
+				}
+			}
+			else if (gMC.boost_sw == 3 && (gKeyTrg & gKeyJump || gMC.boost_cnt % 3 == 1))
+			{
+				//Boost particles (and sound)
+				SetCaret(gMC.x, gMC.y - 0xC00, 7, 1);
+				PlaySoundObject(113, 1);
+			}
+		}
+		//Upwards wind/current
+		else if (gMC.flag & 0x2000)
+		{
+			gMC.ym += gravity1;
+		}
+		//Booster 0.8
+		else if (gMC.equip & 1 && gMC.boost_sw && gMC.ym > -0x400)
+		{
+			//Upwards force
+			gMC.ym -= 0x20;
+			
+			if (!(gMC.boost_cnt % 3))
+			{
+				SetCaret(gMC.x, gMC.hit.bottom / 2 + gMC.y, 7, 3);
+				PlaySoundObject(113, 1);
+			}
+			
+			//Bounce off of ceiling
+			if (gMC.flag & 2)
+				gMC.ym = 0x200;
+		}
+		//Gravity while jump is held
+		else if (gMC.ym < 0 && bKey && gKey & gKeyJump)
+		{
+			gMC.ym += gravity2;
+		}
+		//Normal gravity
+		else
+		{
+			gMC.ym += gravity1;
+		}
+		
+		//Keep player on slopes
+		if (bKey && !(gKeyTrg & gKeyJump))
+		{
+			if (gMC.flag & 0x10 && gMC.xm < 0)
+				gMC.ym = -gMC.xm;
+			if (gMC.flag & 0x20 && gMC.xm > 0)
+				gMC.ym = gMC.xm;
+			if (gMC.flag & 8 && gMC.flag & 0x80000 && gMC.xm < 0)
+				gMC.ym = 0x400;
+			if (gMC.flag & 8 && gMC.flag & 0x10000 && gMC.xm > 0)
+				gMC.ym = 0x400;
+			if (gMC.flag & 8 && gMC.flag & 0x20000 && gMC.flag & 0x40000)
+				gMC.ym = 0x400;
+		}
+		
+		//Limit speed
+		if (!(gMC.flag & 0x100) || gMC.flag & 0xF000)
+		{
+			if (gMC.xm < -0x5FF)
+				gMC.xm = -0x5FF;
+			if (gMC.xm > 0x5FF)
+				gMC.xm = 0x5FF;
+			if (gMC.ym < -0x5FF)
+				gMC.ym = -0x5FF;
+			if (gMC.ym > 0x5FF)
+				gMC.ym = 0x5FF;
+		}
+		else
+		{
+			if (gMC.xm < -0x2FF)
+				gMC.xm = -0x2FF;
+			if (gMC.xm > 0x2FF)
+				gMC.xm = 0x2FF;
+			if (gMC.ym < -0x2FF)
+				gMC.ym = -0x2FF;
+			if (gMC.ym > 0x2FF)
+				gMC.ym = 0x2FF;
+		}
+		
+		//Water splashing
+		if (!gMC.sprash && gMC.flag & 0x100)
+		{
+			int dir;
+			if (gMC.flag & 0x800)
+				dir = 2;
+			else
+				dir = 0;
+			
+			if (gMC.flag & 8 || gMC.ym <= 0x200)
+			{
+				if (gMC.xm > 0x200 || gMC.xm < -0x200)
+				{
+					for (int a = 0; a < 8; a++)
+						SetNpChar(73, gMC.x + (Random(-8, 8) << 9), gMC.y, gMC.xm + Random(-0x200, 0x200), gMC.ym + Random(-0x200, 0x80), dir, 0, 0);
+					
+					PlaySoundObject(56, 1);
+				}
+			}
+			else
+			{
+				for (int a = 0; a < 8; a++)
+					SetNpChar(73, gMC.x + (Random(-8, 8) << 9), gMC.y, gMC.xm + Random(-0x200, 0x200), Random(-0x200, 0x80) - gMC.ym / 2, dir, 0, 0);
+				
+				PlaySoundObject(56, 1);
+			}
+			
+			gMC.sprash = 1;
+		}
+		
+		if (!(gMC.flag & 0x100))
+			gMC.sprash = 0;
+		
+		//Spike damage
+		//if (gMC.flag & 0x400)
+		//	DamageMyChar(10);
+		
+		//Camera
+		if (gMC.direct)
+		{
+			gMC.index_x += 0x200;
+			if (gMC.index_x > 0x8000)
+				gMC.index_x = 0x8000;
+		}
+		else
+		{
+			gMC.index_x -= 0x200;
+			if (gMC.index_x < -0x8000)
+				gMC.index_x = -0x8000;
+		}
+		if (gKey & gKeyUp && bKey)
+		{
+			gMC.index_y -= 0x200;
+			if (gMC.index_y < -0x8000)
+				gMC.index_y = -0x8000;
+		}
+		else if (gKey & gKeyDown && bKey)
+		{
+			gMC.index_y += 0x200;
+			if (gMC.index_y > 0x8000)
+				gMC.index_y = 0x8000;
+		}
+		else
+		{
+			if (gMC.index_y > 0x200)
+				gMC.index_y -= 0x200;
+			if (gMC.index_y < -0x200)
+				gMC.index_y += 0x200;
+		}
+		
+		gMC.tgt_x = gMC.x + gMC.index_x;
+		gMC.tgt_y = gMC.y + gMC.index_y;
+		
+		//Change position
+		if (gMC.xm > resist || gMC.xm < -resist)
+			gMC.x += gMC.xm;
+		gMC.y += gMC.ym;
+	}
+}
+
+void AirProcess()
+{
+	/*
+	if ( unk_81C8598 & 0x10 )
+	{
+	unk_81C8624 = 1000;
+	unk_81C8628 = 0;
+	}
+	else
+	{
+	if ( gMC.flag & 0x100 )
+	{
+	if ( --unk_81C8624 <= 0 )
+	{
+	if ( (unsigned __int8)GetNPCFlag(4000) )
+	{
+	StartTextScript(1100);
+	}
+	else
+	{
+	StartTextScript(41);
+	if ( dir )
+	SetCaret(x, y, 8, 2);
+	else
+	SetCaret(x, y, 8, 0);
+	gMC.cond &= 0x7Fu;
+	}
+	}
+	}
+	else
+	{
+	unk_81C8624 = 1000;
+	}
+	if ( gMC.flag & 0x100 )
+	{
+	unk_81C8628 = 60;
+	}
+	else if ( unk_81C8628 )
+	{
+	--unk_81C8628;
+	}
+	}
+	*/
+}
+
+void ActMyChar(bool bKey)
+{
+	if (gMC.cond & 0x80)
+	{
+		if (gMC.exp_wait)
+			--gMC.exp_wait;
+		
+		if (gMC.shock)
+		{
+			--gMC.shock;
+		}
+		else if (gMC.exp_count)
+		{
+			//SetValueView(&x, &y, gMC.exp_count);
+			gMC.exp_count = 0;
+		}
+		
+		switch (gMC.unit)
+		{
+			case 0:
+				if (!(g_GameFlags & 4) && bKey)
+					AirProcess();
+				ActMyChar_Normal(bKey);
+				break;
+			
+			case 1:
+				//ActMyChar_Stream(bKey);
+				break;
+			
+			default:
+				break;
+		}
+		
+		gMC.cond &= ~0x20;
+	}
 }
 
 void GetMyCharPosition(int *x, int *y)
--- a/src/MyChar.h
+++ b/src/MyChar.h
@@ -51,6 +51,9 @@
 void InitMyChar();
 void AnimationMyChar(bool bKey);
 void ShowMyChar(bool bShow);
+void PutMyChar(int fx, int fy);
+void ActMyChar_Normal(bool bKey);
+void ActMyChar(bool bKey);
 void GetMyCharPosition(int *x, int *y);
 void SetMyCharPosition(int x, int y);
 void MoveMyChar(int x, int y);
--- /dev/null
+++ b/src/MycHit.cpp
@@ -1,0 +1,567 @@
+#include <stdint.h>
+
+#include "WindowsWrapper.h"
+
+#include "MyChar.h"
+#include "Map.h"
+#include "Sound.h"
+#include "Caret.h"
+#include "Back.h"
+#include "KeyControl.h"
+
+void ResetMyCharFlag()
+{
+	gMC.flag = 0;
+}
+
+void PutlittleStar()
+{
+	if (!(gMC.cond & 2) && gMC.ym < -0x200)
+	{
+		PlaySoundObject(3, 1);
+		SetCaret(gMC.x, gMC.y - gMC.hit.top, 13, 0);
+		SetCaret(gMC.x, gMC.y - gMC.hit.top, 13, 0);
+	}
+}
+
+int JudgeHitMyCharBlock(int x, int y)
+{
+	int hit = 0;
+	
+	//Left wall
+	if (gMC.y - gMC.hit.top < (2 * (2 * y + 1) - 1) << 11
+		&& gMC.y + gMC.hit.bottom > (2 * (2 * y - 1) + 1) << 11
+		&& gMC.x - gMC.hit.left < (2 * x + 1) << 12
+		&& gMC.x - gMC.hit.left > x << 13)
+	{
+		//Clip
+		gMC.x = ((2 * x + 1) << 12) + gMC.hit.left;
+		
+		//Halt momentum
+		if (gMC.xm < -0x180)
+			gMC.xm = -0x180;
+		if (!(gKey & gKeyLeft) && gMC.xm < 0)
+			gMC.xm = 0;
+		
+		//Set that a left wall was hit
+		hit |= 1;
+	}
+	
+	//Right wall
+	if (gMC.y - gMC.hit.top < (2 * (2 * y + 1) - 1) << 11
+		&& gMC.y + gMC.hit.bottom > (2 * (2 * y - 1) + 1) << 11
+		&& gMC.x + gMC.hit.right > (2 * x - 1) << 12
+		&& gMC.x + gMC.hit.left < x << 13)
+	{
+		//Clip
+		gMC.x = ((2 * x - 1) << 12) - gMC.hit.right;
+		
+		//Halt momentum
+		if (gMC.xm > 0x180)
+			gMC.xm = 0x180;
+		if (!(gKey & gKeyRight) && gMC.xm > 0)
+			gMC.xm = 0;
+		
+		//Set that a right wall was hit
+		hit |= 4;
+	}
+	
+	//Ceiling
+	if (gMC.x - gMC.hit.right < ((2 * x + 1) << 12) - 0x600
+		&& gMC.x + gMC.hit.right > ((2 * x - 1) << 12) + 0x600
+		&& gMC.y - gMC.hit.top < (2 * y + 1) << 12
+		&& gMC.y - gMC.hit.top > y << 13)
+	{
+		//Clip
+		gMC.y = ((2 * y + 1) << 12) + gMC.hit.top;
+		
+		//Halt momentum
+		if (!(gMC.cond & 2) && gMC.ym < -0x200)
+			PutlittleStar();
+		if (gMC.ym < 0)
+			gMC.ym = 0;
+		
+		//Set that a ceiling was hit
+		hit |= 2;
+	}
+	
+	//Floor
+	if (gMC.x - gMC.hit.right < ((2 * x + 1) << 12) - 0x600
+		&& gMC.x + gMC.hit.right > ((2 * x - 1) << 12) + 0x600
+		&& gMC.y + gMC.hit.bottom > (2 * y - 1) << 12
+		&& gMC.y + gMC.hit.bottom < y << 13)
+	{
+		//Clip
+		gMC.y = ((2 * y - 1) << 12) - gMC.hit.bottom;
+		
+		//Halt momentum
+		if (gMC.ym > 0x400)
+			PlaySoundObject(23, 1);
+		if (gMC.ym > 0)
+			gMC.ym = 0;
+		
+		//Set that a floor was hit
+		hit |= 8;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleA(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y - gMC.hit.top < (y << 13) - (-0x2000 * x + gMC.x) / 2 + 0x800
+		&& gMC.y + gMC.hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) - (-0x2000 * x + gMC.x) / 2 + 0x800 + gMC.hit.top;
+		
+		//Halt momentum
+		if (!(gMC.cond & 2) && gMC.ym < -0x200)
+			PutlittleStar();
+		if (gMC.ym < 0)
+			gMC.ym = 0;
+		
+		//Set that hit a ceiling
+		hit |= 2;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleB(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y - gMC.hit.top < (y << 13) - (-0x2000 * x + gMC.x) / 2 - 0x800
+		&& gMC.y + gMC.hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) - (-0x2000 * x + gMC.x) / 2 - 0x800 + gMC.hit.top;
+		
+		//Halt momentum
+		if (!(gMC.cond & 2) && gMC.ym < -0x200)
+			PutlittleStar();
+		if (gMC.ym < 0)
+			gMC.ym = 0;
+		
+		//Set that hit a ceiling
+		hit |= 2;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleC(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y - gMC.hit.top < (y << 13) + (-0x2000 * x + gMC.x) / 2 - 0x800
+		&& gMC.y + gMC.hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) - (-0x2000 * x + gMC.x) / 2 - 0x800 + gMC.hit.top;
+		
+		//Halt momentum
+		if (!(gMC.cond & 2) && gMC.ym < -0x200)
+			PutlittleStar();
+		if (gMC.ym < 0)
+			gMC.ym = 0;
+		
+		//Set that hit a ceiling
+		hit |= 2;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleD(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y - gMC.hit.top < (y << 13) + (-0x2000 * x + gMC.x) / 2 + 0x800
+		&& gMC.y + gMC.hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) + (-0x2000 * x + gMC.x) / 2 + 0x800 + gMC.hit.top;
+		
+		//Halt momentum
+		if (!(gMC.cond & 2) && gMC.ym < -0x200)
+			PutlittleStar();
+		if (gMC.ym < 0)
+			gMC.ym = 0;
+		
+		//Set that hit a ceiling
+		hit |= 2;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleE(int x, int y)
+{
+	int hit = 0x10000;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y + gMC.hit.bottom > (y << 13) + (-0x2000 * x + gMC.x) / 2 - 0x800
+		&& gMC.y - gMC.hit.top < (2 * y + 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) + (-0x2000 * x + gMC.x) / 2 - 0x800 - gMC.hit.bottom;
+		
+		//Halt momentum
+		if (gMC.ym > 0x400)
+			PlaySoundObject(23, 1);
+		if (gMC.ym > 0)
+			gMC.ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x10028;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleF(int x, int y)
+{
+	int hit = 0x20000;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y + gMC.hit.bottom > (y << 13) + (-0x2000 * x + gMC.x) / 2 + 0x800
+		&& gMC.y - gMC.hit.top < (2 * y + 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) + (-0x2000 * x + gMC.x) / 2 + 0x800 - gMC.hit.bottom;
+		
+		//Halt momentum
+		if (gMC.ym > 0x400)
+			PlaySoundObject(23, 1);
+		if (gMC.ym > 0)
+			gMC.ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x20028;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleG(int x, int y)
+{
+	int hit = 0x40000;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y + gMC.hit.bottom > (y << 13) - (-0x2000 * x + gMC.x) / 2 + 0x800
+		&& gMC.y - gMC.hit.top < (2 * y + 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) - (-0x2000 * x + gMC.x) / 2 + 0x800 - gMC.hit.bottom;
+		
+		//Halt momentum
+		if (gMC.ym > 0x400)
+			PlaySoundObject(23, 1);
+		if (gMC.ym > 0)
+			gMC.ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x40018;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharTriangleH(int x, int y)
+{
+	int hit = 0x80000;
+	
+	if (gMC.x < (2 * x + 1) << 12
+		&& gMC.x > (2 * x - 1) << 12
+		&& gMC.y + gMC.hit.bottom > (y << 13) - (-0x2000 * x + gMC.x) / 2 - 0x800
+		&& gMC.y - gMC.hit.top < (2 * y + 1) << 12)
+	{
+		//Clip
+		gMC.y = (y << 13) - (-0x2000 * x + gMC.x) / 2 - 0x800 - gMC.hit.bottom;
+		
+		//Halt momentum
+		if (gMC.ym > 0x400)
+			PlaySoundObject(23, 1);
+		if (gMC.ym > 0)
+			gMC.ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x80018;
+	}
+	
+	return hit;
+}
+
+int JudgeHitMyCharWater(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x - gMC.hit.right < ((2 * x + 1) << 12) - 0x600
+		&& gMC.x + gMC.hit.right > ((2 * x - 1) << 12) + 0x600
+		&& gMC.y - gMC.hit.top < ((2 * y + 1) << 12) - 0x600
+		&& gMC.y + gMC.hit.bottom > y << 13)
+		hit = 0x100;
+	
+	return hit;
+}
+
+int JudgeHitMyCharDamage(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x - 0x800 < (4 * x + 1) << 11
+		&& gMC.x + 0x800 > (4 * x - 1) << 11
+		&& gMC.y - 0x800 < (y << 13) + 0x600
+		&& gMC.y + 0x800 > (y << 13) - 0x600)
+		hit = 0x400;
+	
+	return hit;
+}
+
+int JudgeHitMyCharDamageW(int x, int y)
+{
+	int hit = 0;
+	
+	if (gMC.x - 0x800 < (4 * x + 1) << 11
+		&& gMC.x + 0x800 > (4 * x - 1) << 11
+		&& gMC.y - 0x800 < (y << 13) + 0x600
+		&& gMC.y + 0x800 > (y << 13) - 0x600)
+		hit = 0xD00;
+	
+	return hit;
+}
+
+int JudgeHitMyCharVectLeft(int x, int y)
+{
+	int hit = 0;
+	if (gMC.x - gMC.hit.right < (4 * (2 * x + 1) - 1) << 10
+		&& gMC.x + gMC.hit.right > (4 * (2 * x - 1) + 1) << 10
+		&& gMC.y - gMC.hit.top < (4 * (2 * y + 1) - 1) << 10
+		&& gMC.y + gMC.hit.bottom > (4 * (2 * y - 1) + 1) << 10)
+		hit = 0x1000;
+	
+	return hit;
+}
+
+int JudgeHitMyCharVectUp(int x, int y)
+{
+	int hit = 0;
+	if (gMC.x - gMC.hit.right < (4 * (2 * x + 1) - 1) << 10
+		&& gMC.x + gMC.hit.right > (4 * (2 * x - 1) + 1) << 10
+		&& gMC.y - gMC.hit.top < (4 * (2 * y + 1) - 1) << 10
+		&& gMC.y + gMC.hit.bottom > (4 * (2 * y - 1) + 1) << 10)
+		hit = 0x2000;
+	
+	return hit;
+}
+
+int JudgeHitMyCharVectRight(int x, int y)
+{
+	int hit = 0;
+	if (gMC.x - gMC.hit.right < (4 * (2 * x + 1) - 1) << 10
+		&& gMC.x + gMC.hit.right > (4 * (2 * x - 1) + 1) << 10
+		&& gMC.y - gMC.hit.top < (4 * (2 * y + 1) - 1) << 10
+		&& gMC.y + gMC.hit.bottom > (4 * (2 * y - 1) + 1) << 10)
+		hit = 0x4000;
+	
+	return hit;
+}
+
+int JudgeHitMyCharVectDown(int x, int y)
+{
+	int hit = 0;
+	if (gMC.x - gMC.hit.right < (4 * (2 * x + 1) - 1) << 10
+		&& gMC.x + gMC.hit.right > (4 * (2 * x - 1) + 1) << 10
+		&& gMC.y - gMC.hit.top < (4 * (2 * y + 1) - 1) << 10
+		&& gMC.y + gMC.hit.bottom > (4 * (2 * y - 1) + 1) << 10)
+		hit = 0x8000;
+	
+	return hit;
+}
+
+void HitMyCharMap()
+{
+	int x = gMC.x / 0x2000;
+	int y = gMC.y / 0x2000;
+	
+	int offy[4];
+	int offx[4];
+	offx[0] = 0;
+	offx[1] = 1;
+	offx[2] = 0;
+	offx[3] = 1;
+	offy[0] = 0;
+	offy[1] = 0;
+	offy[2] = 1;
+	offy[3] = 1;
+	
+	uint8_t atrb[4];
+	for (int i = 0; i < 4; i++)
+	{
+		atrb[i] = GetAttribute(x + offx[i], y + offy[i]);
+		
+		switch (atrb[i])
+		{
+			//Water
+			case 0x02:
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			//Block
+			case 0x05:
+			case 0x41:
+			case 0x43:
+			case 0x46:
+				gMC.flag |= JudgeHitMyCharBlock(x + offx[i], y + offy[i]);
+				break;
+				
+			//Slopes
+			case 0x50:
+				gMC.flag |= JudgeHitMyCharTriangleA(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x51:
+				gMC.flag |= JudgeHitMyCharTriangleB(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x52:
+				gMC.flag |= JudgeHitMyCharTriangleC(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x53:
+				gMC.flag |= JudgeHitMyCharTriangleD(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x54:
+				gMC.flag |= JudgeHitMyCharTriangleE(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x55:
+				gMC.flag |= JudgeHitMyCharTriangleF(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x56:
+				gMC.flag |= JudgeHitMyCharTriangleG(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x57:
+				gMC.flag |= JudgeHitMyCharTriangleH(x + offx[i], y + offy[i]);
+				break;
+				
+			//Water and water blocks
+			case 0x60:
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x61:
+				gMC.flag |= JudgeHitMyCharBlock(x + offx[i], y + offy[i]);
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+			
+			//Spikes
+			case 0x62:
+				gMC.flag |= JudgeHitMyCharDamageW(x + offx[i], y + offy[i]);
+				break;
+				
+			//Water slopes
+			case 0x70:
+				gMC.flag |=  JudgeHitMyCharTriangleA(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x71:
+				gMC.flag |=  JudgeHitMyCharTriangleB(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x72:
+				gMC.flag |=  JudgeHitMyCharTriangleC(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x73:
+				gMC.flag |=  JudgeHitMyCharTriangleD(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x74:
+				gMC.flag |=  JudgeHitMyCharTriangleE(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x75:
+				gMC.flag |=  JudgeHitMyCharTriangleF(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x76:
+				gMC.flag |=  JudgeHitMyCharTriangleG(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x77:
+				gMC.flag |=  JudgeHitMyCharTriangleH(x + offx[i], y + offy[i]);
+				gMC.flag |=  JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			//Wind
+			case 0x80:
+				gMC.flag |= JudgeHitMyCharVectLeft(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x81:
+				gMC.flag |= JudgeHitMyCharVectUp(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x82:
+				gMC.flag |= JudgeHitMyCharVectRight(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0x83:
+				gMC.flag |= JudgeHitMyCharVectDown(x + offx[i], y + offy[i]);
+				break;
+				
+			//Water current
+			case 0xA0:
+				gMC.flag |= JudgeHitMyCharVectLeft(x + offx[i], y + offy[i]);
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			case 0xA1:
+				gMC.flag |= JudgeHitMyCharVectUp(x + offx[i], y + offy[i]);
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+			
+			case 0xA2:
+				gMC.flag |= JudgeHitMyCharVectRight(x + offx[i], y + offy[i]);
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+			
+			case 0xA3:
+				gMC.flag |= JudgeHitMyCharVectDown(x + offx[i], y + offy[i]);
+				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
+				break;
+				
+			default:
+				break;
+		}
+	}
+	
+	if (gMC.y > gWaterY + 0x800)
+		gMC.flag |= 0x100;
+}
--- /dev/null
+++ b/src/MycHit.h
@@ -1,0 +1,3 @@
+#pragma once
+void ResetMyCharFlag();
+void HitMyCharMap();
--- /dev/null
+++ b/src/NpcAct.h
@@ -1,0 +1,7 @@
+#include "NpChar.h"
+void ActNpc000(NPCHAR *npc);
+void ActNpc001(NPCHAR *npc);
+void ActNpc002(NPCHAR *npc);
+void ActNpc003(NPCHAR *npc);
+void ActNpc004(NPCHAR *npc);
+void ActNpc005(NPCHAR *npc);
--- /dev/null
+++ b/src/NpcAct000.cpp
@@ -1,0 +1,486 @@
+#include "WindowsWrapper.h"
+
+#include "MyChar.h"
+#include "NpChar.h"
+#include "Game.h"
+#include "Sound.h"
+#include "Back.h"
+#include "Triangle.h"
+
+//Null
+void ActNpc000(NPCHAR *npc)
+{
+	if (!npc->act_no)
+	{
+		npc->act_no = 1;
+		if (npc->direct == 2)
+			npc->y += 0x2000;
+	}
+	
+	npc->rect = {0, 0, 16, 16};
+}
+
+//Experience
+void ActNpc001(NPCHAR *npc)
+{
+	//When not in wind
+	if (gBack.type != 5 && gBack.type != 6)
+	{
+		if (!npc->act_no)
+		{
+			//Set state
+			npc->act_no = 1;
+			npc->ani_no = Random(0, 4);
+			
+			//Random speed
+			npc->xm = Random(-0x200, 0x200);
+			npc->ym = Random(-0x400, 0);
+			
+			//Random direction (reverse animation or not)
+			if (Random(0, 1) != 0)
+				npc->direct = 0;
+			else
+				npc->direct = 2;
+		}
+		
+		//Gravity
+		if (npc->flag & 0x100)
+			npc->ym += 21;
+		else
+			npc->ym += 42;
+		
+		//Bounce off walls
+		if (npc->flag & 1 && npc->xm < 0)
+			npc->xm = -npc->xm;
+		if (npc->flag & 4 && npc->xm > 0)
+			npc->xm = -npc->xm;
+		
+		//Bounce off ceiling
+		if (npc->flag & 2 && npc->ym < 0)
+			npc->ym = -npc->ym;
+		
+		//Bounce off floor
+		if (npc->flag & 8)
+		{
+			PlaySoundObject(45, 1);
+			npc->ym = -0x280;
+			npc->xm = 2 * npc->xm / 3;
+		}
+		
+		//Play bounce song (and try to clip out of floor if stuck)
+		if (npc->flag & 0xD)
+		{
+			PlaySoundObject(45, 1);
+			if (++npc->count2 > 2)
+				npc->y -= 512;
+		}
+		else
+		{
+			npc->count2 = 0;
+		}
+		
+		//Limit speed
+		if (npc->xm < -0x5FF)
+			npc->xm = -0x5FF;
+		if (npc->xm > 0x5FF)
+			npc->xm = 0x5FF;
+		if (npc->ym < -0x5FF)
+			npc->ym = -0x5FF;
+		if (npc->ym > 0x5FF)
+			npc->ym = 0x5FF;
+	}
+	//In wind
+	else
+	{
+		if (!npc->act_no)
+		{
+			//Set state
+			npc->act_no = 1;
+			
+			//Set random speed
+			npc->ym = Random(-0x80, 0x80);
+			npc->xm = Random(0x7F, 0x100);
+		}
+		
+		//Blow to the left
+		npc->xm -= 8;
+		
+		//Destroy when off-screen
+		if (npc->x <= 0x9FFF)
+			npc->cond = 0;
+		
+		//Limit speed (except pixel applied it to the X position)
+		if (npc->x < -0x5FF)
+			npc->x = -0x5FF;
+		
+		//Bounce off walls
+		if (npc->flag & 1)
+			npc->xm = 0x100;
+		if (npc->flag & 2)
+			npc->ym = 0x40;
+		if (npc->flag & 8)
+			npc->ym = -0x40;
+	}
+	
+	//Move
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+	
+	//Get framerects
+	RECT rect[6];
+	rect[0] = {0x00, 0x10, 0x10, 0x20};
+	rect[1] = {0x10, 0x10, 0x20, 0x20};
+	rect[2] = {0x20, 0x10, 0x30, 0x20};
+	rect[3] = {0x30, 0x10, 0x40, 0x20};
+	rect[4] = {0x40, 0x10, 0x50, 0x20};
+	rect[5] = {0x50, 0x10, 0x60, 0x20};
+	
+	RECT rcNo = {0, 0, 0, 0};
+	
+	//Animate
+	++npc->ani_wait;
+	
+	if (npc->direct)
+	{
+		if (npc->ani_wait > 2)
+		{
+			npc->ani_wait = 0;
+			if (--npc->ani_no < 0)
+				npc->ani_no = 5;
+		}
+	}
+	else if (npc->ani_wait > 2)
+	{
+		npc->ani_wait = 0;
+		if (++npc->ani_no > 5)
+			npc->ani_no = 0;
+	}
+	
+	npc->rect = rect[npc->ani_no];
+	
+	//Size
+	if (npc->act_no)
+	{
+		if (npc->exp == 5)
+		{
+			npc->rect.top += 16;
+			npc->rect.bottom += 16;
+		}
+		else if (npc->exp == 20)
+		{
+			npc->rect.top += 32;
+			npc->rect.bottom += 32;
+		}
+		
+		npc->act_no = 1;
+	}
+	
+	//Delete after 500 frames
+	if (++npc->count1 > 500 && npc->ani_no == 5 && npc->ani_wait == 2)
+		npc->cond = 0;
+	
+	//Blink after 400 frames
+	if (npc->count1 > 400)
+	{
+		if (npc->count1 / 2 & 1)
+			npc->rect = rcNo;
+	}
+}
+
+//Behemoth
+void ActNpc002(NPCHAR *npc)
+{
+	//Rects
+	RECT rcLeft[7];
+	rcLeft[0] = {32, 0, 64, 24};
+	rcLeft[1] = {0, 0, 32, 24};
+	rcLeft[2] = {32, 0, 64, 24};
+	rcLeft[3] = {64, 0, 96, 24};
+	rcLeft[4] = {96, 0, 128, 24};
+	rcLeft[5] = {128, 0, 160, 24};
+	rcLeft[6] = {160, 0, 192, 24};
+
+	RECT rcUp[7];
+	rcUp[0] = {32, 24, 64, 48};
+	rcUp[1] = {0, 24, 32, 48};
+	rcUp[2] = {32, 24, 64, 48};
+	rcUp[3] = {64, 24, 96, 48};
+	rcUp[4] = {96, 24, 128, 48};
+	rcUp[5] = {128, 24, 160, 48};
+	rcUp[6] = {160, 24, 192, 48};
+	
+	//Turn when touching a wall
+	if (npc->flag & 1)
+		npc->direct = 2;
+	else if (npc->flag & 4)
+		npc->direct = 0;
+	
+	switch (npc->act_no)
+	{
+		case 1: //Shot
+			npc->xm = 7 * npc->xm / 8;
+			
+			if (++npc->count1 > 40)
+			{
+				if (npc->shock)
+				{
+					npc->count1 = 0;
+					npc->act_no = 2;
+					npc->ani_no = 6;
+					npc->ani_wait = 0;
+					npc->damage = 5;
+				}
+				else
+				{
+					npc->act_no = 0;
+					npc->ani_wait = 0;
+				}
+			}
+			break;
+		case 2: //Charge
+			if (npc->direct)
+				npc->xm = 0x400;
+			else
+				npc->xm = -0x400;
+			
+			if (++npc->count1 > 200)
+			{
+				npc->act_no = 0;
+				npc->damage = 1;
+			}
+			
+			if (++npc->ani_wait > 5)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+			
+			if (npc->ani_no > 6)
+				npc->ani_no = 5;
+			break;
+		case 0: //Walking
+			if (npc->direct)
+				npc->xm = 0x100;
+			else
+				npc->xm = -0x100;
+			
+			if (++npc->ani_wait > 8)
+			{
+				npc->ani_wait = 0;
+				++npc->ani_no;
+			}
+			
+			if (npc->ani_no > 3)
+				npc->ani_no = 0;
+			
+			if (npc->shock)
+			{
+				npc->count1 = 0;
+				npc->act_no = 1;
+				npc->ani_no = 4;
+			}
+			break;
+	}
+	
+	//Gravity
+	npc->ym += 0x40;
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+	
+	//Move
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+	
+	//Set framerect
+	if (npc->direct)
+		npc->rect = rcUp[npc->ani_no];
+	else
+		npc->rect = rcLeft[npc->ani_no];
+}
+
+//Dead enemy (make sure damage shown doesn't teleport to a new loaded npc)
+void ActNpc003(NPCHAR *npc)
+{
+	if (++npc->count1 > 100)
+		npc->cond = 0;
+	
+	npc->rect = {0, 0, 0, 0};
+}
+
+//Smoke
+void ActNpc004(NPCHAR *npc)
+{
+	RECT rcLeft[8];
+	RECT rcUp[8];
+	
+	rcLeft[0] = {16, 0, 17, 1};
+	rcLeft[1] = {16, 0, 32, 16};
+	rcLeft[2] = {32, 0, 48, 16};
+	rcLeft[3] = {48, 0, 64, 16};
+	rcLeft[4] = {64, 0, 80, 16};
+	rcLeft[5] = {80, 0, 96, 16};
+	rcLeft[6] = {96, 0, 112, 16};
+	rcLeft[7] = {112, 0, 128, 16};
+
+	rcUp[0] = {16, 0, 17, 1};
+	rcUp[1] = {80, 48, 96, 64};
+	rcUp[2] = {0, 128, 16, 144};
+	rcUp[3] = {16, 128, 32, 144};
+	rcUp[4] = {32, 128, 48, 144};
+	rcUp[5] = {48, 128, 64, 144};
+	rcUp[6] = {64, 128, 80, 144};
+	rcUp[7] = {80, 128, 96, 144};
+	
+	if (npc->act_no)
+	{
+		//Slight drag
+		npc->xm = 20 * npc->xm / 21;
+		npc->ym = 20 * npc->ym / 21;
+		
+		//Move
+		npc->x += npc->xm;
+		npc->y += npc->ym;
+	}
+	else
+	{
+		//Move in random direction at random speed
+		if (!npc->direct || npc->direct == 1)
+		{
+			uint8_t deg = Random(0, 0xFF);
+			npc->xm = GetCos(deg) * Random(0x200, 0x5FF) / 0x200;
+			npc->ym = GetSin(deg) * Random(0x200, 0x5FF) / 0x200;
+		}
+		
+		//Set state
+		npc->ani_no = Random(0, 4);
+		npc->ani_wait = Random(0, 3);
+		npc->act_no = 1;
+	}
+	
+	//Animate
+	if (++npc->ani_wait > 4)
+	{
+		npc->ani_wait = 0;
+		npc->ani_no++;
+	}
+	
+	//Set framerect
+	if (npc->ani_no < 8)
+	{
+		if (npc->direct == 1)
+			npc->rect = rcUp[npc->ani_no];
+		if (!npc->direct)
+			npc->rect = rcLeft[npc->ani_no];
+		if (npc->direct == 2)
+			npc->rect = rcLeft[npc->ani_no];
+	}
+	else
+	{
+		//Destroy if over
+		npc->cond = 0;
+	}
+}
+
+//Critter (Green, Egg Corridor)
+void ActNpc005(NPCHAR *npc)
+{
+	RECT rcLeft[3];
+	RECT rcRight[3];
+
+	rcLeft[0] = {0, 48, 16, 64};
+	rcLeft[1] = {16, 48, 32, 64};
+	rcLeft[2] = {32, 48, 48, 64};
+	
+	rcRight[0] = {0, 64, 16, 80};
+	rcRight[1] = {16, 64, 32, 80};
+	rcRight[2] = {32, 64, 48, 80};
+	
+	switch (npc->act_no)
+	{
+		case 0: //Init
+			npc->y += 0x600;
+			npc->act_no = 1;
+			
+		case 1: //Waiting
+			//Look at player
+			if (npc->x <= gMC.x)
+				npc->direct = 2;
+			else
+				npc->direct = 0;
+			
+			//Open eyes near player
+			if (npc->act_wait < 8 || npc->x - 0xE000 >= gMC.x || npc->x + 0xE000 <= gMC.x || npc->y - 0xA000 >= gMC.y || npc->y + 0xA000 <= gMC.y)
+			{
+				if (npc->act_wait < 8)
+					++npc->act_wait;
+				npc->ani_no = 0;
+			}
+			else
+			{
+				npc->ani_no = 1;
+			}
+			
+			//Jump if attacked
+			if (npc->shock)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+			
+			//Jump if player is nearby
+			if (npc->act_wait >= 8 && npc->x - 0x6000 < gMC.x && npc->x + 0x6000 > gMC.x && npc->y - 0xA000 < gMC.y && npc->y + 0x6000 > gMC.y)
+			{
+				npc->act_no = 2;
+				npc->ani_no = 0;
+				npc->act_wait = 0;
+			}
+			break;
+			
+		case 2: //Going to jump
+			if (++npc->act_wait > 8)
+			{
+				//Set jump state
+				npc->act_no = 3;
+				npc->ani_no = 2;
+				
+				//Jump
+				npc->ym = -0x5FF;
+				PlaySoundObject(30, 1);
+				
+				//Jump in facing direction
+				if (npc->direct)
+					npc->xm = 0x100;
+				else
+					npc->xm = -0x100;
+			}
+			break;
+			
+		case 3: //Jumping
+			//Land
+			if (npc->flag & 8)
+			{
+				npc->xm = 0;
+				npc->act_wait = 0;
+				npc->ani_no = 0;
+				npc->act_no = 1;
+				PlaySoundObject(23, 1);
+			}
+			break;
+	}
+	
+	//Gravity
+	npc->ym += 64;
+	if (npc->ym > 0x5FF)
+		npc->ym = 0x5FF;
+	
+	//Move
+	npc->x += npc->xm;
+	npc->y += npc->ym;
+	
+	//Set framerect
+	if (npc->direct)
+		npc->rect = rcRight[npc->ani_no];
+	else
+		npc->rect = rcLeft[npc->ani_no];
+}
\ No newline at end of file
--- /dev/null
+++ b/src/NpcHit.cpp
@@ -1,0 +1,401 @@
+#include "NpChar.h"
+#include "Map.h"
+
+void JadgeHitNpCharBlock(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+
+	if (npc->y - npc->hit.top < ((2 * y + 1) << 12) - 0x600
+		&& npc->y + npc->hit.bottom > ((2 * y - 1) << 12) + 0x600
+		&& npc->x - npc->hit.back < (2 * x + 1) << 12
+		&& npc->x - npc->hit.back > x << 13)
+	{
+		npc->x = ((2 * x + 1) << 12) + npc->hit.back;
+		hit |= 1;
+	}
+	
+	if (npc->y - npc->hit.top < ((2 * y + 1) << 12) - 0x600
+		&& npc->y + npc->hit.bottom > ((2 * y - 1) << 12) + 0x600
+		&& npc->hit.back + npc->x > (2 * x - 1) << 12
+		&& npc->hit.back + npc->x < x << 13)
+	{
+		npc->x = ((2 * x - 1) << 12) - npc->hit.back;
+		hit |= 4;
+	}
+	
+	if (npc->x - npc->hit.back < ((2 * x + 1) << 12) - 0x600
+		&& npc->hit.back + npc->x > ((2 * x - 1) << 12) + 0x600
+		&& npc->y - npc->hit.top < (2 * y + 1) << 12
+		&& npc->y - npc->hit.top > y << 13)
+	{
+		npc->y = ((2 * y + 1) << 12) + npc->hit.top;
+		npc->ym = 0;
+		hit |= 2;
+	}
+	
+	if (npc->x - npc->hit.back < ((2 * x + 1) << 12) - 0x600
+		&& npc->hit.back + npc->x > ((2 * x - 1) << 12) + 0x600
+		&& npc->y + npc->hit.bottom > (2 * y - 1) << 12
+		&& npc->y + npc->hit.bottom < y << 13)
+	{
+		npc->y = ((2 * y - 1) << 12) - npc->hit.bottom;
+		npc->ym = 0;
+		hit |= 8;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleA(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+	
+	if (npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y - npc->hit.top < (y << 13) - (-0x2000 * x + npc->x) / 2 + 0x800
+		&& npc->y + npc->hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		npc->y = npc->hit.top + (y << 13) - (-0x2000 * x + npc->x) / 2 + 0x800;
+		
+		//Halt momentum
+		if (npc->ym < 0)
+			npc->ym = 0;
+		
+		//Set that hit a ceiling
+		hit = 2;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleB(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+	
+	if (npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y - npc->hit.top < (y << 13) - (-0x2000 * x + npc->x) / 2 - 0x800
+		&& npc->y + npc->hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		npc->y = npc->hit.top + (y << 13) - (-0x2000 * x + npc->x) / 2 - 0x800;
+		
+		//Halt momentum
+		if (npc->ym < 0)
+			npc->ym = 0;
+		
+		//Set that hit a ceiling
+		hit = 2;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleC(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+	
+	if (npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y - npc->hit.top < (y << 13) + (-0x2000 * x + npc->x) / 2 - 0x800
+		&& npc->y + npc->hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		npc->y = npc->hit.top + (y << 13) + (-0x2000 * x + npc->x) / 2 - 0x800;
+		
+		//Halt momentum
+		if (npc->ym < 0)
+			npc->ym = 0;
+		
+		//Set that hit a ceiling
+		hit = 2;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleD(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+	
+	if (npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y - npc->hit.top < (y << 13) + (-0x2000 * x + npc->x) / 2 + 0x800
+		&& npc->y + npc->hit.bottom > (2 * y - 1) << 12)
+	{
+		//Clip
+		npc->y = npc->hit.top + (y << 13) + (-0x2000 * x + npc->x) / 2 + 0x800;
+		
+		//Halt momentum
+		if (npc->ym < 0)
+			npc->ym = 0;
+		
+		//Set that hit a ceiling
+		hit = 2;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleE(NPCHAR *npc, int x, int y)
+{
+	int hit = 0x10000;
+
+	if ( npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y + npc->hit.bottom > (y << 13) + (-0x2000 * x + npc->x) / 2 - 0x800
+		&& npc->y - npc->hit.top < (2 * y + 1) << 12 )
+	{
+		//Clip
+		npc->y = (y << 13) + (-0x2000 * x + npc->x) / 2 - 0x800 - npc->hit.bottom;
+		
+		//Halt momentum
+		if (npc->ym > 0)
+			npc->ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x10028;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleF(NPCHAR *npc, int x, int y)
+{
+	int hit = 0x20000;
+
+	if ( npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y + npc->hit.bottom > (y << 13) + (-0x2000 * x + npc->x) / 2 + 0x800
+		&& npc->y - npc->hit.top < (2 * y + 1) << 12 )
+	{
+		//Clip
+		npc->y = (y << 13) + (-0x2000 * x + npc->x) / 2 + 0x800 - npc->hit.bottom;
+		
+		//Halt momentum
+		if (npc->ym > 0)
+			npc->ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x20028;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleG(NPCHAR *npc, int x, int y)
+{
+	int hit = 0x40000;
+
+	if ( npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y + npc->hit.bottom > (y << 13) - (-0x2000 * x + npc->x) / 2 + 0x800
+		&& npc->y - npc->hit.top < (2 * y + 1) << 12 )
+	{
+		//Clip
+		npc->y = (y << 13) - (-0x2000 * x + npc->x) / 2 + 0x800 - npc->hit.bottom;
+		
+		//Halt momentum
+		if (npc->ym > 0)
+			npc->ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x40018;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharTriangleH(NPCHAR *npc, int x, int y)
+{
+	int hit = 0x80000;
+
+	if ( npc->x < (2 * x + 1) << 12
+		&& npc->x > (2 * x - 1) << 12
+		&& npc->y + npc->hit.bottom > (y << 13) - (-0x2000 * x + npc->x) / 2 - 0x800
+		&& npc->y - npc->hit.top < (2 * y + 1) << 12 )
+	{
+		//Clip
+		npc->y = (y << 13) - (-0x2000 * x + npc->x) / 2 - 0x800 - npc->hit.bottom;
+		
+		//Halt momentum
+		if (npc->ym > 0)
+			npc->ym = 0;
+		
+		//Set that hit this slope
+		hit = 0x80018;
+	}
+	
+	npc->flag |= hit;
+}
+
+void JudgeHitNpCharWater(NPCHAR *npc, int x, int y)
+{
+	int hit = 0;
+	
+	if (npc->x - npc->hit.back < (4 * (2 * x + 1) - 1) << 10
+		&& npc->hit.back + npc->x > (4 * (2 * x - 1) + 1) << 10
+		&& npc->y - npc->hit.top < (4 * (2 * y + 1) - 1) << 10
+		&& npc->y + npc->hit.bottom > (4 * (2 * y - 1) + 1) << 10)
+		hit = 0x100;
+	
+	npc->flag |= hit;
+}
+
+void HitNpCharMap()
+{
+	int offy[9];
+	int offx[9];
+	
+	offx[0] = 0;
+	offx[1] = 1;
+	offx[2] = 0;
+	offx[3] = 1;
+	offx[4] = 2;
+	offx[5] = 2;
+	offx[6] = 2;
+	offx[7] = 0;
+	offx[8] = 1;
+	
+	offy[0] = 0;
+	offy[1] = 0;
+	offy[2] = 1;
+	offy[3] = 1;
+	offy[4] = 0;
+	offy[5] = 1;
+	offy[6] = 2;
+	offy[7] = 2;
+	offy[8] = 2;
+	
+	for (int i = 0; i < NPC_MAX; i++)
+	{
+		if ((gNPC[i].cond & 0x80) && !(gNPC[i].bits & 8))
+		{
+			int judg, x, y;
+			if (gNPC[i].size <= 2)
+			{
+				judg = 4;
+				x = gNPC[i].x / 0x2000;
+				y = gNPC[i].y / 0x2000;
+			}
+			else
+			{
+				judg = 9;
+				x = (gNPC[i].x - 0x1000) / 0x2000;
+				y = (gNPC[i].y - 0x1000) / 0x2000;
+			}
+			
+			gNPC[i].flag = 0;
+			
+			for (int j = 0; j < judg; j++)
+			{
+				switch (GetAttribute(x + offx[j], y + offy[j]))
+				{
+					//Water
+					case 0x02:
+					case 0x60:
+					case 0x62:
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					//Block
+					case 0x03:
+					case 0x05:
+					case 0x41:
+					case 0x43:
+						JadgeHitNpCharBlock(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					//Water block
+					case 0x04:
+					case 0x61:
+					case 0x64:
+						JadgeHitNpCharBlock(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					//No NPC block
+					case 0x44:
+						if (!(gNPC[i].bits & npc_ignore44))
+							JadgeHitNpCharBlock(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					//Slopes
+					case 0x50:
+						JudgeHitNpCharTriangleA(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x51:
+						JudgeHitNpCharTriangleB(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x52:
+						JudgeHitNpCharTriangleC(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x53:
+						JudgeHitNpCharTriangleD(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x54:
+						JudgeHitNpCharTriangleE(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x55:
+						JudgeHitNpCharTriangleF(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x56:
+						JudgeHitNpCharTriangleG(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x57:
+						JudgeHitNpCharTriangleH(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					//Water slopes
+					case 0x70:
+						JudgeHitNpCharTriangleA(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x71:
+						JudgeHitNpCharTriangleB(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x72:
+						JudgeHitNpCharTriangleC(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x73:
+						JudgeHitNpCharTriangleD(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x74:
+						JudgeHitNpCharTriangleE(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x75:
+						JudgeHitNpCharTriangleF(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x76:
+						JudgeHitNpCharTriangleG(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+						
+					case 0x77:
+						JudgeHitNpCharTriangleH(&gNPC[i], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gNPC[i], x + offx[j], y + offy[j]);
+						break;
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null
+++ b/src/NpcHit.h
@@ -1,0 +1,4 @@
+#pragma once
+#include "NpChar.h"
+
+void HitNpCharMap();
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -3,6 +3,7 @@
 #include <SDL_rwops.h>
 
 #include "NpcTbl.h"
+#include "NpcAct.h"
 
 NPC_TABLE *gNpcTable;
 
@@ -55,12 +56,12 @@
 //Npc function table
 NPCFUNCTION gpNpcFuncTbl[] =
 {
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
-	nullptr,
+	&ActNpc000,
+	&ActNpc001,
+	&ActNpc002,
+	&ActNpc003,
+	&ActNpc004,
+	&ActNpc005,
 	nullptr,
 	nullptr,
 	nullptr,