timers !?

Mugi

Member
okay, im just too stupid for this apparently, but i can't seem to figure out how to make a timed delay on code execution.

Im working on the scrolling platformer module, and in that module, the health pickup script was empty, so i quickly wrote my own,
it's like this:

Code:
    LDX player1_object
    LDA Object_health,x
    CMP #$08
    BEQ skipGettingHealth
healthCheckLoop:
    INC Object_health,x
    CMP #$08
    BNE healthCheckLoop
skipGettingHealth:
    RTS

super simple, no problem, it checks if i have 8 HP, if not, it adds one and rechecks until i have 8HP.

what i wanted to do was add a delay, so that it would wait.... say, half a second between each loop it does on the health check, making it look like it gradually fills the HP bar instead
of being instantaneous.
I've been digging up the code trying to see if a timer similar to what i need is used somewhere and how to utilize it, but i couldn't get it to work.

plz hlep :p
 

dale_coop

Moderator
Staff member
Yeah it's not easy, timers... I don't feel comfortable with that too (even if I deal with it, everyday, in modern programming languages).
You should take a look at the HandleGameTimer.asm script. And maybe call your subroutine from there.
 

Mugi

Member
i tired to mess with it but all i managed to do was make the game freeze when i pick up the health while not having full HP :p
 

Kasumi

New member
It's probably much easier (and less prone to bugs) to make your HUD delay displaying the actual value, rather than delaying adding to the actual value. Why? Imagine I pickup health. I run into something that hurts, but doesn't kill me. It takes some health. My health is below 8, so more gets added. I can just keep running into it forever, since my health will never stop getting refilled until it's totally filled.

But also, the health pickup itself doesn't need to affect anything over multiple frames.

So the first step. Simplify health pickup to this:
Code:
 LDX player1_object
 lda #8
 sta Object_health,x
    RTS
Second step. Add HudHealth (or something like that) as a variable.
Third step. Use HudHealth instead of Object_health,x as the input value for the HUD. (I know your HUD is custom, so it depends. I made a kind of example below, but obviously not exact.)
Code:
;LDX player1_object;Use delayed RAM instead of the direct value.
;lda Object_health,x;Use delayed RAM instead of the direct value.
lda HudHealth
sta whereverthehudloadsfrom

Fourth step. Modify the above so it adds one if they're different.
Code:
ldx player1_object
lda Object_health,x;If player health is less than HUD health, branch and just use player health.
cmp HudHealth
bcc hudhealthstore
;If here, player Health is greater than or equal to HudHealth
beq hudhealthstore;If equal, we don't want to add to HudHealth, it already matches
;If here, player Health is greater than HudHealth. Our player (probably) picked up health recently.
lda HudHealth
clc
adc #1
hudhealthstore:
sta HudHealth
sta whereverthehudloadsfrom
That will add one value every frame. If you wanna do slower, you can add another variable and do something like:
Code:
ldx player1_object
lda Object_health,x;If player health is less than HUD health, branch and just use player health.
cmp HudHealth
bcc hudhealthstore
;If here, player Health is greater than or equal to HudHealth
beq hudhealthstore;If equal, we don't want to add to HudHealth, it already matches
;If here, player Health is greater than HudHealth. Our player (probably) picked up health recently.
lda HudTimer
clc
adc #$01
sta HudTimer
and #%00000011;Will only add every fourth frame
bne skipaddhud
lda HudHealth
clc
adc #1
hudhealthstore:
sta HudHealth
skipaddhud:
lda HudHealth
sta whereverthehudloadsfrom

You can probably use gameTimer instead of the new variable HudTimer, but I haven't researched enough to be really sure. This also assumes your HUD code runs once every frame, but it probably does. If it doesn't you just need code like that anywhere that runs once every frame.

Edit2: By "use gameTimer", I mean for the same purpose. But it'd look like:
Code:
;If here, player Health is greater than HudHealth. Our player (probably) picked up health recently.
lda gameTimer
and #%00000011;Will only add every fourth frame
bne skipaddhud
lda HudHealth
That is, no add or store. (Since the game already does that.) Figured I should make that clear.
Edit: Forgot an instruction.
 

Mugi

Member
i dont think the delay on filling it is a problem, in my game, health platforms are placed in sparingly, and in locations that are less, monster filled.
the idea was also to make the delay quite short, so that going from 1 HP tp 8 HP would take a second, maybe a bit more at most.

i will have to mess with that code, but unless there is a little shorter way to do it, i might just ditch the whole idea alltogether, that is way too much spent code space for such a minor visual effect really.

at any rate, i put off the whole timer thing for now as i ran into a brick wall with my health platform code to begin with.
i made a health item as above, that works just fine (this is object 04, health pickup)

then i made a health platform tile that spawns object 04 if your health is not full and you press down while standing on it.
that also works.

for some reason though, if you pick up that object 04 that the tile spawned, the game freezes, and i have no idea why lol. been struggling with it for some hours now.

edit: nevermind, i just removed the healthCheckLoop from the above code and just made it set your HP to 8 if it's not 8, and now everything works.
now i'll get to play with the timer :p

the cool part with the whole design of "health platforms" is that it's a tile, so i have a free object to use elsewhere now ^__^

thanks for the timer code btw, as i thought, it's like way above my assembly skills to write that stuff :p
 

Kasumi

New member
There would have to be no potential to get hurt at all while health refilling to not have the bug, and it's harder to ensure that than display it differently! As an example of a game affected by a bug like this, Link's Awakening. The bow is 980 rupees. If you have 980 rupees, you can buy the bow. It slowly counts your rupees down. If you save and quit while it's doing this, when you reload you'd have wherever the counter was. Maybe even 979 rupees. If it was only counting down a display value, you'd have 0 rupees when reloading your save, as you should since you spent that money.

Video:
https://youtu.be/7tj5MhOewec?t=12

Bugwise, at least in my opinion, if you can think of a way for a thing to happen, you should try to prevent it no matter how rare it seems because it's totally gonna happen when a lot of people get their hands on the product.

You can make the code smaller, but what do you consider way too much space? Even the largest version is barely double the amount of bytes of the code in your first post. (And maybe not even. I'm counting bytes that are probably already in your code to display the HUD in the first place.)
 

Mugi

Member
i guess it just looks that large since you commented it so extensively :p

but yeah, i suppose you're right with the bug prevention, i just mentioned that since i have a pretty clear idea of how the health platforms are used, and taking as an example if it takes 2 seconds to fill from 1 to 8, it would still be way too fast for abuse in my game.

at any rate, i'll let you know when i get to this, if i manage to get it to function.

as a reference, the way my hud operates is that it sets object_health,x into temp3 and prints from that (it's set in predraw)
 

Mugi

Member
I might actually give up on the whole health platforms thing, it turns out to be way too complicated for my dumb brain to deactivate the health cross icon if the platform is used :p

either way, i didnt want this code go to waste, so i implemented it, and i have to say i quite like how it looks (made it a little slower though.)

https://youtu.be/eEjMU4RQ1d0
 

Kasumi

New member
Glad it worked, at least. It wasn't exactly tested ;) It seems to deactivate in the video, so is there another case where it doesn't work? Edit: Oh. The beginning where it's "on" but you have full health. I could maybe help with that too. How's it currently done?
 

Mugi

Member
Kasumi said:
Glad it worked, at least. It wasn't exactly tested ;) It seems to deactivate in the video, so is there another case where it doesn't work? Edit: Oh. The beginning where it's "on" but you have full health. I could maybe help with that too. How's it currently done?

I like the fact that it starts counting up from 0 HP during player spawn too, it's a neat little effect. (i will have to test if it happens on every room or just death/start, if that's the case, it will have to be poked at.)


as for the platforms, they look like they work perfectly on the video, but there are multiple issues i have with them. Prepare yourself for this is gonna be a long post :p

The health platform itself is a custom tile type. the problem with this is that it's made out of 3 separate tile graphics, and each is set to tiletype 06 (health platform tile) this leads to the issue that each of the 3 tiles acts as it's own platform.
in the video i solved this by only using the middle piece as a health platform and leaving the edge pieces as normal solid. But this causes issues with collision, as you can only trigger it by standing in a specific spot on the platform.

the second issue is that i dont know how to identify the health cross object as an object (like when you do LDX player1_object to do things to the player.) the DeactivateCurrentObject im using to make the health item dissappear, requires you to load the object before deactivating it, and currently im doing this by using #$01 (because i dont know how to load the object itself, i load it from a position i know where it is at (just set it as object 1 in screen editor.))

the current code i have for the health tile is this:

Code:
    LDA #TILE_SOLID
    STA tile_solidity
  
    CPX player1_object
    BEQ areYouAPlayer
    JMP dontActivateHealthPlatform
areYouAPlayer:
    LDA tileCollisionFlag
    BEQ +
    JMP dontActivateHealthPlatform
+
    LDA gamepad
    AND #%00100000
    BNE ++
    JMP dontActivateHealthPlatform
++
    LDX player1_object
    LDA Object_health,x
    CMP #$08
    BNE skipeverything
    RTS

skipeverything:
    LDA #$01
    STA tileCollisionFlag
    ;ChangeTileAtCollision #$01, #$62

        ; #$01 is the health cross, always place it as "Monster 1" on screen !!!!
        ; TO-DO: Figure a better way to do this.
    LDX #$01                 
    DeactivateCurrentObject
    JMP DoTheHealthThing
dontActivateHealthPlatform:
    RTS

DoTheHealthThing:
    LDX player1_object
    LDA Object_health,x
    CMP #$08
    BEQ skipGettingHealth2
    LDA #$08
    STA Object_health,x
skipGettingHealth2:
    RTS


I could even live with always having the cross there if all else fails , but the collision issue with it is sort of a problem.
another problem with it is that because my code sets a tile collision flag to tiletype 06, it will deactivate ALL the health platforms.

so what im working on solving here for the moment is how to identify in which room i am, and deal with the platforms based on that, (my game will have 5 or 6 levels, and each level has a maximum of 2 of these, some propbly only one) so setting a variable for each of them is not a big deal. I just cant seem to put into code what i want here.

TL;DR:
the global deactivation is an issue.
the health cross respawning / deactivating is an issue.
the collision is an issue.

another TL;RD:

how they're made is that the platform does the healing, and it's just a tiletype.
the animated cross is object #$04 (health pickup)

the way i intended them to work is that an unused platform has the cross, indicating that it's unused. pressing down on the platform triggers it (heals you and makes the cross dissappear) and the whole point is that they stay in used state once used (need to make the cross not respawn.) the fact that their functionaily doesnt respawn at the moment is nice, the problem is that if you have 2 in a stage, they both die when you use the first one lol.

Akin to Shatterhand, where im drawing mechanics from, the idea is to make using the platform cost, but since i havent implemented money yet, they currently work just by ducking on them :p
 

Mugi

Member
Retrobuster said:
That start screen tho!

That bad? :p

I did try a little trick with the platforms and i made it so that if it heals you, it will set a flag "temple_platform used" and then i made a custom script (i called it from predraw to make sure it always runs) that does countobjects #%00100000 to see if "pickup" items are present in the room, then it reads the flag i set, and if 1 it deactivates object 01 (the cross icon)

This actually works, but i still need a way to identify the room in order to know which flag to set, and a way to identify the picup item and destroy it instead of always destroying object 01.


I dont really understand enough about how all that works, but slowly getting there i suppose....
 

Kasumi

New member
Whelp. I've read a lot of NES Maker code today, that's for sure.

Mugi said:
the second issue is that i dont know how to identify the health cross object as an object (like when you do LDX player1_object to do things to the player.)
Object Details, Actions->Action chooses a script the object will run for that action step. When it starts the right index value for the object will already be in X when the script runs.

Generally, I wouldn't do any of this with tile collision. I'd do it all with the object (the animated cross sprite). If the player is overlapping the bounding box of the cross, and is holding down, get 8 health and kill it. But I've yet to come up with a way to do this that wouldn't be ... very involved. Like, you could have a bounding box that doesn't match the visual and a script that runs on every health object that collision checks only the player (and then check down if they're colliding and do the thing). But the super raw collision check code isn't in a subroutine by itself, it's below a lot of other stuff. So you can duplicate, but that's not that good an option.

It might actually be easiest (safest?) to find the nearest health pickup to the health tile (to identify what is a health tile, you loop through all object indices looking for type 4), and if it's close enough deactivate that one but to do that I'd have to read where the tile code is run from so I know what value are safe to look at to determine distance.

Actually, probably easier is to do the distance thing from the health pickup script. You don't really need strict collision for it, since it doesn't move, and it's super easy to get the player index always. But if I recall correctly how NES Maker stores positions for scrolling is kind of different.

So uh...I am probably not really able to help after all, I misunderstood what you wanted. I thought it was just: If health is not 8, be visible. If health is 8, be invisible. So needing to know the object index from the tile wasn't required, and how many there were total also didn't matter.
 

Mugi

Member
Retrobuster said:
No I love it!

Thanks :)


Kasumi said:
Whelp. I've read a lot of NES Maker code today, that's for sure.

Generally, I wouldn't do any of this with tile collision. I'd do it all with the object (the animated cross sprite). If the player is overlapping the bounding box of the cross, and is holding down, get 8 health and kill it. But I've yet to come up with a way to do this that wouldn't be ... very involved. Like, you could have a bounding box that doesn't match the visual and a script that runs on every health object that collision checks only the player (and then check down if they're colliding and do the thing). But the super raw collision check code isn't in a subroutine by itself, it's below a lot of other stuff. So you can duplicate, but that's not that good an option.

It might actually be easiest (safest?) to find the nearest health pickup to the health tile (to identify what is a health tile, you loop through all object indices looking for type 4), and if it's close enough deactivate that one but to do that I'd have to read where the tile code is run from so I know what value are safe to look at to determine distance.

Actually, probably easier is to do the distance thing from the health pickup script. You don't really need strict collision for it, since it doesn't move, and it's super easy to get the player index always. But if I recall correctly how NES Maker stores positions for scrolling is kind of different.

So uh...I am probably not really able to help after all, I misunderstood what you wanted. I thought it was just: If health is not 8, be visible. If health is 8, be invisible. So needing to know the object index from the tile wasn't required, and how many there were total also didn't matter.

It turned complicated really fast, didn't it ? :p
i wasn't considering that it would be this complicated to do, though what im propably gonna end up doing, is that since im using such a limited number of them overall, i will just use screen triggers and set the triggered versions to just omit the health cross item. That way all i have to solve is the health platforms themselves (not sure if you can change tile collisions like that with triggers, need to look into it.)

i will definitely come back to it on code level later on, once i lern2ASM properly, it's been an interesting excersise of failing to program for the past couple days i've fought with it.
 
Top Bottom