shithub: cstory

Download patch

ref: bea22e72e00abd73efce57c949e65f477eee214d
parent: 4a104a527c4c76fb9029da54cfd13bd247eb17b5
author: cuckydev <cuckydev@users.noreply.github.com>
date: Wed Jan 30 11:03:10 EST 2019

bullet

--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,8 @@
 SOURCES = \
 	ArmsItem \
 	Back \
+	BulHit \
+	Bullet \
 	Caret \
 	Config \
 	Draw \
@@ -81,6 +83,7 @@
 	PixTone \
 	Profile \
 	Resource \
+	Shoot \
 	Sound \
 	Stage \
 	TextScr \
--- /dev/null
+++ b/src/BulHit.cpp
@@ -1,0 +1,244 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "Bullet.h"
+#include "NpChar.h"
+#include "Caret.h"
+#include "Sound.h"
+#include "MyChar.h"
+#include "Game.h"
+#include "Map.h"
+
+void Vanish(BULLET *bul)
+{
+	if (bul->code_bullet != 37 && bul->code_bullet != 38 && bul->code_bullet != 39)
+		PlaySoundObject(28, 1);
+	else
+		SetCaret(bul->x, bul->y, 2, 1);
+	bul->cond = 0;
+	SetCaret(bul->x, bul->y, 2, 2);
+}
+
+int JudgeHitBulletBlock(int x, int y, BULLET *bul)
+{
+	int hit = 0;
+	if (bul->x - bul->blockXL < (2 * x + 1) << 12
+		&& bul->blockXL + bul->x > (2 * x - 1) << 12
+		&& bul->y - bul->blockYL < (2 * y + 1) << 12
+		&& bul->blockYL + bul->y > (2 * y - 1) << 12)
+		hit = 0x200;
+	
+	if (hit && (bul->bbits & 0x60) && GetAttribute(x, y) == 0x43)
+	{
+		if (!(bul->bbits & 0x40))
+			bul->cond = 0;
+		printf("%d\n", bul->cond);
+		SetCaret(bul->x, bul->y, 2, 0);
+		PlaySoundObject(12, 1);
+		for (int i = 0; i < 4; i++)
+			SetNpChar(4, x << 13, y << 13, Random(-0x200, 0x200), Random(-0x200, 0x200), 0, 0, 256);
+		ShiftMapParts(x, y);
+	}
+	
+	return hit;
+}
+
+int JudgeHitBulletBlock2(int x, int y, uint8_t *atrb, BULLET *bul)
+{
+	int hit = 0;
+	
+	int block[4];
+	if (bul->bbits & 0x40)
+	{
+		for (int i = 0; i < 4; i++)
+		{
+			block[i] = *atrb == 0x41 || *atrb == 0x61;
+			++atrb;
+		}
+	}
+	else
+	{
+		for (int i = 0; i < 4; i++)
+		{
+			block[i] = *atrb == 0x41 || *atrb == 0x43 || *atrb == 0x61;
+			++atrb;
+		}
+	}
+	
+	int workX = (2 * x + 1) << 12;
+	int workY = (2 * y + 1) << 12;
+	
+	//Left wall
+	if (block[0] && block[2])
+	{
+		if (bul->x - bul->blockXL < workX)
+			hit |= 1;
+	}
+	else if (!block[0] || block[2])
+	{
+		if (!block[0] && block[2] && bul->x - bul->blockXL < workX && bul->blockYL + bul->y > workY + 0x600)
+			hit |= 1;
+	}
+	else if (bul->x - bul->blockXL < workX && bul->y - bul->blockYL < workY - 0x600)
+	{
+		hit |= 1;
+	}
+	
+	//Right wall
+	if (block[1] && block[3])
+	{
+		if (bul->x + bul->blockXL > workX)
+			hit |= 4;
+	}
+	else if (!block[1] || block[3])
+	{
+		if (!block[1] && block[3] && bul->x + bul->blockXL > workX && bul->blockYL + bul->y > workY + 0x600)
+			hit |= 4;
+	}
+	else if (bul->x + bul->blockXL > workX && bul->y - bul->blockYL < workY - 0x600)
+	{
+		hit |= 4;
+	}
+	
+	//Ceiling
+	if (block[0] && block[1])
+	{
+		if (bul->y - bul->blockYL < workY)
+			hit |= 2;
+	}
+	else if (!block[0] || block[1])
+	{
+		if (!block[0] && block[1] && bul->y - bul->blockYL < workY && bul->blockXL + bul->x > workX + 0x600)
+			hit |= 2;
+	}
+	else if (bul->y - bul->blockYL < workY && bul->x - bul->blockXL < workX - 0x600)
+	{
+		hit |= 2;
+	}
+	
+	//Ground
+	if (block[2] && block[3])
+	{
+		if (bul->y + bul->blockYL > workY)
+			hit |= 8;
+	}
+	else if (!block[2] || block[3])
+	{
+		if (!block[2] && block[3] && bul->y + bul->blockYL > workY && bul->blockXL + bul->x > workX + 0x600)
+			hit |= 8;
+	}
+	else if (bul->y + bul->blockYL > workY && bul->x - bul->blockXL < workX - 0x600)
+	{
+		hit |= 8;
+	}
+	
+	//Clip
+	if (bul->bbits & 8)
+	{
+		if (hit & 1)
+			bul->x = workX + bul->blockXL;
+		else if (hit & 4)
+			bul->x = workX - bul->blockXL;
+		else if (hit & 2)
+			bul->y = workY + bul->blockYL;
+		else if (hit & 8)
+			bul->y = workY - bul->blockYL;
+	}
+	else if (hit & 0xF)
+	{
+		Vanish(bul);
+	}
+	
+	return hit;
+}
+
+void HitBulletMap()
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80)
+		{
+			int x = gBul[i].x / 0x2000;
+			int y = gBul[i].y / 0x2000;
+			
+			//Get surrounding tiles
+			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];
+			atrb[0] = GetAttribute(x, y);
+			atrb[1] = GetAttribute(x + 1, y);
+			atrb[2] = GetAttribute(x, y + 1);
+			atrb[3] = GetAttribute(x + 1, y + 1);
+			
+			//Clear hit tiles
+			gBul[i].flag = 0;
+			
+			if (!(gBul[i].bbits & 4))
+			{
+				for (int j = 0; j < 4; j++)
+				{
+					if (gBul[i].cond & 0x80)
+					{
+						switch (atrb[j])
+						{
+							case 0x41:
+							case 0x43:
+							case 0x44:
+							case 0x61:
+							case 0x64:
+								gBul[i].flag |= JudgeHitBulletBlock(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+						/*
+							case 0x50:
+							case 0x70:
+								gBul[i].flag |= JudgeHitBulletTriangleA(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x51:
+							case 0x71:
+								gBul[i].flag |= JudgeHitBulletTriangleB(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x52:
+							case 0x72:
+								gBul[i].flag |= JudgeHitBulletTriangleC(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x53:
+							case 0x73:
+								gBul[i].flag |= JudgeHitBulletTriangleD(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x54:
+							case 0x74:
+								gBul[i].flag |= JudgeHitBulletTriangleE(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x55:
+							case 0x75:
+								gBul[i].flag |= JudgeHitBulletTriangleF(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x56:
+							case 0x76:
+								gBul[i].flag |= JudgeHitBulletTriangleG(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+							case 0x57:
+							case 0x77:
+								gBul[i].flag |= JudgeHitBulletTriangleH(x + offx[j], y + offy[j], &gBul[i]);
+								break;
+						*/
+							default:
+								break;
+						}
+					}
+				}
+				
+				gBul[i].flag |= JudgeHitBulletBlock2(x, y, atrb, &gBul[i]);
+			}
+		}
+	}
+}
--- /dev/null
+++ b/src/BulHit.h
@@ -1,0 +1,2 @@
+#pragma once
+void HitBulletMap();
--- /dev/null
+++ b/src/Bullet.cpp
@@ -1,0 +1,294 @@
+#include "Bullet.h"
+#include "Draw.h"
+#include "Caret.h"
+
+BULLET_TABLE gBulTbl[46] =
+{
+	//TODO: un-ugly this
+	{'\0', '\0', 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}},
+	{'\x04', '\x01', 20, 36, 4, 4, 2, 2, {8, 8, 8, 8}},
+	{'\x06', '\x01', 23, 36, 4, 4, 2, 2, {8, 8, 8, 8}},
+	{'\b', '\x01', 30, 36, 4, 4, 2, 2, {8, 8, 8, 8}},
+	{'\x01', '\x01', 8, 32, 6, 6, 2, 2, {8, 8, 8, 8}},
+	{'\x02', '\x01', 12, 32, 6, 6, 2, 2, {8, 8, 8, 8}},
+	{'\x04', '\x01', 16, 32, 6, 6, 2, 2, {8, 8, 8, 8}},
+	{'\x02', '\x02', 100, 8, 8, 16, 4, 2, {8, 8, 8, 8}},
+	{'\x03', '\x02', 100, 8, 4, 4, 4, 2, {8, 8, 8, 8}},
+	{'\x03', '\x02', 100, 8, 4, 4, 4, 2, {8, 8, 8, 8}},
+	{'\x02', '\x01', 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}},
+	{'\x04', '\x01', 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}},
+	{'\x06', '\x01', 20, 32, 2, 2, 2, 2, {8, 8, 8, 8}},
+	{'\0', '\n', 50, 40, 2, 2, 2, 2, {8, 8, 8, 8}},
+	{'\0', '\n', 70, 40, 4, 4, 4, 4, {8, 8, 8, 8}},
+	{'\0', '\n', 90, 40, 4, 4, 0, 0, {8, 8, 8, 8}},
+	{'\x01', 'd', 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}},
+	{'\x01', 'd', 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}},
+	{'\x01', 'd', 100, 20, 16, 16, 0, 0, {0, 0, 0, 0}},
+	{'\x01', '\x01', 20, 8, 2, 2, 2, 2, {4, 4, 4, 4}},
+	{'\x02', '\x01', 20, 8, 2, 2, 2, 2, {4, 4, 4, 4}},
+	{'\x02', '\x01', 20, 8, 4, 4, 4, 4, {4, 4, 4, 4}},
+	{'\x03', '\x01', 32, 32, 2, 2, 2, 2, {4, 4, 4, 4}},
+	{'\0', 'd', 0, 36, 8, 8, 8, 8, {12, 12, 12, 12}},
+	{'\x7F', '\x01', 2, 4, 8, 4, 8, 4, {0, 0, 0, 0}},
+	{'\x0F', '\x01', 30, 36, 8, 8, 4, 2, {8, 8, 8, 8}},
+	{'\x06', '\x03', 18, 36, 10, 10, 4, 2, {12, 12, 12, 12}},
+	{'\x01', 'd', 30, 36, 6, 6, 4, 4, {12, 12, 12, 12}},
+	{'\0', '\n', 30, 40, 2, 2, 2, 2, {8, 8, 8, 8}},
+	{'\0', '\n', 40, 40, 4, 4, 4, 4, {8, 8, 8, 8}},
+	{'\0', '\n', 40, 40, 4, 4, 0, 0, {8, 8, 8, 8}},
+	{'\x02', 'd', 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}},
+	{'\x02', 'd', 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}},
+	{'\x02', 'd', 100, 20, 12, 12, 0, 0, {0, 0, 0, 0}},
+	{'\x04', '\x04', 20, 32, 4, 4, 3, 3, {8, 8, 24, 8}},
+	{'\x04', '\x02', 20, 32, 2, 2, 2, 2, {8, 8, 24, 8}},
+	{'\x01', '\x01', 20, 32, 2, 2, 2, 2, {8, 8, 24, 8}},
+	{'\x04', '\x04', 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}},
+	{'\b', '\b', 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}},
+	{'\f', '\f', 30, 64, 6, 6, 3, 3, {8, 8, 8, 8}},
+	{'\x03', 'd', 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}},
+	{'\x06', 'd', 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}},
+	{'\v', 'd', 30, 32, 6, 6, 3, 3, {4, 4, 4, 4}},
+	{'\x04', '\x04', 20, 32, 4, 4, 3, 3, {8, 8, 24, 8}},
+	{'\0', '\x04', 4, 4, 0, 0, 0, 0, {0, 0, 0, 0}},
+	{'\x01', '\x01', 1, 36, 1, 1, 1, 1, {1, 1, 1, 1}}
+};
+
+BULLET gBul[BULLET_MAX];
+
+void InitBullet()
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+		gBul[i].cond = 0;
+}
+
+int CountArmsBullet(int arms_code)
+{
+	int count = 0;
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80 && (gBul[i].code_bullet + 2) / 3 == arms_code)
+			++count;
+	}
+	
+	return count;
+}
+
+int CountBulletNum(int bullet_code)
+{
+	int count = 0;
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80 && gBul[i].code_bullet == bullet_code)
+			++count;
+	}
+	
+	return count;
+}
+
+void DeleteBullet(int code)
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80)
+		{
+			if ((gBul[i].code_bullet + 2) / 3 == code)
+				gBul[i].cond = 0;
+		}
+	}
+}
+
+void ClearBullet()
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+		gBul[i].cond = 0;
+}
+
+void PutBullet(int fx, int fy)
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80)
+		{
+			int x, y;
+			
+			switch (gBul[i].direct)
+			{
+				case 0:
+					x = gBul[i].x - gBul[i].view.front;
+					y = gBul[i].y - gBul[i].view.top;
+					break;
+				case 1:
+					x = gBul[i].x - gBul[i].view.top;
+					y = gBul[i].y - gBul[i].view.front;
+					break;
+				case 2:
+					x = gBul[i].x - gBul[i].view.back;
+					y = gBul[i].y - gBul[i].view.top;
+					break;
+				case 3:
+					x = gBul[i].x - gBul[i].view.top;
+					y = gBul[i].y - gBul[i].view.back;
+					break;
+			}
+			
+			PutBitmap3(&grcGame, x / 0x200 - fx / 0x200, y / 0x200 - fy / 0x200, &gBul[i].rect, 17);
+		}
+	}
+}
+
+void SetBullet(int no, int x, int y, int dir)
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (!(gBul[i].cond & 0x80))
+		{
+			memset(&gBul[i], 0, sizeof(BULLET));
+			gBul[i].code_bullet = no;
+			gBul[i].cond = 0x80;
+			gBul[i].direct = dir;
+			gBul[i].damage = gBulTbl[no].damage;
+			gBul[i].life = gBulTbl[no].life;
+			gBul[i].life_count = gBulTbl[no].life_count;
+			gBul[i].bbits = gBulTbl[no].bbits;
+			gBul[i].enemyXL = gBulTbl[no].enemyXL << 9;
+			gBul[i].enemyYL = gBulTbl[no].enemyYL << 9;
+			gBul[i].blockXL = gBulTbl[no].blockXL << 9;
+			gBul[i].blockYL = gBulTbl[no].blockYL << 9;
+			gBul[i].view.back = gBulTbl[no].view.back << 9;
+			gBul[i].view.front = gBulTbl[no].view.front << 9;
+			gBul[i].view.top = gBulTbl[no].view.top << 9;
+			gBul[i].view.bottom = gBulTbl[no].view.bottom << 9;
+			gBul[i].x = x;
+			gBul[i].y = y;
+		}
+	}
+}
+
+void ActBullet_PoleStar(BULLET *bul, int level)
+{
+	if (++bul->count1 <= bul->life_count)
+	{
+		if (bul->act_no)
+		{
+			//Move
+			bul->x += bul->xm;
+			bul->y += bul->ym;
+		}
+		else
+		{
+			bul->act_no = 1;
+			
+			//Set speed
+			switch (bul->direct)
+			{
+				case 0:
+					bul->xm = -0x1000;
+					break;
+				case 1:
+					bul->ym = -0x1000;
+					break;
+				case 2:
+					bul->xm = 0x1000;
+					break;
+				case 3:
+					bul->ym = 0x1000;
+					break;
+			}
+			
+			//Set hitbox
+			if (level == 1)
+			{
+				switch (bul->direct)
+				{
+					case 0:
+						bul->enemyYL = 0x400;
+						break;
+					case 1:
+						bul->enemyXL = 0x400;
+						break;
+					case 2:
+						bul->enemyYL = 0x400;
+						break;
+					case 3:
+						bul->enemyXL = 0x400;
+						break;
+				}
+			}
+			else if (level == 2)
+			{
+				switch (bul->direct)
+				{
+					case 0:
+						bul->enemyYL = 0x800;
+						break;
+					case 1:
+						bul->enemyXL = 0x800;
+						break;
+					case 2:
+						bul->enemyYL = 0x800;
+						break;
+					case 3:
+						bul->enemyXL = 0x800;
+						break;
+				}
+			}
+			
+			//Set framerect
+			switch (level)
+			{
+				case 1:
+					if (bul->direct != 1 && bul->direct != 3)
+						bul->rect = {128, 32, 144, 48};
+					else
+						bul->rect = {144, 32, 160, 48};
+					break;
+				case 2:
+					if (bul->direct != 1 && bul->direct != 3)
+						bul->rect = {160, 32, 176, 48};
+					else
+						bul->rect = {176, 32, 192, 48};
+					break;
+				case 3:
+					if (bul->direct != 1 && bul->direct != 3)
+						bul->rect = {128, 48, 144, 64};
+					else
+						bul->rect = {144, 48, 160, 64};
+					break;
+			}
+		}
+	}
+	else
+	{
+		bul->cond = 0;
+		SetCaret(bul->x, bul->y, 3, 0);
+	}
+}
+
+void ActBullet()
+{
+	for (int i = 0; i < BULLET_MAX; i++)
+	{
+		if (gBul[i].cond & 0x80)
+		{
+			if (gBul[i].life > 0)
+			{
+				switch (gBul[i].code_bullet)
+				{
+					case 4:
+						ActBullet_PoleStar(&gBul[i], 1);
+						break;
+					case 5:
+						ActBullet_PoleStar(&gBul[i], 2);
+						break;
+					case 6:
+						ActBullet_PoleStar(&gBul[i], 3);
+						break;
+				}
+			}
+			else
+			{
+				gBul[i].cond = 0;
+			}
+		}
+	}
+}
--- /dev/null
+++ b/src/Bullet.h
@@ -1,0 +1,58 @@
+#pragma once
+#include <stdint.h>
+#include "WindowsWrapper.h"
+
+struct BULLET
+{
+	int flag;
+	int code_bullet;
+	int bbits;
+	int cond;
+	int x;
+	int y;
+	int xm;
+	int ym;
+	int tgt_x;
+	int tgt_y;
+	int act_no;
+	int act_wait;
+	int ani_wait;
+	int ani_no;
+	uint8_t direct;
+	RECT rect;
+	int count1;
+	int count2;
+	int life_count;
+	int damage;
+	int life;
+	int enemyXL;
+	int enemyYL;
+	int blockXL;
+	int blockYL;
+	RECT view;
+};
+
+struct BULLET_TABLE
+{
+	int8_t damage;
+	int8_t life;
+	int life_count;
+	int bbits;
+	int enemyXL;
+	int enemyYL;
+	int blockXL;
+	int blockYL;
+	RECT view;
+};
+
+#define BULLET_MAX 0x40
+extern BULLET gBul[BULLET_MAX];
+
+void InitBullet();
+int CountArmsBullet(int arms_code);
+int CountBulletNum(int bullet_code);
+void DeleteBullet(int code);
+void ClearBullet();
+void PutBullet(int fx, int fy);
+void SetBullet(int no, int x, int y, int dir);
+void ActBullet();
--- a/src/Caret.cpp
+++ b/src/Caret.cpp
@@ -58,6 +58,108 @@
 		crt->rect = rcLeft[crt->ani_no];
 }
 
+void ActCaret02(CARET *crt)
+{
+	RECT rect_right[4];
+	RECT rect_left[4];
+	RECT rect_up[3];
+	rect_left[0].left = 0;
+	rect_left[0].top = 32;
+	rect_left[0].right = 16;
+	rect_left[0].bottom = 48;
+	rect_left[1].left = 16;
+	rect_left[1].top = 32;
+	rect_left[1].right = 32;
+	rect_left[1].bottom = 48;
+	rect_left[2].left = 32;
+	rect_left[2].top = 32;
+	rect_left[2].right = 48;
+	rect_left[2].bottom = 48;
+	rect_left[3].left = 48;
+	rect_left[3].top = 32;
+	rect_left[3].right = 64;
+	rect_left[3].bottom = 48;
+	rect_right[0].left = 176;
+	rect_right[0].top = 0;
+	rect_right[0].right = 192;
+	rect_right[0].bottom = 16;
+	rect_right[1].left = 192;
+	rect_right[1].top = 0;
+	rect_right[1].right = 208;
+	rect_right[1].bottom = 16;
+	rect_right[2].left = 208;
+	rect_right[2].top = 0;
+	rect_right[2].right = 224;
+	rect_right[2].bottom = 16;
+	rect_right[3].left = 224;
+	rect_right[3].top = 0;
+	rect_right[3].right = 240;
+	rect_right[3].bottom = 16;
+	rect_up[0].left = 0;
+	rect_up[0].top = 32;
+	rect_up[0].right = 16;
+	rect_up[0].bottom = 48;
+	rect_up[1].left = 32;
+	rect_up[1].top = 32;
+	rect_up[1].right = 48;
+	rect_up[1].bottom = 48;
+	rect_up[2].left = 16;
+	rect_up[2].top = 32;
+	rect_up[2].right = 32;
+	rect_up[2].bottom = 48;
+
+	switch (crt->direct)
+	{
+		case 0:
+			crt->ym -= 0x10;
+			crt->y += crt->ym;
+			if (++crt->ani_wait > 5)
+			{
+				crt->ani_wait = 0;
+				++crt->ani_no;
+			}
+			if ( crt->ani_no > 3 )
+				crt->cond = 0;
+			crt->rect = rect_left[crt->ani_no];
+			break;
+			
+		case 1:
+			crt->rect = rect_up[++crt->ani_wait / 2 % 3];
+			if (crt->ani_wait > 24)
+				crt->cond = 0;
+			break;
+			
+		case 2:
+			if ( ++crt->ani_wait > 2 )
+			{
+				crt->ani_wait = 0;
+				++crt->ani_no;
+			}
+			if ( crt->ani_no > 3 )
+				crt->cond = 0;
+			crt->rect = rect_right[crt->ani_no];
+			break;
+	}
+}
+
+void ActCaret03(CARET *crt)
+{
+	RECT rect[4];
+	rect[0] = {0, 48, 16, 64};
+	rect[1] = {16, 48, 32, 64};
+	rect[2] = {32, 48, 48, 64};
+	rect[3] = {48, 48, 64, 64};
+	
+	if (++crt->ani_wait > 2)
+	{
+		crt->ani_wait = 0;
+		if (++crt->ani_no > 3)
+			crt->cond = 0;
+	}
+	
+	crt->rect = rect[crt->ani_no];
+}
+
 void ActCaret08(CARET *crt)
 {
 	if (crt->direct)
@@ -148,22 +250,22 @@
 {
 	ActCaret00,
 	ActCaret01,
-	nullptr, //&ActCaret02,
-	nullptr, //&ActCaret03,
-	nullptr, //&ActCaret04,
-	nullptr, //&ActCaret05,
-	nullptr, //&ActCaret04,
-	nullptr, //&ActCaret07,
+	ActCaret02,
+	ActCaret03,
+	nullptr, //ActCaret04,
+	nullptr, //ActCaret05,
+	nullptr, //ActCaret04,
+	nullptr, //ActCaret07,
 	ActCaret08,
 	ActCaret09,
-	nullptr, //&ActCaret10,
-	nullptr, //&ActCaret11,
-	nullptr, //&ActCaret12,
+	nullptr, //ActCaret10,
+	nullptr, //ActCaret11,
+	nullptr, //ActCaret12,
 	ActCaret13,
-	nullptr, //&ActCaret14,
-	nullptr, //&ActCaret15,
-	nullptr, //&ActCaret16,
-	nullptr, //&ActCaret17
+	nullptr, //ActCaret14,
+	nullptr, //ActCaret15,
+	nullptr, //ActCaret16,
+	nullptr, //ActCaret17,
 };
 
 void ActCaret()
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -67,7 +67,7 @@
 bool StartDirectDraw()
 {
 	//Create renderer
-	gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
+	gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);
 	return true;
 }
 
@@ -145,7 +145,6 @@
 	SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 0);
 	SDL_RenderClear(gRenderer);
 	SDL_RenderCopy(gRenderer, texture, NULL, NULL);
-	SDL_RenderPresent(gRenderer);
 	SDL_SetRenderTarget(gRenderer, NULL);
 	
 	//Set surface's metadata
@@ -272,7 +271,6 @@
 	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
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -13,6 +13,9 @@
 #include "GenericLoad.h"
 #include "ArmsItem.h"
 #include "TextScr.h"
+#include "Bullet.h"
+#include "BulHit.h"
+#include "Shoot.h"
 #include "Fade.h"
 #include "Frame.h"
 #include "Flags.h"
@@ -427,7 +430,7 @@
 	//Initialize everything
 	InitMyChar();
 	InitNpChar();
-	//InitBullet();
+	InitBullet();
 	InitCaret();
 	//InitStar();
 	InitFade();
@@ -474,12 +477,12 @@
 				//HitMyCharBoss();
 				HitNpCharMap();
 				//HitBossMap();
-				//HitBulletMap();
+				HitBulletMap();
 				//HitNpCharBullet();
 				//HitBossBullet();
-				//if (g_GameFlags & 2)
-				//	ShootBullet();
-				//ActBullet();
+				if (g_GameFlags & 2)
+					ShootBullet();
+				ActBullet();
 				ActCaret();
 				MoveFrame3();
 				//ActFlash(frame_x, frame_y);
@@ -504,7 +507,7 @@
 			PutStage_Back(frame_x, frame_y);
 			//PutBossChar(frame_x, frame_y);
 			PutNpChar(frame_x, frame_y);
-			//PutBullet(frame_x, frame_y);
+			PutBullet(frame_x, frame_y);
 			PutMyChar(frame_x, frame_y);
 			//PutStar(frame_x, frame_y);
 			PutMapDataVector(frame_x, frame_y);
--- a/src/Main.cpp
+++ b/src/Main.cpp
@@ -127,6 +127,13 @@
 			gKeyCancel = gKeyShot;
 		}
 		
+		//Swap left and right weapon switch keys
+		if (CheckFileExists("s_reverse"))
+		{
+			gKeyArms = KEY_ARMSREV;
+			gKeyArmsRev = KEY_ARMS;
+		}
+		
 		//Alternate movement keys
 		if (config.move_button_mode)
 		{
@@ -229,6 +236,10 @@
 		}
 		
 		//Create window
+		#ifdef WINDOWS
+		SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"); //This fixes textures unloading in fullscreen
+		#endif
+		
 		gWindow = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, gWindowWidth, gWindowHeight, bFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
 		
 		if (gWindow)
--- a/src/Map.cpp
+++ b/src/Map.cpp
@@ -8,6 +8,7 @@
 #include "Map.h"
 #include "Tags.h"
 #include "Draw.h"
+#include "NpChar.h"
 
 #define PXM_BUFFER_SIZE 0x4B000
 
@@ -121,11 +122,11 @@
 
 bool ChangeMapParts(int x, int y, uint8_t no)
 {
-	if ( gMap.data[y * gMap.width + x] == no )
+	if (gMap.data[y * gMap.width + x] == no)
 		return false;
 	gMap.data[y * gMap.width + x] = no;
-	//for (int i = 0; i <= 2; ++i )
-	//	SetNpChar(4, x << 13, y << 13, 0, 0, 0, 0, 0);
+	for (int i = 0; i < 3; i++)
+		SetNpChar(4, x << 13, y << 13, 0, 0, 0, 0, 0);
 	return true;
 }
 
--- a/src/Resource.cpp
+++ b/src/Resource.cpp
@@ -97,7 +97,7 @@
 	if (!strcmp(name, "BDOWN"))
 	{
 		*size = sizeof(rBDOWN);
-		return rACCESS;
+		return rBDOWN;
 	}
 	if (!strcmp(name, "CEMETERY"))
 	{
--- /dev/null
+++ b/src/Shoot.cpp
@@ -1,0 +1,112 @@
+#include "ArmsItem.h"
+#include "MycParam.h"
+#include "Shoot.h"
+#include "Caret.h"
+#include "Bullet.h"
+#include "Sound.h"
+#include "MyChar.h"
+#include "KeyControl.h"
+
+int empty;
+int spur_charge;
+
+void ShootBullet_PoleStar(int level)
+{
+	int bul_no;
+	switch (level)
+	{
+	case 2:
+		bul_no = 5;
+		break;
+	case 3:
+		bul_no = 6;
+		break;
+	case 1:
+		bul_no = 4;
+		break;
+	}
+	
+	if (CountArmsBullet(2) < 2 && gKeyTrg & gKeyShot)
+	{
+		if (!UseArmsEnergy(1))
+		{
+			PlaySoundObject(37, 1);
+		}
+		else
+		{
+			if (gMC.up)
+			{
+				if (gMC.direct)
+				{
+					SetBullet(bul_no, gMC.x + 0x200, gMC.y - 0x1000, 1);
+					SetCaret(gMC.x + 0x200, gMC.y - 0x1000, 3, 0);
+				}
+				else
+				{
+					SetBullet(bul_no, gMC.x - 0x200, gMC.y - 0x1000, 1);
+					SetCaret(gMC.x - 0x200, gMC.y - 0x1000, 3, 0);
+				}
+			}
+			else if (gMC.down)
+			{
+				if (gMC.direct)
+				{
+					SetBullet(bul_no, gMC.x + 0x200, gMC.y + 0x1000, 3);
+					SetCaret(gMC.x + 0x200, gMC.y + 0x1000, 3, 0);
+				}
+				else
+				{
+					SetBullet(bul_no, gMC.x - 0x200, gMC.y + 0x1000, 3);
+					SetCaret(gMC.x - 0x200, gMC.y + 0x1000, 3, 0);
+				}
+			}
+			else
+			{
+				if (gMC.direct)
+				{
+					SetBullet(bul_no, gMC.x + 0xC00, gMC.y + 0x600, 2);
+					SetCaret(gMC.x + 0x1800, gMC.y + 0x600, 3, 0);
+				}
+				else
+				{
+					SetBullet(bul_no, gMC.x - 0xC00, gMC.y + 0x600, 0);
+					SetCaret(gMC.x - 0x1800, gMC.y + 0x600, 3, 0);
+				}
+			}
+			
+			if (level == 3)
+				PlaySoundObject(49, 1);
+			else
+				PlaySoundObject(32, 1);
+		}
+	}
+}
+
+void ShootBullet()
+{
+	if (empty)
+		--empty;
+	
+	//Only let the player shoot every 4 frames
+	static int soft_rensha;
+	if (soft_rensha)
+		--soft_rensha;
+	
+	if (gKeyTrg & gKeyShot)
+	{
+		if (soft_rensha)
+			return;
+		soft_rensha = 4;
+	}
+	
+	//Run functions
+	if (!(gMC.cond & 2))
+	{
+		switch (gArmsData[gSelectedArms].code)
+		{
+			case 2:
+				ShootBullet_PoleStar(gArmsData[gSelectedArms].level);
+				break;
+		}
+	}
+}
--- /dev/null
+++ b/src/Shoot.h
@@ -1,0 +1,2 @@
+#pragma once
+void ShootBullet();
--