Compare commits

..

No commits in common. "3af70a40bd4af51b9d0b5a49e459a866d7747d83" and "af1977159cb1c1e8b35e3c45c9ab6c125b37e64d" have entirely different histories.

37 changed files with 68 additions and 132 deletions

View File

@ -2,9 +2,6 @@
Repository for Kevinmonitor and co.'s Touhou Station Jam 3 game.
虹魔郷
The game is now fully playable.
All attacks are now available as of 22/8/2022.
+ Remilia Nonspell 1
@ -21,11 +18,6 @@ How to install:
+ Install all files in this repo.
+ Open either th_dnh_ph3sx.exe or th_dnh_ph3sx_legacy.exe (if you cannot open the latter)
To play the full game (with options, language selection, menus, difficulty select, etc.)
+ Select "Package" in the title screen.
+ Select "be gay do crimes". Yes, this is the actual name of the script.
To play attacks individually:
+ Select "Single" in the title screen.

View File

@ -1,65 +1,29 @@
Game Description (on Game Page):
[The Japanese description is translated using DeepL. I am sorry for any mistakes.]
ENGLISH:
A fan-made side story to the brand new instalment of Touhou Project, “100th Black Market”, starring the heroic Chimata Tenkyuu.
A black market at the Scarlet Devil Mansion has opened up! Play as the market god and face the mischievous vampire using the cards for wicked purposes!
Controls:
Z (Hold): Shoot/Confirm
X: Use Spell Card (limited use)/Cancel
Esc: Pause Game
Esc+R: Quick Retry
Esc+Q: Quick Exit to Title
See config.exe to rebind keys.
Read the in-game manual for more information!
Credits:
Game Programmer & Designer
Graphic Design & Artwork
Character & Background Artwork
Spritework
Kevin Minh (@kevinminh_alt)
Additional Artwork
Spritework & Card Artwork
Japanese Translation
Aqwa (@aqwwa58)
Schmagons
Composer (Boss Theme)
Yal (@GameDevYal)
JAPANESE:
東方Projectの完全新作「100番目の闇市」のファンメイドサイドストーリーで、主人公の「天弓千亦」が主演します。
紅魔館に闇市が開かれた!?マーケットの神様として、カードを悪用する吸血鬼に立ち向かえ!
操作方法
Z (ホールド): 撃つ/確認する
X: スペルカード使用(使用制限あり/キャンセル
Esc: ゲームの一時停止
Esc+R: クイックリトライ
Esc+Q: タイトル画面でクイック終了
キーのリバインドはconfig.exeを参照してください。
クレジット
ゲームプログラマー&デザイナー
グラフィックデザイン&アートワーク
Kevin Minh (@kevinminh_alt)
追加アートワーク
Aqwa (@aqwwa58)
Schmagons
作曲家 (ボスのテーマ)
Yal (@GameDevYal)
[INSERT JP TRANSLATION HERE]
——

Binary file not shown.

Binary file not shown.

View File

@ -58,7 +58,7 @@ Lifebar full = (5, 78, 16, 108)
StartItemScript(dirCurrent ~ "./kevin_system/KevinSystem_Item.txt");
TExtendSystem();
//TExtendSystem();
TBossLife();
TBossTimer();
TCurrentFps();
@ -131,7 +131,7 @@ task TExtendSystem(){
//ObjText_SetFontBold(NextText, true);
// Indicates the score threshold needed for the next extend
/*let ExtendThresholdText =
let ExtendThresholdText =
CreateTextObject(
250, 960, 24,
@ -142,7 +142,7 @@ task TExtendSystem(){
);
ObjText_SetFontBold(ExtendThresholdText, true);
ObjText_SetHorizontalAlignment(ExtendThresholdText, ALIGNMENT_RIGHT);*/
ObjText_SetHorizontalAlignment(ExtendThresholdText, ALIGNMENT_RIGHT);
int count = 0;
// Millions
@ -150,8 +150,8 @@ task TExtendSystem(){
];
if(GetCommonData("Difficulty", "Normal") == "Normal"){req = [10, 20, 40, 70];}
else{req = [10, 20, 40, 70];}
if(GetCommonData("Difficulty", "Hard") == "Hard"){req = [20, 80, 200, 500, 800, 1200, 2500, 5000];}
else{req = [15, 50, 100, 180, 300, 600, 1000, 2000, 4000];}
let next = 0;
@ -165,8 +165,8 @@ task TExtendSystem(){
ExtendEffect;
}
}
/*if(next != 8){ObjText_SetText(ExtendThresholdText, "NEXT: " ~ DigitToCommaArray(req[next]*1000000));}
else{ObjText_SetText(ExtendThresholdText, "MAX EXTEND");}*/
if(next != 8){ObjText_SetText(ExtendThresholdText, "NEXT: " ~ DigitToCommaArray(req[next]*1000000));}
else{ObjText_SetText(ExtendThresholdText, "MAX EXTEND");}
yield;
}
}

View File

@ -17,23 +17,21 @@
*/
function <int> _InitDifficulty(int diffInt){
int difficulty = 0;
task _InitDifficulty(int diffInt){
if(GetCommonData("Difficulty", "Normal") == "Normal"){
difficulty = 0;
diffInt = 0;
}
else if(GetCommonData("Difficulty", "Normal") == "Hard"){
difficulty = 1;
else if(GetCommonData("Difficulty", "Normal") == "Hyper"){
diffInt = 1;
}
else if(GetCommonData("Difficulty", "Normal") == "Lunatic"){
difficulty = 2;
else if(GetCommonData("Difficulty", "Normal") == "Unparalleled"){
diffInt = 2;
}
return difficulty;
return;
}
// Explosion Sound Effects
@ -260,7 +258,7 @@ task _GoToBrazil(
if(ObjEnemyBossScene_GetInfo(targetscene, INFO_PLAYER_SHOOTDOWN_COUNT) > 0){
finalItemDrop = minitemdrop;
//itemType = POINT_REGULAR;
itemType = POINT_REGULAR;
}
DeleteShotAll(TYPE_ALL,TYPE_ITEM);

View File

@ -29,14 +29,14 @@ InstallFont("script/KevinSystem/font/AnkeCall.ttf");
// Placeholder
let invalid = "script/KevinSystem/img/lol.png";
let testEnemyTex = "script/game/resourceLib/Spritesheet_StationJam.png";
let testEnemyTex = "script/game/StageLib/TestEnemy.png";
LoadTextureEx(invalid, true, true);
LoadTextureEx(testEnemyTex, true, true);
int PetalEffect = ObjParticleList_Create(OBJ_PARTICLE_LIST_2D);
_EffectListPreRender(PetalEffect, testEnemyTex, [1536, 0, 1792, 256]);
_EffectListPreRender(PetalEffect, testEnemyTex, [512, 0, 768, 256]);
_SoundTask;
// Simple text object creation (adapted from mkm)

View File

@ -27,9 +27,9 @@ int STGHEIGHT = GetStgFrameHeight();
task TBackgroundNew(renderX, renderY){
let objText = ObjText_Create();
ObjText_SetText(objText, ["Thank you for playing![r]Until the next station...", "このゲームを遊ぶをありがとうございました!"][GetCommonData("Language", 0)]);
ObjText_SetFontSize(objText, [38, 45][GetCommonData("Language", 0)]);
ObjText_SetFontType(objText, "コーポレート・ロゴ(ラウンド) ver2 Bold");
ObjText_SetText(objText, "Thank you for playing![r]Until the next pride...");
ObjText_SetFontSize(objText, 36);
ObjText_SetFontType(objText, "Connecting Chain Handserif");
//ObjText_SetMaxWidth(objText, GetScreenWidth/2);
ObjText_SetHorizontalAlignment(objText, ALIGNMENT_CENTER);
@ -185,7 +185,7 @@ task TMenu
let mx = GetScreenWidth/2;
let my = GetScreenHeight/4;
let texts = ["Save Replay", "Back To Title", "Restart Battle"];
let texts = ["Save A Replay", "Depart From The Market", "Re-enter The Parade"];
var countMenu = length(texts);
ascent(var iText in 0 .. countMenu)
{

View File

@ -31,27 +31,19 @@ task TFunFact(){
//int y = 0;
let textchoices = [
["The sun is just a really hot egg tart, right?",
"Touhou.",
"You know what else is as cool as Touhou? It's Kouji Kouda[r]from the hit anime \"Boku no Hero Academia\"!",
"Thanks for playing this game!",
"You can set the amount of starting lives you have in the configurations menu.[r]If you have trouble with difficult patterns or stage sections, now you can blast right through them!"],
["太陽は実際に暑いエッグタルト、ね?",
"東方.",
"このゲームの開発元の一番好きなキャラクターは『僕のヒーローアカデミア』の『口田甲司』ですよ![r]口田くんはすごいとかわいいね...",
"このゲームを遊ぶをありがとうございました!",
"あなたは『OPTIONS』のメニューにはライフカウンターを変化することができます。"],
"The sun is just a really hot egg tart, if you think about it.",
"Gay people.",
"You know what else is as cool as gay Touhous? It's Kouji Kouda[r]from the hit anime \"Boku no Hero Academia\"- *turns into a Kouda plushie*",
"Thanks for playing this game! I hope you enjoyed my gay Touhou endeavours.",
"You can set the amount of starting lives you have in the configurations menu.[r]If you have trouble with difficult patterns or stage sections, now you can blast right through them!"
];
int x = prand_int(0, length(textchoices[GetCommonData("Language", 0)])-1);
int x = prand_int(0, length(textchoices)-1);
//y = length(textchoices);
let objText = ObjText_Create();
ObjText_SetText(objText, textchoices[GetCommonData("Language", 0)][x]);
ObjText_SetFontSize(objText, [38, 45][GetCommonData("Language", 0)]);
ObjText_SetFontType(objText, "コーポレート・ロゴ(ラウンド) ver2 Bold");
ObjText_SetText(objText, textchoices[x]);
ObjText_SetFontSize(objText, 36);
ObjText_SetFontType(objText, "Connecting Chain Handserif");
//ObjText_SetMaxWidth(objText, GetScreenWidth/2);
ObjText_SetHorizontalAlignment(objText, ALIGNMENT_CENTER);
@ -213,7 +205,7 @@ task TMenu
let mx = GetScreenWidth/2;
let my = GetScreenHeight/4;
let texts = ["Resume Game", "Back To Title", "Restart Battle"];
let texts = ["Resume The Faceoff", "Accept Your Losses", "Take Another Shot"];
var countMenu = length(texts);
ascent(var iText in 0 .. countMenu)
{

View File

@ -38,8 +38,6 @@ float BGMRate = GetAreaCommonData("Config", "BGMVol", 100) * 0.01;
}
else{}
SetPlayerLife(GetAreaCommonData("Config", "StartingLife", 5));
SetAutoDeleteObject(true);
ObjSound_Load(objBGM, "script/game/resourceLib/bossTheme.ogg");
@ -88,11 +86,6 @@ task PluralTask(){
bossTrueStart = true;
ObjSound_Play(objBGM);
async{
while(GetPlayerState() != STATE_END){yield;}
ObjSound_Stop(objBGM);
}
while(!Obj_IsDeleted(obj)){
yield;
}

View File

@ -38,9 +38,9 @@ int[] denseBubble = [8, 9, 10];
int[] delayBubble = [15, 12, 10];
float[] speedBubble = [8, 9, 9];
int[] denseCurve = [5, 6, 7];
float[] offsetCurve = [2, 2.4, 4.25];
int[] denseSpiral = [6, 7, 8];
int[] denseCurve = [5, 7, 7];
float[] offsetCurve = [2, 2.8, 4.2];
int[] denseSpiral = [6, 8, 9];
int[] delaySpiral = [10, 8, 10];
int[] speedSpiral = [6, 8, 8];
@ -55,7 +55,7 @@ int[] speedSpiral = [6, 8, 8];
SetAutoDeleteObject(true);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 2; // debug

View File

@ -58,7 +58,7 @@ int[] delaySpiral = [5, 5, 4];
SetAutoDeleteObject(true);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 0; // debug

View File

@ -88,7 +88,7 @@ int[] thresholdStopSpin = [80, 70, 60];
SetAutoDeleteObject(true);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
difficultySelect = 1; // debug

View File

@ -38,16 +38,16 @@ Parameters:
int[] denseSpiral = [6, 7, 8];
float[] angleoffsetSpiral = [1.618*7, 1.618*6, 1.618*5];
float[] speedSpiral = [8.25, 9.5, 11];
float[] speedSpiral = [8, 9.25, 11];
int[] denseRing = [10, 12, 14];
float[] maxspeedRing = [7.5, 9, 10];
float[] maxspeedRing = [7.5, 8.5, 10];
int[] deceltimeRing = [20, 25, 32];
int[] acceltimeRing = [60, 50, 40];
// Remilia takes 36 frames. Preferably, pick a number 36 can divide with.
int[] delayRing = [6, 5, 3];
int[] delayRing = [9, 6, 5];
// How much time Remilia takes to charge her attack and you get to GTFO.
@ -67,7 +67,7 @@ string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
SetAutoDeleteObject(true);
LoadTextureEx(tex, true, false);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 2; // debug
@ -214,7 +214,7 @@ function <void> _VampireChase(){
float ang = GetAngleToPlayer(bossObj);
loop(36/delayRing[difficultySelect]){
loop(36/delayRing){
ascent(i in 0..denseRing[difficultySelect]){
int shot = CreateShotA2(bossX, bossY, maxspeedRing[difficultySelect], ang + 360/denseRing[difficultySelect] * i, -maxspeedRing[difficultySelect]/deceltimeRing[difficultySelect], 0, 0, KEV_AURABALL_RED, 10);
@ -228,7 +228,7 @@ function <void> _VampireChase(){
}
ang += 18;
wait(delayRing[difficultySelect]);
wait(delayRing);
}

View File

@ -40,21 +40,21 @@ Parameters:
*/
int[] denseLine = [3, 4, 5];
int[] speedLine = [9, 10, 12];
float[] delayLine = [20, 18, 15];
int[] speedLine = [8.5, 10, 12];
float[] delayLine = [23, 20, 18];
int[] denseRing = [12, 14, 15];
int[] denseRing = [10, 12, 14];
float[] maxspeedRing = [8, 9, 11];
int[] deceltimeRing = [20, 25, 30];
int[] deceltimeRing = [20, 30, 40];
int[] acceltimeRing = [60, 45, 35];
// Remilia takes 36 frames to charge down the screen. Preferably, pick a number 36 can divide with.
int[] ringDelay = [4, 3, 3];
int[] ringDelay = [12, 9, 6];
// How much time Remilia takes to charge her attack and you get to GTFO.
int[] chargetimeRemi = [60, 45, 40];
int[] chargetimeRemi = [75, 60, 50];
float[] maxspeedBookAim = [10, 12, 15];
int[] bookArray = []; // it's a secret tool that will help us later
@ -73,9 +73,9 @@ string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
SetAutoDeleteObject(true);
LoadTextureEx(tex, true, false);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 2; // debug
//difficultySelect = 0; // debug
SetShotAutoDeleteClip(64, 64, 64, 64);
@ -272,7 +272,7 @@ function <void> ChargeAttack(float x, int colorselect){
x, 0,
90, 90,
3333, 3333,
0, [STG_WIDTH/6, STG_WIDTH/6+60, 3*STG_WIDTH/6][difficultySelect],
0, STG_WIDTH/6,
0xDC7171, 220,
15, chargetimeRemi[difficultySelect], 15
);
@ -307,7 +307,7 @@ function <void> ChargeAttack(float x, int colorselect){
int color = [KEV_AURABALL_RED, KEV_AURABALL_AQUA, KEV_AURABALL_ORANGE, KEV_AURABALL_WHITE, KEV_AURABALL_GREEN, KEV_AURABALL_PINK][colorselect];
loop(36/ringDelay[difficultySelect]){
loop(36/ringDelay){
ascent(i in 0..denseRing[difficultySelect]){
int shot = CreateShotA2(bossX, bossY, maxspeedRing[difficultySelect], ang + 360/denseRing[difficultySelect] * i, -maxspeedRing[difficultySelect]/deceltimeRing[difficultySelect], 0, 0, color, 10);
@ -319,7 +319,7 @@ function <void> ChargeAttack(float x, int colorselect){
//Shoot1;
}
}
wait(ringDelay[difficultySelect]);
wait(ringDelay);
}
@ -331,7 +331,7 @@ function <void> ChargeAttack(float x, int colorselect){
wait(15);
ObjEnemy_SetDamageRate(bossObj, 100, 100);
wait([75, 70, 65][difficultySelect]);
wait(75);
}
@ -370,7 +370,7 @@ task CreateBook(
_BulletRescale(shot, 0.85, true, 1);
Shoot1;
}
wait([5, 4, 3][difficultySelect]);
wait([3, 4, 4][difficultySelect]);
}
wait(delayLine[difficultySelect]);

View File

@ -62,7 +62,7 @@ string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
SetAutoDeleteObject(true);
LoadTextureEx(tex, true, false);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 0; // debug

View File

@ -88,7 +88,7 @@ int[] thresholdStopSpin = [80, 70, 60];
SetAutoDeleteObject(true);
difficultySelect = _InitDifficulty(difficultySelect);
_InitDifficulty(difficultySelect);
//difficultySelect = 1; // debug

View File

@ -76,8 +76,6 @@ function <void> Dialogue(){
//wait(60);
TTextScroll(objText2, "KEEP YOUR SEXINESS");
wait(60);
Obj_Delete(objText);
Obj_Delete(objText2);
Obj_Delete(objText3);

BIN
script/game/config.dat Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 447 KiB

After

Width:  |  Height:  |  Size: 403 KiB

View File

@ -54,7 +54,6 @@ int[] _shotArray = [];
int grazecounter = 0; // For basic graze = PIV mechanic
int shotAlpha = (GetAreaCommonData("Config", "PlayerShotOpacity", 60)*0.01)*255;
float[] PlayerSpd = [10, 5.35];
// Custom events for scoring mechanic
@ -507,7 +506,7 @@ task _ShotType(){
ascent(i in -1..1){
let shotA = CreatePlayerShotA1(-50+x+25-50*i, y, 50, ObjMove_GetAngle(option), 2, 1.1, 2);
_BulletRescalePlayer(shotA, 0.7, true, 1);
ObjRender_SetAlpha(shotA, shotAlpha);
ObjRender_SetAlpha(shotA, 255*(universalAlpha/100));
Obj_SetRenderPriorityI(shotA, 39);
ObjSound_Play(basesfx);
@ -578,7 +577,7 @@ task _ShotType(){
ascent(i in -1..1){
let shotA = CreatePlayerShotA1(-50+x+25-50*i, y, 50, ObjMove_GetAngle(option), 2.6, 1.1, 1);
_BulletRescalePlayer(shotA, 0.7, true, 1);
ObjRender_SetAlpha(shotA, shotAlpha);
ObjRender_SetAlpha(shotA, 255*(universalAlpha/100));
Obj_SetRenderPriorityI(shotA, 39);
ObjSound_Play(basesfx);

View File

@ -24,7 +24,7 @@ ShotData{
id = 2
rect = (512, 512, 768, 896)
render = ALPHA
alpha = 255
alpha = 200
collision = (128, 0, 74) // Hitbox of arrows is not centered on the sprite
}

View File

@ -6,7 +6,7 @@
//--------------------------------------------------------------
//Window Title
// The text to display on the window title.
//window.title = ~ Scarlet Black Market
//window.title = ExRumia Package
//--------------------------------------------------------------
//Screen Size
@ -25,7 +25,7 @@ window.size.list = 960x540 1280x720 1920x1080
//Skip Mode Speed
// The speed multiplier of the skip mode. (Triggered while Left CTRL is held down by default.)
// Limited between 1 and 50.
skip.rate = 0
skip.rate = 20
//--------------------------------------------------------------
//Enable/Disable Unfocused Processing