shithub: cstory

Download patch

ref: 1e7b07a102253b4fb0a2fd0f66acc1043c545619
parent: b29f119f3dcd9d674e87cefe6c51a0100839c828
author: cuckydev <cuckydev@users.noreply.github.com>
date: Mon Jan 28 07:26:35 EST 2019

working on arms and items

--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@
 
 # For an accurate result to the original's code, compile in alphabetical order
 SOURCES = \
+	ArmsItem \
 	Back \
 	Caret \
 	Config \
--- /dev/null
+++ b/src/ArmsItem.cpp
@@ -1,0 +1,302 @@
+#include <string.h>
+
+#include "CommonDefines.h"
+#include "TextScr.h"
+#include "ArmsItem.h"
+#include "Draw.h"
+#include "KeyControl.h"
+#include "Escape.h"
+#include "Sound.h"
+#include "Main.h"
+#include "Game.h"
+
+int gArmsEnergyX = 16;
+
+ARMS gArmsData[ARMS_MAX];
+ITEM gItemData[ITEM_MAX];
+int gSelectedArms;
+int gSelectedItem;
+int gCampTitleY;
+int gCampActive;
+
+void ClearArmsData()
+{
+	gArmsEnergyX = 32;
+	memset(gArmsData, 0, sizeof(gArmsData));
+}
+
+void ClearItemData()
+{
+	memset(gItemData, 0, sizeof(gItemData));
+}
+
+bool AddArmsData(int code, int max_num)
+{
+	for (int i = 0; i < ARMS_MAX; i++)
+	{
+		if (gArmsData[i].code == code || !gArmsData[i].code)
+		{
+			if (!gArmsData[i].code)
+			{
+				memset(&gArmsData[i], 0, sizeof(ARMS));
+				gArmsData[i].level = 1;
+			}
+			
+			gArmsData[i].code = code;
+			gArmsData[i].max_num += max_num;
+			gArmsData[i].num += max_num;
+			if (gArmsData[i].num > gArmsData[i].max_num)
+				gArmsData[i].num = gArmsData[i].max_num;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool SubArmsData(int code)
+{
+	for (int i = 0; i < ARMS_MAX; i++)
+	{
+		if (gArmsData[i].code == code)
+		{
+			//Shift all arms from the right to the left
+			int ia;
+			for (ia = i + 1; ia < ARMS_MAX; ++ia)
+			{
+				gArmsData[ia - 1].code = gArmsData[ia].code;
+				gArmsData[ia - 1].level = gArmsData[ia].level;
+				gArmsData[ia - 1].exp = gArmsData[ia].exp;
+				gArmsData[ia - 1].max_num = gArmsData[ia].max_num;
+				gArmsData[ia - 1].num = gArmsData[ia].num;
+			}
+			
+			gArmsData[ia - 1].code = 0;
+			gSelectedArms = 0;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool TradeArms(int code1, int code2, int max_num)
+{
+	for (int i = 0; i < ARMS_MAX; i++)
+	{
+		if (gArmsData[i].code == code1)
+		{
+			gArmsData[i].level = 1;
+			gArmsData[i].code = code2;
+			gArmsData[i].max_num += max_num;
+			gArmsData[i].num += max_num;
+			gArmsData[i].exp = 0;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool AddItemData(int code)
+{
+	for (int i = 0; i < ITEM_MAX; i++)
+	{
+		if (gItemData[i].code == code || !gItemData[i].code)
+		{
+			gItemData[i].code = code;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool SubItemData(int code)
+{
+	for (int i = 0; i < ITEM_MAX; i++)
+	{
+		if (gItemData[i].code == code)
+		{
+			//Shift all items from the right to the left
+			int ia;
+			for (ia = i + 1; ia < ITEM_MAX; ++ia)
+				gItemData[ia - 1].code = gItemData[ia].code;
+			
+			gItemData[ia - 1].code = 0;
+			gSelectedItem = 0;
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+int CampLoop()
+{
+	RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
+	
+	//Load the inventory script
+	char old_script_path[PATH_LENGTH];
+	GetTextScriptPath(old_script_path);
+	
+	char name[13];
+	strcpy(name, "ArmsItem.tsc");
+	LoadTextScript2(name);
+	
+	gCampTitleY = 24;
+	gCampActive = 0;
+	gSelectedItem = 0;
+	
+	//Run script
+	int arms_num;
+	for (arms_num = 0; gArmsData[arms_num].code != 0; arms_num++);
+	
+	if (arms_num)
+		StartTextScript(gArmsData[gSelectedArms].code + 1000);
+	else
+		StartTextScript(gItemData[gSelectedItem].code + 5000);
+	
+	while (true)
+	{
+		GetTrg();
+		
+		if (gKeyTrg & KEY_ESCAPE)
+		{
+			int escRet = Call_Escape();
+			if (escRet == 0)
+				return 0;
+			if (escRet == 2)
+				return 1;
+		}
+		
+		//if (g_GameFlags & 2)
+		//	MoveCampCursor();
+		
+		int tscRet = TextScriptProc();
+		if (tscRet == 0)
+			return 0;
+		if (tscRet == 2)
+			return 2;
+		
+		PutBitmap4(&rcView, 0, 0, &rcView, 10);
+		//PutCampObject();
+		PutTextScript();
+		PutFramePerSecound();
+		
+		if (!gCampActive && (gKeyItem | gKeyCancel | gKeyOk) & gKeyTrg)
+			break;
+		
+		if (g_GameFlags & 2 && (gKeyItem | gKeyCancel) & gKeyTrg)
+			break;
+		
+		if (!Flip_SystemTask())
+			return 0;
+	}
+	
+	//Resume original script
+	StopTextScript();
+	LoadTextScript_Stage(old_script_path);
+	gArmsEnergyX = 32;
+	return 1;
+}
+
+bool CheckItem(int a)
+{
+	for (int i = 0; i < ITEM_MAX; i++)
+	{
+		if (gItemData[i].code == a)
+			return true;
+	}
+	
+	return false;
+}
+
+bool CheckArms(int a)
+{
+  for (int i = 0; i < ARMS_MAX; i++)
+	{
+		if (gArmsData[i].code == a)
+			return true;
+	}
+	
+	return false;
+}
+
+bool UseArmsEnergy(int num)
+{
+	if (!gArmsData[gSelectedArms].max_num)
+		return true;
+	if (!gArmsData[gSelectedArms].num)
+		return false;
+	gArmsData[gSelectedArms].num -= num;
+	if (gArmsData[gSelectedArms].num < 0)
+		gArmsData[gSelectedArms].num = 0;
+	return true;
+}
+
+bool ChargeArmsEnergy(int num)
+{
+	gArmsData[gSelectedArms].num += num;
+	if (gArmsData[gSelectedArms].num > gArmsData[gSelectedArms].max_num)
+		gArmsData[gSelectedArms].num = gArmsData[gSelectedArms].max_num;
+	return true;
+}
+
+void FullArmsEnergy()
+{
+	for (int a = 0; a < ARMS_MAX; a++)
+	{
+		if (gArmsData[a].code)
+			gArmsData[a].num = gArmsData[a].max_num;
+	}
+}
+
+int RotationArms()
+{
+	int arms_num;
+	for ( arms_num = 0; gArmsData[arms_num].code != 0; arms_num++);
+	if (!arms_num)
+		return 0;
+	
+	//ResetSpurCharge();
+	
+	++gSelectedArms;
+	while (gSelectedArms < arms_num && !gArmsData[gSelectedArms].code)
+		++gSelectedArms;
+	
+	if (gSelectedArms == arms_num)
+		gSelectedArms = 0;
+	
+	gArmsEnergyX = 32;
+	PlaySoundObject(4, 1);
+	
+	return gArmsData[gSelectedArms].code;
+}
+
+int RotationArmsRev()
+{
+	int arms_num;
+	for (arms_num = 0; gArmsData[arms_num].code != 0; arms_num++);
+	if (!arms_num)
+		return 0;
+	
+	//ResetSpurCharge();
+	
+	if (--gSelectedArms < 0)
+		gSelectedArms = arms_num - 1;
+	while (gSelectedArms < arms_num && !gArmsData[gSelectedArms].code)
+		--gSelectedArms;
+	
+	gArmsEnergyX = 0;
+	PlaySoundObject(4, 1);
+	
+	return gArmsData[gSelectedArms].code;
+}
+
+void ChangeToFirstArms()
+{
+	gSelectedArms = 0;
+	gArmsEnergyX = 32;
+	PlaySoundObject(4, 1);
+}
\ No newline at end of file
--- /dev/null
+++ b/src/ArmsItem.h
@@ -1,0 +1,46 @@
+#pragma once
+struct ARMS
+{
+	int code;
+	int level;
+	int exp;
+	int max_num;
+	int num;
+};
+
+struct ITEM
+{
+	int code;
+};
+
+#define ARMS_MAX 8
+#define ITEM_MAX 32
+
+extern int gArmsEnergyX;
+
+extern int gSelectedArms;
+extern int gSelectedItem;
+
+extern ARMS gArmsData[ARMS_MAX];
+extern ITEM gItemData[ITEM_MAX];
+extern int gSelectedArms;
+extern int gSelectedItem;
+extern int gCampTitleY;
+extern int gCampActive;
+
+void ClearArmsData();
+void ClearItemData();
+bool AddArmsData(int code, int max_num);
+bool SubArmsData(int code);
+bool TradeArms(int code1, int code2, int max_num);
+bool AddItemData(int code);
+bool SubItemData(int code);
+int CampLoop();
+bool CheckItem(int a);
+bool CheckArms(int a);
+bool UseArmsEnergy(int num);
+bool ChargeArmsEnergy(int num);
+void FullArmsEnergy();
+int RotationArms();
+int RotationArmsRev();
+void ChangeToFirstArms();
--- a/src/Caret.cpp
+++ b/src/Caret.cpp
@@ -58,6 +58,14 @@
 		crt->rect = rcLeft[crt->ani_no];
 }
 
+void ActCaret08(CARET *crt)
+{
+	if (crt->direct)
+		crt->rect = {32, 80, 48, 96};
+	else
+		crt->rect = {16, 80, 32, 96};
+}
+
 void ActCaret09(CARET *crt)
 {
 	if (++crt->ani_wait <= 4)
@@ -138,8 +146,8 @@
 typedef void (*CARETFUNCTION)(CARET*);
 CARETFUNCTION gpCaretFuncTbl[] =
 {
-	&ActCaret00,
-	&ActCaret01,
+	ActCaret00,
+	ActCaret01,
 	nullptr, //&ActCaret02,
 	nullptr, //&ActCaret03,
 	nullptr, //&ActCaret04,
@@ -146,12 +154,12 @@
 	nullptr, //&ActCaret05,
 	nullptr, //&ActCaret04,
 	nullptr, //&ActCaret07,
-	nullptr, //&ActCaret08,
-	&ActCaret09,
+	ActCaret08,
+	ActCaret09,
 	nullptr, //&ActCaret10,
 	nullptr, //&ActCaret11,
 	nullptr, //&ActCaret12,
-	&ActCaret13,
+	ActCaret13,
 	nullptr, //&ActCaret14,
 	nullptr, //&ActCaret15,
 	nullptr, //&ActCaret16,
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -243,14 +243,30 @@
 	SDL_FreeSurface(surface);
 	
 	//Get rects
-	SDL_Rect frameRect = {0, 0, frameRect.w, frameRect.h};
-	SDL_Rect destRect = RectToSDLRect(rect);
+	SDL_Rect frameRect = RectToSDLRect(rect);
+	frameRect = {frameRect.x * gWindowScale, frameRect.y * gWindowScale, frameRect.w * gWindowScale, frameRect.h * gWindowScale};
 	
-	//Draw texture onto surface
-	SDL_SetRenderTarget(gRenderer, surf[surf_no].texture);
-	SDL_RenderCopy(gRenderer, screenTexture, &frameRect, &destRect);
+	SDL_Texture *textureAccessible = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, frameRect.w, frameRect.h);
+	
+	if (!textureAccessible)
+	{
+		printf("Failed to create real texture for surface id %d\nSDL Error: %s\n", surf_no, SDL_GetError());
+		return;
+	}
+	
+	SDL_SetTextureBlendMode(textureAccessible, SDL_BLENDMODE_BLEND);
+	
+	SDL_SetRenderTarget(gRenderer, textureAccessible);
+	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
+	SDL_RenderClear(gRenderer);
+	SDL_RenderCopy(gRenderer, screenTexture, &frameRect, NULL);
+	SDL_RenderPresent(gRenderer);
 	SDL_SetRenderTarget(gRenderer, NULL);
-
+	
+	//Set surface's metadata
+	surf[surf_no].texture = textureAccessible;
+	
+	//Free stuff
 	SDL_DestroyTexture(screenTexture);
 }
 
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -10,6 +10,7 @@
 #include "NpcHit.h"
 #include "Generic.h"
 #include "GenericLoad.h"
+#include "ArmsItem.h"
 #include "TextScr.h"
 #include "Fade.h"
 #include "Frame.h"
@@ -25,6 +26,7 @@
 #include "Sound.h"
 #include "Organya.h"
 #include "Profile.h"
+#include "MycParam.h"
 #include "Back.h"
 #include "KeyControl.h"
 #include "ValueView.h"
@@ -278,16 +280,11 @@
 			break;
 	}
 	
-	//Reset cliprect, flags, and give the player the booster 0.8?
+	//Reset cliprect, flags, and give the player the nikumaru counter
 	grcGame.left = 0;
 	g_GameFlags = 0;
+	gMC.equip & 0x100;
 	
-	/*
-	v0 = unk_81C8598;
-	BYTE1(v0) |= 1u;
-	unk_81C8598 = v0;
-	*/
-	
 	//Start loop
 	int wait = 0;
 	
@@ -434,8 +431,8 @@
 	//InitStar();
 	InitFade();
 	//InitFlash();
-	//ClearArmsData();
-	//ClearItemData();
+	ClearArmsData();
+	ClearItemData();
 	//ClearPermitStage();
 	//StartMapping();
 	InitFlags();
@@ -518,6 +515,41 @@
 			//PutBossLife();
 			PutFade();
 			
+			if (!(g_GameFlags & 4))
+			{
+				//Open inventory
+				if (gKeyTrg & gKeyItem)
+				{
+					BackupSurface(10, &grcGame);
+					
+					int campRet = CampLoop();
+					if (campRet == 0)
+						return 0;
+					if (campRet == 2)
+						return 1;
+					gMC.cond &= ~1;
+				}
+				/*
+				else if ( unk_81C8598 & 2 && gKeyTrg & gKeyMap )
+				{
+				BackupSurface(10, &grcGame);
+				v3 = MiniMapLoop();
+				if ( !v3 )
+				return 0;
+				if ( v3 == 2 )
+				return 1;
+				}
+				*/
+			}
+			
+			if (g_GameFlags & 2)
+			{
+				if (gKeyTrg & gKeyArms)
+					RotationArms();
+				else if (gKeyTrg & gKeyArmsRev)
+					RotationArmsRev();
+			}
+
 			if (swPlay & 1)
 			{
 				int tscRet = TextScriptProc();
@@ -528,6 +560,14 @@
 			}
 			
 			PutMapName(false);
+			
+			if (g_GameFlags & 2)
+			{
+				PutMyLife(true);
+				PutArmsEnergy(true);
+				PutMyAir((WINDOW_WIDTH - 80) / 2, (WINDOW_HEIGHT - 32) / 2);
+				PutActiveArmsList();
+			}
 			
 			if (g_GameFlags & 8)
 			{
--- a/src/MyChar.cpp
+++ b/src/MyChar.cpp
@@ -5,10 +5,14 @@
 
 #include "MyChar.h"
 #include "MycParam.h"
+#include "ArmsItem.h"
 #include "NpChar.h"
 #include "Draw.h"
 #include "Sound.h"
+#include "ValueView.h"
 #include "KeyControl.h"
+#include "TextScr.h"
+#include "Flags.h"
 #include "Game.h"
 #include "Caret.h"
 
@@ -147,9 +151,9 @@
 	if ((gMC.cond & 0x80u) && !(gMC.cond & 2))
 	{
 		//Draw weapon
-		gMC.rect_arms.left = 24 * 0;//(gArmsData[gSelectedArms].code % 13);
+		gMC.rect_arms.left = 24 * (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.top = 96 * (gArmsData[gSelectedArms].code / 13);
 		gMC.rect_arms.bottom = gMC.rect_arms.top + 16;
 		
 		if (gMC.direct == 2)
@@ -183,7 +187,7 @@
 			PutBitmap3(
 				&grcGame,
 				(gMC.x - gMC.view.left) / 0x200 - fx / 0x200,
-				arms_offset_y + (gMC.y - gMC.view.top) / 0x200 - fy / 0x200,
+				(gMC.y - gMC.view.top) / 0x200 - fy / 0x200 + arms_offset_y,
 				&gMC.rect_arms,
 				11);
 		else
@@ -190,7 +194,7 @@
 			PutBitmap3(
 				&grcGame,
 				(gMC.x - gMC.view.left) / 0x200 - fx / 0x200 - 8,
-				arms_offset_y + (gMC.y - gMC.view.top) / 0x200 - fy / 0x200,
+				(gMC.y - gMC.view.top) / 0x200 - fy / 0x200 + arms_offset_y,
 				&gMC.rect_arms,
 				11);
 		
@@ -633,47 +637,50 @@
 
 void AirProcess()
 {
-	/*
-	if ( unk_81C8598 & 0x10 )
+	if (gMC.equip & 0x10)
 	{
-	unk_81C8624 = 1000;
-	unk_81C8628 = 0;
+		gMC.air = 1000;
+		gMC.air_get = 0;
 	}
 	else
 	{
-	if ( gMC.flag & 0x100 )
-	{
-	if ( --unk_81C8624 <= 0 )
-	{
-	if ( (unsigned __int8)GetNPCFlag(4000) )
-	{
-	StartTextScript(1100);
+		if (gMC.flag & 0x100)
+		{
+			if (--gMC.air <= 0)
+			{
+				if (GetNPCFlag(4000))
+				{
+					//Core cutscene
+					StartTextScript(1100);
+				}
+				else
+				{
+					//Drown
+					StartTextScript(41);
+					
+					if (gMC.direct)
+						SetCaret(gMC.x, gMC.y, 8, 2);
+					else
+						SetCaret(gMC.x, gMC.y, 8, 0);
+					
+					gMC.cond &= ~0x80;
+				}
+			}
+		}
+		else
+		{
+			gMC.air = 1000;
+		}
+		
+		if ( gMC.flag & 0x100 )
+		{
+			gMC.air_get = 60;
+		}
+		else if (gMC.air_get)
+		{
+			--gMC.air_get;
+		}
 	}
-	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)
@@ -689,7 +696,7 @@
 		}
 		else if (gMC.exp_count)
 		{
-			//SetValueView(&x, &y, gMC.exp_count);
+			SetValueView(&gMC.x, &gMC.y, gMC.exp_count);
 			gMC.exp_count = 0;
 		}
 		
--- a/src/MycHit.cpp
+++ b/src/MycHit.cpp
@@ -784,7 +784,7 @@
 				if (hit && gNPC[i].code_char == 87)
 				{
 					PlaySoundObject(20, 1);
-					//AddLifeMyChar(gNPC[i].exp);
+					AddLifeMyChar(gNPC[i].exp);
 					gNPC[i].cond = 0;
 				}
 				
--- a/src/MycParam.cpp
+++ b/src/MycParam.cpp
@@ -1,9 +1,96 @@
 #include "Sound.h"
 #include "MyChar.h"
+#include "MycParam.h"
 #include "NpChar.h"
+#include "CommonDefines.h"
+#include "ArmsItem.h"
 #include "ValueView.h"
 #include "TextScr.h"
+#include "Game.h"
+#include "Draw.h"
+#include "Caret.h"
 
+ARMS_LEVEL gArmsLevelTable[14] =
+{
+	{{0,  0,  100}},
+	{{30, 40, 16}},
+	{{10, 20, 10}},
+	{{10, 20, 20}},
+	{{30, 40, 10}},
+	{{10, 20, 10}},
+	{{10, 20, 30}},
+	{{10, 20, 5}},
+	{{10, 20, 100}},
+	{{30, 60, 0}},
+	{{30, 60, 10}},
+	{{10, 20, 100}},
+	{{1,  1,  1}},
+	{{40, 60, 200}}
+};
+
+void AddExpMyChar(int x)
+{
+	int lv = gArmsData[gSelectedArms].level - 1;
+	int arms_code = gArmsData[gSelectedArms].code;
+	
+	gArmsData[gSelectedArms].exp += x;
+	
+	if (lv == 2)
+	{
+		if (gArmsData[gSelectedArms].exp >= gArmsLevelTable[0].exp[3 * arms_code + 2])
+		{
+			gArmsData[gSelectedArms].exp = gArmsLevelTable[0].exp[3 * arms_code + 2];
+			
+			if (gMC.equip & 0x80)
+			{
+				if (gMC.star < 3)
+					++gMC.star;
+			}
+		}
+	}
+	else
+	{
+		while (lv <= 1)
+		{
+			if (gArmsData[gSelectedArms].exp >= gArmsLevelTable[0].exp[lv + 3 * arms_code])
+			{
+				++gArmsData[gSelectedArms].level;
+				gArmsData[gSelectedArms].exp = 0;
+				
+				if (gArmsData[gSelectedArms].code != 13)
+				{
+					PlaySoundObject(27, 1);
+					SetCaret(gMC.x, gMC.y, 10, 0);
+				}
+			}
+			
+			++lv;
+		}
+	}
+	
+	if (gArmsData[gSelectedArms].code == 13)
+	{
+		gMC.exp_wait = 10;
+	}
+	else
+	{
+		gMC.exp_count += x;
+		gMC.exp_wait = 30;
+	}
+}
+
+void ZeroExpMyChar()
+{
+	gArmsData[gSelectedArms].level = 1;
+	gArmsData[gSelectedArms].exp = 0;
+}
+
+bool IsMaxExpMyChar()
+{
+	return gArmsData[gSelectedArms].level == 3
+		&& gArmsData[gSelectedArms].exp >= gArmsLevelTable[gArmsData[gSelectedArms].code].exp[2];
+}
+
 void DamageMyChar(int damage)
 {
 	if (!gMC.shock)
@@ -21,28 +108,24 @@
 			--gMC.star;
 		
 		//Lose experience
-		/*
-		if ( unk_81C8598 & 4 )
-			v1 = gArmsData[gSelectedArms].exp - damage;
+		if (gMC.equip & 4)
+			gArmsData[gSelectedArms].exp -= damage;
 		else
-			v1 = gArmsData[gSelectedArms].exp - 2 * damage;
-		gArmsData[gSelectedArms].exp = v1;
-		while ( gArmsData[gSelectedArms].exp < 0 )
+			gArmsData[gSelectedArms].exp -= 2 * damage;
+		
+		while (gArmsData[gSelectedArms].exp < 0)
 		{
-		if ( gArmsData[gSelectedArms].level <= 1 )
-		{
-		gArmsData[gSelectedArms].exp = 0;
+			if (gArmsData[gSelectedArms].level <= 1)
+			{
+				gArmsData[gSelectedArms].exp = 0;
+			}
+			else
+			{
+				gArmsData[gSelectedArms].exp += gArmsLevelTable[0].exp[--gArmsData[gSelectedArms].level - 1 + 3 * gArmsData[gSelectedArms].code];
+				if (gMC.life > 0 && gArmsData[gSelectedArms].code != 13)
+					SetCaret(gMC.x, gMC.y, 10, 2);
+			}
 		}
-		else
-		{
-		gArmsData[gSelectedArms].exp += gArmsLevelTable[0].exp[--gArmsData[gSelectedArms].level
-		- 1
-		+ 3 * gArmsData[gSelectedArms].code];
-		if ( word_81C8614 > 0 && gArmsData[gSelectedArms].code != 13 )
-		SetCaret(x, y, 10, 2);
-		}
-		}
-		*/
 		
 		//Tell player how much damage was taken
 		SetValueView(&gMC.x, &gMC.y, -damage);
@@ -56,4 +139,169 @@
 			StartTextScript(40);
 		}
 	}
-}
\ No newline at end of file
+}
+
+void AddLifeMyChar(int x)
+{
+	gMC.life += x;
+	if (gMC.life > gMC.max_life)
+		gMC.life = gMC.max_life;
+	gMC.lifeBr = gMC.life;
+}
+
+void AddMaxLifeMyChar(int val)
+{
+	gMC.max_life += val;
+	if (gMC.max_life > 232)
+		gMC.max_life = 232;
+	gMC.life += val;
+	gMC.lifeBr = gMC.life;
+}
+
+void PutArmsEnergy(bool flash)
+{
+	RECT rcPer = {72, 48, 80, 56};
+	RECT rcLv = {80, 80, 96, 88};
+	RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
+	RECT rcNone = {80, 48, 96, 56};
+	
+	if (gArmsEnergyX > 16)
+		gArmsEnergyX -= 2;
+	if (gArmsEnergyX < 16)
+		gArmsEnergyX += 2;
+	
+	//Draw max ammo
+	if (gArmsData[gSelectedArms].max_num)
+	{
+		PutNumber4(gArmsEnergyX + 32, 16, gArmsData[gSelectedArms].num, 0);
+		PutNumber4(gArmsEnergyX + 32, 24, gArmsData[gSelectedArms].max_num, 0);
+	}
+	else
+	{
+		PutBitmap3(&rcView, gArmsEnergyX + 48, 16, &rcNone, 26);
+		PutBitmap3(&rcView, gArmsEnergyX + 48, 24, &rcNone, 26);
+	}
+	
+	//Draw experience and ammo
+	if (!flash || !((gMC.shock >> 1) & 1))
+	{
+		PutBitmap3(&rcView, gArmsEnergyX + 32, 24, &rcPer, 26);
+		PutBitmap3(&rcView, gArmsEnergyX, 32, &rcLv, 26);
+		PutNumber4(gArmsEnergyX - 8, 32, gArmsData[gSelectedArms].level, 0);
+		
+		RECT rcExpBox = {0, 72, 40, 80};
+		RECT rcExpVal = {0, 80, 0, 88};
+		RECT rcExpMax = {40, 72, 80, 80};
+		RECT rcExpFlash = {40, 80, 80, 88};
+		
+		int lv = gArmsData[gSelectedArms].level - 1;
+		int arms_code = gArmsData[gSelectedArms].code;
+		int exp_now = gArmsData[gSelectedArms].exp;
+		int exp_next = gArmsLevelTable[0].exp[lv + 3 * arms_code];
+		
+		PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpBox, 26);
+		
+		if (lv != 2 || gArmsData[gSelectedArms].exp != gArmsLevelTable[0].exp[3 * arms_code + 2])
+		{
+			if (exp_next)
+				rcExpVal.right += 40 * exp_now / exp_next;
+			else
+				rcExpVal.right = 0;
+			
+			PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpVal, 26);
+		}
+		else
+		{
+			PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpMax, 26);
+		}
+		
+		static int add_flash = true;
+		if (gMC.exp_wait && ((add_flash++ >> 1) & 1))
+			PutBitmap3(&rcView, gArmsEnergyX + 24, 32, &rcExpFlash, 26);
+	}
+}
+
+void PutActiveArmsList()
+{
+	RECT rect = {0, 0, 0, 16};
+
+	int arms_num;
+	for (arms_num = 0; gArmsData[arms_num].code != 0; ++arms_num);
+	
+	if (arms_num)
+	{
+		for (int a = 0; a < arms_num; a++)
+		{
+			//Get X position to draw at
+			int x = 16 * (a - gSelectedArms) + gArmsEnergyX;
+			
+			if (x >= 8)
+			{
+				if (x >= 24)
+					x += 48;
+			}
+			else
+			{
+				x += 16 * (arms_num + 3);
+			}
+			
+			if (8 * (2 * (arms_num + 3) + 1) <= x)
+				x += 16 * (-3 - arms_num);
+			if (x < 72 && x >= 24)
+				x -= 48;
+			
+			//Draw icon
+			rect.left = 16 * gArmsData[a].code;
+			rect.right = rect.left + 16;
+			PutBitmap3(&grcGame, x, 16, &rect, 12);
+		}
+	}
+}
+
+void PutMyLife(bool flash)
+{
+	RECT rcCase = {0, 40, 232, 48};
+	RECT rcLife = {0, 24, 232, 32};
+	RECT rcBr = {0, 32, 232, 40};
+	
+	if (!flash || !((gMC.shock >> 1) & 1))
+	{
+		if (gMC.lifeBr < gMC.life)
+			gMC.lifeBr = gMC.life;
+		
+		if (gMC.lifeBr <= gMC.life)
+			gMC.lifeBr_count = 0;
+		else if (++gMC.lifeBr_count > 30)
+			--gMC.lifeBr;
+		
+		//Draw bar
+		rcCase.right = 64;
+		rcLife.right = 40 * gMC.life / gMC.max_life - 1;
+		rcBr.right = 40 * gMC.lifeBr / gMC.max_life - 1;
+		
+		PutBitmap3(&grcGame, 16, 40, &rcCase, 26);
+		PutBitmap3(&grcGame, 40, 40, &rcBr, 26);
+		PutBitmap3(&grcGame, 40, 40, &rcLife, 26);
+		PutNumber4(8, 40, gMC.lifeBr, 0);
+	}
+}
+
+void PutMyAir(int x, int y)
+{
+	RECT rcAir[2];
+	rcAir[0] = {112, 72, 144, 80};
+	rcAir[1] = {112, 80, 144, 88};
+	
+	if (!(gMC.equip & 0x10) && gMC.air_get)
+	{
+		//Draw how much air is left
+		if (gMC.air_get % 6 <= 3)
+			PutNumber4(x + 32, y, gMC.air / 10, 0);
+		
+		//Draw "AIR" text
+		if (gMC.air % 30 <= 10)
+			PutBitmap3(&grcGame, x, y, &rcAir[1], 26);
+		else
+			PutBitmap3(&grcGame, x, y, &rcAir[0], 26);
+	}
+}
--- a/src/MycParam.h
+++ b/src/MycParam.h
@@ -1,2 +1,15 @@
 #pragma once
+struct ARMS_LEVEL
+{
+	int exp[3];
+};
+
+extern ARMS_LEVEL gArmsLevelTable[14];
+
 void DamageMyChar(int damage);
+void AddLifeMyChar(int x);
+void AddMaxLifeMyChar(int val);
+void PutArmsEnergy(bool flash);
+void PutActiveArmsList();
+void PutMyLife(bool flash);
+void PutMyAir(int x, int y);
--- a/src/NpcAct.h
+++ b/src/NpcAct.h
@@ -13,3 +13,5 @@
 void ActNpc018(NPCHAR *npc);
 
 void ActNpc021(NPCHAR *npc);
+
+void ActNpc032(NPCHAR *npc);
--- a/src/NpcAct020.cpp
+++ b/src/NpcAct020.cpp
@@ -27,3 +27,22 @@
 
 	npc->rect = rect[0];
 }
+
+//Life capsule
+void ActNpc032(NPCHAR *npc)
+{
+	RECT rect[2];
+	rect[0] = {32, 96, 48, 112};
+	rect[1] = {48, 96, 64, 112};
+	
+	if (++npc->ani_wait > 2)
+	{
+		npc->ani_wait = 0;
+		++npc->ani_no;
+	}
+	
+	if (npc->ani_no > 1)
+		npc->ani_no = 0;
+	
+	npc->rect = rect[npc->ani_no];
+}
\ No newline at end of file
--- a/src/NpcTbl.cpp
+++ b/src/NpcTbl.cpp
@@ -88,7 +88,7 @@
 	nullptr,
 	nullptr,
 	nullptr,
-	nullptr,
+	ActNpc032,
 	nullptr,
 	nullptr,
 	nullptr,
--- a/src/Profile.cpp
+++ b/src/Profile.cpp
@@ -7,6 +7,7 @@
 #include "Tags.h"
 #include "Profile.h"
 #include "Fade.h"
+#include "ArmsItem.h"
 #include "Flags.h"
 #include "MyChar.h"
 #include "Frame.h"
@@ -43,11 +44,11 @@
 bool InitializeGame()
 {
 	InitMyChar();
-	//gSelectedArms = 0;
-	//gSelectedItem = 0;
+	gSelectedArms = 0;
+	gSelectedItem = 0;
 	gCounter = 0;
-	//ClearArmsData();
-	//ClearItemData();
+	ClearArmsData();
+	ClearItemData();
 	//ClearPermitStage();
 	//StartMapping();
 	InitFlags();
--- a/src/TextScr.cpp
+++ b/src/TextScr.cpp
@@ -7,10 +7,13 @@
 #include "TextScr.h"
 #include "Draw.h"
 #include "Tags.h"
+#include "ArmsItem.h"
 #include "MyChar.h"
 #include "Fade.h"
 #include "Stage.h"
+#include "MycParam.h"
 #include "Flags.h"
+#include "Profile.h"
 #include "MapName.h"
 #include "KeyControl.h"
 #include "NpChar.h"
@@ -489,6 +492,7 @@
 			gTS.wait = 0;
 			
 			//Parsing time
+			int w, x, y, z;
 			bExit = false;
 			
 			while (!bExit)
@@ -510,7 +514,7 @@
 					else if (gTS.flags & 0x10)
 					{
 						//SAT/CAT/TUR printing
-						int x;
+						x;
 						for (x = gTS.p_read; ; x++)
 						{
 							//Break if reaches command, or new-line
@@ -604,19 +608,65 @@
 						gTS.face = 0;
 						bExit = true;
 					}
+					else if (IS_COMMAND('L','I','+'))
+					{
+						x = GetTextScriptNo(gTS.p_read + 4);
+						AddLifeMyChar(x);
+						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('M','L','+'))
+					{
+						z = GetTextScriptNo(gTS.p_read + 4);
+						AddMaxLifeMyChar(z);
+						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('A','E','+'))
+					{
+						FullArmsEnergy();
+						gTS.p_read += 4;
+					}
+					else if (IS_COMMAND('I','T','+'))
+					{
+						x = GetTextScriptNo(gTS.p_read + 4);
+						PlaySoundObject(38, 1);
+						AddItemData(x);
+						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('I','T','-'))
+					{
+						z = GetTextScriptNo(gTS.p_read + 4);
+						SubItemData(z);
+						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('A','M','+'))
+					{
+						w = GetTextScriptNo(gTS.p_read + 4);
+						x = GetTextScriptNo(gTS.p_read + 9);
+						gNumberTextScript[0] = x;
+						gNumberTextScript[1] = z;
+						PlaySoundObject(38, 1);
+						AddArmsData(w, x);
+						gTS.p_read += 13;
+					}
+					else if (IS_COMMAND('A','M','-'))
+					{
+						z = GetTextScriptNo(gTS.p_read + 4);
+						SubArmsData(z);
+						gTS.p_read += 8;
+					}
 					else if (IS_COMMAND('T','R','A'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
-						int w = GetTextScriptNo(gTS.p_read + 9);
-						int x = GetTextScriptNo(gTS.p_read + 14);
-						int y = GetTextScriptNo(gTS.p_read + 19);
+						z = GetTextScriptNo(gTS.p_read + 4);
+						w = GetTextScriptNo(gTS.p_read + 9);
+						x = GetTextScriptNo(gTS.p_read + 14);
+						y = GetTextScriptNo(gTS.p_read + 19);
 						if (!TransferStage(z, w, x, y))
 							return 0;
 					}
 					else if (IS_COMMAND('M','O','V'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int y = GetTextScriptNo(gTS.p_read + 9);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						y = GetTextScriptNo(gTS.p_read + 9);
 						SetMyCharPosition(x << 13, y << 13);
 						gTS.p_read += 13;
 					}
@@ -632,25 +682,25 @@
 					}
 					else if (IS_COMMAND('F','L','+'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						SetNPCFlag(z);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('F','L','-'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						CutNPCFlag(z);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('S','K','+'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						SetSkipFlag(z);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('S','K','-'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						CutSkipFlag(z);
 						gTS.p_read += 8;
 					}
@@ -744,7 +794,7 @@
 					}
 					else if (IS_COMMAND('E','V','E'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						JumpTextScript(z);
 					}
 					else if (IS_COMMAND('Y','N','J'))
@@ -759,8 +809,8 @@
 					}
 					else if (IS_COMMAND('F','L','J'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int z = GetTextScriptNo(gTS.p_read + 9);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 9);
 						
 						if (GetNPCFlag(x))
 							JumpTextScript(z);
@@ -769,8 +819,8 @@
 					}
 					else if (IS_COMMAND('S','K','J'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int z = GetTextScriptNo(gTS.p_read + 9);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 9);
 						
 						if (GetSkipFlag(x))
 							JumpTextScript(z);
@@ -779,7 +829,7 @@
 					}
 					else if (IS_COMMAND('F','A','I'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						StartFadeIn(z);
 						gTS.mode = 5;
 						gTS.p_read += 8;
@@ -787,7 +837,7 @@
 					}
 					else if (IS_COMMAND('F','A','O'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						StartFadeOut(z);
 						gTS.mode = 5;
 						gTS.p_read += 8;
@@ -800,13 +850,13 @@
 					}
 					else if (IS_COMMAND('S','O','U'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						PlaySoundObject(z, 1);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('C','M','U'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						ChangeMusic(z);
 						gTS.p_read += 8;
 					}
@@ -822,61 +872,76 @@
 					}
 					else if (IS_COMMAND('D','N','P'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						DeleteNpCharEvent(z);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('D','N','A'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						DeleteNpCharCode(z, 1);
 						gTS.p_read += 8;
 					}
 					else if (IS_COMMAND('C','N','P'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int y = GetTextScriptNo(gTS.p_read + 9);
-						int z = GetTextScriptNo(gTS.p_read + 14);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						y = GetTextScriptNo(gTS.p_read + 9);
+						z = GetTextScriptNo(gTS.p_read + 14);
 						ChangeNpCharByEvent(x, y, z);
 						gTS.p_read += 18;
 					}
 					else if (IS_COMMAND('A','N','P'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int y = GetTextScriptNo(gTS.p_read + 9);
-						int z = GetTextScriptNo(gTS.p_read + 14);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						y = GetTextScriptNo(gTS.p_read + 9);
+						z = GetTextScriptNo(gTS.p_read + 14);
 						SetNpCharActionNo(x, y, z);
 						gTS.p_read += 18;
 					}
 					else if (IS_COMMAND('I','N','P'))
 					{
-						int x = GetTextScriptNo(gTS.p_read + 4);
-						int y = GetTextScriptNo(gTS.p_read + 9);
-						int z = GetTextScriptNo(gTS.p_read + 14);
+						x = GetTextScriptNo(gTS.p_read + 4);
+						y = GetTextScriptNo(gTS.p_read + 9);
+						z = GetTextScriptNo(gTS.p_read + 14);
 						ChangeCheckableNpCharByEvent(x, y, z);
 						gTS.p_read += 18;
 					}
 					else if (IS_COMMAND('S','N','P'))
 					{
-						int w = GetTextScriptNo(gTS.p_read + 4);
-						int x = GetTextScriptNo(gTS.p_read + 9);
-						int y = GetTextScriptNo(gTS.p_read + 14);
-						int z = GetTextScriptNo(gTS.p_read + 19);
+						w = GetTextScriptNo(gTS.p_read + 4);
+						x = GetTextScriptNo(gTS.p_read + 9);
+						y = GetTextScriptNo(gTS.p_read + 14);
+						z = GetTextScriptNo(gTS.p_read + 19);
 						SetNpChar(w, x << 13, y << 13, 0, 0, z, 0, 0x100);
 						gTS.p_read += 23;
 					}
 					else if (IS_COMMAND('M','N','P'))
 					{
-						int w = GetTextScriptNo(gTS.p_read + 4);
-						int x = GetTextScriptNo(gTS.p_read + 9);
-						int y = GetTextScriptNo(gTS.p_read + 14);
-						int z = GetTextScriptNo(gTS.p_read + 19);
+						w = GetTextScriptNo(gTS.p_read + 4);
+						x = GetTextScriptNo(gTS.p_read + 9);
+						y = GetTextScriptNo(gTS.p_read + 14);
+						z = GetTextScriptNo(gTS.p_read + 19);
 						MoveNpChar(w, x << 13, y << 13, z);
 						gTS.p_read += 23;
 					}
+					else if (IS_COMMAND('I','N','I'))
+					{
+						InitializeGame();
+						gTS.p_read += 4;
+					}
+					else if (IS_COMMAND('S','V','P'))
+					{
+						SaveProfile(NULL);
+						gTS.p_read += 4;
+					}
+					else if (IS_COMMAND('L','D','P'))
+					{
+						if (!LoadProfile(NULL))
+							InitializeGame();
+					}
 					else if (IS_COMMAND('F','A','C'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						if (gTS.face != z)
 						{
 							gTS.face = z;
@@ -886,7 +951,7 @@
 					}
 					else if (IS_COMMAND('F','A','C'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						if (gTS.face != z)
 						{
 							gTS.face = z;
@@ -896,10 +961,14 @@
 					}
 					else if (IS_COMMAND('G','I','T'))
 					{
-						int z = GetTextScriptNo(gTS.p_read + 4);
+						z = GetTextScriptNo(gTS.p_read + 4);
 						gTS.item = z;
 						gTS.item_y = WINDOW_HEIGHT - 112;
 						gTS.p_read += 8;
+					}
+					else if (IS_COMMAND('E','S','C'))
+					{
+						return 2;
 					}
 					else
 					{
--- a/src/TextScr.h
+++ b/src/TextScr.h
@@ -61,5 +61,6 @@
 bool LoadTextScript_Stage(char *name);
 void GetTextScriptPath(char *path);
 bool StartTextScript(int no);
+void StopTextScript();
 void PutTextScript();
 int TextScriptProc();
\ No newline at end of file
--