#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(); /* Parameters: - Line density - Line speed - Line delay - Ring density - Ring max speed - Delays between rings - Remilia charge time - Aim speed */ int[] denseLine = [3, 4, 5]; int[] speedLine = [9, 10, 12]; float[] delayLine = [20, 18, 15]; int[] denseRing = [12, 14, 15]; float[] maxspeedRing = [8, 9, 11]; 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. int[] ringDelay = [4, 3, 3]; // How much time Remilia takes to charge her attack and you get to GTFO. int[] chargetimeRemi = [60, 45, 40]; float[] maxspeedBookAim = [10, 12, 15]; 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"; // Includes ahoy #include "script/KevinSystem/Universal_Lib.txt" // The library to include all libraries :sans: :nail_care: @Initialize { //SetIntersectionVisualization(true); SetAutoDeleteObject(true); LoadTextureEx(tex, true, false); difficultySelect = _InitDifficulty(difficultySelect); //difficultySelect = 2; // debug 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); //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); } 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; } } @MainLoop { playerY = GetPlayerY(); playerX = GetPlayerX(); //The player position is ALWAYS UPDATED bossX = ObjMove_GetX(bossObj); bossY = ObjMove_GetY(bossObj); ObjEnemy_SetIntersectionCircleToShot(bossObj, ObjMove_GetX(bossObj), ObjMove_GetY(bossObj), 180); 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 - Remilia charge time - Remilia charge delay - Aim speed */ task mainTask { ObjMove_SetDestAtFrame(bossObj, STG_WIDTH/2, STG_HEIGHT/2 , 45, LERP_DECELERATE); wait(45); _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. 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; } // Aim books at the player. // Remove books from bookArray and then restart pattern. } function _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); } /* 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 ChargeAttack(float x, int colorselect){ ObjMove_SetDestAtFrame(bossObj, x, STG_HEIGHT/7, 30, LERP_DECELERATE); wait(30); _CreateCustomTelegraphLine( x, 0, 90, 90, 3333, 3333, 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]; 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); _BulletRescale(shot, 0.6, true, 1); //Shoot1; } } 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); wait([75, 70, 65][difficultySelect]); } task CreateBook( int[] rect, int destX, float scaleEnm, int graphicBullet ){ 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; } 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]); } } } function 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; } task endingnew(){ while(ObjEnemy_GetInfo(bossObj, INFO_LIFE)>0){ yield; } _GoToBrazil(objScene, bossObj, 12, 24); wait(120); ObjSound_SetVolumeRate(fire2, 20); CloseScript(GetOwnScriptID); }