#TouhouDanmakufu[Player] #ScriptVersion[3] #ID["Chimata"] #Title["Chimata Tenkyuu"] #Text["Shot Type: Blank Card Set[r]Spell Card: Shield of Market Regulation"] //#Image["./mariremi_lib/mariremi_illust.png"] #ReplayName["Chimata"] #include "script/KevinSystem/Kevin_PlayerLib.txt" #include "script/KevinSystem/PlayerSoundLib.dnh" #include "./Chimata_Function.dnh" #include "./Chimata_ShotConst.dnh" #include "script/KevinSystem/kevin_system/Kevin_ItemConst.txt" #include "script/KevinSystem/kevin_system/Kevin_ItemLib.txt" let csd = GetCurrentScriptDirectory(); // Global Variables float maxX = GetStgFrameWidth(); float maxY = GetStgFrameHeight(); // Images & Sound let teamimg = csd ~ "./playerlib/Chimata_Sheet.png"; LoadTextureEx(teamimg, true, true); //ObjRender_SetTextureFilterMip(teamimg, FILTER_LINEAR); let sndpath = csd ~ "./sound"; // Other stuff float playerX = 0; float playerY = 0; let objPlayer = GetPlayerObjectID(); int plrender = Obj_GetRenderPriorityI(objPlayer); bool ripplayer = false; float shotspeed = 0; float bombrand = 0; bool bombenable = false; bool focusactive = false; bool ishoming = false; int[] _enemyArray = []; // Prepare an array to store enemy IDs for Kouda's homing shot int[] _existArray = []; 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 const EV_PIV_100 = EV_USER + 100i; // Normal enemies and nons const EV_PIV_250 = EV_USER + 101i; // Spells const EV_PIV_500 = EV_USER + 102i; // Last Spells const EV_PIV_2000 = EV_USER + 103i; // What. @Initialize{ if(!IsCommonDataAreaExists("PIV")){ CreateCommonDataArea("PIV"); SetAreaCommonData("PIV", "currentvalue", 10000); } else{} SetPlayerStateEndEnable(true); // Stuff parameterrender(); playerrender(); Obj_SetRenderPriorityI(objPlayer, 43); plrender = Obj_GetRenderPriorityI(objPlayer); _SoundTask(); //SetIntersectionVisualization(true); // Debug _Mechanic(ripplayer, _enemyArray, _existArray, GetStgFrameWidth(), GetStgFrameHeight(), objPlayer, GetEnemyBossSceneObjectID(), 5, 2, 80); _HitboxRender(ripplayer, objPlayer, teamimg, teamimg, 1280, 512, 1408, 640, 1536, 896, 2048, 1408, 0.3, 0.65); SetShotAutoDeleteClip(256, 256, 256, 256); // Shot functions //_CAVELaser(); _ShotType(); //UniversalAlphaHandle(_shotArray); // Shot data loading LoadPlayerShotData(csd ~ "./Chimata_ShotData.dnh"); } @MainLoop{ _enemyArray = GetIntersectionRegistedEnemyID; shotspeed += 1; // Managing the shot rate //_shotArray = GetAllShotID(TARGET_PLAYER); //UniversalAlphaHandle(_shotArray); playerX = ObjMove_GetX(objPlayer); playerY = ObjMove_GetY(objPlayer); yield; } @Event{ alternative(GetEventType) // Delete effect case(EV_DELETE_SHOT_PLAYER){ let graphic = GetEventArgument(2); float[] position = GetEventArgument(1); let obj = CreatePlayerShotA1(position[0], position[1], 0, ObjMove_GetAngle(GetEventArgument(0)), 0, 99999, graphic); ObjShot_SetIntersectionEnable(obj, false); _DeleteEffect(obj); //if(graphic == ELECTRIC_FIRE_ALT) {_DeleteEffectAlt(obj);} //else{_DeleteEffect(obj);} } // PIV-item spawning events case(EV_PIV_100){ let arg = GetEventArgument(0); CreatePIVItem(PIV_100, arg[0], arg[1]); } case(EV_PIV_250){ let arg = GetEventArgument(0); CreatePIVItem(PIV_250, arg[0], arg[1]); } case(EV_PIV_500){ let arg = GetEventArgument(0); CreatePIVItem(PIV_500, arg[0], arg[1]); } // Basic functionality events case(EV_REQUEST_SPELL){ let bomb = GetPlayerSpell(); if (bomb >= 1){ SetScriptResult(true); SetPlayerSpell(bomb - 1); _Bomb(); _SigilCall(false, teamimg, 768+256, 512, 768+512, 768, objPlayer, GetPlayerInvincibilityFrame()); } else { SetScriptResult(false); } } case(EV_HIT){ ObjSound_Play(predeathsfx); _DeathbombWarning(teamimg, [1536, 384, 1536+512, 384+512], 15, 0.75); } case(EV_PLAYER_SHOOTDOWN){ ObjSound_Play(deathsfx); ripplayer = true; _SigilCall(true, teamimg, 768, 512, 768+256, 768, objPlayer, 120); } case(EV_PLAYER_REBIRTH){ ripplayer = false; SetPlayerInvincibilityFrame(180); _SigilCall(false, teamimg, 768+256, 512, 768+512, 768, objPlayer, 150); SetPlayerSpell( max(2,GetPlayerSpell()) ); } case(EV_GRAZE){ grazecounter += GetEventArgument(0); ObjSound_Play(grazesfx); while(grazecounter >= 10){ SetAreaCommonData("PIV", "currentvalue", GetAreaCommonData("PIV", "currentvalue")+10); grazecounter -= 10; } } } @Finalize{ } // Homing task _HomeShot(int option_) { int shot_ = 0; float duration = 1; float durationOption = 99999; bool homingBool = false; float basepenetrate = ObjShot_GetPenetration(shot_); float basedmg = ObjShot_GetDamage(shot_); // for (int t = 0i; t < durationOption && !Obj_IsDeleted(option_); t++) { // Checks if enemies are on screen. If enemies are visible, enable homing for the shots. // _enemyArray is an array containing all enemy IDs, and is constantly updated in @MainLoop. if (0 < length(_enemyArray)) { float targetDist = 2000; // Arbitrary number (???) int targetID = 0; // Checks distance of every enemy on screen. for each (int enemy in ref _enemyArray) { float enemyX = ObjMove_GetX(enemy); float enemyY = ObjMove_GetY(enemy); if (0 < enemyX && enemyX < maxX && 0 < enemyY && enemyY < maxY) { // Returns the hypotenuse of the triangle formed by the x & y distances between the shot and the enemy. float shotDist = hypot(enemyX - ObjMove_GetX(objPlayer), enemyY - ObjMove_GetY(objPlayer)); // Locks the shot onto the enemy. if (shotDist < targetDist) { targetDist = shotDist; targetID = enemy; homingBool = true; } } } // Code to handle the actual homing. if (homingBool) { for (int f = 0; t < durationOption && !Obj_IsDeleted(option_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE; t++) { ObjShot_SetAutoDelete(option_, false); float shotAngle = NormalizeAngle(ObjMove_GetAngle(option_)); // Angle of the player shot float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(option_), ObjMove_GetX(targetID) - ObjMove_GetX(option_))); // Returns angle from the shot to the enemy. float angleDistance = AngularDistance(shotAngle, targetAngle); // Angular distance between enemy and player shot float homeRate = Interpolate_Decelerate(0, 0.75, min(15, f) / 15); // Homing speed? ObjMove_SetAngle(option_, Interpolate_Decelerate(shotAngle, shotAngle + angleDistance, homeRate)); // Interpolate_Necko f++; yield; } } /*if (homingBool) { for (int f = 0; t < duration && !Obj_IsDeleted(shot_) && !Obj_IsDeleted(targetID) && ObjEnemy_GetInfo(targetID, INFO_LIFE) != 0 && !ObjCol_IsIntersected(shot_); t++) { ObjShot_SetAutoDelete(shot_, false); float shotAngle = NormalizeAngle(ObjMove_GetAngle(shot_)); // Angle of the player shot float targetAngle = NormalizeAngle(atan2(ObjMove_GetY(targetID) - ObjMove_GetY(shot_), ObjMove_GetX(targetID) - ObjMove_GetX(shot_))); // Returns angle from the shot to the enemy. float angleDistance = AngularDistance(shotAngle, targetAngle); // Angular distance between enemy and player shot float homeRate = Interpolate_Decelerate(0, 0.75, min(60, f) / 60); // Homing speed? ObjMove_SetAngle(shot_, Interpolate_Accelerate(shotAngle, shotAngle + angleDistance, 1)); // Interpolate_Necko f++; yield; } ObjShot_SetAutoDelete(shot_, true); ObjMove_SetAngularVelocity(shot_, 0); homingBool = false; }*/ } yield; } } task _SwingBehaviour(target){ float ang = 0; Obj_SetRenderPriorityI(target, 42); while(true){ ObjRender_SetAngleZ(target, 0+20*sin(ang)); ang += 360/120; yield; } } task _ShotType(){ // Offsets for 4 front options // Alternative player option function function PlayerOption( float offsetx, float offsety, texture, int left, int top, int right, int bottom, float scale, int width, int animdelay, int frameno, bool triggeranimation, bool triggerspin, float spinspeed, bool onlyFocus, bool onlyUnfocus ){ // IMPORTANT! let option = ObjShot_Create(OBJ_SHOT); ObjShot_Regist(option); ObjShot_SetAutoDelete(option, false); ObjShot_SetGraphic(option, 3); ObjShot_SetPenetration(option, 9999^9999); ObjShot_SetDamage(option, 0); ObjShot_SetIntersectionEnable(option, false); ObjMove_SetAngle(option, 270); // bool visible; int animate = 0; float optx; float opty; ObjRender_SetScaleXYZ(option, scale); ObjRender_SetBlendType(option, BLEND_ALPHA); ObjRender_SetAlpha(option, 225); Obj_SetRenderPriorityI(option, 41); ObjRender_SetPosition(option, offsetx, offsety, 1); // Animation async{ while(triggeranimation){ ObjSprite2D_SetSourceRect(option, left+width*floor(animate/animdelay), top, right+width*floor(animate/animdelay)-1, bottom-1); animate++; if (animate >= animdelay*frameno){animate = 0;} yield; } } // Rotation async{ float i = 0; while(triggerspin){ //ObjRender_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety, 1); ObjRender_SetAngleZ(option, i); i += spinspeed; yield; } } // Follow async{ while(true){ ObjMove_SetPosition(option, GetPlayerX()+offsetx, GetPlayerY()+offsety); yield; } } // Visibility async{ // Always visible if((onlyFocus && onlyUnfocus) || (!onlyFocus && !onlyUnfocus)) { loop { if(GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;} else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;} yield; } } // Visible when focused only else if(onlyFocus && !onlyUnfocus){ loop { if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) == KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;} else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;} yield; } } // Visible when unfocused only else if(!onlyFocus && onlyUnfocus){ loop { if((GetPlayerState != STATE_NORMAL && GetPlayerState != STATE_HIT) || GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ObjRender_SetAlpha(option, max(0, ObjRender_GetAlpha(option)-15)); visible = false;} else {ObjRender_SetAlpha(option, min(225, ObjRender_GetAlpha(option)+15)); visible = true;} yield; } } } function _FadeIn(){ ascent(i in 0..15){ ObjRender_SetAlpha(option, Interpolate_Decelerate(0, 225, i/15)); yield; } } function _FadeOut(){ ascent(i in 0..15){ ObjRender_SetAlpha(option, Interpolate_Decelerate(225, 0, i/15)); yield; } } return option; } float offsetX1 = 125; float offsetX2 = offsetX1 * 2; float offsetY1 = 75; // Array that contains static/unchanging values for the PlayerOption let val = [0, 512, 256, 768, 0.3, 256, 1, 1, false, false, 0, true, true]; // Option handling (right -> rightmost -> left -> leftmost) float[][] offsetArray = [[offsetX1, offsetY1], [offsetX2, 0], [-offsetX1, offsetY1], [-offsetX2, 0]]; int opt1 = PlayerOption( offsetArray[0][0], offsetArray[0][1], teamimg, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], val[12]); int opt2 = PlayerOption( offsetArray[1][0], offsetArray[1][1], teamimg, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], val[12]); int opt3 = PlayerOption( offsetArray[2][0], offsetArray[2][1], teamimg, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], val[12]); int opt4 = PlayerOption( offsetArray[3][0], offsetArray[3][1], teamimg, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8], val[9], val[10], val[11], val[12]); int[] optArray = [opt1, opt2, opt3, opt4]; _HomingStars(optArray[0], 0); _HomeShot(optArray[0]); _HomingStars(optArray[1], 1); _HomeShot(optArray[1]); _HomingStars(optArray[2], 2); _HomeShot(optArray[2]); _HomingStars(optArray[3], 3); _HomeShot(optArray[3]); task _HomingStars(option, value){ loop{ if(GetVirtualKeyState(VK_SLOWMOVE) != KEY_FREE){ async{ if(value == 0){ ascent(i in 0..15){ ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15)); yield; } } else if(value == 1){ ascent(i in 0..15){ ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*2, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15)); yield; } } else if(value == 2){ ascent(i in 0..15){ ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15)); yield; } } else if(value == 3){ ascent(i in 0..15){ ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*2, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15)); yield; } } } async{ if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){ if(shotspeed % 5 == 0){ float x = ObjRender_GetX(option); float y = ObjRender_GetY(option); 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); Obj_SetRenderPriorityI(shotA, 39); ObjSound_Play(basesfx); } } } } } else{ async{ if(value == 0){ ascent(i in 0..15){ ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 275, i/15)); ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.45, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15)); yield; } } else if(value == 1){ ascent(i in 0..15){ ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 295, i/15)); ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX+offsetX1*0.75, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15)); yield; } } else if(value == 2){ ascent(i in 0..15){ ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 265, i/15)); ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.45, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY+offsetY1, i/15)); yield; } } else if(value == 3){ ascent(i in 0..15){ ObjMove_SetAngle(option, Interpolate_Decelerate(ObjMove_GetAngle(option), 245, i/15)); ObjMove_SetX(option, Interpolate_Decelerate(ObjMove_GetX(option), playerX-offsetX1*0.75, i/15)); ObjMove_SetY(option, Interpolate_Decelerate(ObjMove_GetY(option), playerY, i/15)); yield; } } } async{ if(GetVirtualKeyState(VK_SHOT) != KEY_FREE && IsPermitPlayerShot && !ripplayer){ if(shotspeed % 5 == 0){ float x = ObjRender_GetX(option); float y = ObjRender_GetY(option); 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); Obj_SetRenderPriorityI(shotA, 39); ObjSound_Play(basesfx); } } } } } yield; } } } // Basic player parameters task parameterrender(){ SetPlayerItemScope(120); SetPlayerLife(9); // Debug SetPlayerSpell(2); SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); // (original: 5.25/2.0) SetPlayerRebirthFrame(12); SetPlayerAutoItemCollectLine(GetStgFrameHeight/3); SetPlayerRebirthLossFrame(0); ObjPlayer_AddIntersectionCircleA1(objPlayer, 0, 0, 1.25, 40); } // Renders the shottype // Player sprites task playerrender(){ // Why is this movement code so cursed jesus fucking christ float scale = 0.32; // Scalies int frame = 0; ObjPrim_SetTexture(objPlayer, teamimg); ObjSprite2D_SetSourceRect(objPlayer, 0, 0, 400, 400); ObjSprite2D_SetDestCenter(objPlayer); Obj_SetRenderPriorityI(objPlayer, 42); ObjRender_SetScaleXYZ(objPlayer, scale, scale, 1); // Lower "speed" parameter = FASTER SPEED // FOR WHEN ONLY IDLE SPRITES ARE DONE loop{ frame++; _RenderPlayerMovement(objPlayer, frame, 0, 0, 400, 400, scale, 4, 6); if (frame >= (5*4-1)){frame = 0;} yield; } } task PointblankPlacebo(target, scale, multiplier){ int len = 10; while(GetObjectDistance(target, objPlayer) < 90){ _BulletRescalePlayer(target, scale*multiplier, true, multiplier); // Pointblank yield; } ascent(i in 0..len){ _BulletRescalePlayer(target, Interpolate_Decelerate(scale*multiplier, scale, i/len), true, Interpolate_Decelerate(multiplier, 1, i/len)); yield; } } task Fadein(target, len){ ascent(i in 0..len){ _BulletRescalePlayer(target, Interpolate_Decelerate(0.4, 0.7, i/len), true, Interpolate_Decelerate(0.4, 0.7, i/len)); //ObjRender_SetBlendType(target, BLEND_ADD_ARGB); yield; } ObjRender_SetBlendType(target, BLEND_ALPHA); } task Fadein(target, len, targetscale, targetscalehitbox){ ascent(i in 0..len){ _BulletRescalePlayer(target, Interpolate_Decelerate(0.1, targetscale, i/len), true, Interpolate_Decelerate(1, targetscalehitbox, i/len)); //ObjRender_SetBlendType(target, BLEND_ADD_ARGB); yield; } ObjRender_SetBlendType(target, BLEND_ALPHA); } // Handling of bomb task _Bomb(){ // Preparation SetForbidPlayerShot(true); SetForbidPlayerSpell(true); SetPlayerInvincibilityFrame(32*3+32*3+42*3+120+45); // Spell object let manageObj = GetSpellManageObject(); // SPELL BEGINS ObjSpell_Regist(manageObj); ObjSound_Play(bombsfx); SetPlayerSpeed(PlayerSpd[0]*1.5, PlayerSpd[0]*1.5); int hakkero = CreatePlayerShotA1(playerX, playerY, 0, 0, 12, 999999, 4); ObjShot_SetIntersectionEnable(hakkero, true); ObjShot_SetEraseShot(hakkero, true); ObjShot_SetSpellFactor(hakkero, true); async{ ascent(i in 0..45){ _BulletRescalePlayer(hakkero, Interpolate_Decelerate(0.1, 1, i/45), true, 1); ObjRender_SetAlpha(hakkero, Interpolate_Decelerate(0, 255, i/45)); yield; } } ascent(i in 0..240){ ObjMove_SetPosition(hakkero, playerX, playerY); yield; } // Cleanup, end of spell ObjShot_FadeDelete(hakkero); SetPlayerSpeed(PlayerSpd[0], PlayerSpd[1]); SetForbidPlayerShot(false); wait(60); SetForbidPlayerSpell(false); Obj_Delete(manageObj); // !!! IMPORTANT !!! } // Screenshake function for bomb's duration - adapted from Sparen's tutorials task _BombShake(shaketime, intensity){ float baseintensity = intensity; float shakeno = shaketime; ascent(i in 0..shakeno){ Set2DCameraFocusX(GetStgFrameWidth/2 + rand(-intensity, intensity)); Set2DCameraFocusY(GetStgFrameHeight/2 + rand(-intensity, intensity)); intensity = Interpolate_Decelerate(0, baseintensity, 1-i/shakeno); shaketime--; yield; } while(shaketime > 0){yield;} Set2DCameraFocusX(GetStgFrameWidth/2); Set2DCameraFocusY(GetStgFrameHeight/2); yield; }