460 lines
10 KiB
Plaintext
Executable File
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();
|
|
}
|
|
}
|