ScarletBlackMarket/script/game/Spell2.dnh

470 lines
11 KiB
Plaintext
Raw Permalink Normal View History

2022-08-20 05:42:00 +00:00
#TouhouDanmakufu[Single]
#ScriptVersion[3]
#Title["Remilia Spell 2 (Patchouli Card)"]
#Text["yassification"]
#System["script/KevinSystem/Kevin_System.txt"]
int difficultySelect = 0;
let objScene = GetEnemyBossSceneObjectID();
let csd = GetCurrentScriptDirectory();
let bossObj;
float bossX = 0;
float bossY = 0;
float playerY = 0;
float playerX = 0;
let aniframe = 0;
let aniframe2 = 0;
let spellsnd = ObjSound_Create();
let bossdiesnd = ObjSound_Create();
/*
2022-08-20 05:42:00 +00:00
Parameters:
- Line density
- Line speed
- Line delay
2022-08-20 05:42:00 +00:00
- Ring density
- Ring max speed
- Delays between rings
- Remilia charge time
2022-08-20 05:42:00 +00:00
- Aim speed
2022-08-20 05:42:00 +00:00
*/
int[] denseLine = [3, 4, 5];
2022-08-23 09:48:09 +00:00
int[] speedLine = [9, 10, 12];
float[] delayLine = [20, 18, 15];
2022-08-23 09:48:09 +00:00
int[] denseRing = [12, 14, 15];
float[] maxspeedRing = [8, 9, 11];
2022-08-23 09:48:09 +00:00
int[] deceltimeRing = [20, 25, 30];
int[] acceltimeRing = [60, 45, 35];
// Remilia takes 36 frames to charge down the screen. Preferably, pick a number 36 can divide with.
2022-08-23 09:48:09 +00:00
int[] ringDelay = [4, 3, 3];
// How much time Remilia takes to charge her attack and you get to GTFO.
2022-08-20 05:42:00 +00:00
2022-08-23 09:48:09 +00:00
int[] chargetimeRemi = [60, 45, 40];
float[] maxspeedBookAim = [10, 12, 15];
2022-08-20 05:42:00 +00:00
int[] bookArray = []; // it's a secret tool that will help us later
bool bookShooting = false; // it's a secret tool that will help us later
string tex = "script/game/resourceLib/Spritesheet_StationJam.png";
2022-08-20 05:42:00 +00:00
// Includes ahoy
#include "script/KevinSystem/Universal_Lib.txt" // The library to include all libraries :sans: :nail_care:
@Initialize {
//SetIntersectionVisualization(true);
SetAutoDeleteObject(true);
2022-08-22 10:14:18 +00:00
LoadTextureEx(tex, true, false);
2022-08-20 05:42:00 +00:00
2022-08-23 09:48:09 +00:00
difficultySelect = _InitDifficulty(difficultySelect);
2022-08-20 05:42:00 +00:00
2022-08-23 09:48:09 +00:00
//difficultySelect = 2; // debug
2022-08-20 05:42:00 +00:00
SetShotAutoDeleteClip(64, 64, 64, 64);
if(!IsCommonDataAreaExists("PIV")){
CreateCommonDataArea("PIV");
SetAreaCommonData("PIV", "currentvalue", 10000);
}
else{}
// Create the boss object itself
bossObj = ObjEnemy_Create(OBJ_ENEMY_BOSS);
ObjEnemy_Regist(bossObj);
ObjMove_SetPosition(bossObj, GetCommonData("Boss Position X", STG_WIDTH/2), GetCommonData("Boss Position Y", STG_HEIGHT/2));
ObjEnemy_SetMaximumDamage(bossObj, 999);
_RenderBoss(bossObj);
2022-08-20 05:42:00 +00:00
//WriteLog(spellPIV);
WriteLog(ObjEnemyBossScene_GetInfo(objScene, INFO_SPELL_SCORE));
mainTask();
_FadeInvincibility(bossObj, 150, 150, 1);
endingnew();
}
@Event {
alternative(GetEventType())
case(EV_REQUEST_LIFE) {
SetScriptResult(2500);
2022-08-20 05:42:00 +00:00
}
case(EV_REQUEST_TIMER) {
SetScriptResult(40);
}
// Start firing from books
case(EV_USER+999){
bookShooting = true;
}
// Stop firing from books
case(EV_USER+1000){
bookShooting = false;
}
2022-08-20 05:42:00 +00:00
}
@MainLoop {
playerY = GetPlayerY();
playerX = GetPlayerX();
//The player position is ALWAYS UPDATED
bossX = ObjMove_GetX(bossObj);
bossY = ObjMove_GetY(bossObj);
2022-08-22 10:14:18 +00:00
ObjEnemy_SetIntersectionCircleToShot(bossObj, ObjMove_GetX(bossObj), ObjMove_GetY(bossObj), 180);
2022-08-20 05:42:00 +00:00
yield;
}
@Finalize {
}
/*
Spell 2 (Patchouli):
Remilia summons 5 books (5 elements) (see Philosopher's Stone). These books move to the top of the screen and fire downwards lines that restrict horizontal movement.
Remilia constantly will charge down at the player's horizontal position, leaving behind red rings. The player must weave through the lines of the books.
After 3 charges, the books turn into bats that aim for the player, leaving trails of bullets in their wake. Remilia re-calls 5 books and then the pattern restarts.
Note: Books = Enemies with no registered intersection
Parameters:
- Line density
- Line speed
- Line delay
- Ring density
- Ring speed
- Delays between rings
2022-08-20 05:42:00 +00:00
- Remilia charge time
- Remilia charge delay
- Aim speed
2022-08-20 05:42:00 +00:00
*/
task mainTask {
2022-08-22 10:14:18 +00:00
ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, STG_HEIGHT/2
, 45, LERP_DECELERATE);
2022-08-20 05:42:00 +00:00
wait(45);
2022-08-22 10:14:18 +00:00
_UseCard();
// Create 5 books
CreateBook([0, 0, 256, 256], STG_WIDTH*1/6, 0.65, KEV_LEAF_RED);
CreateBook([256, 0, 512, 256], STG_WIDTH*2/6, 0.65, KEV_LEAF_AQUA);
CreateBook([512, 0, 768, 256], STG_WIDTH*3/6, 0.65, KEV_LEAF_ORANGE);
CreateBook([768, 0, 1024, 256], STG_WIDTH*4/6, 0.65, KEV_LEAF_WHITE);
CreateBook([1024, 0, 1280, 256], STG_WIDTH*5/6, 0.65, KEV_LEAF_GREEN);
bookShooting = true;
// It takes 60 seconds for the books to start firing..
wait(60+delayLine[difficultySelect]*3);
// Repeat 3 times: Choose an area based on the player's position, charge down there while firing fireballs + rings, then return to same position.
2022-08-20 05:42:00 +00:00
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0){
if(playerX <= STG_WIDTH/6 && playerY >= 0){
ChargeAttack(0.5*STG_WIDTH/6, 0);
}
else if(playerX <= 2*STG_WIDTH/6 && playerY >= STG_WIDTH/6){
ChargeAttack(1.5*STG_WIDTH/6, 1);
}
else if(playerX <= 3*STG_WIDTH/6 && playerY >= 2*STG_WIDTH/6){
ChargeAttack(2.5*STG_WIDTH/6, 2);
}
else if(playerX <= 4*STG_WIDTH/6 && playerY >= 3*STG_WIDTH/6){
ChargeAttack(3.5*STG_WIDTH/6, 3);
}
else if(playerX <= 5*STG_WIDTH/6 && playerY >= 4*STG_WIDTH/6){
ChargeAttack(4.5*STG_WIDTH/6, 4);
}
else{
ChargeAttack(5.5*STG_WIDTH/6, 5);
}
yield;
2022-08-20 05:42:00 +00:00
}
// Aim books at the player.
// Remove books from bookArray and then restart pattern.
2022-08-20 05:42:00 +00:00
}
2022-08-22 10:14:18 +00:00
function <void> _UseCard(){
// Remi spell
int cardImg = _Create2DImage(tex, [256, 256, 512, 512]);
ObjRender_SetPosition(cardImg, bossX, bossY, 0);
ascent(i in 0..30){
ObjRender_SetY(cardImg, Interpolate_Decelerate(bossY, bossY - 256, i/30));
ObjRender_SetAlpha(cardImg, Interpolate_Decelerate(0, 255, i/30));
yield;
}
wait(30);
ascent(i in 0..15){
ObjRender_SetAlpha(cardImg, Interpolate_Decelerate(255, 0, i/15));
yield;
}
Obj_Delete(cardImg);
}
2022-08-20 05:42:00 +00:00
/*
Fire: 0, 0, 256, 256
Water: 256, 0, 512, 256
Wood: 512, 0, 768, 256
Metal: 768, 0, 1024, 256
Earth: 1024, 0, 1280, 256
*/
function <void> ChargeAttack(float x, int colorselect){
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT/7, 30, LERP_DECELERATE);
wait(30);
_CreateCustomTelegraphLine(
x, 0,
90, 90,
3333, 3333,
2022-08-23 09:48:09 +00:00
0, [STG_WIDTH/6, STG_WIDTH/6+60, 3*STG_WIDTH/6][difficultySelect],
0xDC7171, 220,
15, chargetimeRemi[difficultySelect], 15
);
wait(chargetimeRemi[difficultySelect]-30);
// MOVEEEEE BITCH
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT/9, 30, LERP_DECELERATE);
wait(25);
//ObjEnemy_SetDamageRate(bossObj, 0, 0);
ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT*1.2, 36, LERP_DECELERATE);
float ang = GetAngleToPlayer(bossObj);
async{
loop(36){
loop(2){
int shot = CreateShotA1(bossX+rand(-STG_HEIGHT/12, STG_HEIGHT/12), bossY, 18, rand(269, 271), KEV_FIRE_RED, 5);
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
else{
_Delay(shot, 5);
_BulletRescale(shot, 0.85, true, 1);
Shoot2;
}
}
wait(1);
}
ObjEnemy_SetDamageRate(bossObj, 0, 0);
}
int color = [KEV_AURABALL_RED, KEV_AURABALL_AQUA, KEV_AURABALL_ORANGE, KEV_AURABALL_WHITE, KEV_AURABALL_GREEN, KEV_AURABALL_PINK][colorselect];
2022-08-23 09:48:09 +00:00
loop(36/ringDelay[difficultySelect]){
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);
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
else{
_Delay(shot, 10);
ObjMove_AddPatternA2(shot, 30, NO_CHANGE, NO_CHANGE, maxspeedRing[difficultySelect]/acceltimeRing[difficultySelect], maxspeedRing[difficultySelect], 0);
2022-08-22 10:14:18 +00:00
_BulletRescale(shot, 0.6, true, 1);
//Shoot1;
}
}
2022-08-23 09:48:09 +00:00
wait(ringDelay[difficultySelect]);
}
wait(45);
ObjMove_SetPosition(bossObj, STG_WIDTH/2, -256);
ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, STG_HEIGHT/2, 30, LERP_DECELERATE);
wait(15);
ObjEnemy_SetDamageRate(bossObj, 100, 100);
2022-08-23 09:48:09 +00:00
wait([75, 70, 65][difficultySelect]);
}
task CreateBook(
int[] rect,
int destX,
float scaleEnm, int graphicBullet
2022-08-20 05:42:00 +00:00
){
int book = _CreateEnemy(
false,
bossX, bossY, destX, STG_HEIGHT/7.5, 60,
scaleEnm, scaleEnm,
99999, -1, -1,
tex,
rect[0], rect[1], rect[2], rect[3]
);
Obj_SetRenderPriorityI(book, 39);
ObjEnemy_SetEnableIntersectionPositionFetching(book, false); // so the lock-on shot doesn't home onto the books
bookArray ~= [book];
// Fire task
async{
wait(60);
while(!Obj_IsDeleted(book) && bookShooting){
loop(denseLine[difficultySelect]){
int shot = CreateShotA1(ObjMove_GetX(book), ObjMove_GetY(book), speedLine[difficultySelect], 90, graphicBullet, 15);
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
else{
_Delay(shot, 10);
_BulletRescale(shot, 0.85, true, 1);
Shoot1;
}
2022-08-23 09:48:09 +00:00
wait([5, 4, 3][difficultySelect]);
}
wait(delayLine[difficultySelect]);
}
}
async{
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE) > 0){
yield;
}
Obj_Delete(book);
}
async{
wait(60);
while(bookShooting){
ascent(i in 0..24){
int shot = CreateShotA1(ObjMove_GetX(book), ObjMove_GetY(book), 12, Interpolate_Smoother(190, 350, i/24), graphicBullet+44, 15);
if(ObjEnemy_GetInfo(bossObj, INFO_LIFE) <= 0){Obj_Delete(shot);}
else{
_Delay(shot, 0);
_BulletRescale(shot, 0.5, true, 1);
}
}
wait(delayLine[difficultySelect]);
}
}
2022-08-20 05:42:00 +00:00
}
function <int> CreateFan (int parent, int way, int graphic, int stack,
float ang, float angspace, float spd1, float spd2, float scale,
int type){
int objPattern = ObjPatternShot_Create();
ObjPatternShot_SetParentObject(objPattern, parent);
if(ObjEnemyBossScene_GetInfo(GetEnemyBossSceneObjectID(), INFO_CURRENT_LIFE) == 0){Obj_Delete(objPattern); return;}
ObjPatternShot_SetPatternType(objPattern, PATTERN_LINE); // PATTERN_FAN or PATTERN_FAN_AIMED
ObjPatternShot_SetShotType(objPattern, OBJ_SHOT);
ObjPatternShot_SetInitialBlendMode(objPattern, BLEND_ALPHA);
ObjPatternShot_SetShotCount(objPattern, way, stack);
ObjPatternShot_SetSpeed(objPattern, spd1, spd2);
ObjPatternShot_SetAngle(objPattern, ang, angspace);
ObjPatternShot_SetBasePointOffset(objPattern, 0, 0);
//ObjPatternShot_SetDelay(objPattern, 15);
ObjPatternShot_SetGraphic(objPattern, graphic);
Shoot2;
int[] arrayPattern = ObjPatternShot_FireReturn(objPattern);
for each (int bullet in ref arrayPattern){
_BulletRescale(bullet, scale, true, 1);
_Delay(bullet, 10);
_EnemyShotFade(bullet, 600, true, 2.5); // Placeholder
Obj_SetRenderPriorityI(bullet, 51);
//if (reflect) {_ReflectToPlayer(bullet);}
}
async{
wait(600);
Obj_Delete(objPattern);
return;
}
return objPattern;
}
2022-08-20 05:42:00 +00:00
task endingnew(){
while(ObjEnemy_GetInfo(bossObj, INFO_LIFE)>0){
yield;
}
_GoToBrazil(objScene, bossObj, 12, 24);
wait(120);
ObjSound_SetVolumeRate(fire2, 20);
CloseScript(GetOwnScriptID);
}