Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
139 KB
Referenced Files
None
Subscribers
None
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/data/script/Backend.pl b/data/script/Backend.pl
index b0ed5e9..a16f287 100644
--- a/data/script/Backend.pl
+++ b/data/script/Backend.pl
@@ -1,601 +1,765 @@
#!/usr/bin/perl -w
# PERL backend for the game
=comment
This is the main perl backend for Mortal Szombat. It loads the other files,
compiles characters, creates shared variables.
1. FIGHTER ACTIONS
1.1. BASIC MOVEMENT 1.2. OFFENSIVE MOVES 1.3. HURT MOVES
Start KneelingPunch Falling
Stand KneelingKick Laying
Walk KneelingUppercut Getup
Back HighPunch HighPunched
Turn LowPunch LowPunched
Hurt HighKick GroinKicked
Block LowKick KneelingPunched
Kneeling Sweep KneelingKicked
Onknees GroinKick Thrown
Jump KneeKick Dead
JumpFW Elbow
JumpBW Grenade
Fun Uppercut
Threat Throw
[fighter-specific stuff]
=cut
=comment
MAIN CONSTANTS
=cut
-$GAMEBITS = 3; # Number of oversampling bits in coordinates
-$GAMEBITS2 = 1 << $GAMEBITS; # 2^(oversampling)
-$SCRWIDTH = 640; # The physical horizontal screen resolution
-$SCRHEIGHT = 480; # The physical vertical screen resolution
-$SCRWIDTH2 = ($SCRWIDTH << $GAMEBITS); # The logical horizontal screen resolution
-$SCRHEIGHT2 = ($SCRHEIGHT << $GAMEBITS); # The logical vertical screen resolution
-$MOVEMARGIN2= 50 << $GAMEBITS; # The logical border for fighters.
-
-$BGWIDTH2 = 1920 << $GAMEBITS; # The logical background width
-$BGHEIGHT2 = 480 << $GAMEBITS; # The logical background height
-
-$GROUND2 = 160 << $GAMEBITS; # The logical ground level.
-$DELMULTIPLIER = 1; # DEL values in states are multiplied by this.
-$MAXCOMBO = 5; # Maximum combo count.
-
-$BgMax = $BGWIDTH2 - $SCRWIDTH2; # The logical maximum camera position
-$BgSpeed = 0; # The current speed of the background movement
-$BgPosition = $BgMax >> 1; # The logical camera position
-$BgScrollEnabled = 1; # Can the background scroll?
-$HitPointScale = 10; # Scale the hit points by this.
-$NextDoodad = 0; # The next doodad to process
-$Debug = 0;
+sub InitMainConstants($$)
+{
+ my ($wide, $numplayers) = @_;
+
+ $MAXPLAYERS = 4; # The maximal number of players in the game
+ $WIDE = $wide;
+ $NUMPLAYERS = $numplayers; # Number of players in the game
+ $GAMEBITS = 3; # Number of oversampling bits in coordinates
+ $GAMEBITS2 = 1 << $GAMEBITS; # 2^(oversampling)
+ $SCRWIDTH = $wide ? 800 : 640; # The physical horizontal screen resolution
+ $SCRHEIGHT = 480; # The physical vertical screen resolution
+ $SCRWIDTH2 = ($SCRWIDTH << $GAMEBITS); # The logical horizontal screen resolution
+ $SCRHEIGHT2 = ($SCRHEIGHT << $GAMEBITS); # The logical vertical screen resolution
+ $MOVEMARGIN2= 50 << $GAMEBITS; # The logical border for fighters.
+
+ $BGWIDTH2 = 1920 << $GAMEBITS; # The logical background width
+ $BGHEIGHT2 = 480 << $GAMEBITS; # The logical background height
+
+ $GROUND2 = 160 << $GAMEBITS; # The logical ground level.
+ $DELMULTIPLIER = 1; # DEL values in states are multiplied by this.
+ $MAXCOMBO = 5; # Maximum combo count.
+
+ $BgMax = $BGWIDTH2 - $SCRWIDTH2; # The logical maximum camera position
+ $BgSpeed = 0; # The current speed of the background movement
+ $BgPosition = $BgMax >> 1; # The logical camera position
+ $BgScrollEnabled = 1; # Can the background scroll?
+ $HitPointScale = 10; # Scale the hit points by this.
+ $NextDoodad = 0; # The next doodad to process
+ $Debug = 0;
+}
+InitMainConstants( 0, 2 );
require 'PlayerInput.pl';
require 'Fighter.pl';
require 'FighterStats.pl';
require 'Doodad.pl';
require 'Keys.pl';
require 'State.pl';
require 'Translate.pl';
require 'Rewind.pl';
=comment
MAIN OBJECTS
=cut
+sub CreateFighters()
+{
+ my ( $i, $fighter );
+
+ @Fighters = ();
+
+ for ( $i=0; $i<$MAXPLAYERS; ++$i )
+ {
+ $fighter = Fighter->new();
+ $fighter->{NUMBER} = $i;
+ $fighter->{OTHER} = $fighter;
+ $Fighters[$i] = $fighter;
+ }
+
+ $Fighters[1]->{OTHER} = $Fighters[0];
+ $Fighters[0]->{OTHER} = $Fighters[1];
+}
-$Fighter1 = Fighter->new();
-$Fighter2 = Fighter->new();
-
-$Fighter1->{NUMBER} = 0;
-$Fighter1->{OTHER} = $Fighter2;
-$Fighter2->{NUMBER} = 1;
-$Fighter2->{OTHER} = $Fighter1;
+CreateFighters();
+CreatePlayerInputs();
-@Fighters = ( $Fighter1, $Fighter2 );
=comment
VARIABLES FOR DRAWING THE SCENE
=cut
$gametick = 0; # Number of Advance()'s called since the start.
$p1x = 10; # Player 1 X position
$p1y = 100; # Player 1 Y position
$p1f = 10; # Player 1 frame
-$p1h = 100; # Player 1 HP
+$p1h = 100; # Player 1 HP (the displayed bar)
+$p1hreal = 100; # Player 1 real HP (actual value, not the displayed bar)
$p2x = 400; # Player 2 X position
$p2y = 100; # Player 2 Y position
$p2f = -40; # Player 2 frame. Negative means flipped.
$p2h = 100; # Player 2 HP
+$p2hreal = 100; # Player 2 real HP (actual value, not the displayed bar)
$bgx = 0; # Background X position
$bgy = 0; # Background Y position
-$over = 0; # Is the game over?
-$ko = 0; # Is one fighter knocked down?
+$over = 0; # Is the game over? Used to end the game / player selection.
+$ko = 0; # Is one fighter knocked down? Used for instant replay, to capture the moment of the KO. Also disables player input / connections
$doodad_x = -1; # Doodad X position
$doodad_y = -1; # Doodad Y position
$doodad_t = -1; # Doodad type
$doodad_f = -1; # Doodad frame number
$doodad_dir = 0; # The direction of the doodad; 1: normal; -1: flipped
-$doodad_gfxowner = -1; # 0: first player; 1: second player; 2: Global doodad
+$doodad_gfxowner = -1; # 0: first player; 1: second player; -1: Global doodad
$doodad_text = ''; # The text of type 0 doodads.
-sub ResetGame($)
+
+=comment
+ResetGame clears 'most' game variables. It should not be called by the
+frontend directly, instead it is used by the various starting functions,
+e.g. "SelectStart" or "JudgementStart".
+=cut
+
+sub ResetGame($$$)
{
- my ($bgposition) = @_;
+ my ($bgposition, $wide, $numplayers) = @_;
+
+ InitMainConstants( $wide, $numplayers );
+
$gametick = 0;
$over = 0;
$ko = 0;
$bgx = 0;
$bgy = 0;
$BgSpeed = 0;
$BgPosition = $bgposition;
$BgScrollEnabled = $bgposition != 0;
+ $ActiveFighters = $numplayers; # Number of fighters not in the Win2 / Dead states.
+ $ActiveTeams = $numplayers; # Number of teams not in the Win2 / Dead states or have more team members.
$OverTimer = 0;
$JudgementMode = 0;
$Debug = 0;
@Doodads = ();
@Sounds = ();
ResetEarthquake();
ResetRewind();
- $Fighter1->Reset() if $Fighter1->{OK};
- $Fighter2->Reset() if $Fighter2->{OK};
- $Input1->Reset();
- $Input2->Reset();
+ my ($fighter, $input);
+ foreach $fighter (@Fighters)
+ {
+ $fighter->Reset if $fighter->{OK};
+ $fighter->{TEAMSIZE} = 1;
+ }
+
+ foreach $input (@Inputs)
+ {
+ $input->Reset();
+ }
}
=comment
JUDGEMENT METHODS
=cut
sub JudgementStart($)
{
- ResetGame(0);
- # $bgy = ( $SCRHEIGHT2 - $BGHEIGHT2 ) >> 1;
+ ResetGame(0, 0, 2);
$JudgementMode = 1;
($JudgementWinner) = @_;
- $Fighter1->{X} = ($JudgementWinner ? 150 : 520 ) * $GAMEBITS2;
- $Fighter1->{DIR} = ($JudgementWinner ? 1 : -1 );
- $Fighter1->{NEXTST} = 'Stand';
- $Fighter1->Update();
-
- $Fighter2->{X} = ($JudgementWinner ? 520 : 150 ) * $GAMEBITS2;
- $Fighter2->{DIR} = ($JudgementWinner ? -1 : 1 );
- $Fighter2->{NEXTST} = 'Stand';
- $Fighter2->Update();
+ my ($i);
+ for ( $i=0; $i<$NUMPLAYERS; ++$i )
+ {
+ $Fighters[$i]->{X} = ($JudgementWinner!=$i ? 150 : 520 ) * $GAMEBITS2;
+ $Fighters[$i]->{DIR} = ($JudgementWinner!=$i ? 1 : -1 );
+ $Fighters[$i]->{NEXTST} = 'Stand';
+ $Fighters[$i]->Update();
+ }
}
=comment
PLAYER SELECTION METHODS
=cut
-sub SelectStart
+sub SelectStart($)
{
- ResetGame(0);
+ my ( $numplayers ) = @_;
+ ResetGame(0,0,$numplayers);
+ my ( $i, $fighter);
- if ( $Fighter1->{OK} )
+ $ActiveTeams = 10000; # Make sure we don't trigger an accidental 'Won' event...
+
+ if ( 2 == $NUMPLAYERS )
{
- $Fighter1->{X} = 80 * $GAMEBITS2;
- $Fighter1->{NEXTST} = 'Stand';
- $Fighter1->Update();
+ for ( $i=0; $i<$NUMPLAYERS; ++$i )
+ {
+ if ($Fighters[$i]->{OK})
+ {
+ $Fighters[$i]->{X} = (100 + 440*$i) * $GAMEBITS2;
+ $Fighters[$i]->{NEXTST} = 'Stand';
+ $Fighters[$i]->{DIR} = $i ? -1 : 1;
+ $Fighters[$i]->Update();
+ }
+ }
}
- if ( $Fighter2->{OK} )
+ else
{
- $Fighter2->{X} = 560 * $GAMEBITS2;
- $Fighter2->{NEXTST} = 'Stand';
- $Fighter2->Update();
+ foreach $fighter (@Fighters)
+ {
+ next unless $fighter->{OK};
+ last if $fighter->{NUMBER} == $NUMPLAYERS;
+ $fighter->{X} = $MOVEMARGIN2 + $SCRWIDTH2 / $NUMPLAYERS * $fighter->{NUMBER};
+ $fighter->{DIR} = 1;
+ $fighter->{NEXTST} = 'Start';
+ $fighter->Update();
+ }
}
}
sub SetPlayerNumber
{
my ($player, $fighterenum) = @_;
my ($f);
DeleteDoodadsOf( $player );
- $f = $player ? $Fighter2 : $Fighter1;
+ $f = $Fighters[$player];
+ return unless defined $f;
$f->Reset($fighterenum);
-
$f->{NEXTST} = 'Stand';
$f->Update();
GetFighterStats($fighterenum);
- $::PlayerName = $::Name
+ $::PlayerName = $::Name;
+ $over = 0;
+ $OverTimer = 0;
+
+ if ( 2 != $NUMPLAYERS )
+ {
+ $f->{X} = $MOVEMARGIN2 + $SCRWIDTH2 / $NUMPLAYERS * $f->{NUMBER};
+ $f->{DIR} = 1;
+ }
}
sub PlayerSelected
{
my ($number) = @_;
- my ($f) = $number ? $Fighter2 : $Fighter1;
+ my ($f) = $Fighters[$number];
+ $f->{NEXTST} = 'Stand';
+ $f->Update();
$f->Event( 'Won' );
$f->Update();
+ $over = 0;
+ $OverTimer = 1;
}
=comment
EARTHQUAKE RELATED METHODS
=cut
@QUAKEOFFSET = ( 0, 6, 11, 15,
16, 15, 11, 6,
0, -6,-11,-15,
-16,-15,-11, -6, 0, 6 );
sub ResetEarthquake
{
$QuakeAmplitude = 0;
$QuakeOffset = 0;
$QuakeX = 0;
$QuakeY = 0;
}
sub AddEarthquake
{
my ($amplitude) = @_;
$QuakeAmplitude += $amplitude;
$QuakeAmplitude = 20 if ( $QuakeAmplitude > 20 );
}
sub AdvanceEarthquake
{
if ( $QuakeAmplitude <= 0.2 )
{
$QuakeAmplitude = $QuakeX = $QuakeY = 0;
return;
}
$QuakeAmplitude -= $QuakeAmplitude / 30 + 0.1;
$QuakeOffset = ( $QuakeOffset + 1 ) % 16;
$QuakeX = $QUAKEOFFSET[$QuakeOffset] * $QuakeAmplitude / 16;
$QuakeY = $QUAKEOFFSET[$QuakeOffset + 1] * $QuakeAmplitude / 16; # 1/1
$bgx -= $QuakeX;
$bgy -= $QuakeY;
$p1x += $QuakeX;
$p1y += $QuakeY;
$p2x += $QuakeX;
$p2y += $QuakeY;
+ $p3x += $QuakeX;
+ $p3y += $QuakeY;
+ $p4x += $QuakeX;
+ $p4y += $QuakeY;
# Do not quake doodads for now.
}
=comment
GAME BACKEND METHODS
=cut
-sub GameStart($$)
+sub GameStart($$$$$)
{
- my ( $MaxHP, $debug ) = @_;
+ my ( $MaxHP, $numplayers, $teamsize, $wide, $debug ) = @_;
+
+ ResetGame( $BgMax >> 1, $wide, $numplayers );
- ResetGame( $BgMax >> 1);
+ $::MaxHP = $MaxHP;
$bgx = ( $SCRWIDTH2 - $BGWIDTH2) >> 1;
$bgy = ( $SCRHEIGHT2 - $BGHEIGHT2 ) >> 1;
$BgScrollEnabled = 1;
$HitPointScale = 1000 / $MaxHP; # 1/1
$Debug = $debug;
-
- $Fighter1->{HP} = $MaxHP;
- $Fighter2->{HP} = $MaxHP;
+
+ my ($fighter);
+ foreach $fighter (@Fighters)
+ {
+ $fighter->{TEAMSIZE} = $teamsize;
+ $fighter->{HP} = $MaxHP;
+ }
$p1h = $p2h = 0;
}
+=comment
+NextTeamMember releases the next team member of the given team. This method
+is called by the frontend when a fighter dies in team mode. The new fighter
+will be released someplace "safe". The team size of the given player will
+be decremented.
+
+Input parameters:
+$player 0 or 1, the player who has his current fighter replaced
+$fighterenum The new fighter who will replace the current figther.
+
+=cut
+
+sub NextTeamMember($$)
+{
+ my ($player, $fighterenum) = @_;
+
+ my ($fighter) = $Fighters[$player];
+ my ($otherx, $oldx);
+
+ -- $fighter->{TEAMSIZE};
+ $oldx = $fighter->{X};
+
+ SetPlayerNumber( $player, $fighterenum );
+ $fighter->{HP} = $::MaxHP;
+ $over = 0;
+ $ko = 0;
+ $OverTimer = 0;
+
+ if ( $NUMPLAYERS == 2 )
+ {
+ $otherx = $Fighters[1-$fighter->{NUMBER}]->{X};
+ if ( $otherx < $BGWIDTH2 / 2 )
+ {
+ $fighter->{X} = $otherx + $SCRWIDTH2 ;#- $MOVEMARGIN2 * 6;
+ $fighter->{DIR} = -1;
+ }
+ else
+ {
+ $fighter->{X} = $otherx - $SCRWIDTH2 ;#+ $MOVEMARGIN2 * 6;
+ $fighter->{DIR} = +1;
+ }
+
+ if ( abs( $fighter->{X} - $oldx ) > $SCRWIDTH2 / 2 )
+ {
+ $fighter->{DELPENALTY} = 100;
+ }
+ }
+ else
+ {
+ if ($BgPosition < $BgMax2/2)
+ {
+ $fighter->{X} = $BgPosition + $SCRWIDTH2 + $MOVEMARGIN2;
+ $fighter->{DIR} = -1;
+ }
+ else
+ {
+ $fighter->{X} = $BgPosition - $MOVEMARGIN2;
+ $fighter->{DIR} = 1;
+ }
+ }
+
+ $fighter->{BOUNDSCHECK} = 0;
+ $fighter->{NEXTST} = 'JumpStart';
+ $fighter->Update();
+}
+
+
=comment
Takes a Fighter object, and returns the data relevant for the frontend.
Parameters:
$fighter The fighter which is to be converted to frontend data.
+$hp The displayed hit points
Returns:
$x The physical X coordinate of the fighter
$y The physical Y coordinate of the fighter
$fnum The frame number of the fighter. A negative sign means the
fighter is flipped horizontally (facing left)
+$hp The displayed hit points
+$hpreal The real HP of the given player
=cut
-sub GetFighterData($)
+sub GetFighterData($$)
{
- my ($fighter) = @_;
- my ($x, $y, $fnum, $f, $hp);
+ my ($fighter, $hp) = @_;
+ my ($x, $y, $fnum, $f);
$fnum = $fighter->{FR};
$f = $fighter->{FRAMES}->[$fnum];
$x = $fighter->{X} / $GAMEBITS2 + $f->{'x'};
$y = $fighter->{Y} / $GAMEBITS2 + $f->{'y'};
if ($fighter->{DIR}<0)
{
$fnum = -$fnum;
$x -= $f->{x}*2 + $f->{w};
}
- return ($x, $y, $fnum);
+ $phTarget = $fighter->{HP}*$HitPointScale;
+ if ( $hp < $phTarget ) { $hp += 5; }
+ if ( $hp > $phTarget ) { $hp -= 3; }
+ $hp = $phTarget if abs($hp - $phTarget) < 3;
+ $hp = 0 if $hp < 0;
+
+ return ($x, $y, $fnum, $hp, $fighter->{HP});
}
sub GetNextDoodadData
{
if ( $NextDoodad >= scalar @Doodads )
{
$doodad_x = $doodad_y = $doodad_t = $doodad_f = $doodad_dir = $doodad_gfxowner = -1;
$doodad_text = '';
return;
}
my ($doodad) = $Doodads[$NextDoodad];
$doodad_x = $doodad->{POS}->[0] / $GAMEBITS2 - $bgx;
$doodad_y = $doodad->{POS}->[1] / $GAMEBITS2 - $bgy;
$doodad_t = $doodad->{T};
$doodad_f = $doodad->{F};
$doodad_dir = $doodad->{DIR};
$doodad_gfxowner = $doodad->{GFXOWNER};
$doodad_text = $doodad->{TEXT};
- if ($doodad_gfxowner < 2 )
+ if ($doodad_gfxowner >=0 )
{
$doodad_x += $Fighters[$doodad_gfxowner]->{FRAMES}->[$doodad_f]->{'x'} * $doodad_dir;
$doodad_y += $Fighters[$doodad_gfxowner]->{FRAMES}->[$doodad_f]->{'y'};
}
++$NextDoodad;
}
sub UpdateDoodads
{
my ($i, $j, $doodad);
for ($i=0; $i<scalar @Doodads; ++$i)
{
$doodad = $Doodads[$i];
$j = Doodad::UpdateDoodad( $doodad );
if ( $j )
{
# Remove this Doodad
splice @Doodads, $i, 1;
--$i;
}
}
}
sub DeleteDoodadsOf($)
{
my ($owner) = @_;
my ($i, $doodad);
for ($i=0; $i<scalar @Doodads; ++$i)
{
$doodad = $Doodads[$i];
if ( $doodad->{OWNER} == $owner )
{
# Remove this Doodad
splice @Doodads, $i, 1;
--$i;
}
}
}
sub GetNextSoundData()
{
# print "GetSoundData: ", scalar @Sounds, join ' ,', @Sounds, "\n";
$sound = pop @Sounds;
$sound = '' unless defined $sound;
}
+sub DoFighterHitEvent($$$)
+{
+ my ($fighter, $other, $hit) = @_;
+
+ $fighter->HitEvent( $other, $other->GetCurrentState()->{HIT}, $hit );
+}
+
+
-sub DoFighterEvents
+sub DoFighterEvents($)
{
- my ($fighter, $hit) = @_;
+ my ($fighter) = @_;
if ( $JudgementMode )
{
if ( $fighter->{NUMBER} == $JudgementWinner )
{
$fighter->Event("Won");
}
else
{
$fighter->Event("Hurt");
}
return;
}
- if ( $hit )
- {
- $fighter->HitEvent( $fighter->{OTHER}->GetCurrentState()->{HIT}, $hit );
- return;
- }
-
- #if ( ($fighter->{X} - $fighter->{OTHER}->{X}) * ($fighter->{DIR}) > 0 )
- if ( $fighter->IsBackTurned )
+ if ( $NUMPLAYERS ==2 and $fighter->IsBackTurned )
{
$fighter->Event("Turn");
}
- if ( $fighter->{OTHER}->{ST} eq 'Dead' )
+ if ( $ActiveTeams <= 1 )
{
$fighter->Event("Won");
}
if ( $fighter->{IDLE} > 150 )
{
my ($r) = $fighter->QuasiRandom( 353 );
$fighter->Event("Fun") if $r==1;
$fighter->Event("Threat") if $r==2;
}
}
sub GameAdvance
{
- my ($hit1, $hit2);
+ my ( @hits, @playerhit, $i, $j, $fighter, $input);
$gametick += 1;
$NextDoodad = 0;
$NextSound = 0;
# 1. ADVANCE THE PLAYERS
- $Input1->Advance();
- $Input2->Advance();
- $Fighter1->Advance( $Input1 ) if $Fighter1->{OK};
- $Fighter2->Advance( $Input2 ) if $Fighter2->{OK};
- $hit2 = $Fighter1->CheckHit() if $Fighter1->{OK};
- $hit1 = $Fighter2->CheckHit() if $Fighter2->{OK};
+ for ( $i=0; $i<$NUMPLAYERS; ++$i ) {
+ $input = $Inputs[$i];
+ $fighter = $Fighters[$i];
+ $input->Advance();
+ $fighter->Advance( $input ) if $fighter->{OK};
+ $hit[$i] = 0;
+ }
+ @hits = ();
+ for ( $i=0; $i<$NUMPLAYERS; ++$i ) {
+ push @hits, ( $Fighters[$i]->CheckHit() );
+ }
+
# 2. Events come here
- DoFighterEvents( $Fighter1, $hit1 ) if $Fighter1->{OK};
- DoFighterEvents( $Fighter2, $hit2 ) if $Fighter2->{OK};
+ foreach $hit (@hits) {
+ print STDERR "hits: $hit->[0] $hit->[1] $hit->[2]\n";
+ DoFighterHitEvent( $hit->[1], $hit->[0], $hit->[2] );
+ }
+
+ for ( $i=0; $i<$NUMPLAYERS; ++$i ) {
+ $fighter = $Fighters[$i];
+ DoFighterEvents( $fighter ) if $fighter->{OK};
+ }
+
UpdateDoodads();
- $Fighter1->Update() if $Fighter1->{OK};
- $Fighter2->Update() if $Fighter2->{OK};
- if ( $OverTimer == 0 and
- ($Fighter1->{ST} eq 'Dead' or $Fighter1->{ST} eq 'Won2') and
- ($Fighter2->{ST} eq 'Dead' or $Fighter2->{ST} eq 'Won2') )
+ for ( $i=0; $i<$NUMPLAYERS; ++$i ) {
+ $fighter = $Fighters[$i];
+ $fighter->Update() if $fighter->{OK};
+ }
+
+ if ( $OverTimer == 0 and $ActiveTeams <= 0 )
{
$OverTimer = 1;
}
elsif ( $OverTimer > 0 )
{
$OverTimer++;
$over = 1 if ( $OverTimer > 200 )
}
# 3. DO THE BACKGROUND SCROLLING THING
if ( $BgScrollEnabled )
{
- $BgOpt = ($Fighter1->{X} + $Fighter2->{X}) / 2; # 1/1 Stupid kdevelop syntax hightlight.
- if ( ($BgOpt - $BgSpeed*50 - $BgPosition) > (320 << $GAMEBITS)) { $BgSpeed++; }
- if ( ($BgOpt - $BgSpeed*50 - $BgPosition) < (320 << $GAMEBITS)) { $BgSpeed--; }
+ $BgOpt = 0;
+ for ( $i=0; $i<$NUMPLAYERS; ++$i ) { $BgOpt += $Fighters[$i]->{X}; }
+ $BgOpt /= $NUMPLAYERS; # 1/1 Stupid kdevelop syntax hightlight.
+ if ( ($BgOpt - $BgSpeed*50 - $BgPosition) > ($SCRWIDTH2 / 2) ) { $BgSpeed++; }
+ if ( ($BgOpt - $BgSpeed*50 - $BgPosition) < ($SCRWIDTH2 / 2) ) { $BgSpeed--; }
$BgPosition+=$BgSpeed;
if ($BgPosition<0) { $BgPosition = $BgSpeed = 0; }
if ($BgPosition>$BgMax) { $BgPosition = $BgMax; $BgSpeed = 0; }
# print "Pos:$BgPosition\tOpt:$BgOpt\tSpd:$BgSpeed\t";
}
# 4. SET GLOBAL VARIABLES FOR THE C++ DRAWING TO READ
- ($p1x, $p1y, $p1f) = GetFighterData( $Fighter1 );
- ($p2x, $p2y, $p2f) = GetFighterData( $Fighter2 );
-
- $phTarget = $Fighter1->{HP}*$HitPointScale;
- if ( $p1h < $phTarget ) { $p1h += 5; }
- if ( $p1h > $phTarget ) { $p1h -= 3; }
- $p1h = $phTarget if abs($p1h - $phTarget) < 3;
- $p1h = 0 if $p1h < 0;
+ ($p1x, $p1y, $p1f, $p1h, $p1hreal) = GetFighterData( $Fighters[0], $p1h );
+ ($p2x, $p2y, $p2f, $p2h, $p2hreal) = GetFighterData( $Fighters[1], $p2h ) if ($NUMPLAYERS >= 2);
+ ($p3x, $p3y, $p3f, $p3h, $p3hreal) = GetFighterData( $Fighters[2], $p3h ) if ($NUMPLAYERS >= 3);
+ ($p4x, $p4y, $p4f, $p3h, $p4hreal) = GetFighterData( $Fighters[3], $p4h ) if ($NUMPLAYERS >= 4);
- $phTarget = $Fighter2->{HP}*$HitPointScale;
- if ( $p2h < $phTarget ) { $p2h += 5; }
- if ( $p2h > $phTarget ) { $p2h -= 3; }
- $p2h = $phTarget if abs($p2h - $phTarget) < 3;
- $p2h = 0 if $p2h < 0;
-
$bgx = $BgPosition >> $GAMEBITS;
$p1x -= $bgx;
$p2x -= $bgx;
+ $p3x -= $bgx;
+ $p4x -= $bgx;
$bgy = 0;
AdvanceEarthquake();
# 5. DEBUG POLYGONS
if ( $Debug )
{
$fr1 = $Fighter1->{FRAMES}->[ $Fighter1->{FR} ];
@p1head = @{ $fr1->{head} };
MirrorPolygon( \@p1head ) if $Fighter1->{DIR} < 0;
OffsetPolygon( \@p1head, $Fighter1->{X} / $GAMEBITS2 - $bgx, $Fighter1->{Y} / $GAMEBITS2 - $bgy );
@p1body = @{ $fr1->{body} };
MirrorPolygon( \@p1body ) if $Fighter1->{DIR} < 0;
OffsetPolygon( \@p1body, $Fighter1->{X} / $GAMEBITS2 - $bgx, $Fighter1->{Y} / $GAMEBITS2 - $bgy );
@p1legs = @{ $fr1->{legs} };
MirrorPolygon( \@p1legs) if $Fighter1->{DIR} < 0;
OffsetPolygon( \@p1legs, $Fighter1->{X} / $GAMEBITS2 - $bgx, $Fighter1->{Y} / $GAMEBITS2 - $bgy );
if ( defined $fr1->{hit} )
{
@p1hit = @{ $fr1->{hit} };
MirrorPolygon( \@p1hit ) if $Fighter1->{DIR} < 0;
OffsetPolygon( \@p1hit, $Fighter1->{X} / $GAMEBITS2 - $bgx, $Fighter1->{Y} / $GAMEBITS2 - $bgy );
}
else
{
undef @p1hit;
}
$fr2 = $Fighter2->{FRAMES}->[ $Fighter2->{FR} ];
@p2head = @{ $fr2->{head} };
MirrorPolygon( \@p2head ) if $Fighter2->{DIR} < 0;
OffsetPolygon( \@p2head, $Fighter2->{X} / $GAMEBITS2 - $bgx, $Fighter2->{Y} / $GAMEBITS2 - $bgy );
@p2body = @{ $fr2->{body} };
MirrorPolygon( \@p2body ) if $Fighter2->{DIR} < 0;
OffsetPolygon( \@p2body, $Fighter2->{X} / $GAMEBITS2 - $bgx, $Fighter2->{Y} / $GAMEBITS2 - $bgy );
@p2legs = @{ $fr2->{legs} };
MirrorPolygon( \@p2legs) if $Fighter2->{DIR} < 0;
OffsetPolygon( \@p2legs, $Fighter2->{X} / $GAMEBITS2 - $bgx, $Fighter2->{Y} / $GAMEBITS2 - $bgy );
if ( defined $fr2->{hit} )
{
@p2hit = @{ $fr2->{hit} };
MirrorPolygon( \@p2hit ) if $Fighter2->{DIR} < 0;
OffsetPolygon( \@p2hit, $Fighter2->{X} / $GAMEBITS2 - $bgx, $Fighter2->{Y} / $GAMEBITS2 - $bgy );
}
else
{
undef @p2hit;
}
}
}
diff --git a/data/script/CollectedStats.pl b/data/script/CollectedStats.pl
index fd33750..8e121c9 100644
--- a/data/script/CollectedStats.pl
+++ b/data/script/CollectedStats.pl
@@ -1,577 +1,592 @@
-%::FighterStats = ( '103' => { 'DATAVERSION' => '1',
- 'CODENAME' => 'Mrsmith',
- 'WEIGHT' => '80kg',
- 'DATAFILE' => 'Mrsmith.dat',
- 'STORY' => 'Mr. Smith comes from the shadows, where he and his evil, disgraced family of de
-mons resided for such a dementing long time. Now, as the last member of his inge
-nious breed, Mr. Smith takes on the tournament to reclaim every of all possessio
-ns his family lost under the dark ages of The Returning Of The Good Wizards. Uns
-toppable and strong enough to beat a Black Dragon by his own hands, Mr. Smith se
-eks trouble wherever he thinks there could be one.',
- 'SHOE' => '44',
- 'NAME' => 'Mr. Smith',
- 'TEAM' => 'Spontán',
- 'STYLE' => 'beer-fu',
- 'ID' => '103',
- 'AGE' => '23',
- 'EMAIL' => 'zaphir@sch.bme.hu',
- 'GENDER' => '1',
- 'DATASIZE' => '6259470',
+%::FighterStats = ( '104' => { 'DATAVERSION' => '1',
+ 'STORY' => 'Jozsi, the ex-designer, after 56hours of non-stop image-editing unexpectedly ju
+st broke down, left his office, and went to live in the mountains. He tried to l
+ive in peace with the nature, far from the civilization, but he couldn\'t defeat
+a voice in his head: REVENGE!
+So now he\'s here...',
+ 'WEIGHT' => '70kg',
'HEIGHT' => '185cm',
- },
- '7' => { 'WEIGHT-hu' => '85',
- 'AGE-hu' => '20',
- 'NAME-hu' => 'Taka Ito',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Bence',
- 'WEIGHT' => '85kg',
- 'SHOE' => '39',
- 'STORY' => 'The "Japanese giant" is a sworn enemy of Descant... after he left
-muddy boot marks all over the freshly mopped porch of the pub, er,
-dojo which has belonged to his ancestors for 16 generations. Since
-he has turned to the dark side of the janitor. His knowledge of
-the "way of the concierge" matches his deep hatred towards army
-boots.',
- 'DATAFILE' => 'Bence.dat',
- 'KEYS' => 'Down Back LPunch - Soap Throw
-Back Fw Back Fw LPunch - Stick Spin
-Back Forward HPunc - Pierce',
- 'SHOE-hu' => '39',
- 'NAME' => 'Jan Ito',
- 'HEIGHT-hu' => '172',
- 'TEAM' => 'Evil',
- 'STYLE' => 'Kururin-do',
- 'ID' => '7',
- 'AGE' => '20',
- 'STYLE-hu' => 'Kururin-do',
- 'STORY-hu' => 'A japán óriás Descant esküdt ellensége, mióta összejárta az általa frissen felmosott
-verandát a 16 generáció óta családja által birtokolt foga-do-ban. Tudását a sötét
-oldal szolgálatába állította. Tudását a "gondnok útján" csak mélységes megvetése a
-vasaltorrú bakancsok iránt szárnyalja túl.',
- 'GENDER' => '1',
- 'DATASIZE' => '6750636',
- 'TEAM-hu' => 'Gonosz',
- 'HEIGHT' => '172cm',
- },
- '15' => { 'TEAM' => 'Good',
- 'STYLE' => 'Glamour',
- 'ID' => '15',
- 'AGE' => '140',
- 'WEIGHT' => '1',
- 'CODENAME' => 'Elf',
- 'STORY' => '...',
- 'SHOE' => '1',
- 'NAME' => 'Pixie',
- 'HEIGHT' => '1',
- },
- '10' => { 'WEIGHT-hu' => 'N/A',
- 'AGE-hu' => '500',
- 'NAME-hu' => 'Rising-san',
- 'WEIGHT' => 'N/A',
- 'CODENAME' => 'Surba',
- 'STORY' => 'Mistically disappeared Aeons ago.. on a Saturday! Now he is back, and
-brought back his destructive techique, unmatched on Earth. Noone knows
-why he joined the Dark Evil Mage...',
- 'SHOE' => 'N/A',
- 'SHOE-hu' => 'Nem visel',
- 'NAME' => 'Rising-san',
- 'HEIGHT-hu' => '50',
- 'TEAM' => 'Evil',
- 'STYLE' => 'Flick-fu',
- 'ID' => '10',
- 'AGE' => '500',
- 'STORY-hu' => 'Sok-sok évvel ezel"ott eltûnt misztikus körülmények között... egy szombati napon!
-És most visszatért. Senki sem tudja honnan jött, de magával hozta pusztító technikáját
-melynek nincs párja a földön. Senki sem érti miért fogadta el a gonosz varázsl
-megbízását...',
- 'STYLE-hu' => 'Pöcc-fu',
- 'TEAM-hu' => 'Gonosz',
- 'HEIGHT' => '50',
- },
- '102' => { 'DATAVERSION' => '1',
- 'CODENAME' => 'Jacint',
- 'WEIGHT' => '200kg',
- 'DATAFILE' => 'Jacint.dat',
- 'STORY' => 'Eats grass. Wanna win the qpa.',
- 'SHOE' => 'don\'t wear shoes',
- 'NAME' => 'Jacint',
- 'TEAM' => 'Schiman',
- 'STYLE' => 'thei-fu',
- 'ID' => '102',
- 'AGE' => '13',
- 'EMAIL' => 'jimmi@sch.bme.hu',
- 'GENDER' => '1',
- 'DATASIZE' => '5534158',
- 'HEIGHT' => '140 cm',
- },
- '1' => { 'WEIGHT-hu' => '50kg + vaságy',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Ulmar',
- 'WEIGHT' => '50kg',
- 'SHOE' => '51',
- 'STORY' => 'After Wastasiwa baka janajo took possession of his time\'s most advanced
-technogadget (read: by accident he was punched so hard that he flew fight into
-a high-tech lab, and got tangled with the WrISt(tm)),
-
-he used all his knowledge to travel to the past (read: he started mashing the buttons, and
-this is how it ended).
-
-Then he knew immediately that he had to destroy
-Saturday! (Read: He has absolutely no idea where he is, or what he is doing...)',
- 'DATAFILE' => 'Ulmar.dat',
- 'KEYS' => 'Back HPunch - Spinning headbutt
-Down Back LPunch - WrISt shot
-Forward Back Forward LPunch - WrISt mash',
- 'SHOE-hu' => '51',
- 'NAME' => 'Watasiwa baka janajo',
- 'HEIGHT-hu' => '168cm',
- 'TEAM' => 'Evil',
- 'STYLE' => 'Clown-fu',
- 'ID' => '1',
- 'AGE' => '15',
- 'STYLE-hu' => 'Bohóc-fu',
- 'STORY-hu' => 'Miután Wasaiwa baka janaijo elszajrézta a kora legfejletebb tudományos cuccosát
-(véletlenül úgy behúztak neki, hogy berepült a laboratoriumba és rátekeredett a CsUKlo(tm)),
-
-azután minden tudását latba vetve vissza utazott a múltba (elkezdte nyomkodni a gombokat a
-CsUKlo(tm)-en és ez lett belõle).
-
-Ezekután már rögtön tudta, hogy itt el kell pusztitania a Szombatot! (õ sem tudja, hogy hol
-is van éppen illetve mit is csinál...)',
+ 'ID' => '104',
+ 'STYLE' => 'cserno-fu',
+ 'TEAM' => 'Good',
+ 'DATAFILE' => 'Jozsi.dat',
+ 'CODENAME' => 'Jozsi',
+ 'AGE' => '60',
+ 'DATASIZE' => '6004229',
'GENDER' => '1',
- 'DATASIZE' => '6316271',
- 'TEAM-hu' => 'Gonosz',
- 'HEIGHT' => '168cm',
+ 'SHOE' => '45',
+ 'NAME' => 'Jozsi a hegyrol',
},
- '11' => { 'WEIGHT-hu' => '110',
- 'AGE-hu' => '35',
- 'NAME-hu' => 'Fûrészes Õrült',
+ '11' => { 'TEAM-hu' => 'Gonosz',
'DATAVERSION' => '1',
- 'CODENAME' => 'Ambrus',
- 'WEIGHT' => '110',
- 'SHOE' => '49',
'STORY' => 'His cradle was found on a tree. Later he chopped up the family that
took him and fed them to the bears. He has been roaming the Canadian
forests, chopping trees and heads alike. On hot summer nights his
maniac laughter echoes far.',
- 'DATAFILE' => 'Ambrus.dat',
- 'KEYS' => 'Down Back LPunch - Axe Toss
-Back Forward HKick - Chop Chop
-Forward Forward LKick - Bonesaw',
- 'SHOE-hu' => '49',
- 'NAME' => 'Mad Sawman',
- 'HEIGHT-hu' => '120',
- 'TEAM' => 'Evil',
- 'STYLE' => 'Sawing',
- 'ID' => '11',
- 'AGE' => '35',
'STYLE-hu' => 'Fanyûvõ',
+ 'AGE-hu' => '35',
+ 'WEIGHT' => '110',
'STORY-hu' => 'Bölcsõjét egy fán találták meg. Késõbb felaprította az egész befogadó családját, és
megetette a medvékkel. Azóta a kanadai erdõkben bolyongva vágja a fákat és az
emberfejeket. Forró nyári éjszakákon mindig hallatszik õrült kacaja.',
+ 'HEIGHT' => '120',
+ 'SHOE-hu' => '49',
+ 'WEIGHT-hu' => '110',
+ 'STYLE' => 'Sawing',
+ 'ID' => '11',
+ 'TEAM' => 'Evil',
+ 'DATAFILE' => 'Ambrus.dat',
+ 'CODENAME' => 'Ambrus',
+ 'AGE' => '35',
'GENDER' => '1',
'DATASIZE' => '6462957',
- 'TEAM-hu' => 'Gonosz',
- 'HEIGHT' => '120',
+ 'SHOE' => '49',
+ 'HEIGHT-hu' => '120',
+ 'KEYS' => 'Down Back LPunch - Axe Toss
+Back Forward HKick - Chop Chop
+Forward Forward LKick - Bonesaw',
+ 'NAME' => 'Mad Sawman',
+ 'NAME-hu' => 'Fûrészes Õrült',
},
- '6' => { 'TEAM' => 'Good',
- 'STYLE' => 'Macy-fu',
- 'ID' => '6',
- 'AGE' => '17',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Macy',
+ '6' => { 'DATAVERSION' => '1',
+ 'STORY' => 'A few years ago (perhaps a little earlier, or maybe later) she was
+found among the clouds in a cradle (falling, of course). She learned
+martial art from brave Son Goku, so she landed on her feet and didn\'t
+die. She\'s been immortal ever since. Who knows for how long? Maybe
+it won\'t be until the next fight agains Evil...',
'WEIGHT' => '41kg',
'STORY-hu' => 'kb. néhány évvel ezelõtt, (vagy talán egy kicsit korábban, esetleg
késõbb) a felhõk között egy pólyában találtak rá (zuhanás közben).
A bátor
Songokutól elleste a harcmûvészet mesteri fortélyait, igy talpra esett és
nem halt meg. Azóta is halhatatlan. Ki tudja, még meddig? Talán a
következõ harcig a gonosz ellen...',
+ 'HEIGHT' => '175cm',
+ 'STYLE' => 'Macy-fu',
+ 'ID' => '6',
+ 'DATAFILE' => 'Macy.dat',
+ 'TEAM' => 'Good',
+ 'CODENAME' => 'Macy',
+ 'AGE' => '17',
'GENDER' => '2',
'DATASIZE' => '5151824',
'SHOE' => '37',
- 'STORY' => 'A few years ago (perhaps a little earlier, or maybe later) she was
-found among the clouds in a cradle (falling, of course). She learned
-martial art from brave Son Goku, so she landed on her feet and didn\'t
-die. She\'s been immortal ever since. Who knows for how long? Maybe
-it won\'t be until the next fight agains Evil...',
- 'DATAFILE' => 'Macy.dat',
'KEYS' => 'Down Back LPunch - Toss
Forward Forward HKick - Scissor Kick',
'NAME' => 'Macy',
- 'HEIGHT' => '175cm',
},
- '100' => { 'NAME.hu' => 'Agent Krampusz',
- 'STYLE.hu' => 'Neo-puff-fu',
+ '12' => { 'TEAM-hu' => 'Jó',
'DATAVERSION' => '1',
- 'CODENAME' => 'Agent',
- 'WEIGHT' => '80kg',
- 'DATAFILE' => 'Agent.dat',
- 'STORY' => 'Once upon a time, there was a competition named after the infamous hostel Schonherz. In this competition
-several hundred different tasks are sent out to be solved by a similar number of students. Creating this
-character was part of such a task.',
- 'SHOE' => '44',
- 'GAMEVERSION' => '0.4',
- 'NAME' => 'Agent Boogie',
- 'WEIGHT.hu' => '80kg',
- 'TEAM' => 'Schonherz',
- 'STYLE' => 'Neo-bang-fu',
- 'ID' => '100',
- 'AGE' => '22',
- 'AGE.hu' => '22',
- 'GENDER' => '1',
- 'DATASIZE' => '4542272',
- 'TEAM.hu' => 'Schonherz',
- 'HEIGHT.hu' => '180cm',
- 'SHOE.hu' => '44',
- 'STORY.hu' => 'Once upon a time, there was a competition named after the infamous hostel Schonherz. In this competition
-several hundred different tasks are sent out to be solved by a similar number of students. Creating this
-character was part of such a task.',
- 'HEIGHT' => '180cm',
- },
- '9' => { 'WEIGHT-hu' => '89',
- 'AGE-hu' => '58',
- 'NAME-hu' => 'Descant',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Descant',
- 'WEIGHT' => '89kg',
- 'SHOE' => '44',
- 'STORY' => 'He was trained in \'Nam in every known weapon and martial art form.
-He fought there on the side of the Americans and the Russians...
-whoever paid more at the moment. Then he used the money to hybernate
-himself until the next great war.. or until the Saturday is in
-trouble. He joined the side with the more CASH...',
- 'DATAFILE' => 'Descant.dat',
- 'KEYS' => 'Down Back LPunch - Aimed Shot
-Back Back LPunch - Hip Shot
-Forward Down HPunch - Knife Throw
-Forward Forward HPunch - Gun Hit',
- 'SHOE-hu' => '44',
- 'NAME' => 'Descant',
- 'HEIGHT-hu' => '180',
- 'TEAM' => 'Good',
- 'STYLE' => 'Murderization',
- 'ID' => '9',
- 'AGE' => '58',
- 'STYLE-hu' => '+halol',
- 'STORY-hu' => 'A Vietnámi háború során képezték ki minden ismert fegyverre és harcm~uvészetre. Már ott
-is az Oroszok és az Amerikaik oldalán harcolt, már aki éppen többet fizetett. Ezután a pénzb"ol
-hibernáltatta magát és csak háborúk esetén olvasztatja föl magát, vagy most mikor a szombat
-bajba kerül most is azon az oldalon van, ahol vastagabb a BUKSZA, most épp a...',
- 'GENDER' => '1',
- 'DATASIZE' => '5877193',
- 'TEAM-hu' => 'Jó',
- 'HEIGHT' => '180cm',
- },
- '2' => { 'WEIGHT-hu' => '70kg',
- 'AGE-hu' => '30',
- 'NAME-hu' => 'Sötét Fekete Gonosz Mágus',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'UPi',
- 'WEIGHT' => '70kg',
- 'SHOE' => '42',
- 'STORY' => 'Member of the Evil Killer Black Antipathic Dim (witted) Fire Mages Leage.
-He was sent to destroy Saturday now and forever! Or maybe he has a secret
-agenda that noone knows about..? Nah...',
- 'DATAFILE' => 'UPi.dat',
- 'KEYS' => 'Back HKick - Spinkick
-Forward Forward HKick - Crane kick
-Down Back LPunch - Fireball
-(also works while crouching)
-Back Up HPunch - Burning Hands',
- 'SHOE-hu' => '42',
- 'NAME' => 'Dark Black Evil Mage',
- 'HEIGHT-hu' => '180cm',
- 'TEAM' => 'Evil leader',
- 'STYLE' => 'Piro-fu',
- 'ID' => '2',
- 'AGE' => '30',
- 'STYLE-hu' => 'Piro-fu',
- 'STORY-hu' => 'A Gonosz Gyilkos Fekete Ellenszenves Sötét (elméjü) tüzvarázslók ligájának
-tagja, kit azzal bíztak meg, hogy elpusztítsa a szombatot egyszer, s
-mindörökre. Talán van valami hátsó szándéka, amirõl senki sem tud? Nincs!',
+ 'STORY' => 'His childhood was determined by Drezda\'s bombing. This trauma has
+caused him to join the army. For the last 30 years he is corporal
+without the slightest hope for advancement. He annoys his
+subordinates with a constant flow of stories of pub fights, until
+they ask for relocation.',
+ 'STYLE-hu' => 'Kocsmabunyó',
+ 'AGE-hu' => '50',
+ 'WEIGHT' => '100',
+ 'STORY-hu' => 'Gyermekkorát meghatározta Drezda lebombázása. E trauma hatására katonai
+pályára állt. Immáron 30 éve a Bundeswehr kötelékében tizedes az
+elõléptetés bárminem~u esélye nélkül.
+
+Alantasait folytonosan kocsmai bunyóinak történeteivel traktálja, amíg azok
+áthelyezésüket nem kérik.',
+ 'HEIGHT' => '180',
+ 'SHOE-hu' => '44',
+ 'WEIGHT-hu' => '100',
+ 'STYLE' => 'Pub Fight',
+ 'ID' => '12',
+ 'TEAM' => 'Good',
+ 'DATAFILE' => 'Dani.dat',
+ 'CODENAME' => 'Dani',
+ 'AGE' => '50',
'GENDER' => '1',
'DATASIZE' => '6462957',
- 'TEAM-hu' => 'Gonosz vezér',
- 'HEIGHT' => '180cm',
- },
- '3' => { 'WEIGHT-hu' => '80kg',
- 'AGE-hu' => '16',
- 'NAME-hu' => 'Boxer',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Zoli',
- 'WEIGHT' => '80kg',
- 'SHOE' => '43',
- 'STORY' => 'Boxer joined the Mortal Szombat team for the sole purpose to punch as
-many people as hard as he possibly can. He has no other purpose
-whatsoever, but at least this keeps him entertained for the time being.',
- 'DATAFILE' => 'Zoli.dat',
- 'KEYS' => 'Back HPunch - Spinning punch
-Down Back LPunch - Weight toss
-Forward Forward HPunch - Leaping punch',
- 'SHOE-hu' => '43',
- 'NAME' => 'Boxer',
- 'HEIGHT-hu' => '180cm',
- 'TEAM' => 'Evil',
- 'STYLE' => 'Kickbox-fu',
- 'ID' => '3',
- 'AGE' => '16',
- 'STYLE-hu' => 'Kickbox-fu',
- 'STORY-hu' => 'Boxer azért csatlakozott a Mortál Szombat csapathoz, hogy minél több
-embernek besomhasson, minél többször, és minél nagyobbat. Más célja ezen
-kívül nincs, de ez is remekül elszórakoztatja középtávon',
- 'GENDER' => '1',
- 'DATASIZE' => '4486206',
- 'TEAM-hu' => 'Gonosz',
- 'HEIGHT' => '180cm',
- },
- '5' => { 'TEAM' => 'Good',
- 'STYLE' => 'Don\'tHurtMe-FU',
- 'ID' => '5',
- 'AGE' => '24',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Sirpi',
- 'WEIGHT' => '76kg',
- 'STYLE-hu' => 'Nebánts-FU',
- 'STORY-hu' => 'Sok évnyi hardcore gamerkedés után, miközben el is hízott jól,
-kikapcsolták nála a villanyt.
-
-Erre nagyon hülye pofát vágott, és ez igy is
-marad mindaddig, amíg le nem számol õsellenségével (vagy még utána is).
-Ezért csatlakozott a jók kicsiny csapatához... Meg amúgy is fél egyedül.',
- 'GENDER' => '1',
- 'DATASIZE' => '5587262',
- 'SHOE' => '41',
- 'STORY' => 'After being a "hardcore" gamer for several years and consuming a
-great amount of food, his electricity was turned off. This has caused
-him to make a very stupid face which lasts till this day, and will
-last until he has defeated his archenemy. This is why he resolved to
-join the good team... also he is frightened alone.',
- 'DATAFILE' => 'Sirpi.dat',
- 'KEYS' => 'Down Forward LPunch - Surprise
-Forward Forward HPunch - Applause',
- 'NAME' => 'Sirpi',
- 'HEIGHT' => '170cm',
- },
- '12' => { 'WEIGHT-hu' => '100',
- 'AGE-hu' => '50',
- 'NAME-hu' => 'Tökéletlen Katona',
- 'DATAVERSION' => '1',
- 'CODENAME' => 'Dani',
- 'WEIGHT' => '100',
'SHOE' => '44',
- 'STORY' => 'His childhood was determined by Drezda\'s bombing. This trauma has
-caused him to join the army. For the last 30 years he is corporal
-without the slightest hope for advancement. He annoys his
-subordinates with a constant flow of stories of pub fights, until
-they ask for relocation.',
- 'DATAFILE' => 'Dani.dat',
+ 'HEIGHT-hu' => '180',
'KEYS' => 'Down Back LPunch - Hat
Forward Forward HPunch - Ramming Attack
Back Down Back LPunch - Stab
Back Forward LKick - Poke',
- 'SHOE-hu' => '44',
'NAME' => 'Imperfect Soldier',
- 'HEIGHT-hu' => '180',
- 'TEAM' => 'Good',
- 'STYLE' => 'Pub Fight',
- 'ID' => '12',
- 'AGE' => '50',
- 'STYLE-hu' => 'Kocsmabunyó',
- 'STORY-hu' => 'Gyermekkorát meghatározta Drezda lebombázása. E trauma hatására katonai
-pályára állt. Immáron 30 éve a Bundeswehr kötelékében tizedes az
-elõléptetés bárminem~u esélye nélkül.
-
-Alantasait folytonosan kocsmai bunyóinak történeteivel traktálja, amíg azok
-áthelyezésüket nem kérik.',
+ 'NAME-hu' => 'Tökéletlen Katona',
+ },
+ '4' => { 'TEAM-hu' => 'Jo vezer',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'His life ambition was to drive a car. Now that this was accomplished,
+he has turned to his second greatest ambition: to be a great martial
+artist superhero. As a start, he has watched the TV series "Kung fu"
+from beginning to end, in one session. His current training consists
+of but this.',
+ 'STYLE-hu' => 'N/A',
+ 'AGE-hu' => '15',
+ 'WEIGHT' => '55kg',
+ 'STORY-hu' => 'Elete fo ambicioja volt, hogy autot vezessen. Most hogy ezt teljesitette, masodik fo
+amibicioja fele fordult: hogy nagy harcmuvessze valjon. Kezdetben ehhez megnezte
+a Kung fu sorozatot elejetol vegeig egyulteben. Kepzettsege jelenleg ebbol all.',
+ 'HEIGHT' => '170cm',
+ 'SHOE-hu' => '41.5',
+ 'WEIGHT-hu' => '55',
+ 'STYLE' => 'N/A',
+ 'ID' => '4',
+ 'TEAM' => 'Good Leader',
+ 'DATAFILE' => 'Cumi.dat',
+ 'CODENAME' => 'Cumi',
+ 'AGE' => '15',
'GENDER' => '1',
+ 'DATASIZE' => '5365949',
+ 'SHOE' => '41.5',
+ 'HEIGHT-hu' => '170',
+ 'KEYS' => 'Down Back LPunch - Finger Shot
+Forward Forward HPunch - Spit
+Back Down Forward - Baseball',
+ 'NAME' => 'Cumi',
+ 'NAME-hu' => 'Cumi',
+ },
+ '13' => { 'DATAVERSION' => '1',
+ 'STORY' => 'Her trials started right in the womb.. her life hung on a single
+umbilical cord! But she was finally born, and got the name
+Aisha ("survives everything"). Since her childhood she survived
+natural disasters and terrorist attacks, and got frankly fed up.
+So one time she said:
+
+"If I survive this, I swear, I\'ll join those stupid Mortal guys!"',
+ 'WEIGHT' => '43.5',
+ 'STORY-hu' => 'A megprobaltatasok akkor kezdodtek, amikor anyukaja a szive alatt hordta.
+Egyetlen koldokzsinoron fuggott az elete! De megszuletett vegul, ezert
+kapta az Aisha ("mindent tulelo") nevet. Aztan gyermekkoratol fogva sok
+termeszeti katasztrofat, terrortamadast atveszelt, es mar kezdett elege
+lenni az egeszbol, igy hat az egyik alkalommal kijelentette, hogy ha ezt
+tulelem, csatlakozom azokhoz a hulye Mortalosokhoz!',
+ 'HEIGHT' => '155',
+ 'STYLE' => 'Death Dance',
+ 'ID' => '13',
+ 'DATAFILE' => 'Kinga.dat',
+ 'TEAM' => 'Good',
+ 'CODENAME' => 'Kinga',
+ 'AGE' => '21',
+ 'GENDER' => '2',
'DATASIZE' => '6462957',
- 'TEAM-hu' => 'Jó',
- 'HEIGHT' => '180',
+ 'SHOE' => '35',
+ 'NAME' => 'Aisha',
},
- '8' => { 'WEIGHT-hu' => '50000000',
- 'AGE-hu' => '21',
- 'NAME-hu' => 'Grizli',
+ '8' => { 'TEAM-hu' => 'Jó',
'DATAVERSION' => '1',
- 'CODENAME' => 'Grizli',
- 'WEIGHT' => 'Several tons',
- 'SHOE' => '49',
'STORY' => 'Grizzly has been long famous for his laziness. He has made laziness a
form of art. In the past 5 years he has been to lazy to watch TV. Every
Saturday he trains in his own special fighting style, one not unlike
that of Bud Spencer, whom he holds as his honorary master. Though,
since he found out that Bud WORKS on Saturdays, he has revoked his
title, and keeps it for himself. He has joined the Good team to fight
to protect the Saturday.',
- 'DATAFILE' => 'Grizli.dat',
- 'KEYS' => 'Down Back LPunch - Bear Shot
-Forward Forward HPunch - Poke
-Down Down LKick - Earthquake
-Back Forward Back HPunch - Nunchaku',
- 'SHOE-hu' => '49',
- 'NAME' => 'Grizzly',
- 'HEIGHT-hu' => '170',
- 'TEAM' => 'Good',
- 'STYLE' => 'Bear dance',
- 'ID' => '8',
- 'AGE' => '21',
'STYLE-hu' => 'Gyakás ala Medve',
+ 'AGE-hu' => '21',
+ 'WEIGHT' => 'Several tons',
'STORY-hu' => 'Grili a lustaságáról volt hires mindig. Olyannyira, hogy amilyen szinten
azt csinálja, az már mûvészet. Az utóbbi 5 évben már a TV
nézéshez is lusta lett.
Minden Szobaton tart edzést a Különbenmegintdühbejövünk do
stilusból, amit még kezdõ korában a TV-bõl sajátított el. A stilus
tiszteletbeli nagymestere maga Bád Szpencer, de sajnos miután Bád-ról
kiderült, hogy szombatonként dolgozik, Grizli elvette tõle a cimet, s
azóta magának tartogatja.
Grizli a szombat ellenesek ádáz gyûlölõje, a jó csapat oszlopos tagja.',
+ 'HEIGHT' => '170cm',
+ 'SHOE-hu' => '49',
+ 'WEIGHT-hu' => '50000000',
+ 'STYLE' => 'Bear dance',
+ 'ID' => '8',
+ 'TEAM' => 'Good',
+ 'DATAFILE' => 'Grizli.dat',
+ 'CODENAME' => 'Grizli',
+ 'AGE' => '21',
'GENDER' => '1',
'DATASIZE' => '7138871',
- 'TEAM-hu' => 'Jó',
- 'HEIGHT' => '170cm',
+ 'SHOE' => '49',
+ 'HEIGHT-hu' => '170',
+ 'KEYS' => 'Down Back LPunch - Bear Shot
+Forward Forward HPunch - Poke
+Down Down LKick - Earthquake
+Back Forward Back HPunch - Nunchaku',
+ 'NAME' => 'Grizzly',
+ 'NAME-hu' => 'Grizli',
},
- '4' => { 'WEIGHT-hu' => '55',
- 'AGE-hu' => '15',
- 'NAME-hu' => 'Cumi',
+ '105' => { 'EMAIL' => 'orca@wap.hu',
'DATAVERSION' => '1',
- 'CODENAME' => 'Cumi',
- 'WEIGHT' => '55kg',
- 'SHOE' => '41.5',
- 'STORY' => 'His life ambition was to drive a car. Now that this was accomplished,
-he has turned to his second greatest ambition: to be a great martial
-artist superhero. As a start, he has watched the TV series "Kung fu"
-from beginning to end, in one session. His current training consists
-of but this.',
- 'DATAFILE' => 'Cumi.dat',
- 'KEYS' => 'Down Back LPunch - Finger Shot
-Forward Forward HPunch - Spit
-Back Down Forward - Baseball',
- 'SHOE-hu' => '41.5',
- 'NAME' => 'Cumi',
- 'HEIGHT-hu' => '170',
- 'TEAM' => 'Good Leader',
- 'STYLE' => 'N/A',
- 'ID' => '4',
- 'AGE' => '15',
- 'STYLE-hu' => 'N/A',
- 'STORY-hu' => 'Elete fo ambicioja volt, hogy autot vezessen. Most hogy ezt teljesitette, masodik fo
-amibicioja fele fordult: hogy nagy harcmuvessze valjon. Kezdetben ehhez megnezte
-a Kung fu sorozatot elejetol vegeig egyulteben. Kepzettsege jelenleg ebbol all.',
+ 'STORY' => 'az most nincs',
+ 'WEIGHT' => '80kg',
+ 'HEIGHT' => '185cm',
+ 'ID' => '105',
+ 'STYLE' => 'sleep-fu',
+ 'TEAM' => 'Mindegy',
+ 'DATAFILE' => 'Sleepy.dat',
+ 'CODENAME' => 'Sleepy',
+ 'AGE' => '25',
+ 'DATASIZE' => '6809466',
'GENDER' => '1',
- 'DATASIZE' => '5365949',
- 'TEAM-hu' => 'Jo vezer',
- 'HEIGHT' => '170cm',
+ 'SHOE' => 'Atlagmamusz',
+ 'NAME' => 'Sleepy',
},
- '101' => { 'DATAVERSION' => '1',
- 'CODENAME' => 'Tejszin',
- 'WEIGHT' => '130kg',
- 'DATAFILE' => 'Tejszin.dat',
- 'STORY' => 'long,long, time ago....:)',
- 'SHOE' => '45',
- 'NAME' => '[10g] Tej-szin',
- 'TEAM' => '[10g]',
- 'STYLE' => 'ultrabrutal',
- 'ID' => '101',
- 'AGE' => '160',
- 'EMAIL' => 'lameron@sch.bme.hu',
+ '100' => { 'SHOE.hu' => '44',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'Once upon a time, there was a competition named after the infamous hostel Schonherz. In this competition
+several hundred different tasks are sent out to be solved by a similar number of students. Creating this
+character was part of such a task.',
+ 'GAMEVERSION' => '0.4',
+ 'HEIGHT.hu' => '180cm',
+ 'AGE.hu' => '22',
+ 'WEIGHT' => '80kg',
+ 'WEIGHT.hu' => '80kg',
+ 'HEIGHT' => '180cm',
+ 'STORY.hu' => 'Once upon a time, there was a competition named after the infamous hostel Schonherz. In this competition
+several hundred different tasks are sent out to be solved by a similar number of students. Creating this
+character was part of such a task.',
+ 'ID' => '100',
+ 'STYLE' => 'Neo-bang-fu',
+ 'TEAM' => 'Schonherz',
+ 'DATAFILE' => 'Agent.dat',
+ 'CODENAME' => 'Agent',
+ 'AGE' => '22',
+ 'DATASIZE' => '4542272',
'GENDER' => '1',
- 'DATASIZE' => '9469281',
+ 'SHOE' => '44',
+ 'STYLE.hu' => 'Neo-puff-fu',
+ 'NAME' => 'Agent Boogie',
+ 'NAME.hu' => 'Agent Krampusz',
+ 'TEAM.hu' => 'Schonherz',
+ },
+ '9' => { 'TEAM-hu' => 'Jó',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'He was trained in \'Nam in every known weapon and martial art form.
+He fought there on the side of the Americans and the Russians...
+whoever paid more at the moment. Then he used the money to hybernate
+himself until the next great war.. or until the Saturday is in
+trouble. He joined the side with the more CASH...',
+ 'STYLE-hu' => '+halol',
+ 'AGE-hu' => '58',
+ 'WEIGHT' => '89kg',
+ 'STORY-hu' => 'A Vietnámi háború során képezték ki minden ismert fegyverre és harcm~uvészetre. Már ott
+is az Oroszok és az Amerikaik oldalán harcolt, már aki éppen többet fizetett. Ezután a pénzb"ol
+hibernáltatta magát és csak háborúk esetén olvasztatja föl magát, vagy most mikor a szombat
+bajba kerül most is azon az oldalon van, ahol vastagabb a BUKSZA, most épp a...',
'HEIGHT' => '180cm',
+ 'SHOE-hu' => '44',
+ 'WEIGHT-hu' => '89',
+ 'STYLE' => 'Murderization',
+ 'ID' => '9',
+ 'TEAM' => 'Good',
+ 'DATAFILE' => 'Descant.dat',
+ 'CODENAME' => 'Descant',
+ 'AGE' => '58',
+ 'GENDER' => '1',
+ 'DATASIZE' => '5877193',
+ 'SHOE' => '44',
+ 'HEIGHT-hu' => '180',
+ 'KEYS' => 'Down Back LPunch - Aimed Shot
+Back Back LPunch - Hip Shot
+Forward Down HPunch - Knife Throw
+Forward Forward HPunch - Gun Hit',
+ 'NAME' => 'Descant',
+ 'NAME-hu' => 'Descant',
},
- '105' => { 'DATAVERSION' => '1',
- 'CODENAME' => 'Sleepy',
- 'WEIGHT' => '80kg',
- 'DATAFILE' => 'Sleepy.dat',
- 'STORY' => 'az most nincs',
- 'SHOE' => 'Atlagmamusz',
- 'NAME' => 'Sleepy',
- 'TEAM' => 'Mindegy',
- 'STYLE' => 'sleep-fu',
- 'ID' => '105',
- 'AGE' => '25',
- 'EMAIL' => 'orca@wap.hu',
+ '10' => { 'TEAM-hu' => 'Gonosz',
+ 'AGE-hu' => '500',
+ 'STYLE-hu' => 'Pöcc-fu',
+ 'STORY' => 'Mistically disappeared Aeons ago.. on a Saturday! Now he is back, and
+brought back his destructive techique, unmatched on Earth. Noone knows
+why he joined the Dark Evil Mage...',
+ 'WEIGHT' => 'N/A',
+ 'STORY-hu' => 'Sok-sok évvel ezel"ott eltûnt misztikus körülmények között... egy szombati napon!
+És most visszatért. Senki sem tudja honnan jött, de magával hozta pusztító technikáját
+melynek nincs párja a földön. Senki sem érti miért fogadta el a gonosz varázsl
+megbízását...',
+ 'SHOE-hu' => 'Nem visel',
+ 'HEIGHT' => '50',
+ 'ID' => '10',
+ 'STYLE' => 'Flick-fu',
+ 'WEIGHT-hu' => 'N/A',
+ 'TEAM' => 'Evil',
+ 'CODENAME' => 'Surba',
+ 'AGE' => '500',
+ 'SHOE' => 'N/A',
+ 'HEIGHT-hu' => '50',
+ 'NAME' => 'Rising-san',
+ 'NAME-hu' => 'Rising-san',
+ },
+ '16' => { 'HEIGHT' => '?',
+ 'ID' => '16',
+ 'STYLE' => '?',
+ 'TEAM' => 'Evil',
+ 'DATAFILE' => 'Judy.dat',
+ 'CODENAME' => 'Judy',
+ 'AGE' => '?',
+ 'DATAVERSION' => '1',
'GENDER' => '1',
- 'DATASIZE' => '6809466',
- 'HEIGHT' => '185cm',
+ 'DATASIZE' => '6462957',
+ 'STORY' => '...',
+ 'SHOE' => '?',
+ 'WEIGHT' => '?',
+ 'NAME' => 'Judy',
},
- '104' => { 'TEAM' => 'Good',
- 'STYLE' => 'cserno-fu',
- 'ID' => '104',
- 'AGE' => '60',
+ '5' => { 'DATAVERSION' => '1',
+ 'STORY' => 'After being a "hardcore" gamer for several years and consuming a
+great amount of food, his electricity was turned off. This has caused
+him to make a very stupid face which lasts till this day, and will
+last until he has defeated his archenemy. This is why he resolved to
+join the good team... also he is frightened alone.',
+ 'STYLE-hu' => 'Nebánts-FU',
+ 'WEIGHT' => '76kg',
+ 'STORY-hu' => 'Sok évnyi hardcore gamerkedés után, miközben el is hízott jól,
+kikapcsolták nála a villanyt.
+
+Erre nagyon hülye pofát vágott, és ez igy is
+marad mindaddig, amíg le nem számol õsellenségével (vagy még utána is).
+Ezért csatlakozott a jók kicsiny csapatához... Meg amúgy is fél egyedül.',
+ 'HEIGHT' => '170cm',
+ 'STYLE' => 'Don\'tHurtMe-FU',
+ 'ID' => '5',
+ 'DATAFILE' => 'Sirpi.dat',
+ 'TEAM' => 'Good',
+ 'CODENAME' => 'Sirpi',
+ 'AGE' => '24',
+ 'GENDER' => '1',
+ 'DATASIZE' => '5587262',
+ 'SHOE' => '41',
+ 'KEYS' => 'Down Forward LPunch - Surprise
+Forward Forward HPunch - Applause',
+ 'NAME' => 'Sirpi',
+ },
+ '7' => { 'TEAM-hu' => 'Gonosz',
'DATAVERSION' => '1',
- 'CODENAME' => 'Jozsi',
- 'WEIGHT' => '70kg',
- 'DATASIZE' => '6004229',
+ 'STORY' => 'The "Japanese giant" is a sworn enemy of Descant... after he left
+muddy boot marks all over the freshly mopped porch of the pub, er,
+dojo which has belonged to his ancestors for 16 generations. Since
+he has turned to the dark side of the janitor. His knowledge of
+the "way of the concierge" matches his deep hatred towards army
+boots.',
+ 'STYLE-hu' => 'Kururin-do',
+ 'AGE-hu' => '20',
+ 'WEIGHT' => '85kg',
+ 'STORY-hu' => 'A japán óriás Descant esküdt ellensége, mióta összejárta az általa frissen felmosott
+verandát a 16 generáció óta családja által birtokolt foga-do-ban. Tudását a sötét
+oldal szolgálatába állította. Tudását a "gondnok útján" csak mélységes megvetése a
+vasaltorrú bakancsok iránt szárnyalja túl.',
+ 'HEIGHT' => '172cm',
+ 'SHOE-hu' => '39',
+ 'WEIGHT-hu' => '85',
+ 'STYLE' => 'Kururin-do',
+ 'ID' => '7',
+ 'TEAM' => 'Evil',
+ 'DATAFILE' => 'Bence.dat',
+ 'CODENAME' => 'Bence',
+ 'AGE' => '20',
'GENDER' => '1',
- 'DATAFILE' => 'Jozsi.dat',
- 'STORY' => 'Jozsi, the ex-designer, after 56hours of non-stop image-editing unexpectedly ju
-st broke down, left his office, and went to live in the mountains. He tried to l
-ive in peace with the nature, far from the civilization, but he couldn\'t defeat
-a voice in his head: REVENGE!
-So now he\'s here...',
- 'SHOE' => '45',
- 'NAME' => 'Jozsi a hegyrol',
+ 'DATASIZE' => '6750636',
+ 'SHOE' => '39',
+ 'HEIGHT-hu' => '172',
+ 'KEYS' => 'Down Back LPunch - Soap Throw
+Back Fw Back Fw LPunch - Stick Spin
+Back Forward HPunc - Pierce',
+ 'NAME' => 'Jan Ito',
+ 'NAME-hu' => 'Taka Ito',
+ },
+ '15' => { 'HEIGHT' => '1',
+ 'STYLE' => 'Glamour',
+ 'ID' => '15',
+ 'TEAM' => 'Good',
+ 'CODENAME' => 'Elf',
+ 'AGE' => '140',
+ 'STORY' => '...',
+ 'SHOE' => '1',
+ 'WEIGHT' => '1',
+ 'NAME' => 'Pixie',
+ },
+ '103' => { 'EMAIL' => 'zaphir@sch.bme.hu',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'Mr. Smith comes from the shadows, where he and his evil, disgraced family of de
+mons resided for such a dementing long time. Now, as the last member of his inge
+nious breed, Mr. Smith takes on the tournament to reclaim every of all possessio
+ns his family lost under the dark ages of The Returning Of The Good Wizards. Uns
+toppable and strong enough to beat a Black Dragon by his own hands, Mr. Smith se
+eks trouble wherever he thinks there could be one.',
+ 'WEIGHT' => '80kg',
'HEIGHT' => '185cm',
+ 'ID' => '103',
+ 'STYLE' => 'beer-fu',
+ 'TEAM' => 'Spontán',
+ 'DATAFILE' => 'Mrsmith.dat',
+ 'CODENAME' => 'Mrsmith',
+ 'AGE' => '23',
+ 'DATASIZE' => '6259470',
+ 'GENDER' => '1',
+ 'SHOE' => '44',
+ 'NAME' => 'Mr. Smith',
},
- '14' => { 'WEIGHT-hu' => 'Nagyon súlyos!',
- 'AGE-hu' => 'Feudális közép...',
+ '3' => { 'TEAM-hu' => 'Gonosz',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'Boxer joined the Mortal Szombat team for the sole purpose to punch as
+many people as hard as he possibly can. He has no other purpose
+whatsoever, but at least this keeps him entertained for the time being.',
+ 'STYLE-hu' => 'Kickbox-fu',
+ 'AGE-hu' => '16',
+ 'WEIGHT' => '80kg',
+ 'STORY-hu' => 'Boxer azért csatlakozott a Mortál Szombat csapathoz, hogy minél több
+embernek besomhasson, minél többször, és minél nagyobbat. Más célja ezen
+kívül nincs, de ez is remekül elszórakoztatja középtávon',
+ 'HEIGHT' => '180cm',
+ 'SHOE-hu' => '43',
+ 'WEIGHT-hu' => '80kg',
+ 'STYLE' => 'Kickbox-fu',
+ 'ID' => '3',
'TEAM' => 'Evil',
+ 'DATAFILE' => 'Zoli.dat',
+ 'CODENAME' => 'Zoli',
+ 'AGE' => '16',
+ 'GENDER' => '1',
+ 'DATASIZE' => '4486206',
+ 'SHOE' => '43',
+ 'HEIGHT-hu' => '180cm',
+ 'KEYS' => 'Back HPunch - Spinning punch
+Down Back LPunch - Weight toss
+Forward Forward HPunch - Leaping punch',
+ 'NAME' => 'Boxer',
+ 'NAME-hu' => 'Boxer',
+ },
+ '102' => { 'EMAIL' => 'jimmi@sch.bme.hu',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'Eats grass. Wanna win the qpa.',
+ 'WEIGHT' => '200kg',
+ 'HEIGHT' => '140 cm',
+ 'ID' => '102',
+ 'STYLE' => 'thei-fu',
+ 'TEAM' => 'Schiman',
+ 'DATAFILE' => 'Jacint.dat',
+ 'CODENAME' => 'Jacint',
+ 'AGE' => '13',
+ 'DATASIZE' => '5534158',
+ 'GENDER' => '1',
+ 'SHOE' => 'don\'t wear shoes',
+ 'NAME' => 'Jacint',
+ },
+ '101' => { 'EMAIL' => 'lameron@sch.bme.hu',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'long,long, time ago....:)',
+ 'WEIGHT' => '130kg',
+ 'HEIGHT' => '180cm',
+ 'ID' => '101',
+ 'STYLE' => 'ultrabrutal',
+ 'TEAM' => '[10g]',
+ 'DATAFILE' => 'Tejszin.dat',
+ 'CODENAME' => 'Tejszin',
+ 'AGE' => '160',
+ 'DATASIZE' => '9469281',
+ 'GENDER' => '1',
+ 'SHOE' => '45',
+ 'NAME' => '[10g] Tej-szin',
+ },
+ '14' => { 'HEIGHT' => '178 cm',
+ 'WEIGHT-hu' => 'Nagyon súlyos!',
+ 'TEAM-hu' => 'Gonosz',
'STYLE' => 'Gloom',
- 'NAME-hu' => 'Apatsuka Anyatsuba',
'ID' => '14',
+ 'TEAM' => 'Evil',
+ 'CODENAME' => 'Misi',
'AGE' => 'Feudal Middle',
- 'STORY-hu' => 'Apatsukát 4 éves kora óta nevelték szülei a szamuráj életmódra, szigor
-keretek között. Apja az elmúlt 20 év leghíresebb harcosa volt. Amint
-minden harci fogást elsajátított apjától, megskalpolta és a skalpját
-fejére illesztette, ezzel megfélemlítve ellenségeit.
-
-Hétközben nõket
-hajszolt, szombaton szívott és berugott. Aztán úgy döntött, hogy ezen a
-szombaton csak õ érezheti jól magát...',
+ 'AGE-hu' => 'Feudális közép...',
'STYLE-hu' => 'Komor',
- 'WEIGHT' => 'Dead',
- 'CODENAME' => 'Misi',
'STORY' => 'Papastuka has been raised strictly in the way of the samurai since age 4.
His father was the most famous warrior of the past 20 years. After he
learned all the jutsu from dad, he skalped him, and put the skalp on his head
to scare his enemies.
On weekdays he is seen chasing women, saturdays he
drinks a lot. Then he decided, that enjoying saturday should belong to him
alone...',
'SHOE' => '43,12748252',
- 'TEAM-hu' => 'Gonosz',
+ 'WEIGHT' => 'Dead',
+ 'STORY-hu' => 'Apatsukát 4 éves kora óta nevelték szülei a szamuráj életmódra, szigor
+keretek között. Apja az elmúlt 20 év leghíresebb harcosa volt. Amint
+minden harci fogást elsajátított apjától, megskalpolta és a skalpját
+fejére illesztette, ezzel megfélemlítve ellenségeit.
+
+Hétközben nõket
+hajszolt, szombaton szívott és berugott. Aztán úgy döntött, hogy ezen a
+szombaton csak õ érezheti jól magát...',
'NAME' => 'Papatsuka Mamatsuba',
- 'HEIGHT' => '178 cm',
+ 'NAME-hu' => 'Apatsuka Anyatsuba',
},
- '13' => { 'TEAM' => 'Good',
- 'STYLE' => 'Death Dance',
- 'ID' => '13',
- 'AGE' => '21',
+ '2' => { 'TEAM-hu' => 'Gonosz vezér',
'DATAVERSION' => '1',
- 'CODENAME' => 'Kinga',
- 'WEIGHT' => '43.5',
- 'STORY-hu' => 'A megprobaltatasok akkor kezdodtek, amikor anyukaja a szive alatt hordta.
-Egyetlen koldokzsinoron fuggott az elete! De megszuletett vegul, ezert
-kapta az Aisha ("mindent tulelo") nevet. Aztan gyermekkoratol fogva sok
-termeszeti katasztrofat, terrortamadast atveszelt, es mar kezdett elege
-lenni az egeszbol, igy hat az egyik alkalommal kijelentette, hogy ha ezt
-tulelem, csatlakozom azokhoz a hulye Mortalosokhoz!',
- 'GENDER' => '2',
+ 'STORY' => 'Member of the Evil Killer Black Antipathic Dim (witted) Fire Mages Leage.
+He was sent to destroy Saturday now and forever! Or maybe he has a secret
+agenda that noone knows about..? Nah...',
+ 'STYLE-hu' => 'Piro-fu',
+ 'AGE-hu' => '30',
+ 'WEIGHT' => '70kg',
+ 'STORY-hu' => 'A Gonosz Gyilkos Fekete Ellenszenves Sötét (elméjü) tüzvarázslók ligájának
+tagja, kit azzal bíztak meg, hogy elpusztítsa a szombatot egyszer, s
+mindörökre. Talán van valami hátsó szándéka, amirõl senki sem tud? Nincs!',
+ 'HEIGHT' => '180cm',
+ 'SHOE-hu' => '42',
+ 'WEIGHT-hu' => '70kg',
+ 'STYLE' => 'Piro-fu',
+ 'ID' => '2',
+ 'TEAM' => 'Evil leader',
+ 'DATAFILE' => 'UPi.dat',
+ 'CODENAME' => 'UPi',
+ 'AGE' => '30',
+ 'GENDER' => '1',
'DATASIZE' => '6462957',
- 'SHOE' => '35',
- 'STORY' => 'Her trials started right in the womb.. her life hung on a single
-umbilical cord! But she was finally born, and got the name
-Aisha ("survives everything"). Since her childhood she survived
-natural disasters and terrorist attacks, and got frankly fed up.
-So one time she said:
+ 'SHOE' => '42',
+ 'HEIGHT-hu' => '180cm',
+ 'KEYS' => 'Back HKick - Spinkick
+Forward Forward HKick - Crane kick
+Down Back LPunch - Fireball
+(also works while crouching)
+Back Up HPunch - Burning Hands',
+ 'NAME' => 'Dark Black Evil Mage',
+ 'NAME-hu' => 'Sötét Fekete Gonosz Mágus',
+ },
+ '1' => { 'TEAM-hu' => 'Gonosz',
+ 'DATAVERSION' => '1',
+ 'STORY' => 'After Wastasiwa baka janajo took possession of his time\'s most advanced
+technogadget (read: by accident he was punched so hard that he flew fight into
+a high-tech lab, and got tangled with the WrISt(tm)),
-"If I survive this, I swear, I\'ll join those stupid Mortal guys!"',
- 'DATAFILE' => 'Kinga.dat',
- 'NAME' => 'Aisha',
- 'HEIGHT' => '155',
+he used all his knowledge to travel to the past (read: he started mashing the buttons, and
+this is how it ended).
+
+Then he knew immediately that he had to destroy
+Saturday! (Read: He has absolutely no idea where he is, or what he is doing...)',
+ 'STYLE-hu' => 'Bohóc-fu',
+ 'WEIGHT' => '50kg',
+ 'STORY-hu' => 'Miután Wasaiwa baka janaijo elszajrézta a kora legfejletebb tudományos cuccosát
+(véletlenül úgy behúztak neki, hogy berepült a laboratoriumba és rátekeredett a CsUKlo(tm)),
+
+azután minden tudását latba vetve vissza utazott a múltba (elkezdte nyomkodni a gombokat a
+CsUKlo(tm)-en és ez lett belõle).
+
+Ezekután már rögtön tudta, hogy itt el kell pusztitania a Szombatot! (õ sem tudja, hogy hol
+is van éppen illetve mit is csinál...)',
+ 'SHOE-hu' => '51',
+ 'HEIGHT' => '168cm',
+ 'WEIGHT-hu' => '50kg + vaságy',
+ 'STYLE' => 'Clown-fu',
+ 'ID' => '1',
+ 'DATAFILE' => 'Ulmar.dat',
+ 'TEAM' => 'Evil',
+ 'CODENAME' => 'Ulmar',
+ 'AGE' => '15',
+ 'GENDER' => '1',
+ 'DATASIZE' => '6316271',
+ 'SHOE' => '51',
+ 'HEIGHT-hu' => '168cm',
+ 'KEYS' => 'Back HPunch - Spinning headbutt
+Down Back LPunch - WrISt shot
+Forward Back Forward LPunch - WrISt mash',
+ 'NAME' => 'Watasiwa baka janajo',
},
);
\ No newline at end of file
diff --git a/data/script/DataHelper.pl b/data/script/DataHelper.pl
index a6aebd6..6f5d349 100644
--- a/data/script/DataHelper.pl
+++ b/data/script/DataHelper.pl
@@ -1,661 +1,682 @@
# DataHelper contains subroutines useful for loading a character's
# frames, and creating his states.
use strict;
require 'FighterStats.pl';
=comment
SITUATIONS ARE:
Ready, Stand, Crouch, (Midair = any + character is flying), Falling
SITUATION DEPENDENT EVENTS ARE:
Highhit, Uppercut, Hit, Groinhit, Leghit, Fall
STANDBY EVENTS ARE:
Won, Hurt, Threat, Fun, Turn
________|___Ready___________Block___Stand___________Crouch______________Midair______Falling
Highhit | HighPunched - HighPunched KneelingPunched (...) (...)
Uppercut| Falling - Falling KneelingPunched (...) (...)
Hit | LowPunched - LowPunched KneelingKicked
Groinhit| GroinKicked - GroinKicked KneelingKicked
Leghit | Swept - Swept KneelingKicked
Fall | Falling - Falling KneelingPunched
FRAME MEMBER DESCRIPTION IS:
x int X coordinate offset of the image relative to the character's anchor.
y int Y coordinate offset of the image relative to the character's anchor.
w int The width of the image.
h int The height of the image.
head array The coordinates of a polygon marking the head within the image, relative to the anchor.
body array The coordinates of a polygon marking the body within the image, relative to the anchor.
legs array The coordinates of a polygon marking the legs within the image, relative to the anchor.
hit array The coordinates of a polygon marking the hit within the image, relative to the anchor.
STATE MEMBER DESCRIPTION IS:
F int The number of the visible frame.
SITU string The situation associated with this state (Ready, Stand, Crouch, Falling)
DEL int The delay before moving to the next state.
NEXTST string The name of the state which follows this state, if none of the CONs is used.
CON hash Connections from this state. The keys are either events or keyboard input.
HIT ? The hit delivered at the beginning of this state.
BLOCK int If true, the character is blocking in his current state.
MOVE int The character's anchor should continously move this much during this state.
DELTAX int The character's anchor should immediately change by this much after this state.
PUSHX int The character is pushed, with this much momentum upon entering this state.
TURN int If true, the character's facing direction changes after this state.
JUMP int The character leaps into the air, with this much initial momentum upon entering this state.
DOODAD string A doodad is created at the beginning of this state. The string contains the doodad's type and speed.
SOUND string The sound effect associated with this state (if any);
HITSND string The sound effect if the HIT is successful.
MISSSND string The sound effect if the HIT fails.
CODE string This code will be evaled at the beginning of this state.
LAYER int The "priority" of the graphics. 5: hurt; 10: block; 15: kneeling; 20: normal; 25: attack
=cut
# Loads the frame data (x, y, w, h) from the given datafile.
# The path to the datafile is inserted automatically. The frame data will
# be shifted by (-PivotX,-PivotY).
#
# Returns an array of frame data. The first element in the array is
# a dummy entry, the second is the first real entry. This is because
# the first thing in the datafile is a PAL entry.
#
# Example: LoadFrames( "ZOLIDATA.DAT.txt" );
sub LoadFrames ($$$)
{
my ($DataName, $PivotX, $PivotY) = @_;
my (@Frames, $data, $frame, $DatName);
# Make sure that Whatever.dat also exists.
$DatName = $DataName;
$DatName =~ s/\.txt$//;
open DATFILE, "../characters/$DatName" || die ("Couldn't open ../characters/$DatName");
close DATFILE;
open DATAFILE, "../characters/$DataName" || die ("Couldn't open ../characters/$DataName");
$data = '';
while ( read DATAFILE, $data, 16384, length($data) )
{
}
close DATAFILE;
print "$DataName file is ", length($data), " bytes long.\n";
# Insert a dummy first row for the palette entry
eval ("\@Frames = ( {}, $data);");
die $@ if $@;
foreach $frame (@Frames)
{
OffsetFrame( $frame, -$PivotX, -$PivotY );
}
print "$DataName loaded, ", scalar @Frames, " frames.\n";
return @Frames;
}
# Creates a frame lookup from a descriptor array.
# The first parameter is the expected number of frames.
# The descriptor array should have frame base names in even positions,
# and lengths at odd. positions. For example:
# ("start", 6, "stand", 4, ... )
#
# The routine will return a lookup which will contain the frame's logical
# name as a key, and its physical index as a value. The logical names are
# simply the basename plus a number. The example above would return:
# ("start1"=>1, "start2"=>2, ..., "start6"=>6, "stand1"=>6, "stand2"=>7, ...)
sub CreateFrameLookup
{
my ($ExpectedCount, @FrameDesc) = @_;
my ($FrameName, $NumFrames);
my ($i, $j);
my (%FrameLookup);
for ( $i=0; $i<scalar @FrameDesc; $i +=2 )
{
$FrameName = $FrameDesc[$i];
$NumFrames = $FrameDesc[$i+1];
for ( $j = 1; $j<=$NumFrames; ++$j )
{
# print "Frame ", (scalar keys %FrameLookup) + 1, " is now called $FrameName$j\n";
+ print "Name redefinition: $FrameName!\n" if defined $FrameLookup{ "$FrameName$j" };
$FrameLookup{ "$FrameName$j" } = (scalar keys %FrameLookup) + 1;
}
}
if ( $ExpectedCount != scalar keys( %FrameLookup ) )
{
die( "Expected number of frames ($ExpectedCount) doesn't equal the actual number of frames: ".
scalar keys(%FrameLookup) );
}
return %FrameLookup;
}
# Helper function. Finds the last frame with a given name in a frame
# lookup structure. Return the index of the last frame (1-based), or
# 0 if none with the given name were found.
#
# Example: If there are 6 "highpunch" frames (highpunch1 to highpunch6),
# FindLastFrame(\%FrameLookup, "highpunch") returns 6.
sub FindLastFrame($$) {
my ($FrameLookup, $FrameName) = @_;
my ($i) = (1);
while ( exists ${$FrameLookup}{"$FrameName$i"} ) { $i++; }
return $i-1;
}
sub OffsetPolygon($$$)
{
my ($poly, $dx, $dy) = @_;
my ($i, $n);
$n = scalar @{$poly};
for ( $i=0; $i < $n; $i+=2 )
{
$poly->[$i] += $dx;
$poly->[$i+1] += $dy;
}
}
sub MirrorPolygon($)
{
my ($poly) = @_;
my ($i, $n);
$n = scalar @{$poly};
for ( $i=0; $i < $n; $i+=2 )
{
$poly->[$i] = - $poly->[$i];
}
}
+sub GetPolygonCenter($)
+{
+ my ($poly) = @_;
+
+ my ($i, $n, $x, $y);
+
+ $n = scalar @{$poly};
+ $x = $y = 0;
+ for ( $i=0; $i < $n; $i+=2 )
+ {
+ $x += $poly->[$i];
+ $y += $poly->[$i+1];
+ }
+
+ return ( $x*2/$n, $y*2/$n );
+}
+
+
sub OffsetFrame($$$) {
my ($frame, $dx, $dy) = @_;
$frame->{'x'} += $dx;
$frame->{'y'} += $dy;
OffsetPolygon( $frame->{head}, $dx, $dy ) if defined ($frame->{head});
OffsetPolygon( $frame->{body}, $dx, $dy ) if defined ($frame->{body});
OffsetPolygon( $frame->{legs}, $dx, $dy ) if defined ($frame->{legs});
OffsetPolygon( $frame->{hit}, $dx, $dy ) if defined ($frame->{hit});
}
# FindLastState returns the last index of a given state.
# For example, if Punch4 is the last in Punch, FindLastState("Punch") is 4.
sub FindLastState($$) {
my ( $States, $StateName ) = @_;
my ( $i ) = ( 1 );
while ( exists ${$States}{ "$StateName $i" } ) { $i++; }
return $i-1;
}
# Translates an abbreviated sequence to a full sequence.
# "-punch" is every punch frame backwards.
# "_punch" is every punch frame except the last one backwards.
# "+punch" is every punch frame forwards.
sub TranslateSequence($$) {
my ($FrameLookup, $Sequence) = @_;
my ($pre, $frame) = $Sequence =~ /^([+-_]{0,1})(\w+)/;
my ($LastFrame) = (FindLastFrame( $FrameLookup, $frame ) );
#$LastFrame = (FindLastFrame( $FrameLookup, "$pre$frame" ) ) if $LastFrame == 0;
#print "Last frame of $frame is $LastFrame.\n";
return "$frame 1-$LastFrame" if ( $pre eq '+' );
return "$frame $LastFrame-1" if ( $pre eq '-' );
return "$frame " . ($LastFrame-1) . "-1" if ( $pre eq '_' );
$Sequence =~ s/\sn(-{0,1})/ $LastFrame$1/; # Replace n- with last frame
$Sequence =~ s/-n/-$LastFrame/; # Replace -n with last frame
return $Sequence;
}
sub SetStateData($$$)
{
my ($state, $FrameDesc, $suffix) = @_;
$state->{DEL} = $FrameDesc->{"DEL$suffix"} if defined $FrameDesc->{"DEL$suffix"};
$state->{HIT} = $FrameDesc->{"HIT$suffix"} if defined $FrameDesc->{"HIT$suffix"};
$state->{CON} = $FrameDesc->{"CON$suffix"} if defined $FrameDesc->{"CON$suffix"};
$state->{BLOCK} = $FrameDesc->{"BLOCK$suffix"} if defined $FrameDesc->{"BLOCK$suffix"};
$state->{NEXTST} = $FrameDesc->{"NEXTST$suffix"} if defined $FrameDesc->{"NEXTST$suffix"};
$state->{MOVE} = $FrameDesc->{"MOVE$suffix"} if defined $FrameDesc->{"MOVE$suffix"};
$state->{DELTAX} = $FrameDesc->{"DELTAX$suffix"} if defined $FrameDesc->{"DELTAX$suffix"};
$state->{PUSHX} = $FrameDesc->{"PUSHX$suffix"} if defined $FrameDesc->{"PUSHX$suffix"};
$state->{TURN} = $FrameDesc->{"TURN$suffix"} if defined $FrameDesc->{"TURN$suffix"};
$state->{JUMP} = $FrameDesc->{"JUMP$suffix"} if defined $FrameDesc->{"JUMP$suffix"};
$state->{SITU} = $FrameDesc->{"SITU$suffix"} if defined $FrameDesc->{"SITU$suffix"};
$state->{DOODAD} = $FrameDesc->{"DOODAD$suffix"} if defined $FrameDesc->{"DOODAD$suffix"};
$state->{SOUND} = $FrameDesc->{"SOUND$suffix"} if defined $FrameDesc->{"SOUND$suffix"};
$state->{CODE} = $FrameDesc->{"CODE$suffix"} if defined $FrameDesc->{"CODE$suffix"};
}
# Adds a sequence to the end of a state
# Sequences are: e.g. "throw 10-14, throw 16, throw 14-10"
# Each piece of the sequence will have $Delay delay.
sub AddStates($$$) {
my ( $States, $Frames, $FrameDesc ) = @_;
my ( $StateName, $SequenceString, $LastState, $i, $sloop, $s, @Sequences );
my ( $from, $to, $frame, $state );
$StateName = $FrameDesc->{'N'};
$SequenceString = $FrameDesc->{'S'};
$FrameDesc->{SITU} = 'Stand' unless defined $FrameDesc->{SITU};
$LastState = FindLastState($States,$StateName)+1;
@Sequences = split ( /\s*,\s*/, $SequenceString );
for ( $sloop = 0; $sloop < scalar @Sequences; ++$sloop )
{
$s = TranslateSequence( $Frames, $Sequences[$sloop] );
#print "Sequence is $s\n";
if ( $s =~ /^\s*(\w+)\s+(\d+)-(\d+)\s*$/ )
{
# Sequence is '<frame> <from>-<to>'
$frame = $1;
$from = $2;
$to = $3;
}
elsif ( $s =~ /^\s*(\w+)\s+(\d+)\s*$/ )
{
# Sequence is '<frame> <number>'
$frame = $1;
$from = $to = $2;
}
else
{
die "Sequence '$s' incorrect.\n";
}
$i = $from;
while (1)
{
die "Error: Frame $frame$i doesn't exist.\n"
unless defined ${$Frames}{"$frame$i"};
$state = { 'F'=>"$frame$i" };
SetStateData( $state, $FrameDesc, '' );
SetStateData( $state, $FrameDesc, $LastState );
if ( ( $sloop == scalar @Sequences -1 ) and ( $i == $to ) )
{
SetStateData( $state, $FrameDesc, 'N' );
}
$States->{"$StateName $LastState"} = $state;
# print "Added state '$StateName $LastState' as frame '$frame$i', delay $Delay\n";
$LastState++;
if ( $from < $to )
{
$i++;
last if $i > $to;
}
else
{
$i--;
last if $i < $to;
}
}
}
}
sub BlockStates($$)
{
my ( $frames, $del) = @_;
my ( $retval, $i );
# We need to make sure that blocking is the same speed for every character.
# Typical is 5 frames, +- 1 frame
$del = int( 25 / $frames ); # 1/1
$retval = { 'N'=>'Block', 'DEL'=>$del, 'S'=>'+block', };
for ($i = 1; $i <= $frames; ++$i )
{
$retval->{"NEXTST$i"} = "Block " . ($i-1);
$retval->{"CON$i"} = { 'block'=> "Block " . ($i+1) };
$retval->{"BLOCK$i"} = 1 if $i*$del > 10;
}
$retval->{'NEXTST1'} = 'Stand';
$retval->{"CON$frames"} = { 'block'=> "Block " . $frames };
return $retval;
}
sub KneelingStates($$$$)
{
my ( $frames, $frames2, $del, $con ) = @_;
my ( $retval, $retval2, $i, $j );
$retval = { 'N'=>'Kneeling', 'DEL'=> $del, 'S' => '+kneeling', 'SITU'=>'Crouch' };
for ( $i = 1; $i <= $frames; ++$i )
{
$retval->{"NEXTST$i"} = "Kneeling " . ($i-1);
$retval->{"CON$i"} = { 'down' => "Kneeling " . ($i+1) };
}
$retval->{'NEXTST1'} = 'Stand';
$retval->{"CON$frames"} = { 'down' => "Onknees" };
$retval2 = { 'N'=>'Onknees', 'DEL'=>$del, 'S' => '+onknees,-onknees', 'SITU'=>'Crouch',
'NEXTST' => "Kneeling $frames" };
$frames2 *= 2;
for ( $i = 1; $i <= $frames2; ++$i )
{
$j = ($i % $frames2) + 1;
$retval2->{"CON$i"} = { %{$con}, 'down'=>"Onknees $j", 'forw'=>"Onknees $j", 'back'=>"Onknees $j" };
}
return ($retval, $retval2);
}
sub JumpStates($$)
{
my ( $frames, $con ) = @_;
my ( $kneelingframes, $onkneesframes,
$kickframes, $punchframes ) = (
FindLastFrame( $frames, 'kneeling' ),
FindLastFrame( $frames, 'onknees' ),
FindLastFrame( $frames, 'kneelingkick' ),
FindLastFrame( $frames, 'kneelingpunch' ) );
- my ( $jump ) = 120;
+ my ( $jumpheight ) = 120;
my ( $i, $j, $statestotal, $statesdown, $statesknees, $deldown,
- $jumpfw, $jumpbw, $flying, $flyingsequence, $jumpkick, $jumppunch );
+ $jump, $jumpfw, $jumpbw, $flying, $flyingsequence, $flyingstart, $jumpkick, $jumppunch );
# The jump's first part is going down on knees, second part is
# on knees, third part is getting up.
if ( $::DELMULTIPLIER )
{
- $statestotal = $jump * 2 / 3 / $::DELMULTIPLIER; # 1/1
+ $statestotal = $jumpheight * 2 / 3 / $::DELMULTIPLIER; # 1/1
}
else
{
- $statestotal = $jump * 2 / 3;
+ $statestotal = $jumpheight * 2 / 3;
}
$statesdown = $statestotal / 4;
$deldown = int($statesdown / $kneelingframes + 0.1); # 1/1
$statesdown = $deldown * $kneelingframes;
$statesknees = $statestotal - $statesdown * 2;
$jump = { 'N'=>'Jump', 'DEL'=> $deldown, 'S'=>'kneeling 1-2, kneeling 1',
- 'JUMPN'=>$jump, NEXTSTN=>'JumpFly', 'SOUND1'=>'slip4.voc', };
+ 'JUMPN'=>$jumpheight, NEXTSTN=>'JumpFly', 'SOUND1'=>'slip4.voc', };
$jumpfw = { %{$jump}, 'N'=>'JumpFW', 'PUSHX3'=>18*16 };
$jumpbw = { %{$jump}, 'N'=>'JumpBW', 'PUSHX3'=>-9*16 };
$flyingsequence = '';
$flying = {};
for ( $i = 0; $i < $statesknees / $deldown; ++$i ) #1/1
{
$j = $i + $statesdown / $deldown; #1/1
$flyingsequence .= 'onknees 1,';
$flying->{"CON$j"} = $con;
# $flying->{"DEL$j"} = 1;
}
$flyingsequence = "+kneeling, $flyingsequence -kneeling";
$flying = { %{$flying}, 'N'=>'JumpFly', 'DEL'=> $deldown, 'S'=>$flyingsequence,
'DELN'=>100 };
+ $flyingstart = { 'N'=>'JumpStart', 'JUMP2'=>$jumpheight, 'PUSHX2'=>9*16, 'DEL1'=>1,
+ 'DEL'=> $deldown, 'S'=>"stand 1,$flyingsequence", 'DELN'=>100 };
print join( ',', %{$flying}), "\n";
$jumpkick = { 'N'=>'JumpKick', 'HIT'=>'Fall',
'DEL'=> int( $statestotal * 2 / 3 / ( $kickframes + $kneelingframes*2 + 3 ) ), # 1/1
'S'=> '+kneelingkick,kneelingkick n, kneelingkick n, kneelingkick n,-kneelingkick,-kneeling',
'HIT'=>'Fall', 'DELN'=>100 };
$jumppunch = { 'N'=>'JumpPunch', 'HIT'=>'Highhit',
'DEL'=> int( $statestotal * 2 / 3 / ( $punchframes + $kneelingframes*2 + 3 ) ), # 1/1
'S'=> '+kneelingpunch,kneelingpunch n, kneelingpunch n, kneelingpunch n,-kneelingpunch,-kneeling',
'HIT'=>'Fall', 'DELN'=>100 };
- return ($jump, $jumpfw, $jumpbw, $flying, $jumpkick, $jumppunch);
+ return ($jump, $jumpfw, $jumpbw, $flying, $flyingstart, $jumpkick, $jumppunch);
}
sub WalkingFrames($$$$$)
{
my ( $frameLookup, $frameArray, $preFrames, $distance, $con ) = @_;
my ( $walkFrames, $totalFrames, $seq, $seq2, $distPerFrame,
$walk, $back, $walkNextst, $backNextst,
$i, $j, );
$totalFrames = FindLastFrame( $frameLookup, 'walk' );
$walkFrames = $totalFrames - $preFrames;
if ( $preFrames > 0 ) {
$seq = "+walk, walk $preFrames-1";
$seq2 = "walk 1-$preFrames, -walk";
} else {
$seq = "+walk";
$seq2 = "-walk";
}
$walk = { 'N'=>'Walk', 'S'=>$seq, 'DEL'=>5, 'CON'=>$con };
$back = { 'N'=>'Back', 'S'=>$seq2, 'DEL'=>5, };
# Add attributes for the 'pre' states.
for ( $i=1; $i <= $preFrames; ++$i )
{
$j = $i + 1;
$walk->{"CON$i"} = { %{$con}, 'forw' => "Walk $j" };
$walk->{"NEXTST$i"} = 'Stand';
$back->{"CON$i"} = { %{$con}, 'back' => "Back $j" };
$back->{"NEXTST$i"} = 'Stand';
}
# Add attributes for the 'walk' states.
$walkNextst = $preFrames ? 'Walk ' . ($totalFrames+1) : 'Stand';
$backNextst = $preFrames ? 'Back ' . ($totalFrames+1) : 'Stand';
$distPerFrame = $distance / $walkFrames; # 1/1
print "*** $preFrames $walkFrames $totalFrames $walkNextst $backNextst\n";
for ( $i=$preFrames+1; $i <= $totalFrames; ++$i )
{
$j = ($i == $totalFrames) ? $preFrames+1 : $i+1;
$walk->{"MOVE$i"} = 4;
$walk->{"NEXTST$i"} = $walkNextst;
$walk->{"CON$i"} = { %{$con}, 'forw' => "Walk $j" };
$back->{"MOVE$i"} = -4;
$back->{"NEXTST$i"} = $backNextst;
$back->{"CON$i"} = { %{$con}, 'back' => "Back $j" };
OffsetFrame( $frameArray->[$frameLookup->{"walk$i"}],
- ($i-$preFrames-1) * $distPerFrame, 0 );
}
return ( $walk, $back );
}
sub TravelingStates( $$$$$$ )
{
my ( $frameLookup, $frameArray, $states, $frameName, $from, $to ) = @_;
-
+
$from = 1 unless $from;
unless ( $to )
{
$to = FindLastFrame( $frameLookup, $frameName );
$to += 1 if $frameName eq 'falling';
}
my ( $fromIndex, $toIndex, $fromFrame, $toFrame, $fromOffset, $toOffset,
$deltax, $i, $state, $nextst );
# 1. Calculate the 'deltax' and 'fromOffset'.
$fromIndex = $frameLookup->{"$frameName$from"};
die "couldn't find frame $frameName$from" unless defined $fromIndex;
$toIndex = $fromIndex - $from + $to;
$fromFrame = $frameArray-> [ $fromIndex ];
$toFrame = $frameArray-> [ $toIndex ];
$fromOffset = $fromFrame->{x} + ($fromFrame->{w} >> 1);
$toOffset = $toFrame->{x} + ($toFrame->{w} >> 1);
$deltax = ( $toOffset - $fromOffset ) / ( $to - $from ); #1/1
# print "Offsets: $fromOffset $toOffset $deltax\n";
# 2. Offset every relevant frame.
for ( $i=$fromIndex; $i<=$toIndex; ++$i )
{
# print "Offsetting frame $i by ", - $fromOffset - $deltax * ($i-$fromIndex), "\n";
OffsetFrame( $frameArray->[$i],
- $fromOffset - $deltax * ($i-$fromIndex), 0 );
}
# 3. Apply deltax to every relevant state.
while ( ($i, $state) = each %{$states} )
{
if ( $state->{F} >= $fromIndex and $state->{F} <= $toIndex )
{
$nextst = $states->{$state->{NEXTST}};
if ( defined($nextst) and $nextst->{F} >= $fromIndex and $nextst->{F} <= $toIndex )
{
$state->{DELTAX} = $deltax * ($nextst->{F} - $state->{F});
# print "Fixing state $i : deltax = ", $state->{DELTAX}, "\n";
}
}
}
}
sub FixStates($$)
{
my ( $frameLookup, $states ) = @_;
my ( $framename, $st, $lastchar, $key, $value, $nextchar, $nextst );
while (($key, $value) = each %{$states})
{
$framename = $value->{'F'};
unless ( $framename =~/^\d+$/ )
{
# Convert non-numeric frames to their numeric counterparts.
die "Can't find image $framename in frame $key" unless defined $frameLookup->{ $framename };
$value->{'F'} = $frameLookup->{ $framename };
}
($st,$lastchar) = $key =~ /(\w+)\s+(\d+)/;
unless ( defined $value->{'NEXTST'} )
{
$nextchar = $lastchar + 1;
$nextst = "$st $nextchar";
unless ( defined $states->{$nextst} ) {
# print "Go to Standby after $key\n";
$nextst = 'Stand';
}
$value->{'NEXTST'} = $nextst;
}
}
}
sub FindShorthands($)
{
my ( $states ) = @_;
my ( $key, $value, $st, $lastchar, %Shorthands );
while (($key, $value) = each %{$states})
{
($st,$lastchar) = $key =~ /(\w+)\s+(\d+)/;
print "$key has no lastchar" unless defined $lastchar;
if ( $lastchar == 1 )
{
$Shorthands{$st} = $states->{$key};
}
}
return %Shorthands;
}
sub CheckStates($$)
{
my ( $fightername, $states ) = @_;
my ( $key,$state, $con );
my ( $seq,$nextst );
while (($key, $state) = each %{$states})
{
die "Bad connection in fighter $fightername to '$state->{NEXTST} from $key!'" unless exists $states->{ $state->{NEXTST} };
next unless $state->{CON};
$con = $state->{CON};
while (($seq, $nextst) = each %{$con})
{
die "Bad connection in fighter $fightername to '$nextst' from $key!" unless exists $states->{$nextst};
}
}
}
return 1;
diff --git a/data/script/Doodad.pl b/data/script/Doodad.pl
index 10c2ea4..a7bd8cf 100644
--- a/data/script/Doodad.pl
+++ b/data/script/Doodad.pl
@@ -1,329 +1,346 @@
=comment
Doodad members are:
T int The Doodad's type. 0 means text.
OWNER int The Doodad's owner (0 for player 1, 1 for player 2, other means no owner)
HOSTILE int 1 if the doodad can collision with players and damage them.
LIFETIME int The amount of time before this doodad dies. -1 means infinite.
POS (int,int) The Doodad's logical position.
SIZE (int,int) The Doodad's physical size.
SPEED (int,int) The Doodad's logical speed.
ACCEL (int,int) The Doodad's logical acceleration.
DIR int 1: heading right; -1: heading left (implies flipped state)
-GFXOWNER int The Doodad's graphics owner (0 for player 1, 1 for player 2, other means global)
+GFXOWNER int The Doodad's graphics owner (0 for player 1, 1 for player 2, -1 means global)
FIRSTFRAME int The first frame of the doodad (only meaningful if GFXOWNER is a player).
FRAMES int The number of frames.
SA int Animation speed
F int The Doodad's frame.
TEXT string The text displayed in a text doodad.
+INITCODE sub This will run then the doodad is created.
UPDATECODE sub This will be ran instead of MoveDoodad if defined.
Doodad types are:
0 Text
1 Zoli's shot
2 UPi's shot
3 UPi's explosion
4 UPi's familiar
+5 Tooth
=cut
use strict;
require 'Collision.pl';
package Doodad;
%Doodad::DoodadDefinitions = (
'ZoliShot' => {
'T' => 1, 'HOSTILE' => 1, 'LIFETIME' => -1,
'SIZE' => [ 64, 64 ], 'SPEED' => [ 48, -25 ], 'ACCEL' => [ 0, 2 ],
- 'GFXOWNER' => 2, 'FIRSTFRAME' => 0, 'FRAMES' => 6,
+ 'GFXOWNER' => -1, 'FIRSTFRAME' => 0, 'FRAMES' => 6,
'SA' => 1/10,
},
+'Tooth' => {
+ 'T' => 5, 'HOSTILE' => 0, 'LIFETIME' => -1,
+ 'SIZE' => [ 24, 24 ], 'SPEED' => [ 20, -20 ], 'ACCEL' => [ 0, 2 ],
+ 'GFXOWNER' => -1, 'FIRSTFRAME' => 0, 'FRAMES' => 12,
+ 'SA' => 1/4,
+ 'INITCODE' => sub {
+ my ($self) = @_;
+ $self->{SA} = $self->{SA} * $self->{DIR};
+ },
+ 'UPDATECODE' => sub {
+ my ($self) = @_;
+ if ( $self->{POS}->[1] > (440 * $::GAMEBITS2) ) {
+ $self->{SPEED}->[1] = -abs( $self->{SPEED}->[1] / 2 );
+ $self->{POS}->[1] = 439 * $::GAMEBITS2;
+ }
+ MoveDoodad( $self );
+ },
+},
+
'UPiShot' => {
'T' => 2, 'HOSTILE' => 1, 'LIFETIME' => -1,
'SIZE' => [170, 22], 'SPEED' => [ 48, 0 ], 'ACCEL' => [ 0, 0 ],
'GFXOWNER' => 0, 'FIRSTFRAME' => 340, 'FRAMES' => 5,
'SA' => 1/5,
},
'UPiExplosion' => {
'T' => 3, 'HOSTILE' => 0, 'LIFETIME' => 30,
'SIZE' => [ 58, 80], 'SPEED' => [ 0, 0 ], 'ACCEL' => [ 0, 0 ],
'GFXOWNER' => 0, 'FIRSTFRAME' => 345, 'FRAMES' => 15,
'SA' => 1/2,
},
'UPiFamiliar' => {
- 'T' => 3, 'HOSTILE' => 0, 'LIFETIME' => -1,
+ 'T' => 4, 'HOSTILE' => 0, 'LIFETIME' => -1,
'SIZE' => [ 20, 20], 'SPEED' => [ 0, 0 ], 'ACCEL' => [ 0, 0 ],
'GFXOWNER' => 0, 'FIRSTFRAME' => 360, 'FRAMES' => 3,
'SA' => 1/10,
'ANGLE' => 0,
'UPDATECODE' => sub {
my ($self) = @_;
my ($fighter, $frame, $head, $targetposx, $targetposy);
- $fighter = $self->{OWNER} ? $::Fighter2 : $::Fighter1;
+ $fighter = $::Fighters[$self->{OWNER}];
$frame = $fighter->{FRAMES}->[$fighter->{FR}];
$head = $frame->{head};
$self->{ANGLE} += 0.05 * $self->{DIR};
$targetposx = $fighter->{X} + $head->[0] * $::GAMEBITS2 * $fighter->{DIR} + sin( $self->{ANGLE} ) * 300;
$targetposy = $fighter->{Y} + $head->[1] * $::GAMEBITS2 + cos( $self->{ANGLE} ) * 300;
if ( $fighter->{HP} > 0 )
{
$self->{ACCEL}->[0] = ($targetposx - $self->{POS}->[0] ) / 200;
$self->{ACCEL}->[1] = ($targetposy - $self->{POS}->[1] ) / 200;
$self->{SPEED}->[0] += $self->{ACCEL}->[0];
$self->{SPEED}->[1] += $self->{ACCEL}->[1];
$self->{SPEED}->[0] *= 0.95;
$self->{SPEED}->[1] *= 0.95;
}
#$self->{SPEED}->[0] = ($targetposx - $self->{POS}->[0]) / 30;
#$self->{SPEED}->[1] = ($targetposy - $self->{POS}->[1]) / 30;
$self->{POS}->[0] += $self->{SPEED}->[0];
$self->{POS}->[1] += $self->{SPEED}->[1];
$self->{F} += $self->{SA};
$self->{F} -= $self->{FRAMES} if $self->{F} > ($self->{FRAMES} + $self->{FIRSTFRAME});
return 0;
},
},
);
=comment
CreateDoodad creates a new doodad, and appends it to the global doodad list,
@Doodads. The parameters are:
x int The logical horizontal position of the center of the doodad
y int The logical vertical position of the center of the doodad
t string The type of the doodad (doodad types are described above)
dir int 1 or -1
owner int The number of the player who 'owns' the doodad (0 or 1, anything else means no owner)
=cut
sub CreateDoodad
{
my ($x, $y, $t, $dir, $owner) = @_;
my ($doodad, $doodaddef, $w, $h);
$doodaddef = $Doodad::DoodadDefinitions{$t};
if ( ( not defined $doodaddef ) and $t != 0 )
{
print "CreateDoodad: Doodad $doodaddef doesn't exist!\n";
- return
+ return;
}
if ( defined $doodaddef )
{
$w = $doodaddef->{SIZE}->[0];
$h = $doodaddef->{SIZE}->[1];
$t = $doodaddef->{T};
}
else
{
$w = $h = $t = 0;
$doodaddef = {};
}
$doodad = {
'T' => $t,
'OWNER' => $owner,
'HOSTILE' => 0,
'LIFETIME' => -1,
'POS' => [ $x - $w * $::GAMEBITS2 / 2, $y - $h * $::GAMEBITS2 / 2 ],
'SIZE' => [ $w, $h ],
'SPEED' => [ 0, 0 ],
'ACCEL' => [ 0, 0 ],
'DIR' => $dir,
'GFXOWNER' => $owner,
'FIRSTFRAME'=> 0,
'FRAMES' => 1,
'SA' => 0,
'F' => 0,
'TEXT' => '',
%{$doodaddef},
};
$doodad->{SIZE} = [@{$doodaddef->{SIZE}} ] if defined $doodaddef->{SIZE};
$doodad->{SPEED} = [@{$doodaddef->{SPEED}}] if defined $doodaddef->{SPEED};
$doodad->{ACCEL} = [@{$doodaddef->{ACCEL}}] if defined $doodaddef->{ACCEL};
$doodad->{F} = $doodad->{FIRSTFRAME};
$doodad->{SPEED}->[0] *= $doodad->{DIR};
$doodad->{ACCEL}->[0] *= $doodad->{DIR};
- $doodad->{GFXOWNER} = $owner if $doodad->{GFXOWNER} < 2;
+ $doodad->{GFXOWNER} = $owner if $doodad->{GFXOWNER} >= 0;
+
+ if ( exists $doodad->{INITCODE} )
+ {
+ # Call the updatecode.
+ &{$doodad->{INITCODE}}( $doodad );
+ }
push @::Doodads, ($doodad);
return $doodad;
}
sub CreateTextDoodad
{
my ($x, $y, $owner, $text) = @_;
my ($self);
$self = CreateDoodad($x, $y, 0, 0, $owner);
$self->{'TEXT'} = $text;
- $self->{'GFXOWNER'} = 2;
+ $self->{'GFXOWNER'} = -1;
return $self;
}
sub RewindData
{
my ($self) = @_;
return {
%{$self},
POS => [ @{$self->{POS}} ],
SIZE => [ @{$self->{SIZE}} ],
SPEED => [ @{$self->{SPEED}} ],
ACCEL => [ @{$self->{ACCEL}} ],
}
}
=comment
UpdateDoodad is called once every game tick.
It should return 0 if the doodad is still active.
If UpdateDoodad returns nonzero, it will be removed in this tick and
deleted.
=cut
sub UpdateDoodad
{
my ($doodad) = @_;
if ( exists $doodad->{UPDATECODE} )
{
# Call the updatecode.
return &{$doodad->{UPDATECODE}}( $doodad );
}
else
{
return MoveDoodad( $doodad );
}
}
sub MoveDoodad
{
my ($doodad) = @_;
if ( $doodad->{LIFETIME} >= 0 )
{
$doodad->{LIFETIME} -= 1;
if ( $doodad->{LIFETIME} < 0 )
{
# Doodad dies.
return 1;
}
}
$doodad->{SPEED}->[0] += $doodad->{ACCEL}->[0];
$doodad->{SPEED}->[1] += $doodad->{ACCEL}->[1];
$doodad->{POS} ->[0] += $doodad->{SPEED}->[0];
$doodad->{POS} ->[1] += $doodad->{SPEED}->[1];
$doodad->{F} += $doodad->{SA};
$doodad->{F} -= $doodad->{FRAMES} if $doodad->{F} > ($doodad->{FRAMES} + $doodad->{FIRSTFRAME});
+ $doodad->{F} += $doodad->{FRAMES} if $doodad->{F} < $doodad->{FIRSTFRAME};
if ( $doodad->{POS}->[0] > $::BGWIDTH2 ) { return 1; }
if ( $doodad->{POS}->[0] < $doodad->{SIZE}->[0] * $::GAMEBITS2 ) { return 1; }
if ( $doodad->{POS}->[1] > $::SCRHEIGHT2 ) { return 1; }
if ( $doodad->{POS}->[1] < $doodad->{SIZE}->[1] * $::GAMEBITS2 ) { return 1; }
if ( $doodad->{HOSTILE} )
{
CheckDoodadHit($doodad);
}
# print "Doodad: POS=", join(',', @{$doodad->{POS}}),
# "; SPEED=", join(',', @{$doodad->{SPEED}}),
# "; ACCEL=", join(',', @{$doodad->{ACCEL}}), "\n";
return 0;
}
sub CheckDoodadHit($)
{
my ( $self ) = @_;
- my ( @poly, $x, $y, $w, $h );
+ my ( @poly, $x, $y, $w, $h, $i, $fighter );
$x = $self->{POS}->[0] / $::GAMEBITS2;
$y = $self->{POS}->[1] / $::GAMEBITS2;
$w = $self->{SIZE}->[0];
$h = $self->{SIZE}->[1];
- @poly = (
- $x, $y,
- $x+$w, $y,
- $x+$w, $y+$h,
- $x, $y+$h );
-
- if ( $self->{OWNER} != 0 )
+ for ( $i=0; $i<$::NUMPLAYERS; ++$i )
{
- if ( $::Fighter1->IsHitAt( \@poly ) )
- {
- DoHitPlayer($self, $::Fighter1);
- }
- }
-
- @poly = (
- $x, $y,
- $x+$w, $y,
- $x+$w, $y+$h,
- $x, $y+$h );
+ next if $i == $self->{OWNER};
+ $fighter = $::Fighters[$i];
+
+ @poly = (
+ $x, $y,
+ $x+$w, $y,
+ $x+$w, $y+$h,
+ $x, $y+$h );
- if ( $self->{OWNER} != 1 )
- {
- if ( $::Fighter2->IsHitAt( \@poly ) )
+ if ( $fighter->IsHitAt( \@poly ) )
{
- DoHitPlayer($self, $::Fighter2);
+ DoHitPlayer($self, $fighter);
}
}
-
+
}
sub DoHitPlayer($$)
{
my ($self,$player) = @_;
$self->{HOSTILE} = 0;
- $player->HitEvent( 'Hit', $self->{T} );
+ $player->HitEvent( $::Fighters[$self->{OWNER}], 'Hit', $self->{T} );
}
=cut
return 1;
diff --git a/data/script/Fighter.pl b/data/script/Fighter.pl
index 23e43aa..e680ce4 100644
--- a/data/script/Fighter.pl
+++ b/data/script/Fighter.pl
@@ -1,854 +1,929 @@
require 'Collision.pl';
require 'DataHelper.pl';
require 'Damage.pl';
package Fighter;
use strict;
=comment
Fighter's members are:
ID int The ID of the fighter
STATS hash Reference to the fighter's stats (includes GENDER)
NAME string The name of the character, e.g. "Ulmar".
FRAMES array The character's frame description.
STATES hash The character's state description.
OK bool Is the fighter good to go?
+TEAMSIZE int The number of fighters left in this figther's team, including this one. 0 when the last one dies.
NUMBER int Player number (either 0 or 1)
X int The fighter's current anchor, horizontal coordinate.
Y int The fighter's current anchor, vertical coordinate.
ST string The name of the fighter's current state.
FR int The number of the fighter's current frame (same as STATES->{ST}->{F}).
DEL int The amount of time before the character moves to the next state.
NEXTST string The name of the next state after this one (calculated by Advance and Event, user by Update).
DIR int -1: the character is facing left; 1: if the character is facing right.
PUSHY int The character's vertical momentum, from jumping/hits.
PUSHX int The character's horizontal momentum, from hits.
HP int Hit points, from 100 down to 0.
IDLE int The amount of game time since the player is ready.
CHECKEHIT int 1 if the hit needs to be checked soon.
DELIVERED int 1 if a hit was delivered in this state.
COMBO int The number of consecutive hits delivered to this fighter.
COMBOHP int The amount of HP delivered in the last combo.
-OTHER hash A reference to the other Fighter
+OTHER Fighter A reference to the other Fighter
LANDINGPENALTY int This is added to DEL when the character lands (used to penaltize blocked jumpkicks). Becomes DELPENALTY upon landing.
DELPENALTY int This is added to DEL in the next state.
-
+BOUNDSCHECK bool Should horizontal bounds checking be done for this fighter (for team mode when new fighter enters)
new
Reset
Advance
CheckHit
IsHitAt
Event
Update
Needs to be subclassed: Reset, NextState
=cut
sub new {
my ($class) = @_;
my $self = {
'NUMBER'=> 0,
'ST' => 'Start',
'FR' => 0,
'DEL' => 0,
'DIR' => 1,
'PUSHY' => 0,
'PUSHX' => 0,
};
bless $self, $class;
return $self;
}
sub RewindData {
my ($self) = @_;
return $self;
}
sub Reset {
my ($self, $fighterenum) = @_;
- die "Insufficient parameters." unless defined $self;# and defined $frames and defined $states;
+ die "Insufficient parameters." unless defined $self;
$fighterenum = $self->{ID} unless defined $fighterenum;
my ($number, $stats);
$number = $self->{NUMBER};
$stats = ::GetFighterStats($fighterenum);
die "Couldn't load stats of fighter $fighterenum\n" unless defined $stats;
unless (defined $stats->{STATES})
{
print "ERROR: The fighter $fighterenum is not yet usable.\n";
$self->{OK} = 0;
return;
}
print STDERR "Resetting fighter $number to character $fighterenum\n";
$self->{ID} = $fighterenum;
$self->{STATS} = $stats;
$self->{NAME} = $stats->{NAME};
$self->{FRAMES} = $stats->{FRAMES};
$self->{STATES} = $stats->{STATES};
$self->{X} = (( $number ? 540 : 100 ) << $::GAMEBITS) + $::BgPosition;
+ $self->{X} = (( $number ? 620 : 180 ) << $::GAMEBITS) + $::BgPosition if $::WIDE;
$self->{Y} = $::GROUND2;
$self->{ST} = 'Start';
$self->{FR} = $self->GetCurrentState()->{F};
$self->{DEL} = 0;
$self->{DIR} = ($number ? -1 : 1);
$self->{PUSHY} = 0;
$self->{PUSHX} = 0;
$self->{HP} = 100;
$self->{IDLE} = 0;
$self->{CHECKHIT} = 0;
$self->{DELIVERED} = 0;
$self->{COMBO} = 0;
$self->{COMBOHP}= 0;
$self->{LANDINGPENALTY} = 0;
$self->{DELPENALTY} = 0;
+ $self->{BOUNDSCHECK} = 1;
$self->{OK} = 1;
&{$self->{STATS}->{STARTCODE}}($self);
}
=comment
Returns a "random" number that is deterministic in the sense that it is
always the same, given the current state of the character and the current
game time.
=cut
sub QuasiRandom($$)
{
my ( $self, $randmax ) = @_;
$randmax = 1 unless $randmax;
return int( $self->{HP} * 543857
+ $self->{NUMBER} * 834973
+ $self->{DEL} * 4358397
+ $self->{IDLE} * 92385029
+ $::gametick * 23095839
+ 5304981 ) % $randmax;
}
=comment
Advance should be called once every game tick. It advances the fighter,
preparing his variables for drawing him in the next tick. Advance also
processes the input if it is appropriate to do so in the current state.
Advance prepares the NEXTST attribute of the player. It does not modify
the current ST yet, because that may depend on hits, event, etc. Advance
should be followed by CheckHit and Event calls, and finally Update.
=cut
sub Advance {
my ($self, $in) = @_;
# print STDERR "$::gametick\t$self->{X},$self->{HP}\t$self->{NUMBER}\t$self->{DEL}\t$self->{IDLE}\n";
my ($stname, # The name of the current state.
$st, # The descriptor of the current state.
$move, # The move associated with the current state.
$i, $j, # temp var.
@body ); # collision detection
$self->{NEXTST} = '';
$stname = $self->{ST};
+
+ return if ( $stname eq 'Dead' );
$st = $self->{'STATES'}->{$stname};
# 1. DECREMENT 'DEL' PROPERTY
$self->{'DEL'}--;
if ( $st->{SITU} eq 'Ready' )
{
$self->{IDLE} = $self->{IDLE} + 1;
}
else
{
$self->{IDLE} = 0;
}
# 2. UPDATE THE HORIZONTAL POSITION
# 2.1. 'MOVE' PLAYER IF NECESSARY
if ( defined $st->{'MOVE'} )
- {
+ {
$move = $st->{'MOVE'}*$self->{'DIR'} * 6;
$self->{'X'} += $move;
}
# 2.2. 'PUSH' PLAYER IF NECESSARY
if ( $self->{PUSHX} )
{
$i = ($self->{PUSHX}+7) / 8; # 1/1; syntax highlight..
$self->{X} += $i;
$self->{PUSHX} -= $i if $self->{PUSHY} == 0;
}
# 2.3. MAKE SURE THE TWO FIGHTERS DON'T "WALK" INTO EACH OTHER
- if ( $self->{Y} >= $::GROUND2 and
- $self->{OTHER}->{Y} >= $::GROUND2 )
+ if ( $::BgScrollEnabled and $self->{Y} >= $::GROUND2 )
{
- my ( $centerX, $centerOtherX, $pushDir );
+ my ( $other, $centerX, $centerOtherX, $pushDir );
$centerX = $self->GetCenterX;
- $centerOtherX = $self->{OTHER}->GetCenterX;
-
- if ( abs($centerX - $centerOtherX) < 60 )
+ for ($i=0; $i<$::NUMPLAYERS; ++$i)
{
- $pushDir = ($centerX > $centerOtherX) ? 1 : -1;
- $self->{X} += 10 * $pushDir;
- $self->{OTHER}->{X} -= 10 * $pushDir;
+ $other = $::Fighters[$i];
+ $centerOtherX = $other->GetCenterX;
+
+ if ( abs($centerX - $centerOtherX) < 60 )
+ {
+ $pushDir = ($centerX > $centerOtherX) ? 1 : -1;
+ $self->{X} += 10 * $pushDir;
+ $other->{X} -= 10 * $pushDir;
+ }
}
}
# 2.4. HORIZONTAL BOUNDS CHECKING
- $self->{X} = $::BgPosition + $::MOVEMARGIN2
- if $self->{X} < $::BgPosition + $::MOVEMARGIN2;
- $self->{X} = $::BgPosition + $::SCRWIDTH2 - $::MOVEMARGIN2
- if $self->{X} > $::BgPosition + $::SCRWIDTH2 - $::MOVEMARGIN2;
+ if ( $self->{BOUNDSCHECK} )
+ {
+ $self->{X} = $::BgPosition + $::MOVEMARGIN2
+ if $self->{X} < $::BgPosition + $::MOVEMARGIN2;
+ $self->{X} = $::BgPosition + $::SCRWIDTH2 - $::MOVEMARGIN2
+ if $self->{X} > $::BgPosition + $::SCRWIDTH2 - $::MOVEMARGIN2;
+ }
# 3. FLYING OR FALLING
if ( $self->{Y} < $::GROUND2 )
{
$self->{PUSHY} += 3;
$self->{Y} += $self->{PUSHY};
if ($self->{Y} >= $::GROUND2)
{
# LANDING
$self->{DELPENALTY} = $self->{LANDINGPENALTY};
$self->{LANDINGPENALTY} = 0;
+ $self->{BOUNDSCHECK} = 1;
if ( $st->{SITU} eq 'Falling')
{
::AddEarthquake( $self->{PUSHY} / 20 ); # 1/1
push @::Sounds, ('splat.wav') if $self->{PUSHY} > 40;
# print "PUSHY = ", $self->{PUSHY}, "; ";
if ( $self->{PUSHY} > 30 )
{
# Bouncing after a fall
$self->{PUSHY} = - $self->{PUSHY} / 2; # 1/1
$self->{Y} = $::GROUND2 - 1;
}
else
{
# Getting up after a fall.
$self->{PUSHY} = 0;
$self->{Y} = $::GROUND2;
$self->{DEL} = 0;
- $self->{NEXTST} = 'Getup';
- $self->{NEXTST} = 'Dead' if $self->{HP} <= 0;
+ if ( $self->{HP} <= 0 ) {
+ $self->{NEXTST} = 'Dead';
+ }
+ else {
+ $self->{NEXTST} = 'Getup';
+ }
}
return;
}
else
{
push @::Sounds, ('thump.wav');
$self->{PUSHY} = 0;
$self->{Y} = $::GROUND2;
if ( substr($self->{ST},0,4) eq 'Jump' )
{
# Landing after a jump
$self->{DEL} = 0;
$self->{NEXTST} = 'Stand';
}
else
{
print "Landed; state: ", $self->{ST}, "\n";
}
return;
}
}
}
return if $self->{'DEL'} > 0;
# 4. DELAYING OVER. MAKE END-OF-STATE CHANGES.
# 4.1. 'DELTAX' displacement if so specified
if ($st->{DELTAX})
{
$self->{X} += $st->{DELTAX} * $self->{DIR} * $::GAMEBITS2;
}
# 4.2. 'TURN' if so specified
if ($st->{TURN})
{
$self->{DIR} = - $self->{DIR};
# Swap input keys..
$i = $in->{Keys}->[2];
$in->{Keys}->[2] = $in->{Keys}->[3];
$in->{Keys}->[3] = $i;
}
# 5. CALCULATE THE NEXT STATE
my ($nextst, $con, $input, $mod, $action, $dist);
-
+
$nextst = $st->{NEXTST};
$con = $st->{CON};
- $dist = ($self->{OTHER}->{X} - $self->{X}) * $self->{DIR};
undef $con if $::ko;
if ( defined $con )
{
+ $dist = ($self->{OTHER}->{X} - $self->{X}) * $self->{DIR};
$self->ComboEnds();
# 5.1. The current state has connections!
($input,$mod) = $in->GetAction();
$mod = '' unless defined $mod;
$action = $input;
# Try to find the best matching connection.
for ( $i = length($mod); $i>=0; --$i )
{
$action = $input . substr( $mod, 0, $i );
last if defined $con->{$action};
}
if ( defined $con->{$action} )
{
# print "dist = $dist. ";
if ( ($action eq 'hpunch' or $action eq 'lpunch') and ($dist>=0) and ($dist<800) )
{
$action = 'hpunchF' if defined $con->{'hpunchF'};
}
elsif ( ($action eq 'hkick' or $action eq 'lkick') and ($dist>=0) and ($dist<900) )
{
$action = 'lkickF' if defined $con->{'lkickF'};
}
$nextst = $con->{$action};
$in->ActionAccepted;
+ if ( $nextst eq 'Back' and $::NUMPLAYERS != 2 ) {
+ $nextst = 'Turn';
+ }
}
}
$self->{'NEXTST'} = $nextst;
}
+=comment
+Checks for hits on all other fighters.
+Returns a list of ($self,$fighter,$hit) triplets.
+=cut
-sub CheckHit
+sub CheckHit($)
{
my ($self) = @_;
- return 0 unless $self->{CHECKHIT};
+ return () unless $self->{CHECKHIT};
$self->{CHECKHIT} = 0;
my ($st, # A reference to the next state.
$nextst, # The name of the next state.
@hit, # The hit array
- $i,
+ @hit2,
+ $i, $j,
+ @retval,
+ $other,
);
$st = $self->{STATES}->{$self->{ST}};
- return 0 unless $st->{HIT};
- return 0 unless defined $self->{FRAMES}->[$st->{F}]->{hit};
+ return @retval unless $st->{HIT};
+ return @retval unless defined $self->{FRAMES}->[$st->{F}]->{hit};
@hit = @{$self->{FRAMES}->[$st->{F}]->{hit}};
if ( $self->{DIR}<0 )
{
::MirrorPolygon( \@hit );
}
::OffsetPolygon( \@hit,
$self->{X} / $::GAMEBITS2,
$self->{Y} / $::GAMEBITS2 );
-
- $i = $self->{OTHER}->IsHitAt( \@hit );
- $self->{DELIVERED} = 1 if $i;
- print "Collision = $i; ";
- if ( $i == 0 )
+ for ( $j=0; $j<$::NUMPLAYERS; ++$j )
+ {
+ $other = $::Fighters[$j];
+ next if $other == $self;
+ @hit2 = @hit;
+ $i = $other->IsHitAt( \@hit2 );
+ if ( $i ) {
+ $self->{DELIVERED} = 1;
+ push @retval, ([$self, $other, $i]);
+ }
+ }
+
+ if ( scalar(@retval) == 0 )
{
# Make the 'Woosh' sound - maybe.
$nextst = $st->{NEXTST};
print "NEXTST = $nextst";
$nextst = $self->{STATES}->{$nextst};
print "NEXTST->HIT = ", $nextst->{HIT}, "\n";
push @::Sounds, ('woosh.wav') unless $nextst->{HIT} and defined $self->{FRAMES}->[$nextst->{F}]->{hit};
}
- return $i;
+ return @retval;
}
sub IsHitAt
{
my ($self, $poly) = @_;
my ($frame, @a);
$frame = $self->{FRAMES}->[$self->{FR}];
::OffsetPolygon( $poly, -$self->{X} / $::GAMEBITS2, -$self->{Y} / $::GAMEBITS2 );
if ( $self->{DIR}<0 )
{
::MirrorPolygon( $poly );
}
#print "IsHitAt (", join(',',@{$poly}),")\n (",
# join(',',@{$frame->{head}}),")\n (",
# join(',',@{$frame->{body}}),")\n (",
# join(',',@{$frame->{legs}}),")\n";
return 1 if ::Collisions( $poly, $frame->{head} );
return 2 if ::Collisions( $poly, $frame->{body} );
return 3 if ::Collisions( $poly, $frame->{legs} );
return 0;
}
=comment
Event($self, $event, $eventpar): Handles the following events:
'Won', 'Hurt', 'Thread', 'Fun', 'Turn'
=cut
sub Event($$$)
{
my ($self, $event, $eventpar) = @_;
my ($st);
$st = $self->GetCurrentState();
if ( ($st->{SITU} eq 'Ready' or $st->{SITU} eq 'Stand') and $event eq 'Won' )
{
$self->{NEXTST} = 'Won' unless substr($self->{ST}, 0, 3) eq 'Won' ;
return;
}
if ( $st->{SITU} eq 'Ready' and $self->{NEXTST} eq '' )
{
$self->{IDLE} = 0;
if ( $event =~ /Hurt|Threat|Fun|Turn/ )
{
if ( $event eq 'Fun' and defined $self->{STATES}->{'Funb'} and $self->QuasiRandom(2)==1 )
{
$event = 'Funb';
}
$self->{NEXTST} = $event;
}
}
}
=comment
Event($self, $event, $eventpar): Handles the following events:
'Highhit', 'Uppercut', 'Hit', 'Groinhit', 'Leghit', 'Fall'
+
+Parameters:
+$other Fighter The fighter who hit me.
+$event string The name of the event (any of the above events)
+$eventpar int/string 1: head hit; 2: body hit; 3: leg hit; Maxcombo: I did a max combo (=fall with 0 damage)
=cut
-sub HitEvent($$$)
+sub HitEvent($$$$)
{
- my ($self, $event, $eventpar) = @_;
+ my ($self, $other, $event, $eventpar) = @_;
my ($st, $blocked, $damage);
$st = $self->GetCurrentState();
# Do events: Highhit, Uppercut, Hit, Groinhit, Leghit, Fall
$eventpar = '' unless defined $eventpar; # Supress useless warning
if ( $eventpar eq 'Maxcombo' ) { $damage = 0; }
- else { $damage = ::GetDamage( $self->{OTHER}->{NAME}, $self->{OTHER}->{ST} ); }
+ else { $damage = ::GetDamage( $other->{NAME}, $other->{ST} ); }
$blocked = $st->{BLOCK};
- $blocked = 0 if ( $self->IsBackTurned() );
+ $blocked = 0 if ( $self->IsBackTurnedTo($other) );
print "Event '$event', '$eventpar'\n";
print "Blocked.\n" if ( $blocked );
# Hit point adjustment here.
$self->{HP} -= $blocked ? $damage >> 3 : $damage;
# Turn if we must.
- $self->{DIR} = ( $self->{X} > $self->{OTHER}->{X} ) ? -1 : 1;
+ $self->{DIR} = ( $self->{X} > $other->{X} ) ? -1 : 1;
# Handle the unfortunate event of the player "dying".
if ( $self->{HP} <= 0 )
{
push @::Sounds, ('bowling.voc');
$self->{NEXTST} = 'Falling';
$self->{PUSHX} = -20 * 3 * $self->{DIR};
$self->{PUSHY} = -80;
$self->{Y} -= 10;
$self->{COMBO} += 1;
$self->{COMBOHP} += $damage;
$self->ComboEnds();
- $::ko = 1;
+ $::ko = 1 if $self->{TEAMSIZE} <= 1 and $::ActiveTeams <= 2;
return;
}
# Handle blocked attacks.
if ( $blocked )
{
push @::Sounds, ('thump.wav');
- $self->HitPush( - $damage * 20 * $self->{DIR} );
- $self->{OTHER}->{DEL} += 20 * $::DELMULTIPLIER;
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
+ $other->{DEL} += 20 * $::DELMULTIPLIER;
- if ( $self->{OTHER}->{Y} < $::GROUND2 )
+ if ( $other->{Y} < $::GROUND2 )
{
- $self->{OTHER}->{PUSHY} = -20 if $self->{OTHER}->{PUSHY} > 0;
- $self->{OTHER}->{PUSHX} *= 0.2;
- $self->{OTHER}->{LANDINGPENALTY} = 30 * $::DELMULTIPLIER;
+ $other->{PUSHY} = -20 if $other->{PUSHY} > 0;
+ $other->{PUSHX} *= 0.2;
+ $other->{LANDINGPENALTY} = 30 * $::DELMULTIPLIER;
}
# $self->{PUSHX} = - $damage * 5 * $self->{DIR};
return;
}
# Handle the rest of the events.
if ( $event eq 'Uppercut' )
{
push @::Sounds, ('evil_laughter.voc');
::AddEarthquake( 20 );
}
- elsif ($event eq 'Groinhit') { push @::Sounds, ('woman_screams.voc'); }
- { push @::Sounds, ('thump3.voc'); }
+ elsif ($event eq 'Groinhit')
+ {
+ push @::Sounds, ('woman_screams.voc');
+ }
+ else
+ {
+ push @::Sounds, ('thump3.voc');
+ }
$self->{COMBO} += 1;
$self->{COMBOHP} += $damage;
$damage *= $self->{COMBO}; # Only for the purpose of pushing
if ( $self->{COMBO} >= $::MAXCOMBO )
{
$self->ComboEnds();
$event = 'Uppercut';
- $self->{OTHER}->HitEvent( 'Fall', 'Maxcombo' );
+ $other->HitEvent( 'Fall', 'Maxcombo' );
}
if ( $st->{SITU} eq 'Crouch' )
{
if ( $event eq 'Uppercut' or $event eq 'Fall' )
{
$self->{NEXTST} = 'Falling';
$self->{PUSHX} = -48 * 3 * $self->{DIR};
$self->{PUSHY} = -100;
$self->{Y} -= 10;
}
else
{
if ($eventpar == 1) {
$self->{NEXTST} = 'KneelingPunched';
} else {
$self->{NEXTST} = 'KneelingKicked';
}
- $self->HitPush( - $damage * 20 * $self->{DIR} );
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
# $self->{PUSHX} = - $damage * 20 * $self->{DIR};
}
return;
}
if ( $st->{SITU} eq 'Falling' )
{
$self->{PUSHY} -= 50;
$self->{PUSHY} = -80 if $self->{PUSHY} > -80;
$self->{Y} -= 10;
return;
}
if ( $self->{Y} < $::GROUND2 )
{
$self->{NEXTST} = 'Falling';
$self->{PUSHY} -= 50;
$self->{PUSHX} = -48 * 3 * $self->{DIR};
return;
}
if ( $event eq 'Highhit' )
{
+ my ( $doodadx, $doodady );
+ ($doodadx, $doodady) = ::GetPolygonCenter( $self->{FRAMES}->[$self->{FR}]->{head} );
+# my ( $doodadx, $doodady ) = @{$self->{FRAMES}->[$self->{FR}]->{head}};
+ Doodad::CreateDoodad( $self->{X} + $doodadx * $::GAMEBITS2 * $self->{DIR},
+ $self->{Y} + $doodady * $::GAMEBITS2,
+ 'Tooth',
+ - $self->{DIR},
+ $self->{NUMBER} );
+
$self->{NEXTST} = 'HighPunched';
- $self->HitPush( - $damage * 20 * $self->{DIR} );
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
# $self->{PUSHX} = - $damage * 20 * $self->{DIR};
}
elsif ( $event eq 'Hit' )
{
if ($eventpar == 1) {
$self->{NEXTST} = 'HighPunched';
} elsif ($eventpar == 2) {
$self->{NEXTST} = 'LowPunched';
} else {
$self->{NEXTST} = 'Swept';
}
- $self->HitPush( - $damage * 20 * $self->{DIR} );
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
# $self->{PUSHX} = - $damage * 20 * $self->{DIR};
}
elsif ( $event eq 'Groinhit' )
{
$self->{NEXTST} = 'GroinKicked';
- $self->HitPush( - $damage * 20 * $self->{DIR} );
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
# $self->{PUSHX} = - $damage * 20 * $self->{DIR};
}
elsif ( $event eq 'Leghit' )
{
$self->{NEXTST} = 'Swept';
- $self->HitPush( - $damage * 20 * $self->{DIR} );
+ $self->HitPush( $other, - $damage * 20 * $self->{DIR} );
# $self->{PUSHX} = - $damage * 20 * $self->{DIR};
}
elsif ( $event eq 'Uppercut' or $event eq 'Fall' )
{
$self->{NEXTST} = 'Falling';
$self->{PUSHX} = -48 * 3 * $self->{DIR};
$self->{PUSHY} = -100;
$self->{Y} -= 10;
}
else
{
die "Unknown event: $event, $eventpar";
}
}
sub GetCurrentState
{
my ($self, $statename) = @_;
my ($stateref);
die unless defined $self;
$statename = $self->{ST} unless defined $statename;
$stateref = $self->{STATES}->{$statename};
return $stateref;
}
sub ComboEnds
{
my ($self) = @_;
my ($combo, $ismaxcombo);
$combo = $self->{COMBO};
$ismaxcombo = $combo >= $::MAXCOMBO;
return unless $combo;
if ( $self->{COMBO} > 1 )
{
my ( $head, $doodad, $x, $y, $combotext );
$combotext = $ismaxcombo ? ::Translate("MAX COMBO!!!") : sprintf( ::Translate('%d-hit combo!'), $self->{COMBO} );
$head = $self->{FRAMES}->[$self->{FR}]->{head};
$x = $self->{X} + $head->[0] * $::GAMEBITS2 * $self->{DIR};
$y = $self->{Y} + $head->[1] * $::GAMEBITS2;
$doodad = Doodad::CreateTextDoodad( $x, $y - 30 * $::GAMEBITS2,
$self->{NUMBER},
$combotext );
$doodad->{LIFETIME} = $ismaxcombo ? 120 : 80;
$doodad->{SPEED} = [-3,-3];
$doodad = Doodad::CreateTextDoodad( $x, $y - 10 * $::GAMEBITS2,
$self->{NUMBER},
sprintf( ::Translate('%d%% damage'), int($self->{COMBOHP}*$::HitPointScale/10) ) );
$doodad->{LIFETIME} = 80;
$doodad->{SPEED} = [+3,-3];
print $self->{COMBO}, "-hit combo for ", $self->{COMBOHP}, " damage.\n";
push @::Sounds, ( $ismaxcombo ? 'crashhh.voc' : 'ba_gooock.voc');
}
$self->{COMBO} = 0;
$self->{COMBOHP} = 0;
}
=comment
Update moves the fighter to his next state, if there is a NEXTST set.
NEXTST should be calculated before calling this method. No further
branching or CON checking is done.
If the next state has JUMP, the character is set aflying.
=cut
sub Update
{
my ($self) = @_;
my ($nextst, # The name of the next state
$st); # The descriptor of the next state.
# Is there a next state defined?
$nextst = $self->{'NEXTST'};
# If there isn't, no updating is necessary.
return unless $nextst;
-
+
+ # ADMINISTER END OF THE STATE MACHINE (WON2 OR DEAD2)
+
+ if ( $nextst eq 'Won2' or $nextst eq 'Dead' ) {
+ $self->{DELPENALTY} = 1000000; # Something awfully large
+ $self->{HP} = -10000 if $nextst eq 'Dead';
+ --$::ActiveFighters;
+ --$::ActiveTeams if $self->{TEAMSIZE}<=1 or $nextst eq 'Won2';
+ }
+
# ADMINISTER THE MOVING TO THE NEXT STATE
$st = $self->GetCurrentState( $nextst );
$self->{'ST'} = $nextst;
$self->{'FR'} = $st->{'F'};
die "ERROR IN STATE $nextst" unless defined $st->{DEL};
$self->{'DEL'} = $st->{'DEL'} * $::DELMULTIPLIER;
$self-> {'DEL'} += $self->{'DELPENALTY'};
$self->{'DELPENALTY'} = 0;
# HANDLE THE JUMP and PUSH ATTRIBUTE
if ( defined ($st->{'JUMP'}) )
{
$self->{'PUSHY'} = -($st->{'JUMP'});
$self->{'Y'} += $self->{'PUSHY'};
}
if ( defined ($st->{'PUSHX'}) )
{
$self->{'PUSHX'} += $st->{'PUSHX'} * $self->{DIR};
}
# HANDLE THE HIT ATTRIBUTE
if ( defined ($st->{HIT}) )
{
$self->{CHECKHIT} = 1 unless $self->{DELIVERED};
}
else
{
$self->{DELIVERED} = 0;
}
# HANDLE THE SOUND ATTRIBUTE
if ( defined $st->{SOUND} )
{
push @::Sounds, ($st->{SOUND});
}
# HANDLE THE CODE ATTRIBUTE
if ( defined ($st->{CODE}) )
{
eval ($st->{CODE}); print $@ if $@;
}
# HANDLE DOODADS
if ( defined ($st->{DOODAD}) )
{
# Create a doodad (probably a shot)
my ($frame, $hit, $doodad, $doodadname);
$frame = $self->{FRAMES}->[$self->{FR}];
$hit = $frame->{hit};
if ( defined $hit )
{
$doodadname = $st->{DOODAD};
$doodad = Doodad::CreateDoodad(
$self->{X} + $hit->[0] * $::GAMEBITS2 * $self->{DIR},
$self->{Y} + $hit->[1] * $::GAMEBITS2,
$doodadname,
$self->{DIR},
$self->{NUMBER} );
}
}
}
=comment
Pushes the fighter back due to being hit. If the fighter is cornered,
the other fighter will be pushed back instead.
=cut
-sub HitPush
+sub HitPush($$$)
{
- my ($self, $pushforce) = @_;
+ my ($self, $other, $pushforce) = @_;
if ( $self->IsCornered )
{
- $self->{OTHER}->{PUSHX} -= $pushforce;
+ $other->{PUSHX} -= $pushforce;
}
else
{
$self->{PUSHX} += $pushforce;
}
}
=comment
Returns the characters 'centerline' in physical coordinates.
=cut
sub GetCenterX
{
my ($self) = @_;
my ($body, $x);
$body = $self->{FRAMES}->[$self->{FR}]->{body};
$x = $body->[0] + $body->[2] + $body->[4] + $body->[6];
return $self->{X} / $::GAMEBITS2 + $x / 4 * $self->{DIR};
}
=comment
Is my back turned to my opponent? Returns true if it is.
=cut
sub IsBackTurned
{
my ($self) = @_;
return ( ($self->{X} - $self->{OTHER}->{X}) * ($self->{DIR}) > 0 );
}
+=comment
+Is my back turned to my opponent? Returns true if it is.
+=cut
+
+sub IsBackTurnedTo($)
+{
+ my ($self, $other) = @_;
+
+ return ( ($self->{X} - $other->{X}) * ($self->{DIR}) > 0 );
+}
+
+
=comment
Returns true if the character is at either end of the arena.
=cut
sub IsCornered
{
my ($self) = @_;
return (($self->{X} <= $::MOVEMARGIN2 + 16)
or ($self->{X} >= $::BGWIDTH2 - $::MOVEMARGIN2 - 16));
}
return 1;
diff --git a/data/script/FighterStats.pl b/data/script/FighterStats.pl
index 5ccafaa..83c52c6 100644
--- a/data/script/FighterStats.pl
+++ b/data/script/FighterStats.pl
@@ -1,672 +1,746 @@
use strict;
use bytes;
=comment
FIGHTER STATS ARE:
ID int All fighters have an integer ID...
NAME string Name of the fighter displayed to the user
GENDER int 1=male 2=female
VERSION int Version of the fighter's code
DATAVERSION int Version of the data file
DATAFILE string Filename of the .DAT file.
STARTCODE sub Executed when Reset() is called on the fighter
TEAM string
STYLE string
AGE string
WEIGHT string
HEIGHT string
SHOE string
STORY string
=cut
=comment
We store both official and 3rd-party characters in the %FighterStats hash.
Official characters have ID's between 1 and 99, contributed characters have
ID's >= 100.
No file should access the %FighterStats hash directly, instead,
RegisterFighter must be used to add fighters and
GetFighterStats must be used to retrieve information.
=cut
%::FighterStats = (
'1'=>
{ 'ID' => 1,
'CODENAME' => 'Ulmar',
'NAME' =>'Watasiwa baka janajo',
'TEAM' =>'Evil',
'STYLE' =>'Clown-fu',
'AGE' =>'15',
'WEIGHT'=>'50kg',
'HEIGHT'=>'168cm',
'SHOE' =>'51',
'STORY' =>
'After Wastasiwa baka janajo took possession of his time\'s most advanced
technogadget (read: by accident he was punched so hard that he flew fight into
a high-tech lab, and got tangled with the WrISt(tm)),
he used all his knowledge to travel to the past (read: he started mashing the buttons, and
this is how it ended).
Then he knew immediately that he had to destroy
Saturday! (Read: He has absolutely no idea where he is, or what he is doing...)',
'KEYS' =>
'Back HPunch - Spinning headbutt
Down Back LPunch - WrISt shot
Forward Back Forward LPunch - WrISt mash',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Bohóc-fu',
'WEIGHT-hu' =>'50kg + vaságy',
'HEIGHT-hu' =>'168cm',
'SHOE-hu' =>'51',
'STORY-hu' =>
'Miután Wasaiwa baka janaijo elszajrézta a kora legfejletebb tudományos cuccosát
(véletlenül úgy behúztak neki, hogy berepült a laboratoriumba és rátekeredett a CsUKlo(tm)),
azután minden tudását latba vetve vissza utazott a múltba (elkezdte nyomkodni a gombokat a
CsUKlo(tm)-en és ez lett belõle).
Ezekután már rögtön tudta, hogy itt el kell pusztitania a Szombatot! (õ sem tudja, hogy hol
is van éppen illetve mit is csinál...)',
},
'2'=>
{ 'ID' => 2,
'CODENAME' => 'UPi',
'NAME' =>'Dark Black Evil Mage',
'TEAM' =>'Evil leader',
'STYLE' =>'Piro-fu',
'AGE' =>'30',
'WEIGHT'=>'70kg',
'HEIGHT'=>'180cm',
'SHOE' =>'42',
'STORY' =>
'Member of the Evil Killer Black Antipathic Dim (witted) Fire Mages Leage.
He was sent to destroy Saturday now and forever! Or maybe he has a secret
agenda that noone knows about..? Nah...',
'KEYS' =>
'Back HKick - Spinkick
Forward Forward HKick - Crane kick
Down Back LPunch - Fireball
(also works while crouching)
Back Up HPunch - Burning Hands',
'NAME-hu' =>'Sötét Fekete Gonosz Mágus',
'TEAM-hu' =>'Gonosz vezér',
'STYLE-hu' =>'Piro-fu',
'AGE-hu' =>'30',
'WEIGHT-hu' =>'70kg',
'HEIGHT-hu' =>'180cm',
'SHOE-hu' =>'42',
'STORY-hu' =>
'A Gonosz Gyilkos Fekete Ellenszenves Sötét (elméjü) tüzvarázslók ligájának
tagja, kit azzal bíztak meg, hogy elpusztítsa a szombatot egyszer, s
mindörökre. Talán van valami hátsó szándéka, amirõl senki sem tud? Nincs!',
},
'3'=>
{ 'ID' => 3,
'CODENAME' => 'Zoli',
'NAME' =>'Boxer',
'TEAM' =>'Evil',
'STYLE' =>'Kickbox-fu',
'AGE' =>'16',
'WEIGHT'=>'80kg',
'HEIGHT'=>'180cm',
'SHOE' =>'43',
'STORY' =>
'Boxer joined the Mortal Szombat team for the sole purpose to punch as
many people as hard as he possibly can. He has no other purpose
whatsoever, but at least this keeps him entertained for the time being.',
'KEYS' =>
'Back HPunch - Spinning punch
Down Back LPunch - Weight toss
Forward Forward HPunch - Leaping punch',
'NAME-hu' =>'Boxer',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Kickbox-fu',
'AGE-hu' =>'16',
'WEIGHT-hu' =>'80kg',
'HEIGHT-hu' =>'180cm',
'SHOE-hu' =>'43',
'STORY-hu' =>
'Boxer azért csatlakozott a Mortál Szombat csapathoz, hogy minél több
embernek besomhasson, minél többször, és minél nagyobbat. Más célja ezen
kívül nincs, de ez is remekül elszórakoztatja középtávon',
},
'4'=>
{ 'ID' => 4,
'CODENAME' => 'Cumi',
'NAME' =>'Cumi',
'TEAM' =>'Good Leader',
'STYLE' =>'N/A',
'AGE' =>'15',
'WEIGHT'=>'55kg',
'HEIGHT'=>'170cm',
'SHOE' =>'41.5',
'STORY' =>
'His life ambition was to drive a car. Now that this was accomplished,
he has turned to his second greatest ambition: to be a great martial
artist superhero. As a start, he has watched the TV series "Kung fu"
from beginning to end, in one session. His current training consists
of but this.',
'KEYS' =>
'Down Back LPunch - Finger Shot
Forward Forward HPunch - Spit
Back Down Forward - Baseball',
'NAME-hu' =>'Cumi',
'TEAM-hu' =>'Jo vezer',
'STYLE-hu' =>'N/A',
'AGE-hu' =>'15',
'WEIGHT-hu'=>'55',
'HEIGHT-hu'=>'170',
'SHOE-hu' =>'41.5',
'STORY-hu' =>
'Elete fo ambicioja volt, hogy autot vezessen. Most hogy ezt teljesitette, masodik fo
amibicioja fele fordult: hogy nagy harcmuvessze valjon. Kezdetben ehhez megnezte
a Kung fu sorozatot elejetol vegeig egyulteben. Kepzettsege jelenleg ebbol all.',
},
'5'=>
{ 'ID' => 5,
'CODENAME' => 'Sirpi',
'NAME' =>'Sirpi',
'TEAM' =>'Good',
'STYLE' =>'Don\'tHurtMe-FU',
'AGE' =>'24',
'WEIGHT'=>'76kg',
'HEIGHT'=>'170cm',
'SHOE' =>'41',
'STORY' =>
'After being a "hardcore" gamer for several years and consuming a
great amount of food, his electricity was turned off. This has caused
him to make a very stupid face which lasts till this day, and will
last until he has defeated his archenemy. This is why he resolved to
join the good team... also he is frightened alone.',
'KEYS' =>
'Down Forward LPunch - Surprise
Forward Forward HPunch - Applause',
'STYLE-hu' => 'Nebánts-FU',
'STORY-hu' =>
'Sok évnyi hardcore gamerkedés után, miközben el is hízott jól,
kikapcsolták nála a villanyt.
Erre nagyon hülye pofát vágott, és ez igy is
marad mindaddig, amíg le nem számol õsellenségével (vagy még utána is).
Ezért csatlakozott a jók kicsiny csapatához... Meg amúgy is fél egyedül.',
},
'6'=>
{ 'ID' => 6,
'CODENAME' => 'Macy',
'NAME' =>'Macy',
'TEAM' =>'Good',
'STYLE' =>'Macy-fu',
'AGE' =>'17',
'WEIGHT'=>'41kg',
'HEIGHT'=>'175cm',
'SHOE' =>'37',
'STORY' =>
'A few years ago (perhaps a little earlier, or maybe later) she was
found among the clouds in a cradle (falling, of course). She learned
martial art from brave Son Goku, so she landed on her feet and didn\'t
die. She\'s been immortal ever since. Who knows for how long? Maybe
it won\'t be until the next fight agains Evil...',
'KEYS' =>
'Down Back LPunch - Toss
Forward Forward HKick - Scissor Kick',
'STORY-hu' =>
'kb. néhány évvel ezelõtt, (vagy talán egy kicsit korábban, esetleg
késõbb) a felhõk között egy pólyában találtak rá (zuhanás közben).
A bátor
Songokutól elleste a harcmûvészet mesteri fortélyait, igy talpra esett és
nem halt meg. Azóta is halhatatlan. Ki tudja, még meddig? Talán a
következõ harcig a gonosz ellen...',
},
'7'=>
{ 'ID' => 7,
'CODENAME' => 'Bence',
'NAME' =>'Jan Ito',
'TEAM' =>'Evil',
'STYLE' =>'Kururin-do',
'AGE' =>'20',
'WEIGHT'=>'85kg',
'HEIGHT'=>'172cm',
'SHOE' =>'39',
'STORY' =>
'The "Japanese giant" is a sworn enemy of Descant... after he left
muddy boot marks all over the freshly mopped porch of the pub, er,
dojo which has belonged to his ancestors for 16 generations. Since
he has turned to the dark side of the janitor. His knowledge of
the "way of the concierge" matches his deep hatred towards army
boots.',
'KEYS' =>
'Down Back LPunch - Soap Throw
Back Fw Back Fw LPunch - Stick Spin
Back Forward HPunc - Pierce',
'NAME-hu' =>'Taka Ito',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Kururin-do',
'AGE-hu' =>'20',
'WEIGHT-hu' =>'85',
'HEIGHT-hu' =>'172',
'SHOE-hu' =>'39',
'STORY-hu' =>
'A japán óriás Descant esküdt ellensége, mióta összejárta az általa frissen felmosott
verandát a 16 generáció óta családja által birtokolt foga-do-ban. Tudását a sötét
oldal szolgálatába állította. Tudását a "gondnok útján" csak mélységes megvetése a
vasaltorrú bakancsok iránt szárnyalja túl.',
},
'8'=>
{ 'ID' => 8,
'CODENAME' => 'Grizli',
'NAME' =>'Grizzly',
'TEAM' =>'Good',
'STYLE' =>'Bear dance',
'AGE' =>'21',
'WEIGHT'=>'Several tons',
'HEIGHT'=>'170cm',
'SHOE' =>'49',
'STORY' =>
'Grizzly has been long famous for his laziness. He has made laziness a
form of art. In the past 5 years he has been to lazy to watch TV. Every
Saturday he trains in his own special fighting style, one not unlike
that of Bud Spencer, whom he holds as his honorary master. Though,
since he found out that Bud WORKS on Saturdays, he has revoked his
title, and keeps it for himself. He has joined the Good team to fight
to protect the Saturday.',
'KEYS' =>
'Down Back LPunch - Bear Shot
Forward Forward HPunch - Poke
Down Down LKick - Earthquake
Back Forward Back HPunch - Nunchaku',
'NAME-hu' =>'Grizli',
'TEAM-hu' =>'Jó',
'STYLE-hu' =>'Gyakás ala Medve',
'AGE-hu' =>'21',
'WEIGHT-hu' =>'50000000',
'HEIGHT-hu' =>'170',
'SHOE-hu' =>'49',
'STORY-hu' =>
'Grili a lustaságáról volt hires mindig. Olyannyira, hogy amilyen szinten
azt csinálja, az már mûvészet. Az utóbbi 5 évben már a TV
nézéshez is lusta lett.
Minden Szobaton tart edzést a Különbenmegintdühbejövünk do
stilusból, amit még kezdõ korában a TV-bõl sajátított el. A stilus
tiszteletbeli nagymestere maga Bád Szpencer, de sajnos miután Bád-ról
kiderült, hogy szombatonként dolgozik, Grizli elvette tõle a cimet, s
azóta magának tartogatja.
Grizli a szombat ellenesek ádáz gyûlölõje, a jó csapat oszlopos tagja.',
},
'9'=>
{ 'ID' => 9,
'CODENAME' => 'Descant',
'NAME' =>'Descant',
'TEAM' =>'Good',
'STYLE' =>'Murderization',
'AGE' =>'58',
'WEIGHT'=>'89kg',
'HEIGHT'=>'180cm',
'SHOE' =>'44',
'STORY' =>
'He was trained in \'Nam in every known weapon and martial art form.
He fought there on the side of the Americans and the Russians...
whoever paid more at the moment. Then he used the money to hybernate
himself until the next great war.. or until the Saturday is in
trouble. He joined the side with the more CASH...',
'KEYS' =>
'Down Back LPunch - Aimed Shot
Back Back LPunch - Hip Shot
Forward Down HPunch - Knife Throw
Forward Forward HPunch - Gun Hit',
'NAME-hu' =>'Descant',
'TEAM-hu' =>'Jó',
'STYLE-hu' =>'+halol',
'AGE-hu' =>'58',
'WEIGHT-hu'=>'89',
'HEIGHT-hu'=>'180',
'SHOE-hu' =>'44',
'STORY-hu' =>
'A Vietnámi háború során képezték ki minden ismert fegyverre és harcm~uvészetre. Már ott
is az Oroszok és az Amerikaik oldalán harcolt, már aki éppen többet fizetett. Ezután a pénzb"ol
hibernáltatta magát és csak háborúk esetén olvasztatja föl magát, vagy most mikor a szombat
bajba kerül most is azon az oldalon van, ahol vastagabb a BUKSZA, most épp a...',
},
'10'=>
{ 'ID' => 10,
'CODENAME' => 'Surba',
'NAME' =>'Rising-san',
'TEAM' =>'Evil',
'STYLE' =>'Flick-fu',
'AGE' =>'500',
'WEIGHT'=>'N/A',
'HEIGHT'=>'50',
'SHOE' =>'N/A',
'STORY' =>
'Mistically disappeared Aeons ago.. on a Saturday! Now he is back, and
brought back his destructive techique, unmatched on Earth. Noone knows
why he joined the Dark Evil Mage...',
'NAME-hu' =>'Rising-san',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Pöcc-fu',
'AGE-hu' =>'500',
'WEIGHT-hu' =>'N/A',
'HEIGHT-hu' =>'50',
'SHOE-hu' =>'Nem visel',
'STORY-hu' =>
'Sok-sok évvel ezel"ott eltûnt misztikus körülmények között... egy szombati napon!
És most visszatért. Senki sem tudja honnan jött, de magával hozta pusztító technikáját
melynek nincs párja a földön. Senki sem érti miért fogadta el a gonosz varázsl
megbízását...',
},
'11'=>
{ 'ID' => 11,
'CODENAME' => 'Ambrus',
'NAME' =>'Mad Sawman',
'TEAM' =>'Evil',
'STYLE' =>'Sawing',
'AGE' =>'35',
'WEIGHT'=>'110',
'HEIGHT'=>'120',
'SHOE' =>'49',
'STORY' =>
'His cradle was found on a tree. Later he chopped up the family that
took him and fed them to the bears. He has been roaming the Canadian
forests, chopping trees and heads alike. On hot summer nights his
maniac laughter echoes far.',
'KEYS' =>
'Down Back LPunch - Axe Toss
Back Forward HKick - Chop Chop
Forward Forward LKick - Bonesaw',
'NAME-hu' =>'Fûrészes Õrült',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Fanyûvõ',
'AGE-hu' =>'35',
'WEIGHT-hu' =>'110',
'HEIGHT-hu' =>'120',
'SHOE-hu' =>'49',
'STORY-hu' =>
'Bölcsõjét egy fán találták meg. Késõbb felaprította az egész befogadó családját, és
megetette a medvékkel. Azóta a kanadai erdõkben bolyongva vágja a fákat és az
emberfejeket. Forró nyári éjszakákon mindig hallatszik õrült kacaja.',
},
'12'=>
{ 'ID' => 12,
'CODENAME' => 'Dani',
'NAME' =>'Imperfect Soldier',
'TEAM' =>'Good',
'STYLE' =>'Pub Fight',
'AGE' =>'50',
'WEIGHT'=>'100',
'HEIGHT'=>'180',
'SHOE' =>'44',
'STORY' =>
'His childhood was determined by Drezda\'s bombing. This trauma has
caused him to join the army. For the last 30 years he is corporal
without the slightest hope for advancement. He annoys his
subordinates with a constant flow of stories of pub fights, until
they ask for relocation.',
'KEYS' =>
'Down Back LPunch - Hat
Forward Forward HPunch - Ramming Attack
Back Down Back LPunch - Stab
Back Forward LKick - Poke',
'NAME-hu' =>'Tökéletlen Katona',
'TEAM-hu' =>'Jó',
'STYLE-hu' =>'Kocsmabunyó',
'AGE-hu' =>'50',
'WEIGHT-hu' =>'100',
'HEIGHT-hu' =>'180',
'SHOE-hu' =>'44',
'STORY-hu' =>
'Gyermekkorát meghatározta Drezda lebombázása. E trauma hatására katonai
pályára állt. Immáron 30 éve a Bundeswehr kötelékében tizedes az
elõléptetés bárminem~u esélye nélkül.
Alantasait folytonosan kocsmai bunyóinak történeteivel traktálja, amíg azok
áthelyezésüket nem kérik.',
},
'13'=>
{ 'ID' => 13,
'CODENAME' => 'Kinga',
'NAME' =>'Aisha',
'TEAM' =>'Good',
'STYLE' =>'Death Dance',
'AGE' =>'21',
'WEIGHT'=>'43.5',
'HEIGHT'=>'155',
'SHOE' =>'35',
'STORY' =>
'Her trials started right in the womb.. her life hung on a single
umbilical cord! But she was finally born, and got the name
Aisha ("survives everything"). Since her childhood she survived
natural disasters and terrorist attacks, and got frankly fed up.
So one time she said:
"If I survive this, I swear, I\'ll join those stupid Mortal guys!"',
'STORY-hu'=>
'A megprobaltatasok akkor kezdodtek, amikor anyukaja a szive alatt hordta.
Egyetlen koldokzsinoron fuggott az elete! De megszuletett vegul, ezert
kapta az Aisha ("mindent tulelo") nevet. Aztan gyermekkoratol fogva sok
termeszeti katasztrofat, terrortamadast atveszelt, es mar kezdett elege
lenni az egeszbol, igy hat az egyik alkalommal kijelentette, hogy ha ezt
tulelem, csatlakozom azokhoz a hulye Mortalosokhoz!',
}, #'
'15'=>
{ 'ID' => 15,
'CODENAME' => 'Elf',
'NAME' => 'Pixie',
'TEAM' => 'Good',
'STYLE' => 'Glamour',
'AGE' => '140',
'WEIGHT'=> '1',
'HEIGHT'=> '1',
'SHOE' => '1',
'STORY' => '...',
},
+'16'=>
+{ 'ID' => 16,
+ 'CODENAME' => 'Judy',
+ 'NAME' => 'Judy',
+ 'TEAM' => 'Evil',
+ 'STYLE' => '?',
+ 'AGE' => '?',
+ 'WEIGHT'=> '?',
+ 'HEIGHT'=> '?',
+ 'SHOE' => '?',
+ 'STORY' => '...',
+},
+
+
+
'14'=>
{ 'ID' => 14,
'CODENAME' => 'Misi',
'NAME' =>'Papatsuka Mamatsuba',
'TEAM' =>'Evil',
'STYLE' =>'Gloom',
'AGE' =>'Feudal Middle',
'WEIGHT'=>'Dead',
'HEIGHT'=>'178 cm',
'SHOE' =>'43,12748252',
'STORY' =>
'Papastuka has been raised strictly in the way of the samurai since age 4.
His father was the most famous warrior of the past 20 years. After he
learned all the jutsu from dad, he skalped him, and put the skalp on his head
to scare his enemies.
On weekdays he is seen chasing women, saturdays he
drinks a lot. Then he decided, that enjoying saturday should belong to him
alone...',
'NAME-hu' =>'Apatsuka Anyatsuba',
'TEAM-hu' =>'Gonosz',
'STYLE-hu' =>'Komor',
'AGE-hu' =>'Feudális közép...',
'WEIGHT-hu' =>'Nagyon súlyos!',
'STORY-hu' =>
'Apatsukát 4 éves kora óta nevelték szülei a szamuráj életmódra, szigor
keretek között. Apja az elmúlt 20 év leghíresebb harcosa volt. Amint
minden harci fogást elsajátított apjától, megskalpolta és a skalpját
fejére illesztette, ezzel megfélemlítve ellenségeit.
Hétközben nõket
hajszolt, szombaton szívott és berugott. Aztán úgy döntött, hogy ezen a
szombaton csak õ érezheti jól magát...',
},
);
sub RegisterFighter($)
{
my ($reginfo) = @_;
# reginfo must contain: ID, GENDER, DATAVERSION, DATASIZE, STARTCODE, FRAMES, STATES, CODENAME
foreach my $attr (qw(ID GENDER DATAVERSION DATASIZE STARTCODE FRAMES STATES CODENAME))
{
die "RegisterFighter: Attribute $attr not found" unless defined $reginfo->{$attr};
}
# CheckStates( $reginfo->{ID}, $reginfo->{STATES} );
my ($fighterenum, $fighterstats);
$fighterenum = $reginfo->{ID};
$fighterstats = $::FighterStats{$fighterenum};
if ( not defined $fighterstats )
{
print "RegisterFighter: Fighter $fighterenum not found, non-syndicated?\n";
$fighterstats = {
'ID' => $fighterenum,
'NAME' =>'Unknown (non-syndicated)',
'TEAM' =>'Unknown',
'STYLE' =>'Unknown',
'AGE' =>'Unknown',
'WEIGHT' =>'Unknown',
'HEIGHT' =>'Unknown',
'SHOE' =>'Unknown',
'STORY' =>'...',
'DATAFILE' => $reginfo->{CODENAME} . '.dat',
%{$reginfo}
};
$::FighterStats{$fighterenum} = $fighterstats;
return;
}
# Add the reginfo to the fighter stats:
%{$fighterstats} = ( 'DATAFILE' => $reginfo->{CODENAME}.'.dat', %{$fighterstats}, %{$reginfo} );
}
sub GetStatsTranslated($$)
{
my ($source, $stat) = @_;
return $source->{"${stat}-$::LanguageCode"} if defined $source->{"${stat}-$::LanguageCode"};
return $source->{$stat};
}
sub GetFighterStats($)
{
my ($fighterenum) = @_;
my ($source) = $::FighterStats{$fighterenum};
$::Codename = $source->{CODENAME};
$::Name = GetStatsTranslated( $source, 'NAME' );
$::Team = GetStatsTranslated( $source, 'TEAM' );
$::Style = GetStatsTranslated( $source, 'STYLE' );
$::Age = GetStatsTranslated( $source, 'AGE' );
$::Weight = GetStatsTranslated( $source, 'WEIGHT' );
$::Height = GetStatsTranslated( $source, 'HEIGHT' );
$::Shoe = GetStatsTranslated( $source, 'SHOE' );
$::Story = GetStatsTranslated( $source, 'STORY' );
$::Keys = GetStatsTranslated( $source, 'KEYS' );
$::Datafile = $source->{'DATAFILE'};
$::Portrait = $::Codename . ".icon.png" if defined $::Codename;
$::Story =~ s/([^\n])\n([^\n])/$1 $2/gms if defined $::Story;
@::StatTags = ( 'Name: ', 'Team: ', 'Style: ', 'Age: ', 'Weight: ', 'Height: ', 'Shoe size: ' );
# print "The data file of $fighterenum is '$::Datafile'\n";
return $source;
}
+sub GetNumberOfAvailableFighters()
+{
+ my ($id, $fighter, $i);
+
+ $i = 0;
+ while ( ($id, $fighter) = each %::FighterStats )
+ {
+ ++$i if defined( $fighter->{DATAFILE} );
+ }
+ $::CppNumberOfAvailableFighters = $i;
+}
-#GetFighterStats(1);
-#print "$::Name $::Team $::Style $::Age $::Weight $::Height $::Shoe\n$::Story\n";
+
+=comment
+
+Returns the number of .pl files in the fighters directory.
+
+param $CharactersDir The name of the characters directory. Might be stored and used later on.
+
+=cut
+
+sub GetNumberOfFighterFiles($)
+{
+ ($::CharactersDir) = shift;
+ # Loads the list of .pl files in the characters directory.
+
+ my (@files, $file );
+
+ opendir CHARDIR, $::CharactersDir;
+ @files = readdir CHARDIR;
+ closedir CHARDIR;
+
+ foreach $file (@files) {
+ push @::CharacterList, $file if ( $file =~ /.pl$/ );
+ }
+
+ return scalar @::CharacterList;
+}
+
+
+=comment
+Loads a fighter file from the characters directory.
+=cut
+
+sub LoadFighterFile($)
+{
+ my ($index) = @_;
+
+ if ($index < 0 or $index >= scalar @::CharacterList) {
+ print "LoadFighterFile: Couldn't load index $index\n";
+ }
+
+ my ($filename, $return);
+ $filename = $::CharactersDir . '/' . $::CharacterList[$index];
+
+ unless ( $return = do $filename ) {
+ print "Couldn't parse $filename: $@\n" if $@;
+ print "Couldn't do $filename: $!\n" unless defined $return;
+ print "Couldn't run $filename\n" unless $return;
+ }
+}
+
return 1;
diff --git a/data/script/PlayerInput.pl b/data/script/PlayerInput.pl
index 35c929d..9f3f39e 100644
--- a/data/script/PlayerInput.pl
+++ b/data/script/PlayerInput.pl
@@ -1,266 +1,272 @@
package PlayerInput;
$KEYTIMEOUT = 80;
sub new {
my ($class, $name) = @_;
my $self = {
'InputQueue' => [],
'InputPointer' => 0,
'Keys' => [0,0,0,0,0,0,0,0,0],
'KeyTimer' => 0,
};
bless ($self, $class);
return $self;
}
sub Reset {
my ($self) = @_;
$self->ClearInput;
$self->{'Keys'} = [0,0,0,0,0,0,0,0,0];
$self->{'KeyTimer'} = 0;
}
sub RewindData {
my ($self) = @_;
my ($rewinddata);
$rewinddata = {
InputQueue => [ @{$self->{InputQueue}} ],
InputPointer => $self->{InputPointer},
Keys => [ @{$self->{Keys}} ],
KeyTimer => $self->{KeyTimer},
};
bless ($rewinddata, PlayerInput);
return $rewinddata;
}
sub ClearInput {
my ($self) = @_;
$self->{'InputQueue'} = [];
$self->{'InputPointer'} = 0;
}
sub Advance {
my ($self) = @_;
my ($ip, $lastkey);
$self->{'KeyTimer'} ++;
$ip = $self->{'InputPointer'};
if ($ip > 0) {
$lastkey = $self->{'InputQueue'}->[$ip-1];
return if ( ($lastkey<5) and ($self->{'Keys'}->[$lastkey]) );
if ( $self->{'KeyTimer'} > $KEYTIMEOUT )
{
$self->{'KeyTimer'} = 0;
$self->ClearInput;
print ".";
}
}
}
sub KeyDown {
my ($self, $key) = @_;
${$self->{'Keys'}}[$key] = 1;
${$self->{'InputQueue'}}[$self->{'InputPointer'}] = $key;
$self->{'InputPointer'} += 1;
$self->{'KeyTimer'} = 0;
}
sub KeyUp {
my ($self, $key) = @_;
${$self->{'Keys'}}[$key] = 0;
}
=comment
GetDefaultAction is used by GetAction. It returns a "default"
action when the last key is no longer pressed. The default
action can be (in order of preference)
* crouching
* blocking
* jumping (fw and bw)
* walking
=cut
sub GetDefaultAction {
my ($self) = @_;
my $k = $self->{'Keys'};
return 'down' if ($k->[1]);
return 'block' if ($k->[4]);
if ( ${$k}[0] ) # Up
{
return 'jumpfw' if ${$k}[3];
return 'jumpbw' if ${$k}[2];
return 'jump';
}
return 'forw' if ($k->[3]);
return 'back' if ($k->[2]);
return '';
}
=comment
GetAction returns two scalars: input and modifier.
Input is any of the following:
lpunch Low punch
hpunch High punch
lkick Low kick
hkick High kick
jump Jump
jumpfw Jump forwards (up+forward)
jumpbw Jump backwards (up+back)
forw Forwards (walk)
back Back (walk)
down Down (crouch)
block Block
'' no action
Modifier applies to action buttons (punch and kick) only. It lists the
non-action buttons pressed before the action button, in reverse order.
The modifiers are U,D,B,F,X for up, down, back, forwards or block.
E.G. if the player presses down, forwards, low punch, the output is:
('lpunch', 'FD').
=cut
sub GetAction {
my ($self) = @_;
my $k = $self->{'Keys'};
my $q = $self->{'InputQueue'};
my $p = $self->{'InputPointer'}-1;
if ($p<0) # No keys pushed
{
return $self->GetDefaultAction();
}
my $lastkey = ${$q}[$p];
unless ( ${$k}[$lastkey] )
{
# Not pushed anymore
return $self->GetDefaultAction();
}
if ($lastkey >=5) # punch or kick
{
my ($act, $mod, $i);
$mod = '';
if ($lastkey==5) { $act = 'lpunch'; }
elsif ($lastkey==6) { $act = 'hpunch'; }
elsif ($lastkey==7) { $act = 'lkick'; }
else { $act = 'hkick'; }
# Add previous keys
for ( $i = $p-1; $i>=0; $i-- )
{
$lastkey = ${$q}[$i]; # Previous key
last if $lastkey>=5; # Only movement keys count
if ($lastkey==0) { $mod .= 'U'; }
elsif ($lastkey==1) { $mod .= 'D'; }
elsif ($lastkey==2) { $mod .= 'B'; }
elsif ($lastkey==3) { $mod .= 'F'; }
elsif ($lastkey==4) { $mod .= 'X'; }
}
print "$act $mod\n";
return ($act,$mod);
}
if ( ${$k}[0] ) # Up
{
return 'jumpfw' if ${$k}[3];
return 'jumpbw' if ${$k}[2];
return 'jump';
}
return 'forw' if $lastkey==3;
return 'back' if $lastkey==2;
return 'down' if $lastkey==1;
return 'block' if $lastkey==4;
}
sub ActionAccepted
{
my ($self) = @_;
my $k = $self->{'Keys'};
my $q = $self->{'InputQueue'};
my $p = $self->{'InputPointer'}-1;
return '' if ($p<0); # No keys pushed
my $lastkey = ${$q}[$p];
return '' unless ${$k}[$lastkey]; # Not pushed anymore
$self->ClearInput if $lastkey>=5;
}
package main;
=comment
The following are interface functions and variables for the C++ code and
Backend.pl
=cut
-$Input1 = new PlayerInput;
-$Input2 = new PlayerInput;
+sub CreatePlayerInputs()
+{
+ my ($i);
+ @::Inputs=();
+ for ( $i=0; $i<$MAXPLAYERS; ++$i )
+ {
+ $::Inputs[$i] = new PlayerInput;
+ }
+}
+
sub KeyDown
{
my ($player, $key) = @_;
#print "KeyDown ($player, $key)\n";
if ( ($key==2) or ($key==3) )
{
# Map left and right to backward and forward based on DIR
my ($dir, $p);
$p = $Fighters[$player];
$dir = ${$p}{'DIR'};
$key = (5 - $key) if ($dir<0);
}
- if ($player==0) { $Input1->KeyDown( $key ); }
- else { $Input2->KeyDown( $key ); }
+ $::Inputs[$player]->KeyDown( $key );
}
sub KeyUp
{
my ($player, $key) = @_;
#print "KeyUp ($player, $key)\n";
if ( ($key==2) or ($key==3) )
{
# Map left and right to backward and forward based on DIR
my ($dir, $p);
$p = $Fighters[$player];
$dir = ${$p}{'DIR'};
$key = (5 - $key) if ($dir<0);
}
- if ($player==0) { $Input1->KeyUp( $key ); }
- else { $Input2->KeyUp( $key ); }
+ $::Inputs[$player]->KeyUp( $key );
}
return 1;

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:25 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70861
Default Alt Text
(139 KB)

Event Timeline