Files
resources/semag/fridaynightfunkin/assets/scripts/characters/pico-blazin.hxc
2025-06-22 12:00:12 -04:00

460 lines
10 KiB
Plaintext
Executable File

import flixel.FlxG;
import funkin.Paths;
import funkin.play.GameOverSubState;
import flixel.util.FlxTimer;
import funkin.play.PlayState;
import funkin.play.PauseSubState;
import funkin.graphics.FunkinSprite;
import funkin.play.character.AnimateAtlasCharacter;
import StringTools;
class PicoBlazinCharacter extends AnimateAtlasCharacter
{
function new()
{
super('pico-blazin');
}
function onCreate(event:ScriptEvent)
{
super.onCreate(event);
this.danceEvery = 0;
this.playAnimation('idle', true, false);
// NOTE: this.x and this.y are not properly set here.
GameOverSubState.musicSuffix = '-pico';
GameOverSubState.blueBallSuffix = '-pico-gutpunch';
PauseSubState.musicSuffix = '-pico';
}
var cantUppercut = false;
function onNoteHit(event:HitNoteScriptEvent)
{
holdTimer = 0;
if (!StringTools.startsWith(event.note.kind, 'weekend-1-')) return;
// SPECIAL CASE: If Pico hits a poor note at low health (at 30% chance),
// Pico may instead punch high (but Darnell will duck below Pico to attempt an uppercut)
// TODO: Maybe add a cooldown to this?
// NOTE: This relies on scripts dispatching to opponents first, which is true at time of writing.
var shouldDoUppercutPrep = wasNoteHitPoorly(event) && isPlayerLowHealth() && isDarnellPreppingUppercut();
if (shouldDoUppercutPrep) {
playPunchHighAnim();
return;
}
if (cantUppercut) {
playBlockAnim();
cantUppercut = false;
return;
}
// Override the hit note animation.
switch (event.note.kind)
{
case "weekend-1-punchlow":
playPunchLowAnim();
case "weekend-1-punchlowblocked":
playPunchLowAnim();
case "weekend-1-punchlowdodged":
playPunchLowAnim();
case "weekend-1-punchlowspin":
playPunchLowAnim();
case "weekend-1-punchhigh":
playPunchHighAnim();
case "weekend-1-punchhighblocked":
playPunchHighAnim();
case "weekend-1-punchhighdodged":
playPunchHighAnim();
case "weekend-1-punchhighspin":
playPunchHighAnim();
case "weekend-1-blockhigh":
playBlockAnim(event.judgement);
case "weekend-1-blocklow":
playBlockAnim(event.judgement);
case "weekend-1-blockspin":
playBlockAnim(event.judgement);
case "weekend-1-dodgehigh":
playDodgeAnim();
case "weekend-1-dodgelow":
playDodgeAnim();
case "weekend-1-dodgespin":
playDodgeAnim();
// Pico ALWAYS gets punched.
case "weekend-1-hithigh":
playHitHighAnim();
case "weekend-1-hitlow":
playHitLowAnim();
case "weekend-1-hitspin":
playHitSpinAnim();
case "weekend-1-picouppercutprep":
playUppercutPrepAnim();
case "weekend-1-picouppercut":
playUppercutAnim(true);
case "weekend-1-darnelluppercutprep":
playIdleAnim();
case "weekend-1-darnelluppercut":
playUppercutHitAnim();
case "weekend-1-idle":
playIdleAnim();
case "weekend-1-fakeout":
playFakeoutAnim();
case "weekend-1-taunt":
playTauntConditionalAnim();
case "weekend-1-tauntforce":
playTauntAnim();
case "weekend-1-reversefakeout":
playIdleAnim(); // TODO: Which anim?
default:
// trace('Unknown note kind: ' + event.note.kind);
}
}
function playAnimation(name:String, restart:Bool, ignoreOther:Bool) {
if (name == "firstDeath") {
// TODO: ACTUALLY play one of the three death animations here.
// Make sure the death music plays with PERFECT timing.
new FlxTimer().start(1.25, afterPicoDeathGutPunchIntro);
} else if (name == "deathConfirm") {
doDeathConfirm();
} else {
super.playAnimation(name, restart, ignoreOther);
}
super.playAnimation(name, restart, ignoreOther);
}
function afterPicoDeathGutPunchIntro():Void {
GameOverSubState.instance.startDeathMusic(1.0, false);
playAnimation('deathLoop', true, false);
}
function doDeathConfirm():Void {
var picoDeathConfirm:FunkinSprite = FunkinSprite.createSparrow(this.x + 905, this.y + 1030, 'picoBlazinDeathConfirm');
picoDeathConfirm.animation.addByPrefix('confirm', "Pico Gut Punch Death0", 24, false);
picoDeathConfirm.animation.play('confirm');
picoDeathConfirm.scale.set(1.75, 1.75);
picoDeathConfirm.zIndex = 1000;
FlxG.state.subState.add(picoDeathConfirm);
picoDeathConfirm.visible = true;
this.visible = false;
picoDeathConfirm.animation.finishCallback = () -> {
picoDeathConfirm.visible = false;
this.visible = true;
}
}
function onNoteMiss(event:NoteScriptEvent)
{
holdTimer = 0;
// SPECIAL CASE: Darnell prepared to uppercut last time and Pico missed! FINISH HIM!
if (isDarnellInUppercut()) {
playUppercutHitAnim();
return;
}
if (willMissBeLethal(event)) {
playHitLowAnim();
return;
}
if (cantUppercut) {
playHitHighAnim();
return;
}
// Override the hit note animation.
switch (event.note.kind)
{
// Pico fails to punch, and instead gets hit!
case "weekend-1-punchlow":
playHitLowAnim();
case "weekend-1-punchlowblocked":
playHitLowAnim();
case "weekend-1-punchlowdodged":
playHitLowAnim();
case "weekend-1-punchlowspin":
playHitSpinAnim();
// Pico fails to punch, and instead gets hit!
case "weekend-1-punchhigh":
playHitHighAnim();
case "weekend-1-punchhighblocked":
playHitHighAnim();
case "weekend-1-punchhighdodged":
playHitHighAnim();
case "weekend-1-punchhighspin":
playHitSpinAnim();
// Pico fails to block, and instead gets hit!
case "weekend-1-blockhigh":
playHitHighAnim();
case "weekend-1-blocklow":
playHitLowAnim();
case "weekend-1-blockspin":
playHitSpinAnim();
// Pico fails to dodge, and instead gets hit!
case "weekend-1-dodgehigh":
playHitHighAnim();
case "weekend-1-dodgelow":
playHitLowAnim();
case "weekend-1-dodgespin":
playHitSpinAnim();
// Pico ALWAYS gets punched.
case "weekend-1-hithigh":
playHitHighAnim();
case "weekend-1-hitlow":
playHitLowAnim();
case "weekend-1-hitspin":
playHitSpinAnim();
// Fail to dodge the uppercut.
case "weekend-1-picouppercutprep":
playPunchHighAnim();
cantUppercut = true;
case "weekend-1-picouppercut":
playUppercutAnim(false);
// Darnell's attempt to uppercut, Pico dodges or gets hit.
case "weekend-1-darnelluppercutprep":
playIdleAnim();
case "weekend-1-darnelluppercut":
playUppercutHitAnim();
case "weekend-1-idle":
playIdleAnim();
case "weekend-1-fakeout":
playHitHighAnim();
case "weekend-1-taunt":
playTauntConditionalAnim();
case "weekend-1-tauntforce":
playTauntAnim();
case "weekend-1-reversefakeout":
playIdleAnim();
default:
trace('Unknown note kind: ' + event.note.kind);
}
}
function willMissBeLethal(event:NoteScriptEvent):Bool {
return (PlayState.instance.health + event.healthChange) <= 0.0;
}
function onNoteGhostMiss(event:GhostMissNoteScriptEvent)
{
if (willMissBeLethal(event)) {
// Darnell throws a punch so that Pico dies.
playHitLowAnim();
} else {
// Pico wildly throws punches but Darnell dodges.
playPunchHighAnim();
}
}
override function onAnimationFinished(name:String)
{
super.onAnimationFinished(name);
}
override function onSongRetry()
{
super.onSongRetry();
cantUppercut = false;
playIdleAnim();
GameOverSubState.musicSuffix = '-pico';
GameOverSubState.blueBallSuffix = '-pico-gutpunch';
PauseSubState.musicSuffix = '-pico';
}
function getDarnell()
{
if (this.debug) return null;
return PlayState.instance.currentStage.getDad();
}
function moveToBack()
{
if (this.debug) return;
this.zIndex = 2000;
PlayState.instance.currentStage.refresh();
}
function moveToFront()
{
if (this.debug) return;
this.zIndex = 3000;
PlayState.instance.currentStage.refresh();
}
function isDarnellPreppingUppercut():Void {
return getDarnell().getCurrentAnimation() == 'uppercutPrep';
}
function isDarnellInUppercut():Void {
return
getDarnell().getCurrentAnimation() == 'uppercut'
|| getDarnell().getCurrentAnimation() == 'uppercut-hold';
}
function wasNoteHitPoorly(event:HitNoteScriptEvent):Bool {
return (event.judgement == "bad" || event.judgement == "shit");
}
function isPlayerLowHealth(event:HitNoteScriptEvent):Bool {
return PlayState.instance.health <= 0.30 * 2.0;
}
// ANIMATIONS
var alternate:Bool = false;
function doAlternate():String {
alternate = !alternate;
return alternate ? '1' : '2';
}
function playBlockAnim(?judgement:String)
{
// on sick block, do a 3rd strike esque "tech" effect
if (judgement == 'sick')
{
//var blendAnims:Array<Int> = [10, 0, 10, 0, 0, 10, 0, 0, 10, 0, 10];
//
//for (blendMode in 0...blendAnims.length)
//{
// new FlxTimer().start(blendMode / 60, function(_) {
//
// if (blendAnims[blendMode] != 10)
// this.color = 0xFF0000FF;
// else
// this.color = 0xFFFFFFFF;
//
// this.blend = blendAnims[blendMode];
// });
//}
}
this.playAnimation('block', true, false);
PlayState.instance.camGame.shake(0.002, 0.1);
moveToBack();
}
function playCringeAnim()
{
this.playAnimation('cringe', true, false);
moveToBack();
}
function playDodgeAnim()
{
this.playAnimation('dodge', true, false);
moveToBack();
}
function playIdleAnim()
{
this.playAnimation('idle', false, false);
moveToBack();
}
function playFakeoutAnim()
{
this.playAnimation('fakeout', true, false);
moveToBack();
}
function playUppercutPrepAnim()
{
this.playAnimation('uppercutPrep', true, false);
moveToFront();
}
function playUppercutAnim(hit:Bool)
{
this.playAnimation('uppercut', true, false);
if (hit) {
PlayState.instance.camGame.shake(0.005, 0.25);
}
moveToFront();
}
function playUppercutHitAnim()
{
this.playAnimation('uppercutHit', true, false);
PlayState.instance.camGame.shake(0.005, 0.25);
moveToBack();
}
function playHitHighAnim()
{
this.playAnimation('hitHigh', true, false);
PlayState.instance.camGame.shake(0.0025, 0.15);
moveToBack();
}
function playHitLowAnim()
{
this.playAnimation('hitLow', true, false);
PlayState.instance.camGame.shake(0.0025, 0.15);
moveToBack();
}
function playHitSpinAnim()
{
this.playAnimation('hitSpin', true, false, true);
PlayState.instance.camGame.shake(0.0025, 0.15);
moveToBack();
}
function playPunchHighAnim()
{
this.playAnimation('punchHigh' + doAlternate(), true, false);
moveToFront();
}
function playPunchLowAnim()
{
this.playAnimation('punchLow' + doAlternate(), true, false);
moveToFront();
}
function playTauntConditionalAnim()
{
if (getCurrentAnimation() == "fakeout") {
playTauntAnim();
} else {
playIdleAnim();
}
}
function playTauntAnim()
{
this.playAnimation('taunt', true, false);
moveToBack();
}
}