› Foros › Retro y descatalogado › Consolas clásicas
gynion escribió:En esa misma imagen puedes ver un montón de elementos gráficos que se repiten. Vamos, que el juego no guarda el escenario así como lo ves, entero, sino por partes, y un simple texto es el que determina como se combinan y se repiten esas partes; por ejemplo, el suelo y el cielo pueden ser larguísimos con un número de escasas cifras.
Si en el escenario vieras continuamente gráficos diferentes, imposible de que sean el resultado de combinaciones sencillas, entonces ocuparía un mayor tamaño.
Sobre la música... no se mucho, la verdad; pero supongo que tampoco se almacenarán como archivos completos, sino que la NES es el piano, y en el código del juego solo viene en simple texto (o comandos) las teclas que hay que pulsar.
paco_man escribió:Incluso así, ¿cuántas lineas de código tendrá el juego?
gynion escribió:paco_man escribió:Incluso así, ¿cuántas lineas de código tendrá el juego?
Eso no se si sabrá, porque a pesar de que los juegos se puedan hackear, no tienen porque disponer del código fuente para ello, y para saber eso hace falta ver todo ese código. desconozco si en el caso de Super Mario Bros su código fue liberado.
;SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY
;by doppelganger (doppelheathen@gmail.com)
;This file is provided for your own use as-is. It will require the character rom data
;and an iNES file header to get it to work.
;There are so many people I have to thank for this, that taking all the credit for
;myself would be an unforgivable act of arrogance. Without their help this would
;probably not be possible. So I thank all the peeps in the nesdev scene whose insight into
;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no
;way I could have done this without your help), as well as the authors of x816 and SMB
;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project,
;which I compared notes with but did not copy from. Last but certainly not least, I thank
;Nintendo for creating this game and the NES, without which this disassembly would
;only be theory.
;Assembles with x816.
;-------------------------------------------------------------------------------------
;DEFINES
;NES specific hardware defines
PPU_CTRL_REG1 = $2000
PPU_CTRL_REG2 = $2001
PPU_STATUS = $2002
PPU_SPR_ADDR = $2003
PPU_SPR_DATA = $2004
PPU_SCROLL_REG = $2005
PPU_ADDRESS = $2006
PPU_DATA = $2007
SND_REGISTER = $4000
SND_SQUARE1_REG = $4000
SND_SQUARE2_REG = $4004
SND_TRIANGLE_REG = $4008
SND_NOISE_REG = $400c
SND_DELTA_REG = $4010
SND_MASTERCTRL_REG = $4015
SPR_DMA = $4014
JOYPAD_PORT = $4016
JOYPAD_PORT1 = $4016
JOYPAD_PORT2 = $4017
; GAME SPECIFIC DEFINES
ObjectOffset = $08
FrameCounter = $09
SavedJoypadBits = $06fc
SavedJoypad1Bits = $06fc
SavedJoypad2Bits = $06fd
JoypadBitMask = $074a
JoypadOverride = $0758
A_B_Buttons = $0a
PreviousA_B_Buttons = $0d
Up_Down_Buttons = $0b
Left_Right_Buttons = $0c
GameEngineSubroutine = $0e
Mirror_PPU_CTRL_REG1 = $0778
Mirror_PPU_CTRL_REG2 = $0779
OperMode = $0770
OperMode_Task = $0772
ScreenRoutineTask = $073c
GamePauseStatus = $0776
GamePauseTimer = $0777
DemoAction = $0717
DemoActionTimer = $0718
TimerControl = $0747
IntervalTimerControl = $077f
Timers = $0780
SelectTimer = $0780
PlayerAnimTimer = $0781
JumpSwimTimer = $0782
RunningTimer = $0783
BlockBounceTimer = $0784
SideCollisionTimer = $0785
JumpspringTimer = $0786
GameTimerCtrlTimer = $0787
ClimbSideTimer = $0789
EnemyFrameTimer = $078a
FrenzyEnemyTimer = $078f
BowserFireBreathTimer = $0790
StompTimer = $0791
AirBubbleTimer = $0792
ScrollIntervalTimer = $0795
EnemyIntervalTimer = $0796
BrickCoinTimer = $079d
InjuryTimer = $079e
StarInvincibleTimer = $079f
ScreenTimer = $07a0
WorldEndTimer = $07a1
DemoTimer = $07a2
Sprite_Data = $0200
Sprite_Y_Position = $0200
Sprite_Tilenumber = $0201
Sprite_Attributes = $0202
Sprite_X_Position = $0203
ScreenEdge_PageLoc = $071a
ScreenEdge_X_Pos = $071c
ScreenLeft_PageLoc = $071a
ScreenRight_PageLoc = $071b
ScreenLeft_X_Pos = $071c
ScreenRight_X_Pos = $071d
PlayerFacingDir = $33
DestinationPageLoc = $34
VictoryWalkControl = $35
ScrollFractional = $0768
PrimaryMsgCounter = $0719
SecondaryMsgCounter = $0749
HorizontalScroll = $073f
VerticalScroll = $0740
ScrollLock = $0723
ScrollThirtyTwo = $073d
Player_X_Scroll = $06ff
Player_Pos_ForScroll = $0755
ScrollAmount = $0775
AreaData = $e7
AreaDataLow = $e7
AreaDataHigh = $e8
EnemyData = $e9
EnemyDataLow = $e9
EnemyDataHigh = $ea
AreaParserTaskNum = $071f
ColumnSets = $071e
CurrentPageLoc = $0725
CurrentColumnPos = $0726
BackloadingFlag = $0728
BehindAreaParserFlag = $0729
AreaObjectPageLoc = $072a
AreaObjectPageSel = $072b
AreaDataOffset = $072c
AreaObjOffsetBuffer = $072d
AreaObjectLength = $0730
StaircaseControl = $0734
AreaObjectHeight = $0735
MushroomLedgeHalfLen = $0736
EnemyDataOffset = $0739
EnemyObjectPageLoc = $073a
EnemyObjectPageSel = $073b
MetatileBuffer = $06a1
BlockBufferColumnPos = $06a0
CurrentNTAddr_Low = $0721
CurrentNTAddr_High = $0720
AttributeBuffer = $03f9
LoopCommand = $0745
DisplayDigits = $07d7
TopScoreDisplay = $07d7
ScoreAndCoinDisplay = $07dd
PlayerScoreDisplay = $07dd
GameTimerDisplay = $07f8
DigitModifier = $0134
VerticalFlipFlag = $0109
FloateyNum_Control = $0110
ShellChainCounter = $0125
FloateyNum_Timer = $012c
FloateyNum_X_Pos = $0117
FloateyNum_Y_Pos = $011e
FlagpoleFNum_Y_Pos = $010d
FlagpoleFNum_YMFDummy = $010e
FlagpoleScore = $010f
FlagpoleCollisionYPos = $070f
StompChainCounter = $0484
VRAM_Buffer1_Offset = $0300
VRAM_Buffer1 = $0301
VRAM_Buffer2_Offset = $0340
VRAM_Buffer2 = $0341
VRAM_Buffer_AddrCtrl = $0773
Sprite0HitDetectFlag = $0722
DisableScreenFlag = $0774
DisableIntermediate = $0769
ColorRotateOffset = $06d4
TerrainControl = $0727
AreaStyle = $0733
ForegroundScenery = $0741
BackgroundScenery = $0742
CloudTypeOverride = $0743
BackgroundColorCtrl = $0744
AreaType = $074e
AreaAddrsLOffset = $074f
AreaPointer = $0750
PlayerEntranceCtrl = $0710
GameTimerSetting = $0715
AltEntranceControl = $0752
EntrancePage = $0751
NumberOfPlayers = $077a
WarpZoneControl = $06d6
ChangeAreaTimer = $06de
MultiLoopCorrectCntr = $06d9
MultiLoopPassCntr = $06da
FetchNewGameTimerFlag = $0757
GameTimerExpiredFlag = $0759
PrimaryHardMode = $076a
SecondaryHardMode = $06cc
WorldSelectNumber = $076b
WorldSelectEnableFlag = $07fc
ContinueWorld = $07fd
CurrentPlayer = $0753
PlayerSize = $0754
PlayerStatus = $0756
OnscreenPlayerInfo = $075a
NumberofLives = $075a ;used by current player
HalfwayPage = $075b
LevelNumber = $075c ;the actual dash number
Hidden1UpFlag = $075d
CoinTally = $075e
WorldNumber = $075f
AreaNumber = $0760 ;internal number used to find areas
CoinTallyFor1Ups = $0748
OffscreenPlayerInfo = $0761
OffScr_NumberofLives = $0761 ;used by offscreen player
OffScr_HalfwayPage = $0762
OffScr_LevelNumber = $0763
OffScr_Hidden1UpFlag = $0764
OffScr_CoinTally = $0765
OffScr_WorldNumber = $0766
OffScr_AreaNumber = $0767
BalPlatformAlignment = $03a0
Platform_X_Scroll = $03a1
PlatformCollisionFlag = $03a2
YPlatformTopYPos = $0401
YPlatformCenterYPos = $58
BrickCoinTimerFlag = $06bc
StarFlagTaskControl = $0746
PseudoRandomBitReg = $07a7
WarmBootValidation = $07ff
SprShuffleAmtOffset = $06e0
SprShuffleAmt = $06e1
SprDataOffset = $06e4
Player_SprDataOffset = $06e4
Enemy_SprDataOffset = $06e5
Block_SprDataOffset = $06ec
Alt_SprDataOffset = $06ec
Bubble_SprDataOffset = $06ee
FBall_SprDataOffset = $06f1
Misc_SprDataOffset = $06f3
SprDataOffset_Ctrl = $03ee
Player_State = $1d
Enemy_State = $1e
Fireball_State = $24
Block_State = $26
Misc_State = $2a
Player_MovingDir = $45
Enemy_MovingDir = $46
SprObject_X_Speed = $57
Player_X_Speed = $57
Enemy_X_Speed = $58
Fireball_X_Speed = $5e
Block_X_Speed = $60
Misc_X_Speed = $64
Jumpspring_FixedYPos = $58
JumpspringAnimCtrl = $070e
JumpspringForce = $06db
SprObject_PageLoc = $6d
Player_PageLoc = $6d
Enemy_PageLoc = $6e
Fireball_PageLoc = $74
Block_PageLoc = $76
Misc_PageLoc = $7a
Bubble_PageLoc = $83
SprObject_X_Position = $86
Player_X_Position = $86
Enemy_X_Position = $87
Fireball_X_Position = $8d
Block_X_Position = $8f
Misc_X_Position = $93
Bubble_X_Position = $9c
SprObject_Y_Speed = $9f
Player_Y_Speed = $9f
Enemy_Y_Speed = $a0
Fireball_Y_Speed = $a6
Block_Y_Speed = $a8
Misc_Y_Speed = $ac
SprObject_Y_HighPos = $b5
Player_Y_HighPos = $b5
Enemy_Y_HighPos = $b6
Fireball_Y_HighPos = $bc
Block_Y_HighPos = $be
Misc_Y_HighPos = $c2
Bubble_Y_HighPos = $cb
SprObject_Y_Position = $ce
Player_Y_Position = $ce
Enemy_Y_Position = $cf
Fireball_Y_Position = $d5
Block_Y_Position = $d7
Misc_Y_Position = $db
Bubble_Y_Position = $e4
SprObject_Rel_XPos = $03ad
Player_Rel_XPos = $03ad
Enemy_Rel_XPos = $03ae
Fireball_Rel_XPos = $03af
Bubble_Rel_XPos = $03b0
Block_Rel_XPos = $03b1
Misc_Rel_XPos = $03b3
SprObject_Rel_YPos = $03b8
Player_Rel_YPos = $03b8
Enemy_Rel_YPos = $03b9
Fireball_Rel_YPos = $03ba
Bubble_Rel_YPos = $03bb
Block_Rel_YPos = $03bc
Misc_Rel_YPos = $03be
.db $46, $24, $90, $08, $95, $51, $78, $fa, $d7, $73
.db $39, $f1, $8c, $01, $a8, $52, $b8, $52, $cc, $01
.db $5f, $b3, $97, $63, $9e, $00, $0e, $81, $16, $24
.db $66, $04, $8e, $00, $fe, $01, $08, $d2, $0e, $06
.db $6f, $47, $9e, $0f, $0e, $82, $2d, $47, $28, $7a
.db $68, $7a, $a8, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;level 4-2
L_UndergroundArea2:
.db $48, $0f
.db $0e, $01, $5e, $02, $bc, $01, $fc, $01, $2c, $82
.db $41, $52, $4e, $04, $67, $25, $68, $24, $69, $24
.db $ba, $42, $c7, $04, $de, $0b, $b2, $87, $fe, $02
.db $2c, $e1, $2c, $71, $67, $01, $77, $00, $87, $01
.db $8e, $00, $ee, $01, $f6, $02, $03, $85, $05, $02
.db $13, $21, $16, $02, $27, $02, $2e, $02, $88, $72
.db $c7, $20, $d7, $07, $e4, $76, $07, $a0, $17, $06
.db $48, $7a, $76, $20, $98, $72, $79, $e1, $88, $62
.db $9c, $01, $b7, $73, $dc, $01, $f8, $62, $fe, $01
.db $08, $e2, $0e, $00, $6e, $02, $73, $20, $77, $23
.db $83, $04, $93, $20, $ae, $00, $fe, $0a, $0e, $82
.db $39, $71, $a8, $72, $e7, $73, $0c, $81, $8f, $32
.db $ae, $00, $fe, $04, $04, $d1, $17, $04, $26, $49
.db $27, $29, $df, $33, $fe, $02, $44, $f6, $7c, $01
.db $8e, $06, $bf, $47, $ee, $0f, $4d, $c7, $0e, $82
.db $68, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;underground bonus rooms area used in many levels
L_UndergroundArea3:
.db $48, $01
.db $0e, $01, $00, $5a, $3e, $06, $45, $46, $47, $46
.db $53, $44, $ae, $01, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $2e, $04, $37, $28, $3a, $48, $46, $47
.db $c7, $07, $ce, $0f, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $33, $53, $43, $51, $46, $40, $47, $50
.db $53, $04, $55, $40, $56, $50, $62, $43, $64, $40
.db $65, $50, $71, $41, $73, $51, $83, $51, $94, $40
.db $95, $50, $a3, $50, $a5, $40, $a6, $50, $b3, $51
.db $b6, $40, $b7, $50, $c3, $53, $df, $4a, $4d, $c7
.db $0e, $81, $00, $5a, $2e, $02, $36, $47, $37, $52
.db $3a, $49, $47, $25, $a7, $52, $d7, $04, $df, $4a
.db $4d, $c7, $0e, $81, $00, $5a, $3e, $02, $44, $51
.db $53, $44, $54, $44, $55, $24, $a1, $54, $ae, $01
.db $b4, $21, $df, $4a, $e5, $07, $4d, $c7
.db $fd
;water area used in levels 5-2 and 6-2
L_WaterArea1:
.db $41, $01
.db $b4, $34, $c8, $52, $f2, $51, $47, $d3, $6c, $03
.db $65, $49, $9e, $07, $be, $01, $cc, $03, $fe, $07
.db $0d, $c9, $1e, $01, $6c, $01, $62, $35, $63, $53
.db $8a, $41, $ac, $01, $b3, $53, $e9, $51, $26, $c3
.db $27, $33, $63, $43, $64, $33, $ba, $60, $c9, $61
.db $ce, $0b, $e5, $09, $ee, $0f, $7d, $ca, $7d, $47
.db $fd
;level 2-2/7-2
L_WaterArea2:
.db $41, $01
.db $b8, $52, $ea, $41, $27, $b2, $b3, $42, $16, $d4
.db $4a, $42, $a5, $51, $a7, $31, $27, $d3, $08, $e2
.db $16, $64, $2c, $04, $38, $42, $76, $64, $88, $62
.db $de, $07, $fe, $01, $0d, $c9, $23, $32, $31, $51
.db $98, $52, $0d, $c9, $59, $42, $63, $53, $67, $31
.db $14, $c2, $36, $31, $87, $53, $17, $e3, $29, $61
.db $30, $62, $3c, $08, $42, $37, $59, $40, $6a, $42
.db $99, $40, $c9, $61, $d7, $63, $39, $d1, $58, $52
.db $c3, $67, $d3, $31, $dc, $06, $f7, $42, $fa, $42
.db $23, $b1, $43, $67, $c3, $34, $c7, $34, $d1, $51
.db $43, $b3, $47, $33, $9a, $30, $a9, $61, $b8, $62
.db $be, $0b, $d5, $09, $de, $0f, $0d, $ca, $7d, $47
.db $fd
;water area used in level 8-4
L_WaterArea3:
.db $49, $0f
.db $1e, $01, $39, $73, $5e, $07, $ae, $0b, $1e, $82
.db $6e, $88, $9e, $02, $0d, $04, $2e, $0b, $45, $09
.db $4e, $0f, $ed, $47
.db $fd
;-------------------------------------------------------------------------------------
;unused space
.db $ff
;-------------------------------------------------------------------------------------
;indirect jump routine called when
;$0770 is set to 1
GameMode:
lda OperMode_Task
jsr JumpEngine
.dw InitializeArea
.dw ScreenRoutines
.dw SecondaryGameSetup
.dw GameCoreRoutine
;-------------------------------------------------------------------------------------
GameCoreRoutine:
ldx CurrentPlayer ;get which player is on the screen
lda SavedJoypadBits,x ;use appropriate player's controller bits
sta SavedJoypadBits ;as the master controller bits
jsr GameRoutines ;execute one of many possible subs
lda OperMode_Task ;check major task of operating mode
cmp #$03 ;if we are supposed to be here,
bcs GameEngine ;branch to the game engine itself
rts
GameEngine:
jsr ProcFireball_Bubble ;process fireballs and air bubbles
ldx #$00
ProcELoop: stx ObjectOffset ;put incremented offset in X as enemy object offset
jsr EnemiesAndLoopsCore ;process enemy objects
jsr FloateyNumbersRoutine ;process floatey numbers
inx
cpx #$06 ;do these two subroutines until the whole buffer is done
bne ProcELoop
jsr GetPlayerOffscreenBits ;get offscreen bits for player object
jsr RelativePlayerPosition ;get relative coordinates for player object
jsr PlayerGfxHandler ;draw the player
jsr BlockObjMT_Updater ;replace block objects with metatiles if necessary
ldx #$01
stx ObjectOffset ;set offset for second
jsr BlockObjectsCore ;process second block object
dex
stx ObjectOffset ;set offset for first
jsr BlockObjectsCore ;process first block object
jsr MiscObjectsCore ;process misc objects (hammer, jumping coins)
jsr ProcessCannons ;process bullet bill cannons
jsr ProcessWhirlpools ;process whirlpools
jsr FlagpoleRoutine ;process the flagpole
jsr RunGameTimer ;count down the game timer
jsr ColorRotation ;cycle one of the background colors
lda Player_Y_HighPos
cmp #$02 ;if player is below the screen, don't bother with the music
bpl NoChgMus
lda StarInvincibleTimer ;if star mario invincibility timer at zero,
beq ClrPlrPal ;skip this part
cmp #$04
bne NoChgMus ;if not yet at a certain point, continue
lda IntervalTimerControl ;if interval timer not yet expired,
bne NoChgMus ;branch ahead, don't bother with the music
jsr GetAreaMusic ;to re-attain appropriate level music
NoChgMus: ldy StarInvincibleTimer ;get invincibility timer
lda FrameCounter ;get frame counter
cpy #$08 ;if timer still above certain point,
bcs CycleTwo ;branch to cycle player's palette quickly
lsr ;otherwise, divide by 8 to cycle every eighth frame
lsr
CycleTwo: lsr ;if branched here, divide by 2 to cycle every other frame
jsr CyclePlayerPalette ;do sub to cycle the palette (note: shares fire flower code)
jmp SaveAB ;then skip this sub to finish up the game engine
ClrPlrPal: jsr ResetPalStar ;do sub to clear player's palette bits in attributes
SaveAB: lda A_B_Buttons ;save current A and B button
sta PreviousA_B_Buttons ;into temp variable to be used on next frame
lda #$00
sta Left_Right_Buttons ;nullify left and right buttons temp variable
UpdScrollVar: lda VRAM_Buffer_AddrCtrl
cmp #$06 ;if vram address controller set to 6 (one of two $0341s)
beq ExitEng ;then branch to leave
lda AreaParserTaskNum ;otherwise check number of tasks
bne RunParser
lda ScrollThirtyTwo ;get horizontal scroll in 0-31 or $00-$20 range
cmp #$20 ;check to see if exceeded $21
bmi ExitEng ;branch to leave if not
lda ScrollThirtyTwo
sbc #$20 ;otherwise subtract $20 to set appropriately
sta ScrollThirtyTwo ;and store
lda #$00 ;reset vram buffer offset used in conjunction with
sta VRAM_Buffer2_Offset ;level graphics buffer at $0341-$035f
RunParser: jsr AreaParserTaskHandler ;update the name table with more level graphics
ExitEng: rts ;and after all that, we're finally done!
;-------------------------------------------------------------------------------------
ScrollHandler:
lda Player_X_Scroll ;load value saved here
clc
adc Platform_X_Scroll ;add value used by left/right platforms
sta Player_X_Scroll ;save as new value here to impose force on scroll
lda ScrollLock ;check scroll lock flag
bne InitScrlAmt ;skip a bunch of code here if set
lda Player_Pos_ForScroll
cmp #$50 ;check player's horizontal screen position
bcc InitScrlAmt ;if less than 80 pixels to the right, branch
lda SideCollisionTimer ;if timer related to player's side collision
bne InitScrlAmt ;not expired, branch
ldy Player_X_Scroll ;get value and decrement by one
dey ;if value originally set to zero or otherwise
bmi InitScrlAmt ;negative for left movement, branch
iny
cpy #$02 ;if value $01, branch and do not decrement
bcc ChkNearMid
dey ;otherwise decrement by one
ChkNearMid: lda Player_Pos_ForScroll
cmp #$70 ;check player's horizontal screen position
bcc ScrollScreen ;if less than 112 pixels to the right, branch
ldy Player_X_Scroll ;otherwise get original value undecremented
ScrollScreen:
tya
sta ScrollAmount ;save value here
clc
adc ScrollThirtyTwo ;add to value already set here
sta ScrollThirtyTwo ;save as new value here
tya
clc
adc ScreenLeft_X_Pos ;add to left side coordinate
sta ScreenLeft_X_Pos ;save as new left side coordinate
sta HorizontalScroll ;save here also
lda ScreenLeft_PageLoc
adc #$00 ;add carry to page location for left
sta ScreenLeft_PageLoc ;side of the screen
and #$01 ;get LSB of page location
sta $00 ;save as temp variable for PPU register 1 mirror
lda Mirror_PPU_CTRL_REG1 ;get PPU register 1 mirror
and #%11111110 ;save all bits except d0
ora $00 ;get saved bit here and save in PPU register 1
sta Mirror_PPU_CTRL_REG1 ;mirror to be used to set name table later
jsr GetScreenPosition ;figure out where the right side is
lda #$08
sta ScrollIntervalTimer ;set scroll timer (residual, not used elsewhere)
jmp ChkPOffscr ;skip this part
InitScrlAmt: lda #$00
sta ScrollAmount ;initialize value here
ChkPOffscr: ldx #$00 ;set X for player offset
jsr GetXOffscreenBits ;get horizontal offscreen bits for player
sta $00 ;save them here
ldy #$00 ;load default offset (left side)
asl ;if d7 of offscreen bits are set,
bcs KeepOnscr ;branch with default offset
iny ;otherwise use different offset (right side)
lda $00
and #%00100000 ;check offscreen bits for d5 set
beq InitPlatScrl ;if not set, branch ahead of this part
KeepOnscr: lda ScreenEdge_X_Pos,y ;get left or right side coordinate based on offset
sec
sbc X_SubtracterData,y ;subtract amount based on offset
sta Player_X_Position ;store as player position to prevent movement further
lda ScreenEdge_PageLoc,y ;get left or right page location based on offset
sbc #$00 ;subtract borrow
sta Player_PageLoc ;save as player's page location
lda Left_Right_Buttons ;check saved controller bits
cmp OffscrJoypadBitsData,y ;against bits based on offset
beq InitPlatScrl ;if not equal, branch
lda #$00
sta Player_X_Speed ;otherwise nullify horizontal speed of player
InitPlatScrl: lda #$00 ;nullify platform force imposed on scroll
sta Platform_X_Scroll
rts
X_SubtracterData:
.db $00, $10
OffscrJoypadBitsData:
.db $01, $02
;-------------------------------------------------------------------------------------
GetScreenPosition:
lda ScreenLeft_X_Pos ;get coordinate of screen's left boundary
clc
adc #$ff ;add 255 pixels
sta ScreenRight_X_Pos ;store as coordinate of screen's right boundary
lda ScreenLeft_PageLoc ;get page number where left boundary is
adc #$00 ;add carry from before
sta ScreenRight_PageLoc ;store as page number where right boundary is
rts
;-------------------------------------------------------------------------------------
GameRoutines:
lda GameEngineSubroutine ;run routine based on number (a few of these routines are
jsr JumpEngine ;merely placeholders as conditions for other routines)
.dw Entrance_GameTimerSetup
.dw Vine_AutoClimb
.dw SideExitPipeEntry
.dw VerticalPipeEntry
.dw FlagpoleSlide
.dw PlayerEndLevel
.dw PlayerLoseLife
.dw PlayerEntrance
.dw PlayerCtrlRoutine
.dw PlayerChangeSize
.dw PlayerInjuryBlink
.dw PlayerDeath
.dw PlayerFireFlower
;-------------------------------------------------------------------------------------
PlayerEntrance:
lda AltEntranceControl ;check for mode of alternate entry
cmp #$02
beq EntrMode2 ;if found, branch to enter from pipe or with vine
lda #$00
ldy Player_Y_Position ;if vertical position above a certain
cpy #$30 ;point, nullify controller bits and continue
bcc AutoControlPlayer ;with player movement code, do not return
lda PlayerEntranceCtrl ;check player entry bits from header
cmp #$06
beq ChkBehPipe ;if set to 6 or 7, execute pipe intro code
cmp #$07 ;otherwise branch to normal entry
bne PlayerRdy
ChkBehPipe: lda Player_SprAttrib ;check for sprite attributes
bne IntroEntr ;branch if found
lda #$01
jmp AutoControlPlayer ;force player to walk to the right
IntroEntr: jsr EnterSidePipe ;execute sub to move player to the right
dec ChangeAreaTimer ;decrement timer for change of area
bne ExitEntr ;branch to exit if not yet expired
inc DisableIntermediate ;set flag to skip world and lives display
jmp NextArea ;jump to increment to next area and set modes
EntrMode2: lda JoypadOverride ;if controller override bits set here,
bne VineEntr ;branch to enter with vine
lda #$ff ;otherwise, set value here then execute sub
jsr MovePlayerYAxis ;to move player upwards (note $ff = -1)
lda Player_Y_Position ;check to see if player is at a specific coordinate
cmp #$91 ;if player risen to a certain point (this requires pipes
bcc PlayerRdy ;to be at specific height to look/function right) branch
rts ;to the last part, otherwise leave
VineEntr: lda VineHeight
cmp #$60 ;check vine height
bne ExitEntr ;if vine not yet reached maximum height, branch to leave
lda Player_Y_Position ;get player's vertical coordinate
cmp #$99 ;check player's vertical coordinate against preset value
ldy #$00 ;load default values to be written to
lda #$01 ;this value moves player to the right off the vine
bcc OffVine ;if vertical coordinate < preset value, use defaults
lda #$03
sta Player_State ;otherwise set player state to climbing
iny ;increment value in Y
lda #$08 ;set block in block buffer to cover hole, then
sta Block_Buffer_1+$b4 ;use same value to force player to climb
OffVine: sty DisableCollisionDet ;set collision detection disable flag
jsr AutoControlPlayer ;use contents of A to move player up or right, execute sub
lda Player_X_Position
cmp #$48 ;check player's horizontal position
bcc ExitEntr ;if not far enough to the right, branch to leave
PlayerRdy: lda #$08 ;set routine to be executed by game engine next frame
sta GameEngineSubroutine
lda #$01 ;set to face player to the right
sta PlayerFacingDir
lsr ;init A
sta AltEntranceControl ;init mode of entry
sta DisableCollisionDet ;init collision detection disable flag
sta JoypadOverride ;nullify controller override bits
ExitEntr: rts ;leave!
;-------------------------------------------------------------------------------------
;$07 - used to hold upper limit of high byte when player falls down hole
AutoControlPlayer:
sta SavedJoypadBits ;override controller bits with contents of A if executing here
PlayerCtrlRoutine:
lda GameEngineSubroutine ;check task here
cmp #$0b ;if certain value is set, branch to skip controller bit loading
beq SizeChk
lda AreaType ;are we in a water type area?
bne SaveJoyp ;if not, branch
ldy Player_Y_HighPos
dey ;if not in vertical area between
bne DisJoyp ;status bar and bottom, branch
lda Player_Y_Position
cmp #$d0 ;if nearing the bottom of the screen or
bcc SaveJoyp ;not in the vertical area between status bar or bottom,
DisJoyp: lda #$00 ;disable controller bits
sta SavedJoypadBits
SaveJoyp: lda SavedJoypadBits ;otherwise store A and B buttons in $0a
and #%11000000
sta A_B_Buttons
lda SavedJoypadBits ;store left and right buttons in $0c
and #%00000011
sta Left_Right_Buttons
lda SavedJoypadBits ;store up and down buttons in $0b
and #%00001100
sta Up_Down_Buttons
and #%00000100 ;check for pressing down
beq SizeChk ;if not, branch
lda Player_State ;check player's state
bne SizeChk ;if not on the ground, branch
ldy Left_Right_Buttons ;check left and right
beq SizeChk ;if neither pressed, branch
lda #$00 ;init page select for enemy objects
sta EnemyObjectPageSel
ldx ObjectOffset ;reload current offset in enemy buffers
rts ;and leave
CheckpointEnemyID:
lda Enemy_ID,x
cmp #$15 ;check enemy object identifier for $15 or greater
bcs InitEnemyRoutines ;and branch straight to the jump engine if found
tay ;save identifier in Y register for now
lda Enemy_Y_Position,x
adc #$08 ;add eight pixels to what will eventually be the
sta Enemy_Y_Position,x ;enemy object's vertical coordinate ($00-$14 only)
lda #$01
sta EnemyOffscrBitsMasked,x ;set offscreen masked bit
tya ;get identifier back and use as offset for jump engine
InitEnemyRoutines:
jsr JumpEngine
;jump engine table for newly loaded enemy objects
.dw InitNormalEnemy ;for objects $00-$0f
.dw InitNormalEnemy
.dw InitNormalEnemy
.dw InitRedKoopa
.dw NoInitCode
.dw InitHammerBro
.dw InitGoomba
.dw InitBloober
.dw InitBulletBill
.dw NoInitCode
.dw InitCheepCheep
.dw InitCheepCheep
.dw InitPodoboo
.dw InitPiranhaPlant
.dw InitJumpGPTroopa
.dw InitRedPTroopa
.dw InitHorizFlySwimEnemy ;for objects $10-$1f
.dw InitLakitu
.dw InitEnemyFrenzy
.dw NoInitCode
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw EndFrenzy
.dw NoInitCode
.dw NoInitCode
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitLongFirebar
kusfo79 escribió:gynion escribió:paco_man escribió:Incluso así, ¿cuántas lineas de código tendrá el juego?
Eso no se si sabrá, porque a pesar de que los juegos se puedan hackear, no tienen porque disponer del código fuente para ello, y para saber eso hace falta ver todo ese código. desconozco si en el caso de Super Mario Bros su código fue liberado.
Al estar programado en ensamblador, se puede saber, simplemente no desensamblas, y la parte que no sean datos, son lineas de código...
De todas formas, un estupendo friqui hizo un desensamblaje con sus comentarios y todo para que lo pudieramos disfrutar (al tener comentarios es mas largo que el código que debía tener en la época)
https://gist.github.com/1wErt3r/4048722
Para haceros una idea de cuanto ocupan esos 40kb....pego solo un 10% del código (no me deja mas);SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY
;by doppelganger (doppelheathen@gmail.com)
;This file is provided for your own use as-is. It will require the character rom data
;and an iNES file header to get it to work.
;There are so many people I have to thank for this, that taking all the credit for
;myself would be an unforgivable act of arrogance. Without their help this would
;probably not be possible. So I thank all the peeps in the nesdev scene whose insight into
;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no
;way I could have done this without your help), as well as the authors of x816 and SMB
;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project,
;which I compared notes with but did not copy from. Last but certainly not least, I thank
;Nintendo for creating this game and the NES, without which this disassembly would
;only be theory.
;Assembles with x816.
;-------------------------------------------------------------------------------------
;DEFINES
;NES specific hardware defines
PPU_CTRL_REG1 = $2000
PPU_CTRL_REG2 = $2001
PPU_STATUS = $2002
PPU_SPR_ADDR = $2003
PPU_SPR_DATA = $2004
PPU_SCROLL_REG = $2005
PPU_ADDRESS = $2006
PPU_DATA = $2007
SND_REGISTER = $4000
SND_SQUARE1_REG = $4000
SND_SQUARE2_REG = $4004
SND_TRIANGLE_REG = $4008
SND_NOISE_REG = $400c
SND_DELTA_REG = $4010
SND_MASTERCTRL_REG = $4015
SPR_DMA = $4014
JOYPAD_PORT = $4016
JOYPAD_PORT1 = $4016
JOYPAD_PORT2 = $4017
; GAME SPECIFIC DEFINES
ObjectOffset = $08
FrameCounter = $09
SavedJoypadBits = $06fc
SavedJoypad1Bits = $06fc
SavedJoypad2Bits = $06fd
JoypadBitMask = $074a
JoypadOverride = $0758
A_B_Buttons = $0a
PreviousA_B_Buttons = $0d
Up_Down_Buttons = $0b
Left_Right_Buttons = $0c
GameEngineSubroutine = $0e
Mirror_PPU_CTRL_REG1 = $0778
Mirror_PPU_CTRL_REG2 = $0779
OperMode = $0770
OperMode_Task = $0772
ScreenRoutineTask = $073c
GamePauseStatus = $0776
GamePauseTimer = $0777
DemoAction = $0717
DemoActionTimer = $0718
TimerControl = $0747
IntervalTimerControl = $077f
Timers = $0780
SelectTimer = $0780
PlayerAnimTimer = $0781
JumpSwimTimer = $0782
RunningTimer = $0783
BlockBounceTimer = $0784
SideCollisionTimer = $0785
JumpspringTimer = $0786
GameTimerCtrlTimer = $0787
ClimbSideTimer = $0789
EnemyFrameTimer = $078a
FrenzyEnemyTimer = $078f
BowserFireBreathTimer = $0790
StompTimer = $0791
AirBubbleTimer = $0792
ScrollIntervalTimer = $0795
EnemyIntervalTimer = $0796
BrickCoinTimer = $079d
InjuryTimer = $079e
StarInvincibleTimer = $079f
ScreenTimer = $07a0
WorldEndTimer = $07a1
DemoTimer = $07a2
Sprite_Data = $0200
Sprite_Y_Position = $0200
Sprite_Tilenumber = $0201
Sprite_Attributes = $0202
Sprite_X_Position = $0203
ScreenEdge_PageLoc = $071a
ScreenEdge_X_Pos = $071c
ScreenLeft_PageLoc = $071a
ScreenRight_PageLoc = $071b
ScreenLeft_X_Pos = $071c
ScreenRight_X_Pos = $071d
PlayerFacingDir = $33
DestinationPageLoc = $34
VictoryWalkControl = $35
ScrollFractional = $0768
PrimaryMsgCounter = $0719
SecondaryMsgCounter = $0749
HorizontalScroll = $073f
VerticalScroll = $0740
ScrollLock = $0723
ScrollThirtyTwo = $073d
Player_X_Scroll = $06ff
Player_Pos_ForScroll = $0755
ScrollAmount = $0775
AreaData = $e7
AreaDataLow = $e7
AreaDataHigh = $e8
EnemyData = $e9
EnemyDataLow = $e9
EnemyDataHigh = $ea
AreaParserTaskNum = $071f
ColumnSets = $071e
CurrentPageLoc = $0725
CurrentColumnPos = $0726
BackloadingFlag = $0728
BehindAreaParserFlag = $0729
AreaObjectPageLoc = $072a
AreaObjectPageSel = $072b
AreaDataOffset = $072c
AreaObjOffsetBuffer = $072d
AreaObjectLength = $0730
StaircaseControl = $0734
AreaObjectHeight = $0735
MushroomLedgeHalfLen = $0736
EnemyDataOffset = $0739
EnemyObjectPageLoc = $073a
EnemyObjectPageSel = $073b
MetatileBuffer = $06a1
BlockBufferColumnPos = $06a0
CurrentNTAddr_Low = $0721
CurrentNTAddr_High = $0720
AttributeBuffer = $03f9
LoopCommand = $0745
DisplayDigits = $07d7
TopScoreDisplay = $07d7
ScoreAndCoinDisplay = $07dd
PlayerScoreDisplay = $07dd
GameTimerDisplay = $07f8
DigitModifier = $0134
VerticalFlipFlag = $0109
FloateyNum_Control = $0110
ShellChainCounter = $0125
FloateyNum_Timer = $012c
FloateyNum_X_Pos = $0117
FloateyNum_Y_Pos = $011e
FlagpoleFNum_Y_Pos = $010d
FlagpoleFNum_YMFDummy = $010e
FlagpoleScore = $010f
FlagpoleCollisionYPos = $070f
StompChainCounter = $0484
VRAM_Buffer1_Offset = $0300
VRAM_Buffer1 = $0301
VRAM_Buffer2_Offset = $0340
VRAM_Buffer2 = $0341
VRAM_Buffer_AddrCtrl = $0773
Sprite0HitDetectFlag = $0722
DisableScreenFlag = $0774
DisableIntermediate = $0769
ColorRotateOffset = $06d4
TerrainControl = $0727
AreaStyle = $0733
ForegroundScenery = $0741
BackgroundScenery = $0742
CloudTypeOverride = $0743
BackgroundColorCtrl = $0744
AreaType = $074e
AreaAddrsLOffset = $074f
AreaPointer = $0750
PlayerEntranceCtrl = $0710
GameTimerSetting = $0715
AltEntranceControl = $0752
EntrancePage = $0751
NumberOfPlayers = $077a
WarpZoneControl = $06d6
ChangeAreaTimer = $06de
MultiLoopCorrectCntr = $06d9
MultiLoopPassCntr = $06da
FetchNewGameTimerFlag = $0757
GameTimerExpiredFlag = $0759
PrimaryHardMode = $076a
SecondaryHardMode = $06cc
WorldSelectNumber = $076b
WorldSelectEnableFlag = $07fc
ContinueWorld = $07fd
CurrentPlayer = $0753
PlayerSize = $0754
PlayerStatus = $0756
OnscreenPlayerInfo = $075a
NumberofLives = $075a ;used by current player
HalfwayPage = $075b
LevelNumber = $075c ;the actual dash number
Hidden1UpFlag = $075d
CoinTally = $075e
WorldNumber = $075f
AreaNumber = $0760 ;internal number used to find areas
CoinTallyFor1Ups = $0748
OffscreenPlayerInfo = $0761
OffScr_NumberofLives = $0761 ;used by offscreen player
OffScr_HalfwayPage = $0762
OffScr_LevelNumber = $0763
OffScr_Hidden1UpFlag = $0764
OffScr_CoinTally = $0765
OffScr_WorldNumber = $0766
OffScr_AreaNumber = $0767
BalPlatformAlignment = $03a0
Platform_X_Scroll = $03a1
PlatformCollisionFlag = $03a2
YPlatformTopYPos = $0401
YPlatformCenterYPos = $58
BrickCoinTimerFlag = $06bc
StarFlagTaskControl = $0746
PseudoRandomBitReg = $07a7
WarmBootValidation = $07ff
SprShuffleAmtOffset = $06e0
SprShuffleAmt = $06e1
SprDataOffset = $06e4
Player_SprDataOffset = $06e4
Enemy_SprDataOffset = $06e5
Block_SprDataOffset = $06ec
Alt_SprDataOffset = $06ec
Bubble_SprDataOffset = $06ee
FBall_SprDataOffset = $06f1
Misc_SprDataOffset = $06f3
SprDataOffset_Ctrl = $03ee
Player_State = $1d
Enemy_State = $1e
Fireball_State = $24
Block_State = $26
Misc_State = $2a
Player_MovingDir = $45
Enemy_MovingDir = $46
SprObject_X_Speed = $57
Player_X_Speed = $57
Enemy_X_Speed = $58
Fireball_X_Speed = $5e
Block_X_Speed = $60
Misc_X_Speed = $64
Jumpspring_FixedYPos = $58
JumpspringAnimCtrl = $070e
JumpspringForce = $06db
SprObject_PageLoc = $6d
Player_PageLoc = $6d
Enemy_PageLoc = $6e
Fireball_PageLoc = $74
Block_PageLoc = $76
Misc_PageLoc = $7a
Bubble_PageLoc = $83
SprObject_X_Position = $86
Player_X_Position = $86
Enemy_X_Position = $87
Fireball_X_Position = $8d
Block_X_Position = $8f
Misc_X_Position = $93
Bubble_X_Position = $9c
SprObject_Y_Speed = $9f
Player_Y_Speed = $9f
Enemy_Y_Speed = $a0
Fireball_Y_Speed = $a6
Block_Y_Speed = $a8
Misc_Y_Speed = $ac
SprObject_Y_HighPos = $b5
Player_Y_HighPos = $b5
Enemy_Y_HighPos = $b6
Fireball_Y_HighPos = $bc
Block_Y_HighPos = $be
Misc_Y_HighPos = $c2
Bubble_Y_HighPos = $cb
SprObject_Y_Position = $ce
Player_Y_Position = $ce
Enemy_Y_Position = $cf
Fireball_Y_Position = $d5
Block_Y_Position = $d7
Misc_Y_Position = $db
Bubble_Y_Position = $e4
SprObject_Rel_XPos = $03ad
Player_Rel_XPos = $03ad
Enemy_Rel_XPos = $03ae
Fireball_Rel_XPos = $03af
Bubble_Rel_XPos = $03b0
Block_Rel_XPos = $03b1
Misc_Rel_XPos = $03b3
SprObject_Rel_YPos = $03b8
Player_Rel_YPos = $03b8
Enemy_Rel_YPos = $03b9
Fireball_Rel_YPos = $03ba
Bubble_Rel_YPos = $03bb
Block_Rel_YPos = $03bc
Misc_Rel_YPos = $03be
.db $46, $24, $90, $08, $95, $51, $78, $fa, $d7, $73
.db $39, $f1, $8c, $01, $a8, $52, $b8, $52, $cc, $01
.db $5f, $b3, $97, $63, $9e, $00, $0e, $81, $16, $24
.db $66, $04, $8e, $00, $fe, $01, $08, $d2, $0e, $06
.db $6f, $47, $9e, $0f, $0e, $82, $2d, $47, $28, $7a
.db $68, $7a, $a8, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;level 4-2
L_UndergroundArea2:
.db $48, $0f
.db $0e, $01, $5e, $02, $bc, $01, $fc, $01, $2c, $82
.db $41, $52, $4e, $04, $67, $25, $68, $24, $69, $24
.db $ba, $42, $c7, $04, $de, $0b, $b2, $87, $fe, $02
.db $2c, $e1, $2c, $71, $67, $01, $77, $00, $87, $01
.db $8e, $00, $ee, $01, $f6, $02, $03, $85, $05, $02
.db $13, $21, $16, $02, $27, $02, $2e, $02, $88, $72
.db $c7, $20, $d7, $07, $e4, $76, $07, $a0, $17, $06
.db $48, $7a, $76, $20, $98, $72, $79, $e1, $88, $62
.db $9c, $01, $b7, $73, $dc, $01, $f8, $62, $fe, $01
.db $08, $e2, $0e, $00, $6e, $02, $73, $20, $77, $23
.db $83, $04, $93, $20, $ae, $00, $fe, $0a, $0e, $82
.db $39, $71, $a8, $72, $e7, $73, $0c, $81, $8f, $32
.db $ae, $00, $fe, $04, $04, $d1, $17, $04, $26, $49
.db $27, $29, $df, $33, $fe, $02, $44, $f6, $7c, $01
.db $8e, $06, $bf, $47, $ee, $0f, $4d, $c7, $0e, $82
.db $68, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;underground bonus rooms area used in many levels
L_UndergroundArea3:
.db $48, $01
.db $0e, $01, $00, $5a, $3e, $06, $45, $46, $47, $46
.db $53, $44, $ae, $01, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $2e, $04, $37, $28, $3a, $48, $46, $47
.db $c7, $07, $ce, $0f, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $33, $53, $43, $51, $46, $40, $47, $50
.db $53, $04, $55, $40, $56, $50, $62, $43, $64, $40
.db $65, $50, $71, $41, $73, $51, $83, $51, $94, $40
.db $95, $50, $a3, $50, $a5, $40, $a6, $50, $b3, $51
.db $b6, $40, $b7, $50, $c3, $53, $df, $4a, $4d, $c7
.db $0e, $81, $00, $5a, $2e, $02, $36, $47, $37, $52
.db $3a, $49, $47, $25, $a7, $52, $d7, $04, $df, $4a
.db $4d, $c7, $0e, $81, $00, $5a, $3e, $02, $44, $51
.db $53, $44, $54, $44, $55, $24, $a1, $54, $ae, $01
.db $b4, $21, $df, $4a, $e5, $07, $4d, $c7
.db $fd
;water area used in levels 5-2 and 6-2
L_WaterArea1:
.db $41, $01
.db $b4, $34, $c8, $52, $f2, $51, $47, $d3, $6c, $03
.db $65, $49, $9e, $07, $be, $01, $cc, $03, $fe, $07
.db $0d, $c9, $1e, $01, $6c, $01, $62, $35, $63, $53
.db $8a, $41, $ac, $01, $b3, $53, $e9, $51, $26, $c3
.db $27, $33, $63, $43, $64, $33, $ba, $60, $c9, $61
.db $ce, $0b, $e5, $09, $ee, $0f, $7d, $ca, $7d, $47
.db $fd
;level 2-2/7-2
L_WaterArea2:
.db $41, $01
.db $b8, $52, $ea, $41, $27, $b2, $b3, $42, $16, $d4
.db $4a, $42, $a5, $51, $a7, $31, $27, $d3, $08, $e2
.db $16, $64, $2c, $04, $38, $42, $76, $64, $88, $62
.db $de, $07, $fe, $01, $0d, $c9, $23, $32, $31, $51
.db $98, $52, $0d, $c9, $59, $42, $63, $53, $67, $31
.db $14, $c2, $36, $31, $87, $53, $17, $e3, $29, $61
.db $30, $62, $3c, $08, $42, $37, $59, $40, $6a, $42
.db $99, $40, $c9, $61, $d7, $63, $39, $d1, $58, $52
.db $c3, $67, $d3, $31, $dc, $06, $f7, $42, $fa, $42
.db $23, $b1, $43, $67, $c3, $34, $c7, $34, $d1, $51
.db $43, $b3, $47, $33, $9a, $30, $a9, $61, $b8, $62
.db $be, $0b, $d5, $09, $de, $0f, $0d, $ca, $7d, $47
.db $fd
;water area used in level 8-4
L_WaterArea3:
.db $49, $0f
.db $1e, $01, $39, $73, $5e, $07, $ae, $0b, $1e, $82
.db $6e, $88, $9e, $02, $0d, $04, $2e, $0b, $45, $09
.db $4e, $0f, $ed, $47
.db $fd
;-------------------------------------------------------------------------------------
;unused space
.db $ff
;-------------------------------------------------------------------------------------
;indirect jump routine called when
;$0770 is set to 1
GameMode:
lda OperMode_Task
jsr JumpEngine
.dw InitializeArea
.dw ScreenRoutines
.dw SecondaryGameSetup
.dw GameCoreRoutine
;-------------------------------------------------------------------------------------
GameCoreRoutine:
ldx CurrentPlayer ;get which player is on the screen
lda SavedJoypadBits,x ;use appropriate player's controller bits
sta SavedJoypadBits ;as the master controller bits
jsr GameRoutines ;execute one of many possible subs
lda OperMode_Task ;check major task of operating mode
cmp #$03 ;if we are supposed to be here,
bcs GameEngine ;branch to the game engine itself
rts
GameEngine:
jsr ProcFireball_Bubble ;process fireballs and air bubbles
ldx #$00
ProcELoop: stx ObjectOffset ;put incremented offset in X as enemy object offset
jsr EnemiesAndLoopsCore ;process enemy objects
jsr FloateyNumbersRoutine ;process floatey numbers
inx
cpx #$06 ;do these two subroutines until the whole buffer is done
bne ProcELoop
jsr GetPlayerOffscreenBits ;get offscreen bits for player object
jsr RelativePlayerPosition ;get relative coordinates for player object
jsr PlayerGfxHandler ;draw the player
jsr BlockObjMT_Updater ;replace block objects with metatiles if necessary
ldx #$01
stx ObjectOffset ;set offset for second
jsr BlockObjectsCore ;process second block object
dex
stx ObjectOffset ;set offset for first
jsr BlockObjectsCore ;process first block object
jsr MiscObjectsCore ;process misc objects (hammer, jumping coins)
jsr ProcessCannons ;process bullet bill cannons
jsr ProcessWhirlpools ;process whirlpools
jsr FlagpoleRoutine ;process the flagpole
jsr RunGameTimer ;count down the game timer
jsr ColorRotation ;cycle one of the background colors
lda Player_Y_HighPos
cmp #$02 ;if player is below the screen, don't bother with the music
bpl NoChgMus
lda StarInvincibleTimer ;if star mario invincibility timer at zero,
beq ClrPlrPal ;skip this part
cmp #$04
bne NoChgMus ;if not yet at a certain point, continue
lda IntervalTimerControl ;if interval timer not yet expired,
bne NoChgMus ;branch ahead, don't bother with the music
jsr GetAreaMusic ;to re-attain appropriate level music
NoChgMus: ldy StarInvincibleTimer ;get invincibility timer
lda FrameCounter ;get frame counter
cpy #$08 ;if timer still above certain point,
bcs CycleTwo ;branch to cycle player's palette quickly
lsr ;otherwise, divide by 8 to cycle every eighth frame
lsr
CycleTwo: lsr ;if branched here, divide by 2 to cycle every other frame
jsr CyclePlayerPalette ;do sub to cycle the palette (note: shares fire flower code)
jmp SaveAB ;then skip this sub to finish up the game engine
ClrPlrPal: jsr ResetPalStar ;do sub to clear player's palette bits in attributes
SaveAB: lda A_B_Buttons ;save current A and B button
sta PreviousA_B_Buttons ;into temp variable to be used on next frame
lda #$00
sta Left_Right_Buttons ;nullify left and right buttons temp variable
UpdScrollVar: lda VRAM_Buffer_AddrCtrl
cmp #$06 ;if vram address controller set to 6 (one of two $0341s)
beq ExitEng ;then branch to leave
lda AreaParserTaskNum ;otherwise check number of tasks
bne RunParser
lda ScrollThirtyTwo ;get horizontal scroll in 0-31 or $00-$20 range
cmp #$20 ;check to see if exceeded $21
bmi ExitEng ;branch to leave if not
lda ScrollThirtyTwo
sbc #$20 ;otherwise subtract $20 to set appropriately
sta ScrollThirtyTwo ;and store
lda #$00 ;reset vram buffer offset used in conjunction with
sta VRAM_Buffer2_Offset ;level graphics buffer at $0341-$035f
RunParser: jsr AreaParserTaskHandler ;update the name table with more level graphics
ExitEng: rts ;and after all that, we're finally done!
;-------------------------------------------------------------------------------------
ScrollHandler:
lda Player_X_Scroll ;load value saved here
clc
adc Platform_X_Scroll ;add value used by left/right platforms
sta Player_X_Scroll ;save as new value here to impose force on scroll
lda ScrollLock ;check scroll lock flag
bne InitScrlAmt ;skip a bunch of code here if set
lda Player_Pos_ForScroll
cmp #$50 ;check player's horizontal screen position
bcc InitScrlAmt ;if less than 80 pixels to the right, branch
lda SideCollisionTimer ;if timer related to player's side collision
bne InitScrlAmt ;not expired, branch
ldy Player_X_Scroll ;get value and decrement by one
dey ;if value originally set to zero or otherwise
bmi InitScrlAmt ;negative for left movement, branch
iny
cpy #$02 ;if value $01, branch and do not decrement
bcc ChkNearMid
dey ;otherwise decrement by one
ChkNearMid: lda Player_Pos_ForScroll
cmp #$70 ;check player's horizontal screen position
bcc ScrollScreen ;if less than 112 pixels to the right, branch
ldy Player_X_Scroll ;otherwise get original value undecremented
ScrollScreen:
tya
sta ScrollAmount ;save value here
clc
adc ScrollThirtyTwo ;add to value already set here
sta ScrollThirtyTwo ;save as new value here
tya
clc
adc ScreenLeft_X_Pos ;add to left side coordinate
sta ScreenLeft_X_Pos ;save as new left side coordinate
sta HorizontalScroll ;save here also
lda ScreenLeft_PageLoc
adc #$00 ;add carry to page location for left
sta ScreenLeft_PageLoc ;side of the screen
and #$01 ;get LSB of page location
sta $00 ;save as temp variable for PPU register 1 mirror
lda Mirror_PPU_CTRL_REG1 ;get PPU register 1 mirror
and #%11111110 ;save all bits except d0
ora $00 ;get saved bit here and save in PPU register 1
sta Mirror_PPU_CTRL_REG1 ;mirror to be used to set name table later
jsr GetScreenPosition ;figure out where the right side is
lda #$08
sta ScrollIntervalTimer ;set scroll timer (residual, not used elsewhere)
jmp ChkPOffscr ;skip this part
InitScrlAmt: lda #$00
sta ScrollAmount ;initialize value here
ChkPOffscr: ldx #$00 ;set X for player offset
jsr GetXOffscreenBits ;get horizontal offscreen bits for player
sta $00 ;save them here
ldy #$00 ;load default offset (left side)
asl ;if d7 of offscreen bits are set,
bcs KeepOnscr ;branch with default offset
iny ;otherwise use different offset (right side)
lda $00
and #%00100000 ;check offscreen bits for d5 set
beq InitPlatScrl ;if not set, branch ahead of this part
KeepOnscr: lda ScreenEdge_X_Pos,y ;get left or right side coordinate based on offset
sec
sbc X_SubtracterData,y ;subtract amount based on offset
sta Player_X_Position ;store as player position to prevent movement further
lda ScreenEdge_PageLoc,y ;get left or right page location based on offset
sbc #$00 ;subtract borrow
sta Player_PageLoc ;save as player's page location
lda Left_Right_Buttons ;check saved controller bits
cmp OffscrJoypadBitsData,y ;against bits based on offset
beq InitPlatScrl ;if not equal, branch
lda #$00
sta Player_X_Speed ;otherwise nullify horizontal speed of player
InitPlatScrl: lda #$00 ;nullify platform force imposed on scroll
sta Platform_X_Scroll
rts
X_SubtracterData:
.db $00, $10
OffscrJoypadBitsData:
.db $01, $02
;-------------------------------------------------------------------------------------
GetScreenPosition:
lda ScreenLeft_X_Pos ;get coordinate of screen's left boundary
clc
adc #$ff ;add 255 pixels
sta ScreenRight_X_Pos ;store as coordinate of screen's right boundary
lda ScreenLeft_PageLoc ;get page number where left boundary is
adc #$00 ;add carry from before
sta ScreenRight_PageLoc ;store as page number where right boundary is
rts
;-------------------------------------------------------------------------------------
GameRoutines:
lda GameEngineSubroutine ;run routine based on number (a few of these routines are
jsr JumpEngine ;merely placeholders as conditions for other routines)
.dw Entrance_GameTimerSetup
.dw Vine_AutoClimb
.dw SideExitPipeEntry
.dw VerticalPipeEntry
.dw FlagpoleSlide
.dw PlayerEndLevel
.dw PlayerLoseLife
.dw PlayerEntrance
.dw PlayerCtrlRoutine
.dw PlayerChangeSize
.dw PlayerInjuryBlink
.dw PlayerDeath
.dw PlayerFireFlower
;-------------------------------------------------------------------------------------
PlayerEntrance:
lda AltEntranceControl ;check for mode of alternate entry
cmp #$02
beq EntrMode2 ;if found, branch to enter from pipe or with vine
lda #$00
ldy Player_Y_Position ;if vertical position above a certain
cpy #$30 ;point, nullify controller bits and continue
bcc AutoControlPlayer ;with player movement code, do not return
lda PlayerEntranceCtrl ;check player entry bits from header
cmp #$06
beq ChkBehPipe ;if set to 6 or 7, execute pipe intro code
cmp #$07 ;otherwise branch to normal entry
bne PlayerRdy
ChkBehPipe: lda Player_SprAttrib ;check for sprite attributes
bne IntroEntr ;branch if found
lda #$01
jmp AutoControlPlayer ;force player to walk to the right
IntroEntr: jsr EnterSidePipe ;execute sub to move player to the right
dec ChangeAreaTimer ;decrement timer for change of area
bne ExitEntr ;branch to exit if not yet expired
inc DisableIntermediate ;set flag to skip world and lives display
jmp NextArea ;jump to increment to next area and set modes
EntrMode2: lda JoypadOverride ;if controller override bits set here,
bne VineEntr ;branch to enter with vine
lda #$ff ;otherwise, set value here then execute sub
jsr MovePlayerYAxis ;to move player upwards (note $ff = -1)
lda Player_Y_Position ;check to see if player is at a specific coordinate
cmp #$91 ;if player risen to a certain point (this requires pipes
bcc PlayerRdy ;to be at specific height to look/function right) branch
rts ;to the last part, otherwise leave
VineEntr: lda VineHeight
cmp #$60 ;check vine height
bne ExitEntr ;if vine not yet reached maximum height, branch to leave
lda Player_Y_Position ;get player's vertical coordinate
cmp #$99 ;check player's vertical coordinate against preset value
ldy #$00 ;load default values to be written to
lda #$01 ;this value moves player to the right off the vine
bcc OffVine ;if vertical coordinate < preset value, use defaults
lda #$03
sta Player_State ;otherwise set player state to climbing
iny ;increment value in Y
lda #$08 ;set block in block buffer to cover hole, then
sta Block_Buffer_1+$b4 ;use same value to force player to climb
OffVine: sty DisableCollisionDet ;set collision detection disable flag
jsr AutoControlPlayer ;use contents of A to move player up or right, execute sub
lda Player_X_Position
cmp #$48 ;check player's horizontal position
bcc ExitEntr ;if not far enough to the right, branch to leave
PlayerRdy: lda #$08 ;set routine to be executed by game engine next frame
sta GameEngineSubroutine
lda #$01 ;set to face player to the right
sta PlayerFacingDir
lsr ;init A
sta AltEntranceControl ;init mode of entry
sta DisableCollisionDet ;init collision detection disable flag
sta JoypadOverride ;nullify controller override bits
ExitEntr: rts ;leave!
;-------------------------------------------------------------------------------------
;$07 - used to hold upper limit of high byte when player falls down hole
AutoControlPlayer:
sta SavedJoypadBits ;override controller bits with contents of A if executing here
PlayerCtrlRoutine:
lda GameEngineSubroutine ;check task here
cmp #$0b ;if certain value is set, branch to skip controller bit loading
beq SizeChk
lda AreaType ;are we in a water type area?
bne SaveJoyp ;if not, branch
ldy Player_Y_HighPos
dey ;if not in vertical area between
bne DisJoyp ;status bar and bottom, branch
lda Player_Y_Position
cmp #$d0 ;if nearing the bottom of the screen or
bcc SaveJoyp ;not in the vertical area between status bar or bottom,
DisJoyp: lda #$00 ;disable controller bits
sta SavedJoypadBits
SaveJoyp: lda SavedJoypadBits ;otherwise store A and B buttons in $0a
and #%11000000
sta A_B_Buttons
lda SavedJoypadBits ;store left and right buttons in $0c
and #%00000011
sta Left_Right_Buttons
lda SavedJoypadBits ;store up and down buttons in $0b
and #%00001100
sta Up_Down_Buttons
and #%00000100 ;check for pressing down
beq SizeChk ;if not, branch
lda Player_State ;check player's state
bne SizeChk ;if not on the ground, branch
ldy Left_Right_Buttons ;check left and right
beq SizeChk ;if neither pressed, branch
lda #$00 ;init page select for enemy objects
sta EnemyObjectPageSel
ldx ObjectOffset ;reload current offset in enemy buffers
rts ;and leave
CheckpointEnemyID:
lda Enemy_ID,x
cmp #$15 ;check enemy object identifier for $15 or greater
bcs InitEnemyRoutines ;and branch straight to the jump engine if found
tay ;save identifier in Y register for now
lda Enemy_Y_Position,x
adc #$08 ;add eight pixels to what will eventually be the
sta Enemy_Y_Position,x ;enemy object's vertical coordinate ($00-$14 only)
lda #$01
sta EnemyOffscrBitsMasked,x ;set offscreen masked bit
tya ;get identifier back and use as offset for jump engine
InitEnemyRoutines:
jsr JumpEngine
;jump engine table for newly loaded enemy objects
.dw InitNormalEnemy ;for objects $00-$0f
.dw InitNormalEnemy
.dw InitNormalEnemy
.dw InitRedKoopa
.dw NoInitCode
.dw InitHammerBro
.dw InitGoomba
.dw InitBloober
.dw InitBulletBill
.dw NoInitCode
.dw InitCheepCheep
.dw InitCheepCheep
.dw InitPodoboo
.dw InitPiranhaPlant
.dw InitJumpGPTroopa
.dw InitRedPTroopa
.dw InitHorizFlySwimEnemy ;for objects $10-$1f
.dw InitLakitu
.dw InitEnemyFrenzy
.dw NoInitCode
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw EndFrenzy
.dw NoInitCode
.dw NoInitCode
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitLongFirebar
paco_man escribió:kusfo79 escribió:
Al estar programado en ensamblador, se puede saber, simplemente no desensamblas, y la parte que no sean datos, son lineas de código...
De todas formas, un estupendo friqui hizo un desensamblaje con sus comentarios y todo para que lo pudieramos disfrutar (al tener comentarios es mas largo que el código que debía tener en la época)
https://gist.github.com/1wErt3r/4048722
Para haceros una idea de cuanto ocupan esos 40kb....pego solo un 10% del código (no me deja mas);SMBDIS.ASM - A COMPREHENSIVE SUPER MARIO BROS. DISASSEMBLY
;by doppelganger (doppelheathen@gmail.com)
;This file is provided for your own use as-is. It will require the character rom data
;and an iNES file header to get it to work.
;There are so many people I have to thank for this, that taking all the credit for
;myself would be an unforgivable act of arrogance. Without their help this would
;probably not be possible. So I thank all the peeps in the nesdev scene whose insight into
;the 6502 and the NES helped me learn how it works (you guys know who you are, there's no
;way I could have done this without your help), as well as the authors of x816 and SMB
;Utility, and the reverse-engineers who did the original Super Mario Bros. Hacking Project,
;which I compared notes with but did not copy from. Last but certainly not least, I thank
;Nintendo for creating this game and the NES, without which this disassembly would
;only be theory.
;Assembles with x816.
;-------------------------------------------------------------------------------------
;DEFINES
;NES specific hardware defines
PPU_CTRL_REG1 = $2000
PPU_CTRL_REG2 = $2001
PPU_STATUS = $2002
PPU_SPR_ADDR = $2003
PPU_SPR_DATA = $2004
PPU_SCROLL_REG = $2005
PPU_ADDRESS = $2006
PPU_DATA = $2007
SND_REGISTER = $4000
SND_SQUARE1_REG = $4000
SND_SQUARE2_REG = $4004
SND_TRIANGLE_REG = $4008
SND_NOISE_REG = $400c
SND_DELTA_REG = $4010
SND_MASTERCTRL_REG = $4015
SPR_DMA = $4014
JOYPAD_PORT = $4016
JOYPAD_PORT1 = $4016
JOYPAD_PORT2 = $4017
; GAME SPECIFIC DEFINES
ObjectOffset = $08
FrameCounter = $09
SavedJoypadBits = $06fc
SavedJoypad1Bits = $06fc
SavedJoypad2Bits = $06fd
JoypadBitMask = $074a
JoypadOverride = $0758
A_B_Buttons = $0a
PreviousA_B_Buttons = $0d
Up_Down_Buttons = $0b
Left_Right_Buttons = $0c
GameEngineSubroutine = $0e
Mirror_PPU_CTRL_REG1 = $0778
Mirror_PPU_CTRL_REG2 = $0779
OperMode = $0770
OperMode_Task = $0772
ScreenRoutineTask = $073c
GamePauseStatus = $0776
GamePauseTimer = $0777
DemoAction = $0717
DemoActionTimer = $0718
TimerControl = $0747
IntervalTimerControl = $077f
Timers = $0780
SelectTimer = $0780
PlayerAnimTimer = $0781
JumpSwimTimer = $0782
RunningTimer = $0783
BlockBounceTimer = $0784
SideCollisionTimer = $0785
JumpspringTimer = $0786
GameTimerCtrlTimer = $0787
ClimbSideTimer = $0789
EnemyFrameTimer = $078a
FrenzyEnemyTimer = $078f
BowserFireBreathTimer = $0790
StompTimer = $0791
AirBubbleTimer = $0792
ScrollIntervalTimer = $0795
EnemyIntervalTimer = $0796
BrickCoinTimer = $079d
InjuryTimer = $079e
StarInvincibleTimer = $079f
ScreenTimer = $07a0
WorldEndTimer = $07a1
DemoTimer = $07a2
Sprite_Data = $0200
Sprite_Y_Position = $0200
Sprite_Tilenumber = $0201
Sprite_Attributes = $0202
Sprite_X_Position = $0203
ScreenEdge_PageLoc = $071a
ScreenEdge_X_Pos = $071c
ScreenLeft_PageLoc = $071a
ScreenRight_PageLoc = $071b
ScreenLeft_X_Pos = $071c
ScreenRight_X_Pos = $071d
PlayerFacingDir = $33
DestinationPageLoc = $34
VictoryWalkControl = $35
ScrollFractional = $0768
PrimaryMsgCounter = $0719
SecondaryMsgCounter = $0749
HorizontalScroll = $073f
VerticalScroll = $0740
ScrollLock = $0723
ScrollThirtyTwo = $073d
Player_X_Scroll = $06ff
Player_Pos_ForScroll = $0755
ScrollAmount = $0775
AreaData = $e7
AreaDataLow = $e7
AreaDataHigh = $e8
EnemyData = $e9
EnemyDataLow = $e9
EnemyDataHigh = $ea
AreaParserTaskNum = $071f
ColumnSets = $071e
CurrentPageLoc = $0725
CurrentColumnPos = $0726
BackloadingFlag = $0728
BehindAreaParserFlag = $0729
AreaObjectPageLoc = $072a
AreaObjectPageSel = $072b
AreaDataOffset = $072c
AreaObjOffsetBuffer = $072d
AreaObjectLength = $0730
StaircaseControl = $0734
AreaObjectHeight = $0735
MushroomLedgeHalfLen = $0736
EnemyDataOffset = $0739
EnemyObjectPageLoc = $073a
EnemyObjectPageSel = $073b
MetatileBuffer = $06a1
BlockBufferColumnPos = $06a0
CurrentNTAddr_Low = $0721
CurrentNTAddr_High = $0720
AttributeBuffer = $03f9
LoopCommand = $0745
DisplayDigits = $07d7
TopScoreDisplay = $07d7
ScoreAndCoinDisplay = $07dd
PlayerScoreDisplay = $07dd
GameTimerDisplay = $07f8
DigitModifier = $0134
VerticalFlipFlag = $0109
FloateyNum_Control = $0110
ShellChainCounter = $0125
FloateyNum_Timer = $012c
FloateyNum_X_Pos = $0117
FloateyNum_Y_Pos = $011e
FlagpoleFNum_Y_Pos = $010d
FlagpoleFNum_YMFDummy = $010e
FlagpoleScore = $010f
FlagpoleCollisionYPos = $070f
StompChainCounter = $0484
VRAM_Buffer1_Offset = $0300
VRAM_Buffer1 = $0301
VRAM_Buffer2_Offset = $0340
VRAM_Buffer2 = $0341
VRAM_Buffer_AddrCtrl = $0773
Sprite0HitDetectFlag = $0722
DisableScreenFlag = $0774
DisableIntermediate = $0769
ColorRotateOffset = $06d4
TerrainControl = $0727
AreaStyle = $0733
ForegroundScenery = $0741
BackgroundScenery = $0742
CloudTypeOverride = $0743
BackgroundColorCtrl = $0744
AreaType = $074e
AreaAddrsLOffset = $074f
AreaPointer = $0750
PlayerEntranceCtrl = $0710
GameTimerSetting = $0715
AltEntranceControl = $0752
EntrancePage = $0751
NumberOfPlayers = $077a
WarpZoneControl = $06d6
ChangeAreaTimer = $06de
MultiLoopCorrectCntr = $06d9
MultiLoopPassCntr = $06da
FetchNewGameTimerFlag = $0757
GameTimerExpiredFlag = $0759
PrimaryHardMode = $076a
SecondaryHardMode = $06cc
WorldSelectNumber = $076b
WorldSelectEnableFlag = $07fc
ContinueWorld = $07fd
CurrentPlayer = $0753
PlayerSize = $0754
PlayerStatus = $0756
OnscreenPlayerInfo = $075a
NumberofLives = $075a ;used by current player
HalfwayPage = $075b
LevelNumber = $075c ;the actual dash number
Hidden1UpFlag = $075d
CoinTally = $075e
WorldNumber = $075f
AreaNumber = $0760 ;internal number used to find areas
CoinTallyFor1Ups = $0748
OffscreenPlayerInfo = $0761
OffScr_NumberofLives = $0761 ;used by offscreen player
OffScr_HalfwayPage = $0762
OffScr_LevelNumber = $0763
OffScr_Hidden1UpFlag = $0764
OffScr_CoinTally = $0765
OffScr_WorldNumber = $0766
OffScr_AreaNumber = $0767
BalPlatformAlignment = $03a0
Platform_X_Scroll = $03a1
PlatformCollisionFlag = $03a2
YPlatformTopYPos = $0401
YPlatformCenterYPos = $58
BrickCoinTimerFlag = $06bc
StarFlagTaskControl = $0746
PseudoRandomBitReg = $07a7
WarmBootValidation = $07ff
SprShuffleAmtOffset = $06e0
SprShuffleAmt = $06e1
SprDataOffset = $06e4
Player_SprDataOffset = $06e4
Enemy_SprDataOffset = $06e5
Block_SprDataOffset = $06ec
Alt_SprDataOffset = $06ec
Bubble_SprDataOffset = $06ee
FBall_SprDataOffset = $06f1
Misc_SprDataOffset = $06f3
SprDataOffset_Ctrl = $03ee
Player_State = $1d
Enemy_State = $1e
Fireball_State = $24
Block_State = $26
Misc_State = $2a
Player_MovingDir = $45
Enemy_MovingDir = $46
SprObject_X_Speed = $57
Player_X_Speed = $57
Enemy_X_Speed = $58
Fireball_X_Speed = $5e
Block_X_Speed = $60
Misc_X_Speed = $64
Jumpspring_FixedYPos = $58
JumpspringAnimCtrl = $070e
JumpspringForce = $06db
SprObject_PageLoc = $6d
Player_PageLoc = $6d
Enemy_PageLoc = $6e
Fireball_PageLoc = $74
Block_PageLoc = $76
Misc_PageLoc = $7a
Bubble_PageLoc = $83
SprObject_X_Position = $86
Player_X_Position = $86
Enemy_X_Position = $87
Fireball_X_Position = $8d
Block_X_Position = $8f
Misc_X_Position = $93
Bubble_X_Position = $9c
SprObject_Y_Speed = $9f
Player_Y_Speed = $9f
Enemy_Y_Speed = $a0
Fireball_Y_Speed = $a6
Block_Y_Speed = $a8
Misc_Y_Speed = $ac
SprObject_Y_HighPos = $b5
Player_Y_HighPos = $b5
Enemy_Y_HighPos = $b6
Fireball_Y_HighPos = $bc
Block_Y_HighPos = $be
Misc_Y_HighPos = $c2
Bubble_Y_HighPos = $cb
SprObject_Y_Position = $ce
Player_Y_Position = $ce
Enemy_Y_Position = $cf
Fireball_Y_Position = $d5
Block_Y_Position = $d7
Misc_Y_Position = $db
Bubble_Y_Position = $e4
SprObject_Rel_XPos = $03ad
Player_Rel_XPos = $03ad
Enemy_Rel_XPos = $03ae
Fireball_Rel_XPos = $03af
Bubble_Rel_XPos = $03b0
Block_Rel_XPos = $03b1
Misc_Rel_XPos = $03b3
SprObject_Rel_YPos = $03b8
Player_Rel_YPos = $03b8
Enemy_Rel_YPos = $03b9
Fireball_Rel_YPos = $03ba
Bubble_Rel_YPos = $03bb
Block_Rel_YPos = $03bc
Misc_Rel_YPos = $03be
.db $46, $24, $90, $08, $95, $51, $78, $fa, $d7, $73
.db $39, $f1, $8c, $01, $a8, $52, $b8, $52, $cc, $01
.db $5f, $b3, $97, $63, $9e, $00, $0e, $81, $16, $24
.db $66, $04, $8e, $00, $fe, $01, $08, $d2, $0e, $06
.db $6f, $47, $9e, $0f, $0e, $82, $2d, $47, $28, $7a
.db $68, $7a, $a8, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;level 4-2
L_UndergroundArea2:
.db $48, $0f
.db $0e, $01, $5e, $02, $bc, $01, $fc, $01, $2c, $82
.db $41, $52, $4e, $04, $67, $25, $68, $24, $69, $24
.db $ba, $42, $c7, $04, $de, $0b, $b2, $87, $fe, $02
.db $2c, $e1, $2c, $71, $67, $01, $77, $00, $87, $01
.db $8e, $00, $ee, $01, $f6, $02, $03, $85, $05, $02
.db $13, $21, $16, $02, $27, $02, $2e, $02, $88, $72
.db $c7, $20, $d7, $07, $e4, $76, $07, $a0, $17, $06
.db $48, $7a, $76, $20, $98, $72, $79, $e1, $88, $62
.db $9c, $01, $b7, $73, $dc, $01, $f8, $62, $fe, $01
.db $08, $e2, $0e, $00, $6e, $02, $73, $20, $77, $23
.db $83, $04, $93, $20, $ae, $00, $fe, $0a, $0e, $82
.db $39, $71, $a8, $72, $e7, $73, $0c, $81, $8f, $32
.db $ae, $00, $fe, $04, $04, $d1, $17, $04, $26, $49
.db $27, $29, $df, $33, $fe, $02, $44, $f6, $7c, $01
.db $8e, $06, $bf, $47, $ee, $0f, $4d, $c7, $0e, $82
.db $68, $7a, $ae, $01, $de, $0f, $6d, $c5
.db $fd
;underground bonus rooms area used in many levels
L_UndergroundArea3:
.db $48, $01
.db $0e, $01, $00, $5a, $3e, $06, $45, $46, $47, $46
.db $53, $44, $ae, $01, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $2e, $04, $37, $28, $3a, $48, $46, $47
.db $c7, $07, $ce, $0f, $df, $4a, $4d, $c7, $0e, $81
.db $00, $5a, $33, $53, $43, $51, $46, $40, $47, $50
.db $53, $04, $55, $40, $56, $50, $62, $43, $64, $40
.db $65, $50, $71, $41, $73, $51, $83, $51, $94, $40
.db $95, $50, $a3, $50, $a5, $40, $a6, $50, $b3, $51
.db $b6, $40, $b7, $50, $c3, $53, $df, $4a, $4d, $c7
.db $0e, $81, $00, $5a, $2e, $02, $36, $47, $37, $52
.db $3a, $49, $47, $25, $a7, $52, $d7, $04, $df, $4a
.db $4d, $c7, $0e, $81, $00, $5a, $3e, $02, $44, $51
.db $53, $44, $54, $44, $55, $24, $a1, $54, $ae, $01
.db $b4, $21, $df, $4a, $e5, $07, $4d, $c7
.db $fd
;water area used in levels 5-2 and 6-2
L_WaterArea1:
.db $41, $01
.db $b4, $34, $c8, $52, $f2, $51, $47, $d3, $6c, $03
.db $65, $49, $9e, $07, $be, $01, $cc, $03, $fe, $07
.db $0d, $c9, $1e, $01, $6c, $01, $62, $35, $63, $53
.db $8a, $41, $ac, $01, $b3, $53, $e9, $51, $26, $c3
.db $27, $33, $63, $43, $64, $33, $ba, $60, $c9, $61
.db $ce, $0b, $e5, $09, $ee, $0f, $7d, $ca, $7d, $47
.db $fd
;level 2-2/7-2
L_WaterArea2:
.db $41, $01
.db $b8, $52, $ea, $41, $27, $b2, $b3, $42, $16, $d4
.db $4a, $42, $a5, $51, $a7, $31, $27, $d3, $08, $e2
.db $16, $64, $2c, $04, $38, $42, $76, $64, $88, $62
.db $de, $07, $fe, $01, $0d, $c9, $23, $32, $31, $51
.db $98, $52, $0d, $c9, $59, $42, $63, $53, $67, $31
.db $14, $c2, $36, $31, $87, $53, $17, $e3, $29, $61
.db $30, $62, $3c, $08, $42, $37, $59, $40, $6a, $42
.db $99, $40, $c9, $61, $d7, $63, $39, $d1, $58, $52
.db $c3, $67, $d3, $31, $dc, $06, $f7, $42, $fa, $42
.db $23, $b1, $43, $67, $c3, $34, $c7, $34, $d1, $51
.db $43, $b3, $47, $33, $9a, $30, $a9, $61, $b8, $62
.db $be, $0b, $d5, $09, $de, $0f, $0d, $ca, $7d, $47
.db $fd
;water area used in level 8-4
L_WaterArea3:
.db $49, $0f
.db $1e, $01, $39, $73, $5e, $07, $ae, $0b, $1e, $82
.db $6e, $88, $9e, $02, $0d, $04, $2e, $0b, $45, $09
.db $4e, $0f, $ed, $47
.db $fd
;-------------------------------------------------------------------------------------
;unused space
.db $ff
;-------------------------------------------------------------------------------------
;indirect jump routine called when
;$0770 is set to 1
GameMode:
lda OperMode_Task
jsr JumpEngine
.dw InitializeArea
.dw ScreenRoutines
.dw SecondaryGameSetup
.dw GameCoreRoutine
;-------------------------------------------------------------------------------------
GameCoreRoutine:
ldx CurrentPlayer ;get which player is on the screen
lda SavedJoypadBits,x ;use appropriate player's controller bits
sta SavedJoypadBits ;as the master controller bits
jsr GameRoutines ;execute one of many possible subs
lda OperMode_Task ;check major task of operating mode
cmp #$03 ;if we are supposed to be here,
bcs GameEngine ;branch to the game engine itself
rts
GameEngine:
jsr ProcFireball_Bubble ;process fireballs and air bubbles
ldx #$00
ProcELoop: stx ObjectOffset ;put incremented offset in X as enemy object offset
jsr EnemiesAndLoopsCore ;process enemy objects
jsr FloateyNumbersRoutine ;process floatey numbers
inx
cpx #$06 ;do these two subroutines until the whole buffer is done
bne ProcELoop
jsr GetPlayerOffscreenBits ;get offscreen bits for player object
jsr RelativePlayerPosition ;get relative coordinates for player object
jsr PlayerGfxHandler ;draw the player
jsr BlockObjMT_Updater ;replace block objects with metatiles if necessary
ldx #$01
stx ObjectOffset ;set offset for second
jsr BlockObjectsCore ;process second block object
dex
stx ObjectOffset ;set offset for first
jsr BlockObjectsCore ;process first block object
jsr MiscObjectsCore ;process misc objects (hammer, jumping coins)
jsr ProcessCannons ;process bullet bill cannons
jsr ProcessWhirlpools ;process whirlpools
jsr FlagpoleRoutine ;process the flagpole
jsr RunGameTimer ;count down the game timer
jsr ColorRotation ;cycle one of the background colors
lda Player_Y_HighPos
cmp #$02 ;if player is below the screen, don't bother with the music
bpl NoChgMus
lda StarInvincibleTimer ;if star mario invincibility timer at zero,
beq ClrPlrPal ;skip this part
cmp #$04
bne NoChgMus ;if not yet at a certain point, continue
lda IntervalTimerControl ;if interval timer not yet expired,
bne NoChgMus ;branch ahead, don't bother with the music
jsr GetAreaMusic ;to re-attain appropriate level music
NoChgMus: ldy StarInvincibleTimer ;get invincibility timer
lda FrameCounter ;get frame counter
cpy #$08 ;if timer still above certain point,
bcs CycleTwo ;branch to cycle player's palette quickly
lsr ;otherwise, divide by 8 to cycle every eighth frame
lsr
CycleTwo: lsr ;if branched here, divide by 2 to cycle every other frame
jsr CyclePlayerPalette ;do sub to cycle the palette (note: shares fire flower code)
jmp SaveAB ;then skip this sub to finish up the game engine
ClrPlrPal: jsr ResetPalStar ;do sub to clear player's palette bits in attributes
SaveAB: lda A_B_Buttons ;save current A and B button
sta PreviousA_B_Buttons ;into temp variable to be used on next frame
lda #$00
sta Left_Right_Buttons ;nullify left and right buttons temp variable
UpdScrollVar: lda VRAM_Buffer_AddrCtrl
cmp #$06 ;if vram address controller set to 6 (one of two $0341s)
beq ExitEng ;then branch to leave
lda AreaParserTaskNum ;otherwise check number of tasks
bne RunParser
lda ScrollThirtyTwo ;get horizontal scroll in 0-31 or $00-$20 range
cmp #$20 ;check to see if exceeded $21
bmi ExitEng ;branch to leave if not
lda ScrollThirtyTwo
sbc #$20 ;otherwise subtract $20 to set appropriately
sta ScrollThirtyTwo ;and store
lda #$00 ;reset vram buffer offset used in conjunction with
sta VRAM_Buffer2_Offset ;level graphics buffer at $0341-$035f
RunParser: jsr AreaParserTaskHandler ;update the name table with more level graphics
ExitEng: rts ;and after all that, we're finally done!
;-------------------------------------------------------------------------------------
ScrollHandler:
lda Player_X_Scroll ;load value saved here
clc
adc Platform_X_Scroll ;add value used by left/right platforms
sta Player_X_Scroll ;save as new value here to impose force on scroll
lda ScrollLock ;check scroll lock flag
bne InitScrlAmt ;skip a bunch of code here if set
lda Player_Pos_ForScroll
cmp #$50 ;check player's horizontal screen position
bcc InitScrlAmt ;if less than 80 pixels to the right, branch
lda SideCollisionTimer ;if timer related to player's side collision
bne InitScrlAmt ;not expired, branch
ldy Player_X_Scroll ;get value and decrement by one
dey ;if value originally set to zero or otherwise
bmi InitScrlAmt ;negative for left movement, branch
iny
cpy #$02 ;if value $01, branch and do not decrement
bcc ChkNearMid
dey ;otherwise decrement by one
ChkNearMid: lda Player_Pos_ForScroll
cmp #$70 ;check player's horizontal screen position
bcc ScrollScreen ;if less than 112 pixels to the right, branch
ldy Player_X_Scroll ;otherwise get original value undecremented
ScrollScreen:
tya
sta ScrollAmount ;save value here
clc
adc ScrollThirtyTwo ;add to value already set here
sta ScrollThirtyTwo ;save as new value here
tya
clc
adc ScreenLeft_X_Pos ;add to left side coordinate
sta ScreenLeft_X_Pos ;save as new left side coordinate
sta HorizontalScroll ;save here also
lda ScreenLeft_PageLoc
adc #$00 ;add carry to page location for left
sta ScreenLeft_PageLoc ;side of the screen
and #$01 ;get LSB of page location
sta $00 ;save as temp variable for PPU register 1 mirror
lda Mirror_PPU_CTRL_REG1 ;get PPU register 1 mirror
and #%11111110 ;save all bits except d0
ora $00 ;get saved bit here and save in PPU register 1
sta Mirror_PPU_CTRL_REG1 ;mirror to be used to set name table later
jsr GetScreenPosition ;figure out where the right side is
lda #$08
sta ScrollIntervalTimer ;set scroll timer (residual, not used elsewhere)
jmp ChkPOffscr ;skip this part
InitScrlAmt: lda #$00
sta ScrollAmount ;initialize value here
ChkPOffscr: ldx #$00 ;set X for player offset
jsr GetXOffscreenBits ;get horizontal offscreen bits for player
sta $00 ;save them here
ldy #$00 ;load default offset (left side)
asl ;if d7 of offscreen bits are set,
bcs KeepOnscr ;branch with default offset
iny ;otherwise use different offset (right side)
lda $00
and #%00100000 ;check offscreen bits for d5 set
beq InitPlatScrl ;if not set, branch ahead of this part
KeepOnscr: lda ScreenEdge_X_Pos,y ;get left or right side coordinate based on offset
sec
sbc X_SubtracterData,y ;subtract amount based on offset
sta Player_X_Position ;store as player position to prevent movement further
lda ScreenEdge_PageLoc,y ;get left or right page location based on offset
sbc #$00 ;subtract borrow
sta Player_PageLoc ;save as player's page location
lda Left_Right_Buttons ;check saved controller bits
cmp OffscrJoypadBitsData,y ;against bits based on offset
beq InitPlatScrl ;if not equal, branch
lda #$00
sta Player_X_Speed ;otherwise nullify horizontal speed of player
InitPlatScrl: lda #$00 ;nullify platform force imposed on scroll
sta Platform_X_Scroll
rts
X_SubtracterData:
.db $00, $10
OffscrJoypadBitsData:
.db $01, $02
;-------------------------------------------------------------------------------------
GetScreenPosition:
lda ScreenLeft_X_Pos ;get coordinate of screen's left boundary
clc
adc #$ff ;add 255 pixels
sta ScreenRight_X_Pos ;store as coordinate of screen's right boundary
lda ScreenLeft_PageLoc ;get page number where left boundary is
adc #$00 ;add carry from before
sta ScreenRight_PageLoc ;store as page number where right boundary is
rts
;-------------------------------------------------------------------------------------
GameRoutines:
lda GameEngineSubroutine ;run routine based on number (a few of these routines are
jsr JumpEngine ;merely placeholders as conditions for other routines)
.dw Entrance_GameTimerSetup
.dw Vine_AutoClimb
.dw SideExitPipeEntry
.dw VerticalPipeEntry
.dw FlagpoleSlide
.dw PlayerEndLevel
.dw PlayerLoseLife
.dw PlayerEntrance
.dw PlayerCtrlRoutine
.dw PlayerChangeSize
.dw PlayerInjuryBlink
.dw PlayerDeath
.dw PlayerFireFlower
;-------------------------------------------------------------------------------------
PlayerEntrance:
lda AltEntranceControl ;check for mode of alternate entry
cmp #$02
beq EntrMode2 ;if found, branch to enter from pipe or with vine
lda #$00
ldy Player_Y_Position ;if vertical position above a certain
cpy #$30 ;point, nullify controller bits and continue
bcc AutoControlPlayer ;with player movement code, do not return
lda PlayerEntranceCtrl ;check player entry bits from header
cmp #$06
beq ChkBehPipe ;if set to 6 or 7, execute pipe intro code
cmp #$07 ;otherwise branch to normal entry
bne PlayerRdy
ChkBehPipe: lda Player_SprAttrib ;check for sprite attributes
bne IntroEntr ;branch if found
lda #$01
jmp AutoControlPlayer ;force player to walk to the right
IntroEntr: jsr EnterSidePipe ;execute sub to move player to the right
dec ChangeAreaTimer ;decrement timer for change of area
bne ExitEntr ;branch to exit if not yet expired
inc DisableIntermediate ;set flag to skip world and lives display
jmp NextArea ;jump to increment to next area and set modes
EntrMode2: lda JoypadOverride ;if controller override bits set here,
bne VineEntr ;branch to enter with vine
lda #$ff ;otherwise, set value here then execute sub
jsr MovePlayerYAxis ;to move player upwards (note $ff = -1)
lda Player_Y_Position ;check to see if player is at a specific coordinate
cmp #$91 ;if player risen to a certain point (this requires pipes
bcc PlayerRdy ;to be at specific height to look/function right) branch
rts ;to the last part, otherwise leave
VineEntr: lda VineHeight
cmp #$60 ;check vine height
bne ExitEntr ;if vine not yet reached maximum height, branch to leave
lda Player_Y_Position ;get player's vertical coordinate
cmp #$99 ;check player's vertical coordinate against preset value
ldy #$00 ;load default values to be written to
lda #$01 ;this value moves player to the right off the vine
bcc OffVine ;if vertical coordinate < preset value, use defaults
lda #$03
sta Player_State ;otherwise set player state to climbing
iny ;increment value in Y
lda #$08 ;set block in block buffer to cover hole, then
sta Block_Buffer_1+$b4 ;use same value to force player to climb
OffVine: sty DisableCollisionDet ;set collision detection disable flag
jsr AutoControlPlayer ;use contents of A to move player up or right, execute sub
lda Player_X_Position
cmp #$48 ;check player's horizontal position
bcc ExitEntr ;if not far enough to the right, branch to leave
PlayerRdy: lda #$08 ;set routine to be executed by game engine next frame
sta GameEngineSubroutine
lda #$01 ;set to face player to the right
sta PlayerFacingDir
lsr ;init A
sta AltEntranceControl ;init mode of entry
sta DisableCollisionDet ;init collision detection disable flag
sta JoypadOverride ;nullify controller override bits
ExitEntr: rts ;leave!
;-------------------------------------------------------------------------------------
;$07 - used to hold upper limit of high byte when player falls down hole
AutoControlPlayer:
sta SavedJoypadBits ;override controller bits with contents of A if executing here
PlayerCtrlRoutine:
lda GameEngineSubroutine ;check task here
cmp #$0b ;if certain value is set, branch to skip controller bit loading
beq SizeChk
lda AreaType ;are we in a water type area?
bne SaveJoyp ;if not, branch
ldy Player_Y_HighPos
dey ;if not in vertical area between
bne DisJoyp ;status bar and bottom, branch
lda Player_Y_Position
cmp #$d0 ;if nearing the bottom of the screen or
bcc SaveJoyp ;not in the vertical area between status bar or bottom,
DisJoyp: lda #$00 ;disable controller bits
sta SavedJoypadBits
SaveJoyp: lda SavedJoypadBits ;otherwise store A and B buttons in $0a
and #%11000000
sta A_B_Buttons
lda SavedJoypadBits ;store left and right buttons in $0c
and #%00000011
sta Left_Right_Buttons
lda SavedJoypadBits ;store up and down buttons in $0b
and #%00001100
sta Up_Down_Buttons
and #%00000100 ;check for pressing down
beq SizeChk ;if not, branch
lda Player_State ;check player's state
bne SizeChk ;if not on the ground, branch
ldy Left_Right_Buttons ;check left and right
beq SizeChk ;if neither pressed, branch
lda #$00 ;init page select for enemy objects
sta EnemyObjectPageSel
ldx ObjectOffset ;reload current offset in enemy buffers
rts ;and leave
CheckpointEnemyID:
lda Enemy_ID,x
cmp #$15 ;check enemy object identifier for $15 or greater
bcs InitEnemyRoutines ;and branch straight to the jump engine if found
tay ;save identifier in Y register for now
lda Enemy_Y_Position,x
adc #$08 ;add eight pixels to what will eventually be the
sta Enemy_Y_Position,x ;enemy object's vertical coordinate ($00-$14 only)
lda #$01
sta EnemyOffscrBitsMasked,x ;set offscreen masked bit
tya ;get identifier back and use as offset for jump engine
InitEnemyRoutines:
jsr JumpEngine
;jump engine table for newly loaded enemy objects
.dw InitNormalEnemy ;for objects $00-$0f
.dw InitNormalEnemy
.dw InitNormalEnemy
.dw InitRedKoopa
.dw NoInitCode
.dw InitHammerBro
.dw InitGoomba
.dw InitBloober
.dw InitBulletBill
.dw NoInitCode
.dw InitCheepCheep
.dw InitCheepCheep
.dw InitPodoboo
.dw InitPiranhaPlant
.dw InitJumpGPTroopa
.dw InitRedPTroopa
.dw InitHorizFlySwimEnemy ;for objects $10-$1f
.dw InitLakitu
.dw InitEnemyFrenzy
.dw NoInitCode
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw InitEnemyFrenzy
.dw EndFrenzy
.dw NoInitCode
.dw NoInitCode
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitShortFirebar
.dw InitLongFirebar
La leche, pues sí que ocupa, son bastantes lineas aún quitando los comentarios. No comprendo como el css de una web con menos lineas y "chicha" pueda pesar más. Que poco ha avanzado la cosa en 30 años.
EDITO: Acabo de verlo, 16.300 lineas de código de hace 30 años que ocupan 40 kb.
Cozumel escribió:Piénsalo así, si los programas no fueran cada vez más ineficientes, haría más de 10 años que no se venderían ordenadores.
Antes navegabas por internet con un procesador a 66 Mhz y ahora necesitas uno con 4.000 Mhz porque los navegadores consumen más recursos para hacer prácticamente lo mismo.
De hecho, mi portátil de penúltima generación con Windows 8 funciona más lento que mi 486 con Windows´95 o mi 086 con Gem Desktop y si lo pienso fríamente me doy cuenta que hace más cosas en apariencia que en realidad.
Calculinho escribió:Había un emulador desconstruction o algo así, para NES que emulada el juego y mostraba al mismo tiempo una paleta con los colores y sprites que usaba la nes en cada momento. Se entiende mejor su funcionamiento para quien interese.
alexoiter escribió:Cozumel escribió:Piénsalo así, si los programas no fueran cada vez más ineficientes, haría más de 10 años que no se venderían ordenadores.
Antes navegabas por internet con un procesador a 66 Mhz y ahora necesitas uno con 4.000 Mhz porque los navegadores consumen más recursos para hacer prácticamente lo mismo.
De hecho, mi portátil de penúltima generación con Windows 8 funciona más lento que mi 486 con Windows´95 o mi 086 con Gem Desktop y si lo pienso fríamente me doy cuenta que hace más cosas en apariencia que en realidad.
Ahora los navegadores hacen bastantes más cosas que antaño.
Cozumel escribió:alexoiter escribió:Cozumel escribió:Piénsalo así, si los programas no fueran cada vez más ineficientes, haría más de 10 años que no se venderían ordenadores.
Antes navegabas por internet con un procesador a 66 Mhz y ahora necesitas uno con 4.000 Mhz porque los navegadores consumen más recursos para hacer prácticamente lo mismo.
De hecho, mi portátil de penúltima generación con Windows 8 funciona más lento que mi 486 con Windows´95 o mi 086 con Gem Desktop y si lo pienso fríamente me doy cuenta que hace más cosas en apariencia que en realidad.
Ahora los navegadores hacen bastantes más cosas que antaño.
Por supuesto que hacen más cosas, pero no hacen 60 veces más cosas, que es la diferencia en bruto entre 66 y 4.000 Mhz.
En mi opinión, el consumo ineficiente de recursos explica en mayor grado la necesidad de que los usuarios actualicen sus equipos por otros más potentes que el propio desarrollo de las aplicaciones.
En los últimos 10 años las aplicaciones no han mejorado tanto como los requisitos mínimos de los equipos que necesitas para hacerlas funcionar correctamente.
Hodor escribió:Hoy en día un lenguaje de programación ampliamente utilizado en el desarrollo web como Javascript es capaz de ejecutar los mismos juegos que tu 486 y Pentium simplemente a través del navegador.
OsQuiLLa escribió:La verdad que es sorprendente lo que se hacia en la epoca...... yo con lo que alucine bastante es con lo que ocupa el Zelda Ocarina Of time..... creo que eran 32megas....
Una pasadaaa tambien @kusfo79 tu cuando programas lo haces en ensamblador ??
Brocan escribió:@Promis, deja deja, me quedo con Unity o UE4 de lejos
Brocan escribió:@Promis, es un buen comienzo. Yo empecé con ensamblador, luego C, luego C+ensamblador, luego C++, luego Opengl, luego DirectX, luego C#, luego Ogre, luego UE y por último Unity.
Esta muy bien empezar desde abajo y poco a poco, así vas viendo un poco todo lo que se cuece en un engine y como se hace, aunque conforme pasa el tiempo necesitas que te lo den más mascado y tener más posibilidades a tu alcance.
Es el mismo símil que una calculadora, al principio todos aprendemos a sumar, restar, etc... pero cuando aprendemos integrales, derivadas, etc... usamos al calculadora para hacer las cuentas
Mucho ánimo con el aprendizaje, la verdad es que es muy gratificante ver como van saliendo cositas aunque sean sencillitas.
Calculinho escribió:@lestar no estarás confundiendo el Mario Bros con el Super Mario Bros? Porque si bien no es un juego HD con cinemáticas plagadas de explosiones y música orquestal, me parece un análisis bastante injusto describirlo como corto, repetitivo y poca variedad. Especialmente para su momento, que significó más bien todo lo contrario. Yo antes de este Mario para NES tenía Battle City, Pac-Man, los tres Donkey Kong y Tetris. Situándonos en la época, todos estos juegos si son cortos, repetitivos y poca variedad de música. Mario Bros fue el primer juego que contaba una aventura y que al terminar la fase, aparecía una nueva y diferente, esto hoy parece una tontería, pero para la época respecto a lo anterior suponía que al terminar una fase, tenías un juego nuevo en el siguiente nivel.
Sobre la variedad de niveles ya me dirás que más querías en la época respecto a otros juegos teniendo fases de campo, acuáticas, subterráneas, castillo y montaña (setas o aéreas).
Promis escribió:@Brocan
Y encima pudieron vivir muchos años con ensamblador. Se introducirían cosas nuevas pero no cambiaría mucho el cuento.
.
kusfo79 escribió:Promis escribió:@Brocan
Y encima pudieron vivir muchos años con ensamblador. Se introducirían cosas nuevas pero no cambiaría mucho el cuento.
.
Ui, pero en ensamblador, era diferente para cada procesador (Z80, 8086, etc) y encima no te podías abstraer de las características de cada máquina (Mapa de memória, puertos, etc). Yo creo que un programador en ensamblador que pogramase en varias máquinas, debía volverse loco!