shithub: cstory

Download patch

ref: 66e96f47b7063835eb145156a2587d002518a58d
parent: 02133ba1afbdf4af9b8c509faae6b3429762528c
author: cuckydev <cuckydev@users.noreply.github.com>
date: Fri Feb 1 20:19:12 EST 2019

omega

--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,9 @@
 SOURCES = \
 	ArmsItem \
 	Back \
+	Boss \
 	BossLife \
+	BossOhm \
 	BulHit \
 	Bullet \
 	Caret \
binary files /dev/null b/build/pre-omega Profile.dat differ
--- /dev/null
+++ b/src/Boss.cpp
@@ -1,0 +1,352 @@
+#include <stdint.h>
+#include <string.h>
+
+#include "WindowsWrapper.h"
+
+#include "Boss.h"
+#include "BossOhm.h"
+#include "NpChar.h"
+#include "MyChar.h"
+#include "Sound.h"
+#include "NpcHit.h"
+#include "Caret.h"
+#include "TextScr.h"
+#include "ValueView.h"
+#include "Draw.h"
+#include "Map.h"
+#include "Bullet.h"
+
+NPCHAR gBoss[BOSS_MAX];
+
+void InitBossChar(int code)
+{
+	memset(gBoss, 0, sizeof(gBoss));
+	gBoss[0].cond = 0x80;
+	gBoss[0].code_char = code;
+}
+
+void PutBossChar(int fx, int fy)
+{
+	for (int b = BOSS_MAX - 1; b >= 0; b--)
+	{
+		if (gBoss[b].cond & 0x80)
+		{
+			int a;
+			if (gBoss[b].shock)
+			{
+				a = 2 * ((gBoss[b].shock >> 1) & 1) - 1;
+			}
+			else
+			{
+				a = 0;
+				
+				if (gBoss[b].bits & npc_showDamage && gBoss[b].damage_view)
+				{
+					SetValueView(&gBoss[b].x, &gBoss[b].y, gBoss[b].damage_view);
+					gBoss[b].damage_view = 0;
+				}
+			}
+			
+			int side;
+			if (gBoss[b].direct)
+				side = gBoss[b].view.back;
+			else
+				side = gBoss[b].view.front;
+			
+			PutBitmap3(
+				&grcGame,
+				(gBoss[b].x - side) / 0x200 - fx / 0x200 + a,
+				(gBoss[b].y - gBoss[b].view.top) / 0x200 - fy / 0x200,
+				&gBoss[b].rect,
+				22);
+		}
+	}
+}
+
+void SetBossCharActNo(int a)
+{
+	gBoss[0].act_no = a;
+}
+
+void HitBossBullet()
+{
+	for (int bos = 0; bos < BOSS_MAX; bos++)
+	{
+		if (gBoss[bos].cond & 0x80)
+		{
+			for (int bul = 0; bul < BULLET_MAX; bul++)
+			{
+				if (gBul[bul].cond & 0x80 && gBul[bul].damage != -1)
+				{
+					//Check if bullet touches boss
+					bool bHit = false;
+					if (gBoss[bos].bits & npc_shootable
+						&& gBoss[bos].x - gBoss[bos].hit.back < gBul[bul].x + gBul[bul].enemyXL
+						&& gBoss[bos].x + gBoss[bos].hit.back > gBul[bul].x - gBul[bul].enemyXL
+						&& gBoss[bos].y - gBoss[bos].hit.top < gBul[bul].y + gBul[bul].enemyYL
+						&& gBoss[bos].y + gBoss[bos].hit.bottom > gBul[bul].y - gBul[bul].enemyYL)
+						bHit = true;
+					else if (gBoss[bos].bits & npc_invulnerable
+						&& gBoss[bos].x - gBoss[bos].hit.back < gBul[bul].x + gBul[bul].blockXL
+						&& gBoss[bos].x + gBoss[bos].hit.back > gBul[bul].x - gBul[bul].blockXL
+						&& gBoss[bos].y - gBoss[bos].hit.top < gBul[bul].y + gBul[bul].blockYL
+						&& gBoss[bos].y + gBoss[bos].hit.bottom > gBul[bul].y - gBul[bul].blockYL)
+						bHit = true;
+						
+					if (bHit)
+					{
+						//Damage boss
+						if (gBoss[bos].bits & npc_shootable)
+						{
+							int bos_;
+							if (gBoss[bos].cond & 0x10)
+								bos_ = 0;
+							else
+								bos_ = bos;
+							
+							gBoss[bos_].life -= gBul[bul].damage;
+							
+							if (gBoss[bos_].life > 0)
+							{
+								if (gBoss[bos].shock < 14)
+								{
+									SetCaret(gBul[bul].x, gBul[bul].y, 11, 0);
+									SetCaret(gBul[bul].x, gBul[bul].y, 11, 0);
+									SetCaret(gBul[bul].x, gBul[bul].y, 11, 0);
+									PlaySoundObject(gBoss[bos_].hit_voice, 1);
+								}
+								
+								gBoss[bos].shock = 8;
+								gBoss[bos_].shock = 8;
+								gBoss[bos_].damage_view -= gBul[bul].damage;
+							}
+							else
+							{
+								gBoss[bos_].life = bos_;
+								
+								if ((gMC.cond & 0x80) && gBoss[bos_].bits & npc_eventDie)
+								{
+									StartTextScript(gBoss[bos_].code_event);
+								}
+								else
+								{
+									PlaySoundObject(gBoss[bos_].destroy_voice, 1);
+									
+									switch (gBoss[bos_].size)
+									{
+										case 1:
+											SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 4);
+											break;
+										case 2:
+											SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 8);
+											break;
+										case 3:
+											SetDestroyNpChar(gBoss[bos_].x, gBoss[bos_].y, gBoss[bos_].view.back, 16);
+											break;
+									}
+									
+									gBoss[bos_].cond = 0;
+								}
+							}
+							
+							if (--gBul[bul].life <= 0)
+								gBul[bul].cond = 0;
+						}
+						else if (gBul[bul].code_bullet != 13
+							&& gBul[bul].code_bullet != 14
+							&& gBul[bul].code_bullet != 15
+							&& gBul[bul].code_bullet != 28
+							&& gBul[bul].code_bullet != 29
+							&& gBul[bul].code_bullet != 30)
+						{
+							if (!(gBul[bul].bbits & 0x10))
+							{
+								SetCaret(gBul[bul].x, gBul[bul].y, 2, 2);
+								PlaySoundObject(31, 1);
+								gBul[bul].cond = 0;
+							}
+						}
+						else
+						{
+							gBul[bul].life--;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+void ActBossChar_0()
+{
+	;
+}
+
+BOSSFUNCTION gpBossFuncTbl[10] =
+{
+	&ActBossChar_0,
+	&ActBossChar_Omega,
+	nullptr, //&ActBossChar_Frog,
+	nullptr, //&ActBossChar_MonstX,
+	nullptr, //&ActBossChar_Core,
+	nullptr, //&ActBossChar_Ironhead,
+	nullptr, //&ActBossChar_Twin,
+	nullptr, //&ActBossChar_Undead,
+	nullptr, //&ActBossChar_Press,
+	nullptr, //&ActBossChar_Ballos
+};
+
+void ActBossChar()
+{
+	if (gBoss[0].cond & 0x80)
+	{
+		if (gpBossFuncTbl[gBoss[0].code_char] != nullptr)
+			gpBossFuncTbl[gBoss[0].code_char]();
+		
+		for (int bos = 0; bos < BOSS_MAX; bos++)
+		{
+			if (gBoss[bos].shock)
+				gBoss[bos].shock--;
+		}
+	}
+}
+
+void HitBossMap()
+{
+	int offx[16];
+	int offy[16];
+	uint8_t atrb[16];
+	
+	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;
+	offx[9] = -1;
+	offx[10] = -1;
+	offx[11] = -1;
+	offx[12] = -1;
+	offx[13] = 0;
+	offx[14] = 1;
+	offx[15] = 2;
+	
+	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;
+	offy[9] = -1;
+	offy[10] = 0;
+	offy[11] = 1;
+	offy[12] = 2;
+	offy[13] = -1;
+	offy[14] = -1;
+	offy[15] = -1;
+	
+	for (int b = 0; b < BOSS_MAX; b++)
+	{
+		if ((gBoss[b].cond & 0x80) && !(gBoss[b].bits & npc_ignoreSolid))
+		{
+			int judg;
+			if (gBoss[b].size < 3)
+				judg = 4;
+			else
+				judg = 16;
+			
+			int x = gBoss[b].x / 0x2000;
+			int y = gBoss[b].y / 0x2000;
+			
+			gBoss[b].flag = 0;
+			for (int j = 0; j < judg; j++)
+			{
+				atrb[j] = GetAttribute(x + offx[j], y + offy[j]);
+				
+				switch (atrb[j])
+				{
+					case 0x02:
+					case 0x60:
+					case 0x61:
+					case 0x64:
+						JadgeHitNpCharBlock(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x05:
+					case 0x41:
+					case 0x43:
+						JadgeHitNpCharBlock(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x44:
+						if (!(gBoss[b].bits & npc_ignore44))
+							JadgeHitNpCharBlock(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x50:
+						JudgeHitNpCharTriangleA(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x51:
+						JudgeHitNpCharTriangleB(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x52:
+						JudgeHitNpCharTriangleC(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x53:
+						JudgeHitNpCharTriangleD(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x54:
+						JudgeHitNpCharTriangleE(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x55:
+						JudgeHitNpCharTriangleF(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x56:
+						JudgeHitNpCharTriangleG(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x57:
+						JudgeHitNpCharTriangleH(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x70:
+						JudgeHitNpCharTriangleA(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x71:
+						JudgeHitNpCharTriangleB(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x72:
+						JudgeHitNpCharTriangleC(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x73:
+						JudgeHitNpCharTriangleD(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x74:
+						JudgeHitNpCharTriangleE(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x75:
+						JudgeHitNpCharTriangleF(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x76:
+						JudgeHitNpCharTriangleG(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					case 0x77:
+						JudgeHitNpCharTriangleH(&gBoss[b], x + offx[j], y + offy[j]);
+						JudgeHitNpCharWater(&gBoss[b], x + offx[j], y + offy[j]);
+						break;
+					default:
+						continue;
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null
+++ b/src/Boss.h
@@ -1,0 +1,15 @@
+#pragma once
+#include "NpChar.h"
+
+#define BOSS_MAX 20
+extern NPCHAR gBoss[BOSS_MAX];
+
+typedef void (*BOSSFUNCTION)(void);
+extern BOSSFUNCTION gpBossFuncTbl[10];
+
+void InitBossChar(int code);
+void PutBossChar(int fx, int fy);
+void SetBossCharActNo(int a);
+void HitBossBullet();
+void ActBossChar();
+void HitBossMap();
--- a/src/BossLife.cpp
+++ b/src/BossLife.cpp
@@ -2,6 +2,7 @@
 
 #include "Draw.h"
 #include "NpChar.h"
+#include "Boss.h"
 #include "WindowsWrapper.h"
 
 static struct
@@ -37,11 +38,10 @@
 
 bool StartBossLife2(void)
 {
-	// TODO uncomment me when Boss.cpp is done!
-//	gBL.flag = true;
-//	gBL.max = gBoss[0].life;
-//	gBL.br = gBoss[0].life;
-//	gBL.pLife = &gBoss[0].life;
+	gBL.flag = true;
+	gBL.max = gBoss[0].life;
+	gBL.br = gBoss[0].life;
+	gBL.pLife = &gBoss[0].life;
 	return true;
 }
 
--- /dev/null
+++ b/src/BossOhm.cpp
@@ -1,0 +1,465 @@
+#include <string.h>
+
+#include "WindowsWrapper.h"
+
+#include "Boss.h"
+#include "NpChar.h"
+#include "MyChar.h"
+#include "Sound.h"
+#include "Frame.h"
+#include "Bullet.h"
+#include "Flash.h"
+#include "Game.h"
+
+void ActBoss01_12()
+{
+	RECT rcLeft[1];
+	RECT rcRight[1];
+	rcLeft[0] = {80, 56, 104, 72};
+	rcRight[0] = {104, 56, 128, 72};
+
+	for (int i = 1; i <= 2; i++)
+	{
+		gBoss[i].y = (gBoss[i].y + gBoss[i + 2].y - 0x1000) / 2;
+		
+		if (gBoss[i].direct)
+		{
+			gBoss[i].rect = rcRight[gBoss[i].count2];
+			gBoss[i].x = gBoss[0].x + 0x2000;
+		}
+		else
+		{
+			gBoss[i].rect = rcLeft[gBoss[i].count2];
+			gBoss[i].x = gBoss[0].x - 0x2000;
+		}
+	}
+}
+
+void ActBoss01_34()
+{
+	RECT rcRight[2];
+	RECT rcLeft[2];
+
+	rcLeft[0] = { 0, 56, 40, 88 };
+	rcLeft[1] = { 40, 56, 80, 88 };
+	rcRight[0] = { 0, 88, 40, 120 };
+	rcRight[1] = { 40, 88, 80, 120 };
+
+	for (int i = 3; i <= 4; i++)
+	{
+		switch (gBoss[i].act_no)
+		{
+			case 0:
+				gBoss[i].act_no = 1;
+			case 1:
+				if (i == 3)
+					gBoss[i].x = gBoss[0].x - 0x2000;
+				if (i == 4)
+					gBoss[i].x = gBoss[0].x + 0x2000;
+
+				gBoss[i].y = gBoss[0].y;
+				break;
+
+			case 3:
+				if (i == 3)
+					gBoss[i].x = gBoss[0].x - 0x2000;
+				if (i == 4)
+					gBoss[i].x = gBoss[0].x + 0x2000;
+
+				gBoss[i].tgt_y = gBoss[0].y + 0x3000;
+				gBoss[i].y += (gBoss[i].tgt_y - gBoss[i].y) / 2;
+				break;
+
+			default:
+				break;
+		}
+
+		gBoss[i].count2 = !((gBoss[i].flag & 8) && gBoss[i].y > gBoss[i].tgt_y);
+
+		if (gBoss[i].direct)
+			gBoss[i].rect = rcRight[gBoss[i].count2];
+		else
+			gBoss[i].rect = rcLeft[gBoss[i].count2];
+	}
+}
+
+void ActBoss01_5()
+{
+	if (!gBoss[5].act_no)
+	{
+		gBoss[5].bits |= npc_solidSoft | npc_ignoreSolid;
+		gBoss[5].hit = { 0x2800, 0x4800, 0x2800, 0x2000 };
+		gBoss[5].act_no = 1;
+	}
+	
+	if (gBoss[5].act_no == 1)
+	{
+		gBoss[5].x = gBoss[0].x;
+		gBoss[5].y = gBoss[0].y;
+	}
+}
+
+void ActBossChar_Omega()
+{
+	switch (gBoss[0].act_no)
+	{
+	case 0:
+		gBoss[0].x = 0x1B6000;
+		gBoss[0].y = 0x20000;
+
+		gBoss[0].view = { 0x5000, 0x5000, 0x5000, 0x2000 };
+
+		gBoss[0].tgt_x = 0x1B6000;
+		gBoss[0].tgt_y = 0x20000;
+
+		gBoss[0].hit_voice = 52;
+
+		gBoss[0].hit = { 0x1000, 0x3000, 0x1000, 0x2000 };
+
+		gBoss[0].bits = (npc_ignoreSolid | npc_eventDie | npc_showDamage);
+		gBoss[0].size = 3;
+		gBoss[0].exp = 1;
+		gBoss[0].code_event = 210;
+		gBoss[0].life = 400;
+
+		gBoss[1].cond = 0x80;
+		gBoss[1].view = { 0x1800, 0x1000, 0x1800, 0x1000 };
+		gBoss[1].bits = npc_ignoreSolid;
+
+		memcpy(&gBoss[2], &gBoss[1], sizeof(gBoss[2]));
+
+		gBoss[1].direct = 0;
+		gBoss[2].direct = 2;
+
+		gBoss[3].cond = 0x80;
+		gBoss[3].view = { 0x3000, 0x2000, 0x2000, 0x2000 };
+		gBoss[3].hit_voice = 52;
+		gBoss[3].hit = { 0x1000, 0x1000, 0x1000, 0x1000 };
+		gBoss[3].bits = npc_ignoreSolid;
+
+		gBoss[3].y = gBoss[0].y;
+		gBoss[3].direct = 0;
+
+		memcpy(&gBoss[4], &gBoss[3], sizeof(gBoss[4]));
+		gBoss[4].direct = 2;
+		gBoss[3].x = gBoss[0].x + 0x2000;
+		gBoss[5].cond = 0x80;
+		break;
+
+	case 20: //Rising out of the ground
+		gBoss[0].act_no = 30;
+		gBoss[0].act_wait = 0;
+		gBoss[0].ani_no = 0;
+	case 30:
+		SetQuake(2);
+		gBoss[0].y -= 0x200;
+
+		if (!(++gBoss[0].act_wait & 3))
+			PlaySoundObject(26, 1);
+
+		if (gBoss[0].act_wait >= 48)
+		{
+			gBoss[0].act_no = 40;
+			gBoss[0].act_wait = 0;
+
+			if (gBoss[0].life <= 280)
+			{
+				gBoss[0].act_no = 110;
+
+				gBoss[0].bits |= npc_shootable;
+				gBoss[0].bits &= ~npc_ignoreSolid;
+				gBoss[3].bits &= ~npc_ignoreSolid;
+				gBoss[4].bits &= ~npc_ignoreSolid;
+
+				gBoss[3].act_no = 3;
+				gBoss[4].act_no = 3;
+				gBoss[5].hit.top = 0x2000;
+			}
+		}
+		break;
+
+	case 40:
+		if (++gBoss[0].act_wait >= 48)
+		{
+			gBoss[0].act_wait = 0;
+			gBoss[0].act_no = 50;
+			gBoss[0].count1 = 0;
+			gBoss[5].hit.top = 0x2000;
+			PlaySoundObject(102, 1);
+		}
+		break;
+
+	case 50: //Open mouth
+		if (++gBoss[0].count1 > 2)
+		{
+			gBoss[0].count1 = 0;
+			++gBoss[0].count2;
+		}
+
+		if (gBoss[0].count2 == 3)
+		{
+			gBoss[0].act_no = 60;
+			gBoss[0].act_wait = 0;
+			gBoss[0].bits |= npc_shootable;
+			gBoss[0].hit.left = 0x2000;
+			gBoss[0].hit.right = 0x2000;
+		}
+		break;
+
+	case 60: //Shoot out of mouth
+		if (++gBoss[0].act_wait > 20 && gBoss[0].act_wait < 80 && !(gBoss[0].act_wait % 3))
+		{
+			if (Random(0, 9) <= 7)
+				SetNpChar(48, gBoss[0].x, gBoss[0].y - 0x2000, Random(-0x100, 0x100), -0x333, 0, NULL, 0x100);
+			else
+				SetNpChar(48, gBoss[0].x, gBoss[0].y - 0x2000, Random(-0x100, 0x100), -0x333, 2, NULL, 0x100);
+
+			PlaySoundObject(39, 1);
+		}
+
+		if (gBoss[0].act_wait >= 200 || CountArmsBullet(6))
+		{
+			gBoss[0].count1 = 0;
+			gBoss[0].act_no = 70;
+			PlaySoundObject(102, 1);
+		}
+		break;
+
+	case 70: //Close mouth
+		if (++gBoss[0].count1 > 2)
+		{
+			gBoss[0].count1 = 0;
+			--gBoss[0].count2;
+		}
+
+		if (gBoss[0].count2 == 1)
+			gBoss[0].damage = 20;
+
+		if (!gBoss[0].count2)
+		{
+			PlaySoundObject(102, 1);
+			PlaySoundObject(12, 1);
+
+			gBoss[0].act_no = 80;
+			gBoss[0].act_wait = 0;
+
+			gBoss[0].bits &= ~npc_shootable;
+
+			gBoss[0].hit.left = 0x3000;
+			gBoss[0].hit.right = 0x3000;
+			gBoss[5].hit.top = 0x4800;
+
+			gBoss[0].damage = 0;
+		}
+		break;
+
+	case 80:
+		if (++gBoss[0].act_wait >= 48)
+		{
+			gBoss[0].act_wait = 0;
+			gBoss[0].act_no = 90;
+		}
+		break;
+
+	case 90: //Go back into the ground
+		SetQuake(2);
+		gBoss[0].y += 0x200;
+
+		if (!(++gBoss[0].act_wait & 3))
+			PlaySoundObject(26, 1);
+
+		if (gBoss[0].act_wait >= 48)
+		{
+			gBoss[0].act_wait = 0;
+			gBoss[0].act_no = 100;
+		}
+		break;
+
+	case 100: //Move to proper position for coming out of the ground
+		if (++gBoss[0].act_wait >= 120)
+		{
+			gBoss[0].act_wait = 0;
+			gBoss[0].act_no = 30;
+
+			gBoss[0].x = gBoss[0].tgt_x + (Random(-64, 64) << 9);
+			gBoss[0].y = gBoss[0].tgt_y;
+		}
+		break;
+
+	case 110:
+		if (++gBoss[0].count1 > 2)
+		{
+			gBoss[0].count1 = 0;
+			++gBoss[0].count2;
+		}
+
+		if (gBoss[0].count2 == 3)
+		{
+			gBoss[0].act_no = 120;
+			gBoss[0].act_wait = 0;
+			gBoss[0].hit.left = 0x2000;
+			gBoss[0].hit.right = 0x2000;
+		}
+		break;
+
+	case 120:
+		if (++gBoss[0].act_wait >= 50 || CountArmsBullet(6))
+		{
+			gBoss[0].act_no = 130;
+			PlaySoundObject(102, 1);
+			gBoss[0].act_wait = 0;
+			gBoss[0].count1 = 0;
+		}
+
+		if (gBoss[0].act_wait < 30 && !(gBoss[0].act_wait % 5))
+		{
+			SetNpChar(48, gBoss[0].x, gBoss[0].y - 0x2000, Random(-0x155, 0x155), -0x333, 0, NULL, 0x100);
+			PlaySoundObject(39, 1);
+		}
+		break;
+
+	case 130:
+		if (++gBoss[0].count1 > 2)
+		{
+			gBoss[0].count1 = 0;
+			--gBoss[0].count2;
+		}
+
+		if (gBoss[0].count2 == 1)
+			gBoss[0].damage = 20;
+
+		if (!gBoss[0].count2)
+		{
+			gBoss[0].act_no = 140;
+			gBoss[0].bits |= npc_shootable;
+
+			gBoss[0].hit.left = 0x2000;
+			gBoss[0].hit.right = 0x2000;
+
+			gBoss[0].ym = -0x5FF;
+
+			PlaySoundObject(102, 1);
+			PlaySoundObject(12, 1);
+			PlaySoundObject(25, 1);
+
+			if (gBoss[0].x < gMC.x)
+				gBoss[0].xm = 0x100;
+			if (gBoss[0].x > gMC.x)
+				gBoss[0].xm = -0x100;
+
+			gBoss[0].damage = 0;
+			gBoss[5].hit.top = 0x4800;
+		}
+		break;
+
+	case 140:
+		if (gMC.flag & 8 && gBoss[0].ym > 0)
+			gBoss[5].damage = 20;
+		else
+			gBoss[5].damage = 0;
+
+		gBoss[0].ym += 0x24;
+		if (gBoss[0].ym > 0x5FF)
+			gBoss[0].ym = 0x5FF;
+
+		gBoss[0].x += gBoss[0].xm;
+		gBoss[0].y += gBoss[0].ym;
+
+		if (gBoss[0].flag & 8)
+		{
+			gBoss[0].act_no = 110;
+			gBoss[0].act_wait = 0;
+			gBoss[0].count1 = 0;
+
+			gBoss[5].hit.top = 0x2000;
+			gBoss[5].damage = 0;
+
+			PlaySoundObject(26, 1);
+			PlaySoundObject(12, 1);
+
+			SetQuake(30);
+		}
+		break;
+
+	case 150:
+		SetQuake(2);
+
+		if (!(++gBoss[0].act_wait % 12))
+			PlaySoundObject(52, 1);
+
+		SetDestroyNpChar(gBoss[0].x + (Random(-48, 48) << 9), gBoss[0].y + (Random(-48, 24) << 9), 1, 1);
+
+		if (gBoss[0].act_wait > 100)
+		{
+			gBoss[0].act_wait = 0;
+			gBoss[0].act_no = 160;
+			SetFlash(gBoss[0].x, gBoss[0].y, 1);
+			PlaySoundObject(35, 1);
+		}
+		break;
+
+	case 160:
+		SetQuake(40);
+
+		if (++gBoss[0].act_wait > 50)
+		{
+			gBoss[0].cond = 0;
+			gBoss[1].cond = 0;
+			gBoss[2].cond = 0;
+			gBoss[3].cond = 0;
+			gBoss[4].cond = 0;
+			gBoss[5].cond = 0;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	RECT rect[4];
+
+	rect[0].left = 0;
+	rect[0].top = 0;
+	rect[0].right = 80;
+	rect[0].bottom = 56;
+	rect[1].left = 80;
+	rect[1].top = 0;
+	rect[1].right = 160;
+	rect[1].bottom = 56;
+	rect[2].left = 160;
+	rect[2].top = 0;
+	rect[2].right = 240;
+	rect[2].bottom = 56;
+	rect[3].left = 80;
+	rect[3].top = 0;
+	rect[3].right = 160;
+	rect[3].bottom = 56;
+
+	gBoss[0].rect = rect[gBoss[0].count2];
+
+	gBoss[1].shock = gBoss[0].shock;
+	gBoss[2].shock = gBoss[0].shock;
+	gBoss[3].shock = gBoss[0].shock;
+	gBoss[4].shock = gBoss[0].shock;
+
+	ActBoss01_34();
+	ActBoss01_12();
+	ActBoss01_5();
+
+	if (!gBoss[0].life && gBoss[0].act_no < 150)
+	{
+		gBoss[0].act_no = 150;
+		gBoss[0].act_wait = 0;
+		gBoss[0].damage = 0;
+		gBoss[5].damage = 0;
+
+		for (int i = 0; i < NPC_MAX; i++)
+		{
+			if (gNPC[i].cond & 0x80)
+			{
+				if (gNPC[i].code_char == 48)
+					gNPC[i].cond = 0;
+			}
+		}
+	}
+}
--- /dev/null
+++ b/src/BossOhm.h
@@ -1,0 +1,2 @@
+#pragma once
+void ActBossChar_Omega();
--- a/src/Bullet.cpp
+++ b/src/Bullet.cpp
@@ -1,6 +1,8 @@
 #include "Bullet.h"
 #include "Draw.h"
 #include "Caret.h"
+#include "NpChar.h"
+#include "Game.h"
 
 BULLET_TABLE gBulTbl[46] =
 {
@@ -264,6 +266,96 @@
 	}
 }
 
+void ActBullet_MachineGun(BULLET *bul, int level)
+{
+	RECT rect1[4];
+	RECT rect2[4];
+	RECT rect3[4];
+	
+	rect1[0] = {64, 0, 80, 16};
+	rect1[1] = {80, 0, 96, 16};
+	rect1[2] = {96, 0, 112, 16};
+	rect1[3] = {112, 0, 128, 16};
+	rect2[0] = {64, 16, 80, 32};
+	rect2[1] = {80, 16, 96, 32};
+	rect2[2] = {96, 16, 112, 32};
+	rect2[3] = {112, 16, 128, 32};
+	rect3[0] = {64, 32, 80, 48};
+	rect3[1] = {80, 32, 96, 48};
+	rect3[2] = {96, 32, 112, 48};
+	rect3[3] = {112, 32, 128, 48};
+	
+	if (++bul->count1 <= bul->life_count)
+	{
+		if (bul->act_no)
+		{
+			bul->x += bul->xm;
+			bul->y += bul->ym;
+			
+			switch ( level )
+			{
+				case 1:
+					bul->rect = rect1[bul->direct];
+					break;
+				case 2:
+					bul->rect = rect2[bul->direct];
+					if (bul->direct != 1 && bul->direct != 3)
+						SetNpChar(127, bul->x, bul->y, 0, 0, 0, 0, 256);
+					else
+						SetNpChar(127, bul->x, bul->y, 0, 0, 1, 0, 256);
+					break;
+				case 3:
+					bul->rect = rect3[bul->direct];
+					SetNpChar(128, bul->x, bul->y, 0, 0, bul->direct, 0, 256);
+					break;
+			}
+		}
+		else
+		{
+			int move;
+			switch (level)
+			{
+				case 1:
+					move = 0x1000;
+					break;
+				case 2:
+					move = 0x1000;
+					break;
+				case 3:
+					move = 0x1000;
+					break;
+			}
+			
+			bul->act_no = 1;
+			
+			switch (bul->direct)
+			{
+				case 0:
+					bul->xm = -move;
+					bul->ym = Random(-0xAA, 0xAA);
+					break;
+				case 1:
+					bul->xm = Random(-0xAA, 0xAA);
+					bul->ym = -move;
+					break;
+				case 2:
+					bul->xm = move;
+					bul->ym = Random(-0xAA, 0xAA);
+					break;
+				case 3:
+					bul->xm = Random(-0xAA, 0xAA);
+					bul->ym = move;
+					break;
+			}
+		}
+	}
+	else
+	{
+		bul->cond = 0;
+		SetCaret(bul->x, bul->y, 3, 0);
+	}
+}
+
 void ActBullet()
 {
 	for (int i = 0; i < BULLET_MAX; i++)
@@ -282,6 +374,15 @@
 						break;
 					case 6:
 						ActBullet_PoleStar(&gBul[i], 3);
+						break;
+					case 10:
+						ActBullet_MachineGun(&gBul[i], 1);
+						break;
+					case 11:
+						ActBullet_MachineGun(&gBul[i], 2);
+						break;
+					case 12:
+						ActBullet_MachineGun(&gBul[i], 3);
 						break;
 				}
 			}
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -10,6 +10,7 @@
 #include "NpcHit.h"
 #include "MiniMap.h"
 #include "Generic.h"
+#include "Boss.h"
 #include "GenericLoad.h"
 #include "ArmsItem.h"
 #include "TextScr.h"
@@ -142,15 +143,15 @@
 		
 		//Update everything
 		ActNpChar();
-		//ActBossChar();
+		ActBossChar();
 		ActBack();
 		ResetMyCharFlag();
 		HitMyCharMap();
 		HitMyCharNpChar();
-		//HitMyCharBoss();
+		HitMyCharBoss();
 		HitNpCharMap();
-		//HitBossMap();
-		//HitBossBullet();
+		HitBossMap();
+		HitBossBullet();
 		ActCaret();
 		MoveFrame3();
 		ProcFade();
@@ -162,7 +163,7 @@
 		GetFramePosition(&frame_x, &frame_y);
 		PutBack(frame_x, frame_y);
 		PutStage_Back(frame_x, frame_y);
-		//PutBossChar(frame_x, frame_y);
+		PutBossChar(frame_x, frame_y);
 		PutNpChar(frame_x, frame_y);
 		PutMapDataVector(frame_x, frame_y);
 		PutStage_Front(frame_x, frame_y);
@@ -471,18 +472,18 @@
 				
 				//ActStar();
 				ActNpChar();
-				//ActBossChar();
+				ActBossChar();
 				ActValueView();
 				ActBack();
 				ResetMyCharFlag();
 				HitMyCharMap();
 				HitMyCharNpChar();
-				//HitMyCharBoss();
+				HitMyCharBoss();
 				HitNpCharMap();
-				//HitBossMap();
+				HitBossMap();
 				HitBulletMap();
 				HitNpCharBullet();
-				//HitBossBullet();
+				HitBossBullet();
 				if (g_GameFlags & 2)
 					ShootBullet();
 				ActBullet();
@@ -508,7 +509,7 @@
 			GetFramePosition(&frame_x, &frame_y);
 			PutBack(frame_x, frame_y);
 			PutStage_Back(frame_x, frame_y);
-			//PutBossChar(frame_x, frame_y);
+			PutBossChar(frame_x, frame_y);
 			PutNpChar(frame_x, frame_y);
 			PutBullet(frame_x, frame_y);
 			PutMyChar(frame_x, frame_y);
--- a/src/MyChar.h
+++ b/src/MyChar.h
@@ -40,9 +40,9 @@
 	int lifeBr_count;
 	int air;
 	int air_get;
-	char sprash;
-	char ques;
-	char boost_sw;
+	int8_t sprash;
+	int8_t ques;
+	int8_t boost_sw;
 	int boost_cnt;
 };
 
--- a/src/MycHit.cpp
+++ b/src/MycHit.cpp
@@ -7,6 +7,7 @@
 #include "Map.h"
 #include "Sound.h"
 #include "Caret.h"
+#include "Boss.h"
 #include "Back.h"
 #include "Game.h"
 #include "TextScr.h"
@@ -434,6 +435,11 @@
 				gMC.flag |= JudgeHitMyCharBlock(x + offx[i], y + offy[i]);
 				break;
 				
+			//Spikes
+			case 0x42u:
+				gMC.flag |= JudgeHitMyCharDamage(x + offx[i], y + offy[i]);
+				break;
+				
 			//Slopes
 			case 0x50:
 				gMC.flag |= JudgeHitMyCharTriangleA(x + offx[i], y + offy[i]);
@@ -477,7 +483,7 @@
 				gMC.flag |= JudgeHitMyCharWater(x + offx[i], y + offy[i]);
 				break;
 			
-			//Spikes
+			//Water spikes
 			case 0x62:
 				gMC.flag |= JudgeHitMyCharDamageW(x + offx[i], y + offy[i]);
 				break;
@@ -777,7 +783,7 @@
 				if (hit && gNPC[i].code_char == 86)
 				{
 					PlaySoundObject(42, 1);
-					//AddBulletMyChar(gNPC[i].code_event, gNPC[i].exp);
+					AddBulletMyChar(gNPC[i].code_event, gNPC[i].exp);
 					gNPC[i].cond = 0;
 				}
 				
@@ -823,6 +829,62 @@
 		}
 		
 		//Create question mark when NPC hasn't been interacted with
+		if (gMC.ques)
+			SetCaret(gMC.x, gMC.y, 9, 0);
+	}
+}
+
+void HitMyCharBoss()
+{
+	if ((gMC.cond & 0x80) && !(gMC.cond & 2))
+	{
+		for (int b = 0; b < BOSS_MAX; b++)
+		{
+			if (gBoss[b].cond & 0x80)
+			{
+				int hit;
+				if (gBoss[b].bits & npc_solidSoft)
+				{
+					hit = JudgeHitMyCharNPC(&gBoss[b]);
+					gMC.flag |= hit;
+				}
+				else if (gBoss[b].bits & npc_solidHard)
+				{
+					hit = JudgeHitMyCharNPC4(&gBoss[b]);
+					gMC.flag |= hit;
+				}
+				else
+				{
+					hit = JudgeHitMyCharNPC3(&gBoss[b]);
+				}
+				
+				if (!(g_GameFlags & 4) && hit && gBoss[b].bits & npc_eventTouch)
+				{
+					StartTextScript(gBoss[b].code_event);
+					gMC.ques = 0;
+				}
+				
+				if (gBoss[b].bits & npc_rearTop)
+				{
+					if (hit & 4 && gBoss[b].xm < 0)
+						DamageMyChar(gBoss[b].damage);
+					if (hit & 1 && gBoss[b].xm > 0)
+						DamageMyChar(gBoss[b].damage);
+				}
+				else if (hit && gBoss[b].damage && !(g_GameFlags & 4))
+				{
+					DamageMyChar(gBoss[b].damage);
+				}
+				
+				if (!(g_GameFlags & 4) && hit && (gMC.cond & 1) && gBoss[b].bits & npc_interact)
+				{
+					StartTextScript(gBoss[b].code_event);
+					gMC.xm = 0;
+					gMC.ques = 0;
+				}
+			}
+		}
+		
 		if (gMC.ques)
 			SetCaret(gMC.x, gMC.y, 9, 0);
 	}
--- a/src/MycHit.h
+++ b/src/MycHit.h
@@ -2,3 +2,4 @@
 void ResetMyCharFlag();
 void HitMyCharMap();
 void HitMyCharNpChar();
+void HitMyCharBoss();
--- a/src/NpChar.cpp
+++ b/src/NpChar.cpp
@@ -17,7 +17,9 @@
 #include "Draw.h"
 
 NPCHAR gNPC[NPC_MAX];
-
+int gCurlyShoot_wait;
+int gCurlyShoot_x;
+int gCurlyShoot_y;
 int gSuperXpos;
 int gSuperYpos;
 
--- a/src/NpChar.h
+++ b/src/NpChar.h
@@ -72,7 +72,9 @@
 };
 
 extern NPCHAR gNPC[NPC_MAX];
-
+extern int gCurlyShoot_wait;
+extern int gCurlyShoot_x;
+extern int gCurlyShoot_y;
 extern int gSuperXpos;
 extern int gSuperYpos;
 
--- a/src/NpcAct.h
+++ b/src/NpcAct.h
@@ -47,6 +47,8 @@
 
 void ActNpc046(NPCHAR *npc);
 
+void ActNpc048(NPCHAR *npc);
+
 void ActNpc058(NPCHAR *npc);
 void ActNpc059(NPCHAR *npc);
 void ActNpc060(NPCHAR *npc);
@@ -88,6 +90,9 @@
 void ActNpc119(NPCHAR *npc);
 
 void ActNpc125(NPCHAR *npc);
+
+void ActNpc127(NPCHAR *npc);
+void ActNpc128(NPCHAR *npc);
 
 void ActNpc145(NPCHAR *npc);
 
--- a/src/NpcAct040.cpp
+++ b/src/NpcAct040.cpp
@@ -5,6 +5,7 @@
 #include "MyChar.h"
 #include "NpChar.h"
 #include "Game.h"
+#include "Caret.h"
 #include "Sound.h"
 #include "Back.h"
 #include "Triangle.h"
@@ -355,6 +356,66 @@
 	}
 
 	npc->rect = rect[0];
+}
+
+//Omega projectiles
+void ActNpc048(NPCHAR *npc)
+{
+	if (npc->flag & 1 && npc->xm < 0)
+	{
+		npc->xm = -npc->xm;
+	}
+	else if (npc->flag & 4 && npc->xm > 0)
+	{
+		npc->xm = -npc->xm;
+	}
+	else if (npc->flag & 8)
+	{
+		if (++npc->count1 <= 2 && npc->direct != 2)
+		{
+			npc->ym = -0x100;
+		}
+		else
+		{
+			VanishNpChar(npc);
+			SetCaret(npc->x, npc->y, 2, 0);
+		}
+	}
+	
+	if (npc->direct == 2)
+	{
+		npc->bits &= ~npc_shootable;
+		npc->bits |= npc_invulnerable;
+	}
+	
+	npc->ym += 5;
+	npc->y += npc->ym;
+	npc->x += npc->xm;
+	
+	RECT rcLeft[2];
+	RECT rcRight[2];
+	rcLeft[0] = {288, 88, 304, 104};
+	rcLeft[1] = {304, 88, 320, 104};
+	rcRight[0] = {288, 104, 304, 120};
+	rcRight[1] = {304, 104, 320, 120};
+	
+	if (++npc->ani_wait > 2)
+	{
+		npc->ani_wait = 0;
+		if (++npc->ani_no > 1)
+			npc->ani_no = 0;
+	}
+	
+	if (++npc->act_wait > 750)
+	{
+		SetCaret(npc->x, npc->y, 2, 0);
+		npc->cond = 0;
+	}
+	
+	if (npc->direct)
+		npc->rect = rcRight[npc->ani_no];
+	else
+		npc->rect = rcLeft[npc->ani_no];
 }
 
 //Basu (Egg Corridor)
--- a/src/NpcAct120.cpp
+++ b/src/NpcAct120.cpp
@@ -35,3 +35,93 @@
 	else
 		npc->rect = rc[1];
 }
+
+//Machine gun trail (Level 2)
+void ActNpc127(NPCHAR *npc)
+{
+	RECT rcV[3];
+	RECT rcH[3];
+	rcV[0] = {112, 48, 128, 64};
+	rcV[1] = {112, 64, 128, 80};
+	rcV[2] = {112, 80, 128, 96};
+	rcH[0] = {64, 80, 80, 96};
+	rcH[1] = {80, 80, 96, 96};
+	rcH[2] = {96, 80, 112, 96};
+	
+	if (++npc->ani_wait > 0)
+	{
+		npc->ani_wait = 0;
+		if (++npc->ani_no > 2)
+			npc->cond = 0;
+	}
+	
+	if (npc->direct)
+		npc->rect = rcV[npc->ani_no];
+	else
+		npc->rect = rcH[npc->ani_no];
+}
+
+//Machine gun trail (Level 3)
+void ActNpc128(NPCHAR *npc)
+{
+	RECT rcLeft[5];
+	RECT rcRight[5];
+	RECT rcUp[5];
+	RECT rcDown[5];
+
+	rcLeft[0] = {0, 0, 0, 0};
+	rcLeft[1] = {176, 16, 184, 32};
+	rcLeft[2] = {184, 16, 192, 32};
+	rcLeft[3] = {192, 16, 200, 32};
+	rcLeft[4] = {200, 16, 208, 32};
+	rcRight[0] = {0, 0, 0, 0};
+	rcRight[1] = {232, 16, 240, 32};
+	rcRight[2] = {224, 16, 232, 32};
+	rcRight[3] = {216, 16, 224, 32};
+	rcRight[4] = {208, 16, 216, 32};
+	rcUp[0] = {0, 0, 0, 0};
+	rcUp[1] = {176, 32, 192, 40};
+	rcUp[2] = {176, 40, 192, 48};
+	rcUp[3] = {192, 32, 208, 40};
+	rcUp[4] = {192, 40, 208, 48};
+	rcDown[0] = {0, 0, 0, 0};
+	rcDown[1] = {208, 32, 224, 40};
+	rcDown[2] = {208, 40, 224, 48};
+	rcDown[3] = {224, 32, 232, 40};
+	rcDown[4] = {224, 40, 232, 48};
+	
+	if (!npc->act_no)
+	{
+		npc->act_no = 1;
+		
+		if (npc->direct && npc->direct != 2)
+		{
+			npc->view.front = 0x1000;
+			npc->view.top = 0x800;
+		}
+		else
+		{
+			npc->view.front = 0x800;
+			npc->view.top = 0x1000;
+		}
+	}
+	
+	if (++npc->ani_no > 4)
+		npc->cond = 0;
+	
+	switch (npc->direct)
+	{
+		case 0:
+			npc->rect = rcLeft[npc->ani_no];
+			break;
+		case 1:
+			npc->rect = rcUp[npc->ani_no];
+			break;
+		case 2:
+			npc->rect = rcRight[npc->ani_no];
+			break;
+		case 3:
+			npc->rect = rcDown[npc->ani_no];
+			break;
+	}
+}
\ No newline at end of file
--- a/src/NpcHit.h
+++ b/src/NpcHit.h
@@ -1,5 +1,15 @@
 #pragma once
 #include "NpChar.h"
 
+void JadgeHitNpCharBlock(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleA(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleB(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleC(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleD(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleE(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleF(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleG(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharTriangleH(NPCHAR *npc, int x, int y);
+void JudgeHitNpCharWater(NPCHAR *npc, int x, int y);
 void HitNpCharMap();
 void HitNpCharBullet();
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -104,6 +104,7 @@
 	nullptr,
 	ActNpc046,
 	nullptr,
+	ActNpc048,
 	nullptr,
 	nullptr,
 	nullptr,
@@ -113,7 +114,6 @@
 	nullptr,
 	nullptr,
 	nullptr,
-	nullptr,
 	ActNpc058,
 	ActNpc059,
 	ActNpc060,
@@ -183,8 +183,8 @@
 	nullptr,
 	ActNpc125,
 	nullptr,
-	nullptr,
-	nullptr,
+	ActNpc127,
+	ActNpc128,
 	nullptr,
 	nullptr,
 	nullptr,
--- a/src/Profile.cpp
+++ b/src/Profile.cpp
@@ -11,6 +11,7 @@
 #include "Flags.h"
 #include "MiniMap.h"
 #include "MyChar.h"
+#include "NpChar.h"
 #include "Frame.h"
 #include "SelStage.h"
 #include "ValueView.h"
@@ -39,7 +40,8 @@
 {
 	//Get path
 	char path[PATH_LENGTH];
-	if ( name )
+	
+	if (name)
 		sprintf(path, "%s/%s", gModulePath, name);
 	else
 		sprintf(path, "%s/%s", gModulePath, gDefaultName);
@@ -115,9 +117,9 @@
 
 bool LoadProfile(char *name)
 {
+	//Get path
 	char path[PATH_LENGTH];
 	
-	//Get path
 	if (name)
 		strcpy(path, name);
 	else
@@ -215,7 +217,7 @@
 	CutNoise();
 	//InitStar();
 	ClearValueView();
-	//gCurlyShoot_wait = 0;
+	gCurlyShoot_wait = 0;
 	return true;
 }
 
@@ -238,7 +240,7 @@
 	InitBossLife();
 	CutNoise();
 	ClearValueView();
-	//gCurlyShoot_wait = 0;
+	gCurlyShoot_wait = 0;
 	SetFadeMask();
 	SetFrameTargetMyChar(16);
 	return true;
--- a/src/Shoot.cpp
+++ b/src/Shoot.cpp
@@ -82,6 +82,132 @@
 	}
 }
 
+void ShootBullet_Machinegun1(int level)
+{
+	if (CountArmsBullet(4) < 5)
+	{
+		int bul_no;
+		switch (level)
+		{
+			case 1:
+				bul_no = 10;
+				break;
+			case 2:
+				bul_no = 11;
+				break;
+			case 3:
+				bul_no = 12;
+				break;
+		}
+		
+		if (!(gKey & gKeyShot))
+			gMC.rensha = 6;
+		
+		if (gKey & gKeyShot)
+		{
+			if (++gMC.rensha > 6)
+			{
+				gMC.rensha = 0;
+				if (!UseArmsEnergy(1))
+				{
+					PlaySoundObject(37, 1);
+					
+					if (!empty)
+					{
+						SetCaret(gMC.x, gMC.y, 16, 0);
+						empty = 50;
+					}
+				}
+				else
+				{
+					if (gMC.up)
+					{
+						if (level == 3)
+							gMC.ym += 0x100;
+					
+						if (gMC.direct)
+						{
+							SetBullet(bul_no, gMC.x + 0x600, gMC.y - 0x1000, 1);
+							SetCaret(gMC.x + 0x600, gMC.y - 0x1000, 3, 0);
+						}
+						else
+						{
+							SetBullet(bul_no, gMC.x - 0x600, gMC.y - 0x1000, 1);
+							SetCaret(gMC.x - 0x600, gMC.y - 0x1000, 3, 0);
+						}
+					}
+					else if (gMC.down)
+					{
+						if (level == 3)
+						{
+							if (gMC.ym > 0)
+								gMC.ym /= 2;
+							
+							if (gMC.ym > -0x400)
+							{
+								gMC.ym -= 0x200;
+								if (gMC.ym < -0x400)
+									gMC.ym = -0x400;
+							}
+						}
+						
+						if (gMC.direct)
+						{
+							SetBullet(bul_no, gMC.x + 0x600, gMC.y + 0x1000, 3);
+							SetCaret(gMC.x + 0x600, gMC.y + 0x1000, 3, 0);
+						}
+						else
+						{
+							SetBullet(bul_no, gMC.x - 0x600, gMC.y + 0x1000, 3);
+							SetCaret(gMC.x - 0x600, gMC.y + 0x1000, 3, 0);
+						}
+					}
+					else
+					{
+						if (gMC.direct)
+						{
+							SetBullet(bul_no, gMC.x + 0x1800, gMC.y + 0x600, 2);
+							SetCaret(gMC.x + 0x1800, gMC.y + 0x600, 3, 0);
+						}
+						else
+						{
+							SetBullet(bul_no, gMC.x - 0x1800, gMC.y + 0x600, 0);
+							SetCaret(gMC.x - 0x1800, gMC.y + 0x600, 3, 0);
+						}
+					}
+					
+					if (level == 3)
+						PlaySoundObject(49, 1);
+					else
+						PlaySoundObject(32, 1);
+				}
+			}
+		}
+		else
+		{
+			static int wait = 0;
+			
+			++wait;
+			if (gMC.equip & 8)
+			{
+				if (wait > 1)
+				{
+					wait = 0;
+					ChargeArmsEnergy(1);
+				}
+			}
+			else 
+			{
+				if (wait > 4)
+				{
+					wait = 0;
+					ChargeArmsEnergy(1);
+				}
+			}
+		}
+	}
+}
+
 void ShootBullet()
 {
 	if (empty)
@@ -106,6 +232,9 @@
 		{
 			case 2:
 				ShootBullet_PoleStar(gArmsData[gSelectedArms].level);
+				break;
+			case 4:
+				ShootBullet_Machinegun1(gArmsData[gSelectedArms].level);
 				break;
 		}
 	}
--- a/src/Stage.cpp
+++ b/src/Stage.cpp
@@ -8,6 +8,7 @@
 #include "Map.h"
 #include "MapName.h"
 #include "MyChar.h"
+#include "Boss.h"
 #include "Draw.h"
 #include "Tags.h"
 #include "Frame.h"
@@ -195,7 +196,7 @@
 		InitCaret();
 		ClearValueView();
 		ResetQuake();
-		//InitBossChar(gTMT[no].boss_no);
+		InitBossChar(gTMT[no].boss_no);
 		ResetFlash();
 		gStageNo = no;
 		return true;
--- a/src/TextScr.cpp
+++ b/src/TextScr.cpp
@@ -17,6 +17,7 @@
 #include "Profile.h"
 #include "Map.h"
 #include "MiniMap.h"
+#include "Boss.h"
 #include "MapName.h"
 #include "KeyControl.h"
 #include "NpChar.h"
@@ -1032,6 +1033,12 @@
 					{
 						z = GetTextScriptNo(gTS.p_read + 4);
 						DeleteNpCharCode(z, 1);
+						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('B','O','A'))
+					{
+						z = GetTextScriptNo(gTS.p_read + 4);
+						SetBossCharActNo(z);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('C','N','P'))