Coding NES Subroutines

Поділитися
Вставка
  • Опубліковано 25 чер 2024
  • Learn all about programming subroutines in the 6502 assembly on the NES.
    Support the channel on Patreon: / neshacker
    Code Challenge:
    Submissions will be chosen from the comments through 1/22/2023 and the winner selected and pinned on 2/1/2023.
    Music:
    Evgeny Bardyuzha - Speed Freak
    2050 - Nova
    Luke Melville - After Midnight
    Alchemorph - Raintown (My Love fore You) - Instrumental Version
    Chapters:
    0:00 Introduction
    0:28 Subroutines Explained
    2:07 The Stack
    5:08 Using Parameters
    6:49 Coding Challenge
  • Наука та технологія

КОМЕНТАРІ • 233

  • @aidangarvey7049
    @aidangarvey7049 Рік тому +60

    Here's my submission for the challenge, it's my first time programming in 6502 so there might be mistakes (I'm more familiar with 68K)
    ; =============================================
    ; pickup_refill
    ; ---------------------------------------------
    ; Refills player health or weapon from a pickup
    ; ---------------------------------------------
    ; Parameters:
    ; $00: pickup type (health = 0, weapon = 1)
    ; $01: pickup size (small = 0, large = 1)
    ; ---------------------------------------------
    ; Notes:
    ; - Player's health is stored at $0100
    ; - Player's weapon charge is stored at $0101
    ; =============================================
    pickup_refill:
    ; get pickup type in X so desired player stat is at $0100,X
    ldx $00
    ; load stat value into A
    lda $0100,X

    ; get pickup size, add appropriate amount to A
    ldy $01
    beq small_pickup
    ; large pickup: grant 25 health/weapon
    adc #15
    ; (intentional fall-through to add rest of value)
    small_pickup:
    ; small pickup: grant 10 health/weapon
    adc #10
    ; if we went over 100 health/weapon, limit to 100
    cmp #100
    bmi save_value
    lda #100
    save_value:
    ; store new health/weapon value
    sta $0100,X
    rts

    • @NesHacker
      @NesHacker  Рік тому +15

      Congrats! The patrons chose your code to get pinned! Shout out to the runners up: @dedgzus6808, @kentwidman, and @soulite2574 :D

    • @aidangarvey7049
      @aidangarvey7049 Рік тому +6

      Thank you so much to everyone who voted for me!

    • @CallousCoder
      @CallousCoder Рік тому +4

      That’ll do nicely for sure.

    • @EvilSandwich
      @EvilSandwich Рік тому +7

      One tiny and easily fixable issue. It looks like you're storing the player's health and weapon charge on the Stack Page.
      Just swap out the $0100 and $0101 with $0300 and $0301 and you're perfect! :)
      Great job though!

    • @brighthades5968
      @brighthades5968 Рік тому +4

      @@EvilSandwich Most games don't use the whole stack area so they can store other values there

  • @AndyScott
    @AndyScott Рік тому +149

    I love watching these thinking "one day I'll do this" knowing full well I will not....yet I will watch this kind of magnificently crafted educational lesson all day long.

    • @zzeck431
      @zzeck431 Рік тому +17

      There are online 6502 assemblers and emulators you can use to begin. I used skilldrick easy 6502, because I was too lazy to dig up my cc65 assembler setup.

    • @NesHacker
      @NesHacker  Рік тому +35

      Honestly I just think it’s cool that so many people like the things that I like too :)

    • @dedgzus6808
      @dedgzus6808 Рік тому +6

      I always had the same thought to but then after this video I just opened notepad and wrote up some code. Give it a shot.

    • @InsaneFirebat
      @InsaneFirebat Рік тому +7

      Programming has been an interest of mine since I was young, but it was super intimidating with no formal education. I started off making copy/paste edits in Super Metroid's speedrun practice hack source and eventually started looking up what the opcodes do. Once I started looking into addressing modes, the doors flew open and everything started to make sense. It's been very rewarding and I wish they'd taught me this stuff in elementary school. Hope you can dig in some day. The 65x processors are awesome.

    • @Cubearr
      @Cubearr Рік тому +3

      Honestly and truly: Just start doing it. post about it on rhdn or anywhere else, ask questions, do research, thumb through sections of code and try to understand it. you can make it happen for you, it just takes some focus and a little bit of work. Doing it badly is fine, just doing it at all is fun and rewarding.

  • @MerrStudio
    @MerrStudio Рік тому +47

    Holy crap this channel is underrated AF. Watched the video first, noticed the like count/views second. Both of these should be x100 at least! You just earned a sub sir.

  • @guillermomoreno4287
    @guillermomoreno4287 Рік тому +41

    The editing, information and quality are top notch

    • @NesHacker
      @NesHacker  Рік тому +5

      Thanks, I try my best :)

  • @scottwilliams895
    @scottwilliams895 Рік тому +5

    First time watching your channel. Big ups to your style!
    This video is basically a course mini-lecture on teaching programming, while still being interesting to watch for those of us students who aren't doing the homework.

    • @NesHacker
      @NesHacker  Рік тому +2

      That’s the idea, at least. The hope is that the videos straddle the line between lecture and entertainment, and do it so everyone comes away with something 😀

    • @scottwilliams895
      @scottwilliams895 Рік тому

      @@NesHacker You hit it just right! Half way thru, I was like "Yeah, I *should* learn to program in Assembly... for the NES!! "

    • @CallousCoder
      @CallousCoder Рік тому

      Maybe you’ll like a lot of my content too. I have a rom of C64 and some Amiga now. And also ARM64 assembly on Linux.
      But also game hacking cracking which uses 6502, z80 and 68000

  • @jake967
    @jake967 Рік тому +5

    Outstanding visuals!

  • @3DSage
    @3DSage Рік тому +6

    You make me want to program a NES game! Really great and clear explanation so thank you!

    • @Cr_nch
      @Cr_nch Рік тому +1

      -3d on nes-

    • @NesHacker
      @NesHacker  Рік тому +1

      Nice! It’s definitely work but it is totally doable, just start small and build up from there :)

  • @MrBoogerblood
    @MrBoogerblood Рік тому +4

    I’m addicted to these videos. I have way too many other things going on to ever hope to have time to mess with this too but you’re subject matter presentation is next level. So much info crammed into a 15-20 min video and it doesn’t feel overwhelming. Great job man.

    • @NesHacker
      @NesHacker  Рік тому +1

      Thanks, I put a lot into them so I am glad you like the videos so much 😀

  • @akkoestranha4323
    @akkoestranha4323 Рік тому +6

    I was waiting this so much! Love your videos!

    • @NesHacker
      @NesHacker  Рік тому

      Thanks, I’m happy to oblige :)

  • @repeaterlanes8024
    @repeaterlanes8024 Рік тому +4

    Health: $00FF
    Energy: $00FE
    32 bytes in the zero page for subroutine parameters like you would do.
    1 byte ($0000) actually used for this function. the High nybble (Bits 4 - 7) will be type, the Low nybble (Bits 0 - 3) will be the amount. This method would allow 16 types and 16 amounts in case it will be used elsewhere, however in this case it will be optimised for this challenge
    refill:
    lda #$F0
    and $00 //Obtain the high nybble to dictate what type to add to
    lsr
    lsr
    lsr
    lsr
    tax
    lda #$19 //Load 25 into Accumulator. This is the small amount
    pha
    lda #$0F
    and $00 //Obtain the low nybble to dictate what amount to add to the variable
    beq skip_big_refill //If 0, then it is the small amount, otherwise add 25 to the value to get the medium amt
    pla
    adc #$19 //Add 25 to Accumulator, making the amount from earlier to the medium amount, 50
    pha
    skip_big_refill:
    pla
    clc
    adc $FE, x //Add the corresponding variable (Health or Energy) to Accumulator
    cmp #$64 // check if result is more than 100. if so, set the Accumulator to 100
    bpl skip_clamp
    lda #$64
    skip_clamp:
    sta $FE, x //finally, store the accumulator to the variable
    rts
    (Fair note, its been a while since ive coded 6502 asm, so my syntax might be off. dont really have a way to verify it admittedly but i hope it works)
    (Edit: Forgot to shift the upper nibble parameter 4 times to the left)

  • @sanderbos4243
    @sanderbos4243 9 місяців тому

    Found your channel yesterday while looking for 6502 documentation online, and your 6502 Assembly Crash Course playlist this is part of has been unimaginably helpful to me! I've also got VS Code set up with fceux64 using your tutorial, so it is time to crank out the classic Game of Life! :D

  • @maverick_loneshark
    @maverick_loneshark Рік тому +18

    あけましておめでとうございます、 NESHacker!
    Kind of tied up with attempts at modern, wannabe-retro game dev right now (trying to write a better shader for simulating a high end CRT), but you have me inching closer and closer to doing a NES homebrew game jam.
    Thank you for all of the valuable NES dev info!

    • @NesHacker
      @NesHacker  Рік тому +7

      You’re more than welcome, and happy new year to you too, Maverick!

    • @jimmyraconteur2522
      @jimmyraconteur2522 Рік тому +1

      LOL I love your handle! It reminds me of a character from a Yakuza game!

    • @maverick_loneshark
      @maverick_loneshark Рік тому +2

      @@jimmyraconteur2522 for all we know, *this* IS a game...

  • @Raubritterr222
    @Raubritterr222 Рік тому +2

    I love your NES videos so MUCH! Thank you! 🎮

  • @JustixLoL
    @JustixLoL Рік тому

    Omfg, last month everything I've been doing is digging info about old consoles, especially the NES and programming 6502 cpu. Planned to develop a small NES game to touch it myself for better understanding and HERE YOU ARE - THE HERO! Right in time! Many thanks for you exceptionally helpful material! Please, keep going

    • @NesHacker
      @NesHacker  Рік тому

      The hero, huh? Haha, well I don't know about that, but I am glad I can help!

  • @ajhieb
    @ajhieb Рік тому +3

    What a great start to the year! NesHacker and Retro Game Mechanics Explained posting new videos on the same day!

    • @NesHacker
      @NesHacker  Рік тому +2

      I considered releasing it yesterday… but I was worried people would be too tired to digest 6502 assembly xD

  • @NesHacker
    @NesHacker  Рік тому +3

    Just an FYI: the finalists for the coding challenge have been selected and the poll is up on Patreon. Voting ends Monday (Feb 6th) at 11:59 PM EST, after which I'll pin the winning post here.

    • @dedgzus6808
      @dedgzus6808 Рік тому

      I'd like to nominate my code for its simplicity and because it gets the job done in only 9 lines of code.

    • @NesHacker
      @NesHacker  Рік тому +1

      @@dedgzus6808 That was the very reason I chose you as one of the finalists. But now it's in the hands of the patrons ;D

    • @dedgzus6808
      @dedgzus6808 Рік тому

      @@NesHacker Haha. Thanks. Also for your information, after I finally got myself around to writing those couple of lines of 6502asm it took hold of me and I've been working on getting a "game" working. Currently messing with getting scrolling working. Thanks for the videos.

  • @djrmarketing598
    @djrmarketing598 Рік тому +3

    Funny when you say 6502 assembly the first thing that comes to mind is Commodore 64 programming, but that was 10 year old me back in the day having no idea that 6502's were in just about everything by 1988. Had I been 10 years older I probably could have put all that learning to use professionally, but alas it was my gateway to x86 assembly language. I made so many inline assembly routines inside C and Pascal programs back then, back when every cycle mattered.

  • @ebs777
    @ebs777 Рік тому +5

    I been working on super mario bros hacks on and off for a couple years and even knowing the asm i do now your videos always teach me something new. Thank you so much

    • @NesHacker
      @NesHacker  Рік тому +2

      You’re very welcome, I’m glad to help :)

  • @8_BitKing
    @8_BitKing Рік тому +4

    really nice videos and great animations!

  • @tmanley1985
    @tmanley1985 Рік тому

    I never subscribed so fast in my life. This is incredibly well done.

    • @NesHacker
      @NesHacker  Рік тому

      Nice! This was probably my best editing job thus far, so I hope you like my other videos too.

  • @seanrobertson7122
    @seanrobertson7122 Рік тому +3

    I think you're reaching a good pace/level of explanation with these last few videos... tbh I was a bit worried when inx/dex took up 3 minutes in the first one haha. Great to see the very practical example of using parameters especially.

    • @NesHacker
      @NesHacker  Рік тому +1

      Haha, yeah… Now that I’ve covered a lot of the basics I feel I can go more briskly and use broader strokes without getting bogged down in the details too much.

  • @orti1283
    @orti1283 Рік тому

    Thank you so much for such magnificent content!

    • @NesHacker
      @NesHacker  Рік тому

      Haha, "magnificent" is quite the compliment. Thank you!

  • @caldog20
    @caldog20 Рік тому

    Video is very well put together

  • @Ribiveer
    @Ribiveer Рік тому +25

    I haven't got a lot of experience writing assembly code from scratch, mainly having edited assembly from Super Mario Bros., so this is good exercise for me! Though that Super Mario Bros. is my only real experience with assembly might show a little...
    ; First, let's define RAM values. Starting at $0300 since you did in the video as well.
    ; Though I wonder, why not $0200? The stack ends at $01FF, and I can't find anything about $0200 - $02FF being used for anything. I do $0300 just to be safe, though.
    Bars = $0300 ; This is where the "list" of bars starts. Since it starts at the Health Bar, it's got the same value as it.
    HealthBar = $0300
    WeaponBar = $0301
    ; Somewhere else, we have some values for the amounts to add. These contain values of 10, 20 and 50.
    CapsuleValues:
    .db $0a, $14, $32
    ; This is how this method would be called:
    ldy #$01 ; We load the type of bar to refill. In this case, the weapon bar. Storing it in Y will be useful for our trick coming up.
    ldx #$02 ; We load the amount to refill. In this case, 50. Storing it in X will be useful for our trick coming up
    jsr HandleCapsule ; Onto our subroutine!
    ; Somewhere else...
    HandleCapsule:
    lda Bars,y ; The Y register means that it gets added to the address, so we load the value at $0300 + $01 = $0301, the Weapon Bar, into the accumulator.
    clc ; Prepare for adding by clearing the carry.
    adc CapsuleValues,x ; We do the same trick here: add X to the address of our starting value. In this case, we add 2, so we get the third value from CapsuleValues: $32
    cmp #$65 ; We compare the resulting value with 101
    bcc ExitHandleCapsule ; If A < 101, we're good! We can exit the subroutine.
    lda #$64 ; Otherwise, we're gonna take the value of 100 instead
    ExitHandleCapsule:
    sta Bars,y ; Finally we store our value, be it 100 or something below it, into our designated Bar.
    rts ; We can go back to the previous part in the code, now!

    • @dedgzus6808
      @dedgzus6808 Рік тому +4

      Very similar to my method expect you never push values onto the stack to be sure the registers don't get corrupted. also you used a more rigid amount method.

    • @ClassicTVMan1981X
      @ClassicTVMan1981X Рік тому

      In Super Mario All-Stars (for the Super NES), the lives code for both Super Mario Bros. and Super Mario Bros.: The Lost Levels went like this:
      lda NumberofLives ; load the current player's lives counter
      inc NumberofLives ; increase the lives counter by one if Mario/Luigi collects a 1-UP Mushroom, 100 coins, knocks down eight or more enemies in a row with a Koopa shell or Buzzy Beetle, or stomps on a Koopa shell or Buzzy Beetle at least eight times on a stairstep.
      cmp #$80 ; compare resulting value with 128
      bcc EndCheckL ; if A less than 128, we're fine and we can leave the subroutine!
      lda #$7f ; otherwise, set this value to 127 instead
      sta NumberofLives ; store whatever number we have, be it 127 or lower, into $075A,
      EndCheckL:
      rtl ; and leave!
      (the RTL at the end means "return from subroutine, long" which indicates we can use this subroutine in other program banks; for example, since the code above is originally in bank 4 at address 0x8596, if we want to jump to it in other program banks we use these four bytes: 22 96 85 04, the leading 22 pointing to JSL, or "jump to subroutine, long")

    • @Nat-qm5vb
      @Nat-qm5vb 8 місяців тому +1

      To answer your question way after you asked it, by convention the $0200-$02FF space in RAM is used for sprite data, which gets written directly to the OAM DMA register on the PPU during VBLANK.

    • @Ribiveer
      @Ribiveer 8 місяців тому

      @@Nat-qm5vb Ah, I see. Thank you for answering!

  • @soulite2574
    @soulite2574 Рік тому +4

    My code for the refill subroutine (expanded to avoid people spoiling themselves, ca65 syntax because that's what I'm used to)
    ("params" is a 32 byte variable in the zeropage, +0 +1 etc, are offsets)
    PlayerRefill: ;PLAYER REFILL SUBROUTINE
    ; (params+0: type) - if refill is for health or energy
    ; (params+1: amount) - how much health/energy to refill
    LDA params+0
    CMP #$01
    ;Switch on type (0-Energy Refill, 1-Health Refill)
    BNE :+
    JMP PlayerRefillHealth
    :
    PlayerRefillEnergy:
    ;Add refill to energy
    LDA params+1
    CLC
    ADC playerEnergy ;A = playerEnergy + ammount
    ;IF the result exceeds max energy, set to max energy
    CMP #100
    BCC :+
    LDA #100
    :
    STA playerEnergy
    JMP PlayerRefillEnd
    PlayerRefillHealth:
    ;Add refill to health
    LDA params+1
    CLC
    ADC playerHealth ;A = playerHealth + ammount
    ;IF the result exceeds max energy, set to max energy
    CMP #100
    BCC :+
    LDA #100
    :
    STA playerHealth
    PlayerRefillEnd:
    RTS

  • @trapr00t
    @trapr00t Рік тому +2

    Just love explanation clarity, EXCELLENT VIDEO, can't wait for more! (I eddited and removed INCORRECT stuff about pushing ppu status to the stack, that I writen before to awoid confusion)

    • @michaelbarry8005
      @michaelbarry8005 Рік тому +1

      In my version of reality *BRK* , *IRQ* and *NMI* push the processor status register after pushing the return address (three bytes total), but *JSR* stacks only the return address - 1 (two bytes total).

    • @NesHacker
      @NesHacker  Рік тому +1

      Yeah I am pretty sure JSR doesn't push the processor status. At least according to my 1976 MOS Microcomputers Programming Manual, it doesn't :D

    • @trapr00t
      @trapr00t Рік тому

      @@NesHacker ah, I'm so sorry for the missinformation, I checked it to, and it appears that I truly confused it with NMI I feel embarrassed, for my irresponsible comment before 😳

  • @brandongunnarson7483
    @brandongunnarson7483 Рік тому +1

    I wish I knew the first thing about assembly but this is awesome!

    • @NesHacker
      @NesHacker  Рік тому +1

      Thanks :D, I’m glad you watched the episode anyway, haha

  • @gadgetdeez7069
    @gadgetdeez7069 6 місяців тому

    I know this is an old video but i really like the format. Making the viewer do a little homework for a contest is legit awesome too. Love seeing atuff like this. Only gripe is i feel the vids are a little on the short side. Right when the itch is a out satisfied you pull the plug. Darnit. Lol

  • @jimmyraconteur2522
    @jimmyraconteur2522 Рік тому

    Your videos are excellent!

    • @NesHacker
      @NesHacker  Рік тому +1

      Thank you, I appreciate that :D

  • @keytronic5631
    @keytronic5631 Рік тому +13

    Great to hear that you will do this full time.
    Lovely animations. How are you doing these? What software are you using? manim?
    Also what is your profession before you went all in on this channel?
    Cheers,

    • @NesHacker
      @NesHacker  Рік тому +8

      I use After Effects for the animations along with Photoshop and Illustrator to create most of the graphics. As far as what I did before the channel? It’s a shocker: I was a software engineer xD

  • @consis
    @consis Рік тому

    beautiful vid

  • @thedrunkmonkshow
    @thedrunkmonkshow Рік тому +1

    Thanks so much and now I better understand how this works in Assembly. As someone who's only dabbled with high level languages, I never understood how to replicate variables, Sub Routines and Functions in Assembly. I only knew the JMP command and not the JSR and RTS and i also didn't understand how to pass arguments to and from. There's an online Javascript 6502 emulator so yeah..lemme try building my own like a pixel plotting routine to put this new knowledge into action. 😄

    • @NesHacker
      @NesHacker  Рік тому +1

      You’re welcome, sounds like you’re in for a world of new fun :)

  • @razorbackroar
    @razorbackroar Рік тому +1

    Fav channel

  • @menitoon8759
    @menitoon8759 2 місяці тому

    When will the next episode be released ?
    I want to actually make a NES game !
    But I really love your videos, they're so helpful !

  • @oleschoolgamers
    @oleschoolgamers Рік тому +5

    Crazy editing skills, I think you're videos are as good as your NES explanations haha. What do you use for video editing anyway?

    • @NesHacker
      @NesHacker  Рік тому +2

      Thanks! I use Final Cut Pro to edit. After Effects, Illustrator, & Photoshop for graphics.

  • @Chad_Thundercock
    @Chad_Thundercock Рік тому +1

    4:55
    What, no man - Stack Overflow is always my first go to when I need something obscure sorted out.

  • @kyoobqa
    @kyoobqa Рік тому +6

    For such quality, you are criminally underrated.

    • @NesHacker
      @NesHacker  Рік тому +4

      I guess that’s a lot better than being overrated xD

  • @vakulasan4613
    @vakulasan4613 Рік тому

    Amazing illustrations, great video editing and main - you can see it on "one breath" because every detail is explained. Keep doing so. Good luck. From me like 👍 and subscription🔔)

    • @NesHacker
      @NesHacker  Рік тому

      The plan is to keep going as long as I can ☺️

  • @kayakexcursions5570
    @kayakexcursions5570 Рік тому +7

    ;6502 asm:
    ;refill(x=type, c=amount)
    ;health type x=0
    ;weapon type x=1
    ;c = large amount (64)
    ;nc = small amount (32)
    healthVal = $00 ;players health value
    weaponVal = $01 ;players weapon value
    Refill:
    lda #32 ;set a as small amount
    bcc Small ;branch if small required
    lda #64 ;set a as large amount
    Small:
    clc ;clear carry for addition
    adc healthVal,x ;add a and value
    sta healthVal,x ;store new value
    cmp #101 ;check for overflow
    bcs Max ;branch if over 100
    rts ;return
    Max:
    lda #100 ;set a as max value
    sta healthVal,x ;store max value
    rts ;return
    ;z80 asm:
    ;refill(z flag = type, c flag = amount)
    ;z = weapon type
    ;nz = health type
    ;c = large (64)
    ;nc = small (32)
    healthVal = $0000
    weaponVal = $0001
    Refill:
    ld a,32 ;set a as small amount
    jp nc,Small ;skip multiply if small selected
    rla ;set a as large amount
    Small:
    ld hl,healthVal ;point to health value
    jp nz,Health ;skip increment if health selected
    inc hl ;point to weapon value
    Health:
    add a,(hl) ;add amount to value
    cp 101 ;check for overflow
    ld (hl),a ;store new amount
    ret nc ;return if no overflow
    ld (hl),100 ;set value to max
    ret ;return with max value

    • @kayakexcursions5570
      @kayakexcursions5570 Рік тому +1

      I know I said I was going to make an NES game in a previous comment, but unfortunately I haven't had time. That's going to be my new years resolution I guess, to make an NES game! Currently I only know z80 so I started off with that. I left the z80 in the comment and tried to convert it to 6502 as close as possible. Its my first time using 6502 and I realized using only flags as an input wasn't going to work. Lda modifies the z flag and rol a modifies both the z and c flag. I swapped rol a for lda so I could at least save the carry flag. z80 and 6502 are very similar, just have to forget about the extra registers.

    • @NesHacker
      @NesHacker  Рік тому +2

      Hey it’s no rush, just start small and chip away at it… But most of all, have fun learning and playing around. Hopefully my videos will help along the way, and know that I’m rooting for ya! :)

    • @soulite2574
      @soulite2574 Рік тому +2

      dude really went above and beyond with the Z80 code, respect

    • @tr1p1ea
      @tr1p1ea Рік тому +1

      Z80, nice 😀

    • @kayakexcursions5570
      @kayakexcursions5570 Рік тому

      @@tr1p1ea Haha, I know you trip, Im the assembly bandit.

  • @spearPYN
    @spearPYN Рік тому

    I am Atari 8-bit programmer but the 6502 assembly explanations are top notch.

    • @NesHacker
      @NesHacker  Рік тому

      Atari, C64, and NES programmers are all like cousins. Our choice in console is different, but we all love hacking some 6502 😆

  • @alexeisenhart
    @alexeisenhart Рік тому +2

    This is a great video! What software do you use for your code animations?

    • @NesHacker
      @NesHacker  Рік тому

      I mostly use After Effects.

  • @jumanji4037
    @jumanji4037 Рік тому

    Really nice video and well explained! I’ve been looking for some courses and tutorials for making NES games and your videos have really helped explain the basics. Which resources or websites would you recommend for learning more?
    Thanks and looking forward to your future videos!

    • @NesHacker
      @NesHacker  Рік тому +1

      www.nesdev.org/wiki/Nesdev_Wiki - This has a ton of information on programming the NES, but it can be a little hard to get through at times. I don't have any books in particular to share, sorry.

    • @jumanji4037
      @jumanji4037 Рік тому

      Thanks! I’ll have a look to it.

  • @marcus9374
    @marcus9374 Рік тому +1

    Your videos are great!! Confrats for your work!
    One question I always have is how do things like events are coded using assembly. Examples like “when character touches an enemy, X happens”. The other one would be around types and hierarchy. Are analogies around objetc oriented programming observed somehow in these games code? If not, what are the constructs developers use to represente those concepts?
    Those would be great topics for a future video!

    • @NesHacker
      @NesHacker  Рік тому +1

      It's all done as part of the game loop. An event messaging system would be way to heavyweight to implement with such limited system resources. So you would simply do the checks for everything that "can" happen as part of the main game loop logic. Old-school game programming is quite a bit different than modern game engines.

  • @BainesMkII
    @BainesMkII Рік тому +4

    While I understand wanting to stick to a single concept, it feels like you should have mentioned manually saving and restoring register values with the stack (when necessary) when entering and exiting subroutines.

    • @NesHacker
      @NesHacker  Рік тому +3

      Yeah for sure, it’s always a challenge to figure out what to include and what not to. That’s a super valid and common use for the stack so I should have probably included it!

  • @exxor9108
    @exxor9108 11 місяців тому +1

    The way that you speak and explain how subroutines work, I'd love to hear you explain the note block crash glitch in Super Mario Bros. 3. The one that speedrunners use to jump from world 7-1 to the chamber Princess Toadstool is held in. I say Toadstool because she wasn't named Peach in the US until after Super Mario 64.

    • @NesHacker
      @NesHacker  11 місяців тому

      Oh interesting, yeah that's a pretty good idea. I'd have to do the research first, of course (and be able to pull it off myself so I can get a feel for it xD).

  • @NullUndefined1337
    @NullUndefined1337 Рік тому

    😉 thanks XD nice video perfekt sound ^^

    • @NesHacker
      @NesHacker  Рік тому +1

      Yeah I was pretty happy with the sound design on this one. Glad you liked it! :D

  • @ric8248
    @ric8248 Рік тому

    This tutorials are absolutely awesome, made me instantly like and subscribe. Thank you very much for uploading. And ughh I hate to say this, but for some reason it bothers me to no end how the elements on the screen feel the need to jump whenever they are mentioned! It makes waaay more harm than good. So there you go, sorry for this unsolicited feedback, but it's been killing me lol.

    • @NesHacker
      @NesHacker  Рік тому +1

      So I spend a *lot* of time working on the animations for these videos, usually it is the majority of the work. In some sections I don't want to make things too complicated so the viewer can focus on what I'm saying while using the visual reference to help guide their understanding. That said, leaving still graphics up for too long can make things kinda boring, so I use the jump and camera zooms to keep a sense of motion while focusing on a single shot.
      If I find a better way to do this in the future, I'll certainly use the bounce less and and less :D

    • @ric8248
      @ric8248 Рік тому

      @@NesHacker maybe it's my fault for binge watching all the videos since l discovered your channel yesterday

    • @NesHacker
      @NesHacker  Рік тому +1

      @@ric8248 Haha I find ZERO fault with you binge watching all of my videos 🤣

  • @soulite2574
    @soulite2574 Рік тому +1

    When I'm in an underrated channel challenge and my opponent is NesHacker (insert Squidward glass braking gif)

    • @NesHacker
      @NesHacker  Рік тому +1

      Not gonna lie, it’s unreasonable how happy your comment made me xD

  • @nasrimarc7050
    @nasrimarc7050 Рік тому

    You can imagine that, this game was coded in assembler language by the 90's dev team

  • @Oxxyjoe
    @Oxxyjoe 11 днів тому

    I request a part two, where you walk me through one or two of the subroutines that got submitted in response to this challenge. In particular, also, how Did megaman really handle the refill capsule spawning?

  • @MattHughson
    @MattHughson Рік тому +1

    You mentioned coding your own games in this video a few times. Are there any NES homebrew you've worked on? Or do you do hacks?

    • @NesHacker
      @NesHacker  Рік тому +2

      I’ve done some really small game projects in the past and have been chipping away at a bigger project for a while now, though progress is slow since I started the channel 😂

    • @MattHughson
      @MattHughson Рік тому +1

      @@NesHacker Awesome! I can't wait. Do you post dev updates on the project anywhere that I could follow (twitter, etc)?

  • @vuurniacsquarewave5091
    @vuurniacsquarewave5091 Рік тому

    I think some context is needed to understand how I'd do this. I have a fixed size array of existing objects on the screen. Let's say the game can handle up to 16 of such. So the 16 bytes represent the object ID of the active object. A value of $FF represents that there is nothing in that slot and the game is free to use it for spawning a new object. This could be a bullet, a pickup, or the stage might want to spawn something, whatever the case may be.
    Every frame there is a subroutine called "ObjectHandler" that looks through the 16 ID slots and if the value is $FF it skips to the next one, otherwise it will load a 16-bit pointer with the object ID as the index into the pointer tables (one for the high byte, and one for the low byte) and then jump to that pointer. So now each object can have its behavior defined, but of course I could have the same pointer included in the tables more than once for common stuff. Let's say we're in the "obj_Capsule" routine from either of the four capsule items' object IDs.
    Now as you'll see this code makes a few assumptions and restricts you to the following rules to work properly:
    - The capsule object IDs MUST be arranged in order and their lowest two bits must be 00, 01, 10, 11 in that order.
    - The player's hp and weapon energy must be in two neighboring RAM addresses because we will add the capsules' refill amount to them in an indexed way.
    Starting state of the CPU registers:
    A - undefined, still holds part of the address we loaded
    X - Object ID we currently looked up and jumped to
    Y - undefined
    obj_Capsule:
    txa
    and #%00000011 ; use the low two bits of the object ID as a new index to grab the refill amount
    tay
    and #%00000001 ; create an index to decide if it's hp or weapon energy
    tax
    lda obj_Player_hp,x
    clc
    adc arr_obj_Capsule_refill,y
    ldx @zplocal_currentobjslot ; this is a temporary ZP variable the ObjectHandler uses to know which of the 16 slots it's processing right now, gets incremented after every slot
    lda #$FF
    sta obj_slot,x ; the object 'removes itself from the list of existing objects'
    ; here you could call an init subroutine to start a sound effect of the capsule being picked up
    rts ; goes to the common end point where processing one obj_slot ends
    arr_obj_Capsule_refill:
    .db $02,$04,$02,$04 ; we could have all four capsules have any arbitrary amount that they refill.

  • @meepk633
    @meepk633 Рік тому

    Great animations. What do you use?

    • @NesHacker
      @NesHacker  Рік тому

      I use After Effects mostly

  • @johnmills3864
    @johnmills3864 Рік тому

    Whooo !

  • @thanhvinhle2893
    @thanhvinhle2893 Рік тому +1

    struct capsule{
    uint8_t type:1;
    uint8_t amount:7;
    }
    And then a function with parameter is that struct...
    Oops, sorry wrong language 😅

  • @ChrisBouchard
    @ChrisBouchard Рік тому +2

    I know in some architectures it's common to pass parameters and return values on the stack. E.g., push on the arguments before the JSR, and then write in the return value before the RTS. This has the benefit that subroutines are reentrant, but does eat up more stack space. Is this style used at all in NES programming?

    • @dedgzus6808
      @dedgzus6808 Рік тому

      When JSR is called it pushes the address for the RTS onto the stack so you would have to pull that address off of the stack, store it, pull your parameters, store them, run your subroutine, push the return onto the stack and then load your return address, push it onto the stack and then call RTS. I don't know why anyone would do it that way but I am no expert.

    • @ChrisBouchard
      @ChrisBouchard Рік тому

      @@dedgzus6808 In that calling convention, you would push your arguments before the JSR, and then read them by offset relative to the stack pointer inside the subroutine. (Though as I write this I'm not actually sure if the 6502 has stack-relative addressing. Without that, this would be painful, as you say.)

    • @ChrisBouchard
      @ChrisBouchard Рік тому

      Reading more, I see that 6502 doesn't have native stack-relative addressing - so yeah, maybe this calling convention wouldn't be very popular for NES programing.
      I guess in theory you could move the stack pointer into the X register and use it to do indirect addressing. So you could do something like
      TSX ; Copy stack pointer into X. (I'm assuming that it points to the top of the stack -- if it points to the next free location, we need an extra INX.)
      INX ; Point one byte below stack pointer, first argument
      LDA $100,X ; Load argument
      INX ; Move pointer to next argument
      CLC
      ADC $100,X ; Add it to the second argument
      I suppose it would be easier to achieve reentrancy by passing arguments by known address and having the convention that the caller must preserve and restore those memory locations.

  • @mykalimba
    @mykalimba Рік тому

    If your subroutine is simple/straightforward enough, you can often pass arguments in registers!

    • @NesHacker
      @NesHacker  Рік тому

      True, and super useful sometimes!

  • @scottwilliams895
    @scottwilliams895 Рік тому

    Your content & production quality far exceeds your current # of Subscribers.
    2023-01-29: 20.8K
    I expect that number will grow very quickly.

    • @NesHacker
      @NesHacker  Рік тому

      I think you might be right...
      2023-01-31: 21.2K

  • @mykalimba
    @mykalimba Рік тому

    For me, and possibly many other "old school" coders who got started on 8-bit home computers, calling too many subroutines in assembly language will always be the first thing that comes to mind when I hear the term "stack overflow". These days, most coders know "stack overflow" only to mean that website you go to when you don't know how to solve a coding problem and you need someone else to do it for you. :D

    • @NesHacker
      @NesHacker  Рік тому

      Mhm, I figured some of the newer folks wouldn’t know the term’s origin. So it was a fun thing to throw in there :)

  • @michaelbarry8005
    @michaelbarry8005 Рік тому

    Nicely done. At 3:30 you show the low byte of the return address being pushed first, which is incorrect, but only significant if you are doing low-level stack manipulation or manually constructing and pushing your own "return addresses" like Woz did in Sweet-16 and the Apple ][ monitor ROM.

    • @NesHacker
      @NesHacker  Рік тому

      Oops, yeah it's high-byte then low-byte of return address, right?

  • @Diablokiller999
    @Diablokiller999 Рік тому

    Maybe you should've said something about saving registers before entering a subroutine?
    Otherwise the subroutine could overwrite stuff you are currently calculating/using :D
    Also you can use the stack to transfer parameters or return values fast, since it uses only one clock cycle on most architectures.

  • @grendell
    @grendell Рік тому

    Any guidance for when to use a subroutine/.proc and when to use a macro? Am I correct in guessing that macros function similarly to C, with simple text replacement?

    • @NesHacker
      @NesHacker  Рік тому +2

      Macros can get really *really* tricky if you use them too much… I plan on doing an episode about my take on them, but here’s the TL;DR: if it’s something where you’d have to write out all the code anyway (e.g. setting parameters for a routine, etc.) then use a macro. If you absolutely have to save the cycles it would cost to perform the JSR and RTS *and* you can significantly improve the readability of your code then use a macro. Otherwise, stick with subroutines.

  • @Kaijuking84
    @Kaijuking84 Рік тому

    First of all what an Awesome channel. And secondly, I'm just gonna throw this out here I'm in school for computer programming and working full time with a family to support. Does anyone know of any resources I could use to help with my studies, I'm not a slow learner, but working full time trying to support my family kinda puts my brain on the fryer, some I'm looking for any resources I can find audiobooks, anything, something I can multi-task with while I'm working.

  • @majinnaibu
    @majinnaibu Рік тому +1

    Why don't you use the stack for parameters/return values/local vars? Is there some larger problem with recursion on the NES that makes it not matter? Or maybe a lack of a good way to address the memory relative to the stack pointer?
    Cool tutorials by the way. I haven't touched asm in like 20 years.

    • @NesHacker
      @NesHacker  Рік тому

      You can use the stack to hold params, but it's kinda annoying since the jsr instruction pushes the return to the stack. So best case scenario you'd be pulling the stack pointer into the X register and doing some weird offset loads and then finally having to pop them off at the end. Not too bad, but if you're doing something where cycles count (like rendering during a PPU vblank) then it might bite you.

  • @luxuryhomes8889
    @luxuryhomes8889 Рік тому

    so if the control flow has a routine and savor tine executing the task for the 16-bit on the stack??? i think im getting it

  • @saltymashedpotatoes
    @saltymashedpotatoes Рік тому +1

    Piece of cake.

  • @mikethered123
    @mikethered123 Рік тому

    Any tips for knowing “where” you are without knowing the memlocs/memory map? How does it know when to “interrupt” “normal” routines and do graphics? What about slow down?

    • @NesHacker
      @NesHacker  Рік тому

      Kinda, so the return values for each routine call will be pushed to the stack and the vectors that define the entry points for interrupt handlers are always located in the same spot of the ROM ($FFFA-$FFFF). It’s a little complicated but if you pause a program at any point you can work out if you’re in the “main” thread or an interrupt handler by working backwards through the call stack until you get either to the main loop or a handler. Though it’s possible to write code that obfuscates this by jumping into an interrupt handler and jumping out before the RTI.

  • @cron93
    @cron93 Рік тому

    I do web programming, but if I wanted to get into this, is there a way to get the old source code for NES games and run them on a local computer?

  • @ssygon2
    @ssygon2 Рік тому

    4:38 JSR many times without returning = stack buffer overflow 😂

    • @NesHacker
      @NesHacker  Рік тому

      Just write a recursive routine without a base case 😛

  • @BillAnt
    @BillAnt 10 місяців тому

    So what happens if a subroutine pushes more data onto the stack without popping it off before reaching the RTS? Would that mess up the RTS address? Gotta love a StackOverflow.... the programmer's website that is. ;)

  • @lapalourde75
    @lapalourde75 Рік тому +1

    👍
    You use nesasm3 like compiler?
    Thanks

    • @RandyFortier
      @RandyFortier Рік тому +2

      He posted a video which walks you through the environment setup. I recommend checking that out.

    • @NesHacker
      @NesHacker  Рік тому +1

      I use ca65 which is part of the cc65 suite. Like Randy said, check out my “NES Development Environment” video and I show the tools I use (for the most part, I mostly use Mesen now over FCEUX).

    • @lapalourde75
      @lapalourde75 Рік тому

      @@NesHacker 👍😃

  • @akko8210
    @akko8210 Рік тому

    Hey! I got a Quick question in 1:19 in one of the lines of the code shows this: bpl :+ .What is this about?

    • @grendell
      @grendell Рік тому +1

      bpl is "branch on plus" or "branch on positive", and ":+" refers to the next label in the code, so that bpl :+ looks at the result of the sbc, cmp's it to the value at $301, and skips the lda #0 if it is greater, presumably to avoid health going negative/underflowing. Hope that helps!

    • @akko8210
      @akko8210 Рік тому +1

      @@grendell Thx man

    • @NesHacker
      @NesHacker  Рік тому +1

      You’re great @grendell, I’ve been shooting video all day and was finally taking a moment to come answer this and boom! You had me covered :)

    • @DarkKodKod
      @DarkKodKod Рік тому

      Just to add to this answer. :+ refers to the next label. :++ is for the second next label, :- is to go back to the previous label. Usually you use unnamed labels to avoid collisions for some trivial code flow. Like a loop or just whatever you want that you think you don't need to name the label for whatever reason.

  • @ClergetMusic
    @ClergetMusic Рік тому +1

    What is the synth piece playing ca. 5:45?

    • @NesHacker
      @NesHacker  Рік тому +1

      I think that’s “After Midnight” by Luke Melville. Just so you know, I usually put new songs I use in videos in the description for the video, ordered by when they’re played in the video :)

  • @2lt.hyakutaro382
    @2lt.hyakutaro382 Рік тому

    My solution (although late for the challenge)
    I use the following memory locations:
    ; $00: character's health
    ; $01: character's energy
    ; $02: type param (=0 for health, =1 for weapon)
    ; $03: big/small param (=0 for small capsule, =1 for big capsule)
    capsule_values:
    .byte 20, 50, 30, 60
    ; small health, big health, small energy, big energy
    refill:
    lda $02
    asl
    adc $03
    tax
    ldy $02
    lda $00, y
    adc capsule_values, x
    cmp #100
    bcc :+ ; if health(or energy) >= 100
    lda #100
    :
    sta $00, y
    rts

  • @LBXZero
    @LBXZero Рік тому +2

    From memory of my assembly language class, shouldn't there be other stack related instructions to store register values to the stack? One of the issues of jumping around to functions and subroutines is your subroutine interruption may involve using a register that already holds data that needs to be restored when jumping back to the parent loop. Of course, we can say that not saving important register outputs to memory in a timely manner is a bad thing as well as your parameter could be a value stored in a register for immediate access. But I will say when you jump around to subroutines, knowing the instructions to push register values on the stack and popping back into place is important.

    • @NesHacker
      @NesHacker  Рік тому +1

      It’s a good point, I considered going in-depth on the stack related registers but I felt it would drag the video a little off topic. That said, no reason I couldn’t do a follow up to give the stack a little more love :)

    • @LBXZero
      @LBXZero Рік тому

      @@NesHacker I figure you will have a whole video in regards to the stack and all that fun.

  • @RetroCheats
    @RetroCheats Рік тому

    I usually write game genie codes.

    • @NesHacker
      @NesHacker  Рік тому

      That makes sense, you know… considering 😂

  • @yod1213
    @yod1213 Рік тому

    @NesHacker Can you do some SNES videos? Im especially interested in the SNES's sprite handling capabilities, because I always though that it was rather weak showing considering its specs.

    • @NesHacker
      @NesHacker  Рік тому

      I’m hoping to dip into some 16-bit content in the future, I’ll keep you and your wanting to see how sprites work in mind when I do

  • @renecura
    @renecura Рік тому

    I understand that you put the parameters in ram for clarity, so this comment is just to add a bit of info. In general, the parameters goes to the stack to be in some way just for the subroutine. And more, you can make recursive subroutines.

    • @NesHacker
      @NesHacker  Рік тому +1

      No, I put them in the RAM because this is how it is usually done when writing 6502 by hand. If you're working on compiler for a higher level language, this would probably be the way to handle them, but when programming in assembly this would rarely, if ever, be done.

    • @renecura
      @renecura Рік тому

      @@NesHacker indeed, that is what a compiler does in general. I wonder why is this strategy not preferred when writing asm by hand.

    • @NesHacker
      @NesHacker  Рік тому +1

      @@renecura Mostly because of cycle overhead. Using stack manipulation instructions to manage the parameters on the stack adds a lot of cycles. The 2A03 (modified 6502) on the NES clocks in at 1.79 MHz on NTSC, which is really slow. Considering some operations, like VRAM updates, need to be done in roughly 2500 cycles and every little bit of optimization counts.
      Further, I think doing it that way causes your code to become *less* readable. Since you don't often need recursion, and most subroutines are *not* general purpose. It's best to simply map out the parameters to RAM for the application in most cases, as opposed to using a general purpose approach.

    • @renecura
      @renecura Рік тому

      @@NesHacker great! Ty for the explaination!

  • @Archeious
    @Archeious Рік тому +1

    When passing the parameters why does you just push the parameters onto the stack? That is what we would do on old school x86 processors (and I think happens on current processors). I am not familiar is 6502.

    • @NesHacker
      @NesHacker  Рік тому

      Well you could, but there’s the issue that they’d be pushed prior to the JSR, so you’d have to do some bespoke stack handling to manage them along with the return address. The approach works fine, but it’s a lot easier to handle parameters in the zero page, especially if you don’t need a generalized and flexible approach (which is usually the case when writing 6502 assembly by hand).

  • @Lilithe
    @Lilithe Рік тому

    Solution:
    - 0 page has a table of value, 1-byte address (within 0 page)
    - routine takes a single byte, split into bits, each bit representing one of 8 stats to effect
    - routine starts by multiplying the active bit in the input byte by 2 byte address spaces within the table (each table entry has 2 bytes, a value and an address)
    - routine loads the target byte within the 0 page, based on the target address from the table, with the value from the table
    - return
    Does that work?

  • @Cyberfoxxy
    @Cyberfoxxy Рік тому

    So you'd need to write a parameter stack too to use nested subroutines.

    • @NesHacker
      @NesHacker  Рік тому

      If you wanted a generalized approach, like an ABI for use by a compiler, you’d basically have to do that. A simple solution would be to have stack frames based on lexical levels to keep track of all the variables in a systematic way based on call.
      In practice when writing programs at the assembly level you don’t often need to go that deep. For instance, you can store variables elsewhere temporarily when you need to free up the parameter space.

  • @darkseid2584
    @darkseid2584 Рік тому

    I almost clicked on the back btn after hearing this 00:27

  • @JarppaGuru
    @JarppaGuru 4 місяці тому

    6:58 i have know idea. im here learn LOL load value jump routine that do something with it- mean load 2 value(parameter) do something in subroutine based on parameter. thats that? i passed without coding

  • @leandrormor
    @leandrormor Рік тому +2

    I'm trying to paste either my code or my link but they are not showing up =|

    • @NesHacker
      @NesHacker  Рік тому +1

      Hmm… not sure what could be happening. Others have been able to post their code 🤔

    • @leandrormor
      @leandrormor Рік тому

      @@NesHacker I got it, yt was filtering out if my code contains a link to .asm file

  • @kez963
    @kez963 Рік тому

    Can I program nes using apple iic? 😅

  • @technomicah
    @technomicah Рік тому +1

    ;I'm new at 6502 assembly, but I think I know a simple method for health/weapon refill subroutine
    currentHealth = $0300 ;current health value
    currentWeapon = $0301 ;current health value
    refillType = $0444 ;Refill type parameter. 0 is health and 1 is weapon refill
    refillAmount = $0445 ;Refill type parameter, small is 16 and large is 32
    capsule:
    ldx refillType ;load refill type to X, making it the health/weapon modifyer
    lda currentHealth,x ;load current health/weapon to A
    clc
    adc refillAmount ;add refill amount to current health/weapon value
    cmp #$64 ;new value vs max value, max is 100 or 0x64
    bcc :+ ;more than max? From the NES loops video
    lda #$64 ;we've exceeded max, load max value of 100 instead
    :sta currentHealth,x ;store new health/weapon level to RAM
    rts
    ;I've edited it a couple times as my understanding for 6502 gets clearer
    Prior to watching your videos I really had no idea on how 6502 assembly code worked. I've learned alot from watching your videos.
    This last video really challenged me to actually apply what I've learned. I'm amazed that I was able to come up with a solution that seems to make sense to me... Hope it makes sense.
    Thank you for your amazing videos!!! They've really satisfied a 30+ year desire to know how those old games worked. Looking forward to more. I'd like to some day edit the famicom game Convoy No Nazo to actually be playable

    • @technomicah
      @technomicah Рік тому

      ;After thinking about this for a couple of days, I think this routine should handle all the power-up items.
      ;I'd like to clean this up while its on my mind
      ;I'll store the current power-up item info in one masked byte @$0444
      ;Edit, I forgot the Etanks
      currentHealth = $0300 ;current health level
      currentWeapon = $0301 ;current weapon level
      currentLives = $0302 ;current number of lives left
      currentEtanks = $0303 ;current number of etanks left
      collectedLetters = $0304 ;One byte that has the high 4 bits for the Beat letters collected and we can use the remaining 4 bits for something like the power balancer from MM6
      powerUp = $0444 ;power-up
      ;Weapon/health-up when bit1 is set, bit0=weapon/health modifier (0 is health and 1 is weapon) and bit4/5 determine if its +16 or +32 weapon/health-up
      ;1-Up/Etank when bit2 is set, bit0 1=Etank, 0=1-Up, the other 6 bits arnt used in this case
      ;Beat letter (or power balancer) when bit3 is set, bit7=B, bit6=E, bit5=A, bit4=T, bit0=Power Balancer
      power-up:
      lda powerUp ; load powerUp byte to A
      and #$02 ; begin checking if its a health/weapon-up by looking at bit1
      beq :Other Item ; if A is 0, branch to then check what kind of item it is
      lda powerUp ; load powerUp byte to A again
      and #$01 ; determine if its a health/weapon-up by looking at bit0
      tax ; store result of A in X as our health/weapon modifier
      lda powerUp ; load powerUp byte to A for a 3rd time
      and #$30 ; so we get only the increase value of +16 or +32
      clc
      adc currentHealth,x ; refill current health/weapon, offset by X
      cmp #$64 ; is the new value more than 100?
      bcc:+ ; branch over the next line if the carry is clear, meaning that adding the refill didnt exceed 100
      lda #$64 ; load 100 (max refill) to A, we wont run this line unless we've met or exceeded max refill of 100
      :sta currentHealth,x ; store new health/weapon amount after adding refill
      jmp End Sub-routine: ; jump to the end of the sub-routine
      Other Item:
      lda powerUp ; load powerUp byte to A, again
      and #$08 ; begin checking if its a BEAT letter or Power Balancer by looking at bit3
      beq :Add 1-Up ; if A is 0, then item must be a 1-Up/Etank by process of elimination, jump to that code to finish it up
      lda powerUp ; load powerUp byte to A for the third time (didn't I say that already?)
      eor #$08 ; Exclusive Or out the bit that identifies it being a Beat/power balance item
      clc
      adc collectedLetters ; the location in RAM would have the same bit mask BEAT---(PowerBalancer), so I think adding it is okay, non?
      jmp End Sub-routine: ; jump to the end of the sub-routine

      Add 1-Up:
      lda powerUp ; load powerUp byte to A, again
      and #$01 ; check if its a 1-up/Etank by looking at bit0
      tax ; store result of A in X as our 1-Up/Etank modifier
      inc currentLives, X ;increment lives or Etanks if X is 1
      End Sub-routine:
      rts ; return from sub-routine
      ; I think that should do it. This time took me less time than the first

  • @dedgzus6808
    @dedgzus6808 Рік тому +3

    I've never written any 6502 asm before but here ya go. Sorry if there are syntax errors and I tried to comment so you'd understand the addresses
    apply_item:
    ldx $01 ; $0001 is 0 for health, 1 for weapon
    lda $0300,x ; $0300 is address for health, $0301 for weapon
    clc
    adc $02 ; $0002 is amount
    cmp #100 ; check if it's over 100
    bcc :+
    lda #100 ; if so set to 100
    : sta $0300,x ; store the result
    rts
    edit: removed pushing and pulling from stack as it is not assumed that it is done

    • @dedgzus6808
      @dedgzus6808 Рік тому

      Any and all feedback would be welcome.

  • @DobinSergei
    @DobinSergei 10 місяців тому

    You didn't cover here saving and restoring registers values before and after subroutines. Without that, people get stuck in simplest task.
    For ex. if you use registers X or Y as a counter in loop, then JSR, where you definitely will change them, it will break everything.

  • @zzeck431
    @zzeck431 Рік тому +1

    I used skilldrick's easy 6502
    define SMALL 2
    define LARGE 10
    define HEALTH 0
    define ENERGY 1
    define HEALTH_ADDR 2
    define ENERGY_ADDR 3
    LDA #HEALTH_ADDR
    STA 0
    LDA #0
    STA 1
    LDA #100
    STA HEALTH_ADDR
    LDA #1
    STA ENERGY_ADDR
    LDA #LARGE
    LDY #ENERGY
    JSR meters
    ;for checking result in debugger registry dump
    LDA ENERGY_ADDR
    BRK
    ;A passes container size, SMALL or LARGE
    ;Y passes container type, HEALTH or ENERGY
    meters:
    CLC
    ADC (0), Y
    CMP #100
    BCC less_max
    LDA #100
    less_max:
    STA (0), Y
    RTS

  • @xs6819
    @xs6819 Рік тому

    You still write code for that old stuff!!!!!

    • @NesHacker
      @NesHacker  Рік тому

      Yeah it’s fun, there’s a whole hobby community of folks that do 😁

  • @sunxnes
    @sunxnes Рік тому

    print "Hello World!"

    • @NesHacker
      @NesHacker  Рік тому +1

      I’m afraid that’s gonna cause a buffer overflow, you forgot the null character at the end! ;D

  • @SuperNickid
    @SuperNickid 4 місяці тому

    @NESHacker: Could you explain the reason why sometimes because of a glitch in the game, the game can execute the X-cordonate of sprite as program code. ua-cam.com/video/l-oUiG3yJE8/v-deo.html The stack did over flow into my capture card that is what cause the excessive corrupt graphic, the excessive corrupt graphic where not part of the game. My capture card is fine, it did not break it, and my capture card is still working properly. The JSR instruction place with the shell is JSR $8F$E3 Since the X of sprite start on $0090 that is mario X postion, $0091 X postion of the last enemies that spond if the other 4 are full. So the $0093 sprite cordinate de-spond at X coordinated $20, the $0094 at X coordinated $E3 and then $0095 at X coordinated $8F.

  • @Waferdicing
    @Waferdicing Рік тому

    💚🖤🖤🤎❤️💙💙💜😆

  • @ashlandwithouttheshd
    @ashlandwithouttheshd Рік тому

    Stacks are FIFO not FILO

    • @NesHacker
      @NesHacker  Рік тому

      Queues are FIFO (First-In First Out). Stacks are very much FILO or LIFO (First-In Last-Out, or Last-In First-Out).

    • @ashlandwithouttheshd
      @ashlandwithouttheshd Рік тому

      @@NesHacker you’re right. Looking at this again idk what I was thinking when I posted that

  • @hugeuglygorillaz9599
    @hugeuglygorillaz9599 Рік тому

    Well, dammit... I get why the website is called "Stack Overflow" now. Nerds are weird. Lol

  • @joevaghn457
    @joevaghn457 Рік тому

    Why the f*ck do you sound so much like swankybox XDDDD

    • @NesHacker
      @NesHacker  Рік тому

      I don't know who that is 🤔

  • @kentwidman
    @kentwidman Рік тому +8

    It was fun messing around with how to structure the refill code and subroutines. This is what I came up with using your starting template:
    .export Main
    .segment "CODE"
    .proc Main
    ; Current healthbar value
    ldx #10
    stx $0300
    ; Current weaponbar value
    ldx #50
    stx $0301
    ; Call health/weapon refill subroutines.
    jsr small_health_refill ; after routine: healthbar = 18, weaponbar = 50
    jsr large_health_refill ; after routine: healthbar = 48, weaponbar = 50
    jsr large_health_refill ; after routine: healthbar = 78, weaponbar = 50
    jsr small_health_refill ; after routine: healthbar = 86, weaponbar = 50
    jsr small_weapon_refill ; after routine: healthbar = 86, weaponbar = 58
    jsr large_weapon_refill ; after routine: healthbar = 86, weaponbar = 88
    jsr large_health_refill ; after routine: healthbar = 100, weaponbar = 88
    jsr large_health_refill ; after routine: healthbar = 100, weaponbar = 88
    jsr small_health_refill ; after routine: healthbar = 100, weaponbar = 88
    jsr small_weapon_refill ; after routine: healthbar = 100, weaponbar = 96
    jsr large_weapon_refill ; after routine: healthbar = 100, weaponbar = 100
    rts ; End of Main
    small_health_refill:
    ; load parameters for refill subroutine
    ldx #0 ; type = health
    stx $00
    ldx #8 ; amount = 8
    stx $01
    jsr refill
    rts ; End of small_health_refill
    large_health_refill:
    ; load parameters for refill subroutine
    ldx #0 ; type = health
    stx $00
    ldx #30 ; amount = 30
    stx $01
    jsr refill
    rts ; End of large_health_refill
    small_weapon_refill:
    ; load parameters for refill subroutine
    ldx #1 ; type = weapon
    stx $00
    ldx #8 ; amount = 8
    stx $01
    jsr refill
    rts ; End of small_weapon_refill
    large_weapon_refill:
    ; load parameters for refill subroutine
    ldx #1 ; type = weapon
    stx $00
    ldx #30 ; amount = 30
    stx $01
    jsr refill
    rts ; End of large_weapon_refill
    ; refills heathbar or weaponbar located at $0300 or $0301
    ; params (type $00, amount $01)
    ; type == 0, setting heathbar
    ; type == 1, setting weaponbar
    refill:
    ldx $00 ; x is use as an offset for heathbar or weaponbar.
    lda $0300, X ; load heathbar or weaponbar
    clc
    adc $01 ; Add refill amount
    cmp #100 ; make sure new health/weapon value is not over 100
    bcc skip_refill_limit
    lda #100 ; set health/weapon value to 100
    skip_refill_limit:
    sta $0300, X ; set final amount for health or weapon bar.
    rts ; End of refill
    .endproc

    • @strayling1
      @strayling1 Рік тому

      Looks good to me. This should be pinned.

  • @matsbjnnes366
    @matsbjnnes366 Рік тому

    Far from optimal, but after lots of debugging it seems to work as intended! The pickup data is controlled by the byte $00. The LSF controls the pickup size (0 means small, 1 is big) and the one to the left controls pickup type (0 is energy, 1 is health)
    ```
    ; Memory Map
    ;
    ; Zero Page:
    ; $00 -> $1F - Parameters
    ; $20 -> $2F - Player Data
    .export Main
    .segment "CODE"
    .proc Main
    ; Player Health - Address $20
    lda #50
    sta $20
    ; Player Energy - Address $21
    lda #50
    sta $21
    ; Pickup small health orb
    lda #%00000010
    sta $00
    jsr Pickup
    rts
    .endproc
    ; Refill pickup - params in zero page $00
    Pickup:
    ; Mask lsb - Pickup Size
    lda $00
    and #%00000001
    ; Test bit - 1 means big
    cmp #1
    beq big
    bne small
    big:
    clc
    ; Mask second bit - Pickup Type
    lda $00
    and #%00000010
    ; Test bit - true means health
    cmp #2
    bne :+
    ; Health Pickup
    lda #30
    adc $20
    sta $20
    rts
    ; Energy Pickup
    :lda #30
    adc $21
    sta $21
    rts
    small:
    clc
    ; Mask second bit - Pickup Type
    lda $00
    and #%00000010
    ; Test bit - true means health
    cmp #2
    bne :+
    ; Health Pickup
    lda #15
    adc $20
    sta $20
    rts
    ; Energy Pickup
    :lda #15
    adc $21
    sta $21
    rts
    ```

  • @Octal_Covers
    @Octal_Covers Рік тому

    ; Here's the code I came up with
    ; Note: I'm a bit rusty with 6502 assembly, as the last time I did it was in 2019
    ; How did I do?
    ; A: xxxxxxyy
    ; most sig y: type (0 -> health, 1 -> power)
    ; least sig y: value (0 -> small [5], 1 -> big [10])
    refill:
    ; Push A to stack to store value
    pha
    ; Check size bit
    and $01
    cmp $01
    bne reAmEl
    ; Big
    ldx #0A
    jmp reAmEn
    ; Refill Amount Else
    reAmEl:
    ; Small
    ldx #05
    ; Refill Amount End
    reAmEn:
    ; Pull A from stack to get value
    pla
    ; Check type bit
    and $02
    cmp $02
    bne reTyEl
    ; Energy
    stx $01
    jmp ReTyEn
    ; Refill Type Else
    reTyEl:
    ; Health
    stx $00
    ; Refill Type End
    reTyEn:
    rts

  • @iDontProgramInCpp
    @iDontProgramInCpp Рік тому +1

    This should work..
    ; refill(type, amount):
    ; How to call:
    ; pha