How can I impliment an image-based health?

KReed92
07 Aug 2013, 10:08
Hiya :) I have a (hopefully) more simple problem I need help solving today. I'd like to impliment a health system that shows an avatar of the player character with the background of the avatar changing colours to represent the health (probably using "if" statements to provoke the changes. Such as "if using imageA then use imageB").

I understand this can't be done in the status panel which is fine but what I'd like to figure out is how I could make this be displayed in the game window at all times? I contemplated having it just show the health when it actually changes but because of other systems I'm using, the player could really do with seeing their health at all times. Any ideas?

Many thanks x

jaynabonne
07 Aug 2013, 12:19
Where would you like the image to be?

One option is to use the image pane, which is typically used for room images. You can take it over and put what you wish there. You can either set a picture using:

SetFramePicture("GoodHealth.png")

or you can set full-blown HTML using something like:

request (SetPanelContents, "<img src=\"" + GetFileURL(filename) + "\" onload=\"setPanelHeight()\"/>")

The contents would be whatever HTML you like in the latter case, including an image.

To keep Quest from removing the pane on each turn, you need to provide an empty override for ClearPictureFrame as follows:

 <function name="ClearFramePicture">
</function>

If you don't wish to have the entire top of the screen in use, then give an idea of where you'd like it (near the command prompt, hovering, etc). I'm sure it can be done.

KReed92
07 Aug 2013, 13:25
Thank you for the reply :)

I thought of using the room image pane lol :) It might be a bit too big for the small avatar I'll be using though (unless it resizes itself to the size of the image?) because it'd be a shame to take up the screen with a big pane if it only has a small image in it.

As for any other location, I guess just above or below the command bar would be a good spot yeah :)

I'm not 100% sure what you meant by hovering so I can't really say either way with that lol.

jaynabonne
07 Aug 2013, 14:40
By hovering, I just meant overlayed on top of the text.

If you add this:

      JS.eval("$('#gamePanel').css('background-color', 'transparent')")
JS.eval("$('#gamePanel').css('text-align', 'right')")


and use the frame picture, then it will right-align the picture at the top and make the rest of the pane transparent so you can see the text underneath. That's effectively hovering the image in the top right corner.

KReed92
07 Aug 2013, 15:21
Ok I'll give that a try, thanks. Where should I put that code? Sorry if that's a bit of a dumb question, lol :/

jaynabonne
07 Aug 2013, 15:48
It only needs to be done once, so you could put it in your game's start script.

If that's not good enough (or if you prefer), then we should be able to work up something tied to the command line. Let me know.

KReed92
07 Aug 2013, 16:05
That worked perfectly! Thank you very much. Now my question is how to change that depending on the health? I've thought of two ways it MIGHT work but would like your input on them :)

First Way: have an off-screen health integar and then add a change script that does something along the lines of "if health is less than 70% then change current room image to healthok" etc. I'm not sure if it's possible to change the room picture using this method though.

Second (long) Way: Every time a player looses health, it does an "if player is in room and if health is less than this then..." etc. which would take soooooo long but was the only other way I thought of.

jaynabonne
07 Aug 2013, 16:18
I think the most straightforward would be the change script for the player's health attribute, your first option. That way, it happens automatically whenever health is updated, and you don't need to remember to call "update health UI" after each change. (There is another way to go, which is a turn script, which basically updates the image after each turn.)

You should be able to update the picture from there just fine. So your change script could have something like:

if (player.health > 70) {
image = "playergood.jpg"
} else if (player.health > 50) {
image = "playerhurting.jpg"
} else if (player.health > 25) {
image = "playerstruggling.jpg"
} else if (player.health > 0) {
image = "playerdying.jpg"
} else {
image = "playerdead.jpg"
}
SetFramePicture(image)

KReed92
08 Aug 2013, 10:24
Sorry for taking so long to get back to you, I've only just had time to try out the changescript code you sent. Unfortunately I tested it out and nothing happened in-game. I set a timer to decrease the player's health so that I could watch it cycle through the images easily but none of the images appeared (not even the default one for when heath is greater than 75). Not sure what went wrong :/

jaynabonne
08 Aug 2013, 11:07
Could you post what you've done (or some sample thereof, like the change script and the timer)? It's hard to grope in the dark. :)

KReed92
08 Aug 2013, 12:09
Sure :)

Here's the script for the change:

if (player.stamina >75) {
image = "healthworried.png"
}
else if (player.stamina >50) {
image = "healthscared.png"
}
else if (player.stamina >25) {
image = "healthterrified.png"
}
else if (player.stamina >0) {
finish
}
SetFramePicture (image)


And here's the timer's script:

player.stamina = player.stamina -2
if (player.stamina >15) {
DisableTimer (running)
}


The timer's countdown is just 1 second (and the timer itself is initiated by the player typing the command 'run') Hope this helps :) I'd laugh if I've just missed out a bit of code somewhere (wouldn't surprise me!)

jaynabonne
08 Aug 2013, 12:14
Is the change script for "changedstamina" on the player? (just checking) And is it of type "script"? Try putting an "msg" in the script to make sure it's being run.

What is name of the timer (is it "running")? If so, then you're disabling the timer right away. Do you know for sure the timer is going off? Perhaps putting an msg in there would help verify.

KReed92
08 Aug 2013, 12:37
I figured one thing out, lol. I was using > (greater than) instead of < (less than) in the stuff, so yeah it was disabling the timer immediately lol... it was supposed to only do that if the stamina dropped too low.

Now I have a new problem. All I have done is change the >'s to <'s and now I have an error lol.

Error running script: Error compiling expression 'image': Unknown object or variable 'image'


This happens when I initiate the run command which is odd because it shouldn't really be looking to update the image unless stamina drops to certain points anyway.

jaynabonne
08 Aug 2013, 12:43
It scares me that you said ">'s" ( plural). The only bad one was in the timer. The rest (e.g. in the change script) were correct.

What ranges do you want for the pics?

KReed92
08 Aug 2013, 12:52
Eek, I think my brain is getting fried if I'm making it worse x) lol.

Ok so at the start of the game, the default image should be 'healthcalm.png' which should be displayed if stamina is 75 or greater. Then when stamina drops below 75, it should display 'healthworried.png'. If it then drops below 50, it should display 'healthscared.png' and if it drops below 25, it should displey 'healthterrified.png'.

I think I'm probably panicking because I wanted a portian of the game to be playable tomorrow as a demo for my friend but I'm not sure it'll even be playable by then with all the mistakes I'm making lol.

jaynabonne
08 Aug 2013, 13:03
Don't panic! :)

So then you're change script would be:

if (player.stamina >75) {
image = "healthcalm.png"
}
else if (player.stamina >50) {
image = "healthworried.png"
}
else if (player.stamina >25) {
image = "healthscared.png"
}
else if (player.stamina >0) {
image = "healthterrified.png"
} else {
// You might need or want a "healthdead", as it will fall through to setting the image anyway.
// Or use terrified again.
finish
}
SetFramePicture (image)

jaynabonne
08 Aug 2013, 13:08
Also, to get the initial picture to show up, default the stamina value to 0, and then explicitly set it to 100 with an assignment so that the changed script will fire.

KReed92
08 Aug 2013, 13:18
Oh my lord, it's working! lol. YAY! Thank you.

I notcied the pictures kept flickering as it was constantly being changed. Like at 98 the calm image flickered. It was still the calm image like it wa ssupposed to be but it had flickered as though it had been changed and it did that every time stamina decreased. Is there a way to avoid that blinking effect? I thought of using 'first time' but remembered that it would never change it again after that. It's not a huge issue though. I can tell my friend that the flickering is a game mechanic designed to let him know his stamina is dropping ;) sneaky... hehe.

Also, rather unrelated (sort of) but another thing I wanted to put in the game was a button mashing section (whereby the player has to mash any key to shake off an enemy) but aside from some kind of use of the 'wait for key press' button (which I think would be too slow) I'm not sure if it can be done. Basically the way this ties in with the stamina is that if the player has low stamina, their attempt to shake the enemy off would be harder. I might have to find a different way of implimenting that perhaps but thought I'd throw it out there.

I'm making a text adventure remake of the Clock Tower SNES game, if that helps. Why? Just for the kicks really lol, and my friend really likes text adventure games over normal games so this way I can get him to play a classic ;)

EDIT: I just saw your second message. After setting the default to 0 and setting a 100 on game start, I got this error:
Error running script: Error compiling expression 'player.stamina >75': CompareElement: Operation 'GreaterThan' is not defined for types 'Boolean' and 'Int32'
I've seen this error a LOT in the past when working with custom attributes and it always got on my nerves because it never made sense why it had a problem with the 'greater than/less than' side of things.

jaynabonne
08 Aug 2013, 13:53
To prevent flicker, you can check if it needs to change.

Create an attribute on the player called "lastimage", of type string. It doesn't need an initial value. Then change:

SetFramePicture (image)

to:

if (image <> player.lastimage) {
SetFramePicture (image)
player.lastimage = image
}

The problem you see with the ">" sounds like player.stamina is not defined. Do you have a default attribute set for it (e.g. of type int)?

jaynabonne
08 Aug 2013, 14:00
Actually, I take that back. It sounds like "stamina" is of type "boolean".

KReed92
08 Aug 2013, 14:04
Here's an attached screencap showing the integar (and the newly pasted code) :)
lalala.png

KReed92
08 Aug 2013, 14:10
Ok just an update: Following the latest test, the flickering has stopped and everything works fine in terms of health changing and image showing (and even carries into the next room which I thought I'd need to do seperately) :D Thank you sooo much!

Did you have any ideas regarding the 'button mashing' question by the way? I'm still scratching my head over that one.

jaynabonne
08 Aug 2013, 14:22
I had done a test a while back about trapping keydown events in JavaScript. I've shown myself it can be done, and the attached sample shows one way to do it.

You need to include the JS file "glue.js" in your project. Then you simply call:

JS.Hook("somefunctionname")

and then that function whose name you pass will be called whenever a key is pressed - any key (even shift, ctrl, caps lock).

<function name="somefunctionname" parameters="keyCode">
msg("Keycode = " + keyCode)
</function>

Note that this is using ASLEvent to notify the app. And ASLEvent (I recently discovered) causes turn scripts to run. Bear that in mind.

BTW, feel free to change the names. This was just some test code, so you have names like "Hook" and "glue". :)

KReed92
08 Aug 2013, 14:35
Just tried the test file :) Great work! And I love that you can't type anything else whilst it's running (stops the player from trying to leave the room or interact with objects instead of fighting the enemy)

How I could I then impliment it so that it works in this kind of scenario:

Enemy attacks player. Player is given a cue to mash a button, then the game starts a timer and they have to mash any button, say, 50 times in the space of 10 seconds. If they succeed, they push the enemy down and can then move freely (the keymash script should stop at this point too) but if they fail, the script stops but instead do allowing them to move, they get killed.

I'd like to make it so that the number of times they have to mash the key increases depending on their stamina level (i.e: calm might require 40 taps in 10 seconds, worried might require 50, scared 60 or terrified 70 etc. etc.) The more panicked they are, the more they have to tap.

I'm beginning to feel like I'm thinking too complex for it all to be possible but I'm also growing increasingly surprised at just what CAN be done in Quest (e.g: the picture changing with health I thought would have been impossible until today).

jaynabonne
08 Aug 2013, 14:51
You should still be able to type while it's running. Are you seeing differently?

The simplest approach would be to set a counter to 0 (in the game object!) when the mash session starts and increment it for each key press received via the hook function. Set a timer and just count how many keys you get until the timer goes off. How you manage the necessary key presses is up to you. :)

If you want to unhook the key listener, then do:

JS.eval("window.removeEventListener('keydown', document.getElementById('gameContent'))")

KReed92
08 Aug 2013, 14:59
Ah no, you're right I can still type lol.

As for the rest of it, my head just went BOOM. Not sure I'll be able to figure this out.

increment it for each key press received via the hook function. Set a timer and just count how many keys you get until the timer goes off



I was lost at that bit. I'm not sure how to incriment it that way. Is it an 'if' thing? like 'if key is pressed'? Sorry for being such a noob lol, I've never worked with anything that complex before. I really do want to get it down though 'cause if this can work it'll really make the enemy fights nice and dramatic as the player litterally panicks to hit the key enough times. :)

jaynabonne
08 Aug 2013, 15:14
Well in the code I gave you, you call "Hook" and pass it the name of a function to be called for each key press. So basically, by increment, I just mean something like this, in the function whose name you pass to Hook:


<function name="MyKeyHook" parameters="keyCode">
game.keycount = game.keycount+1
</function>

Just be sure to set it to 0 somewhere (like, as a default attribute value).

What you could do is to just let it be hooked all the time. It will just happily count keystrokes throughout the game. When you want them to start mashing, make note of the keycount:

game.startcount = game.keycount

and then when the timer goes off, see what the difference is:

keyspressed = game.keycount - game.startcount

Then you can do your comparisons to see if they hit enough keys.

KReed92
08 Aug 2013, 15:25
Hmm, ok thanks :) I've not reached the stage where I'm placing the enemy in yet. I have a couple of bits to do first so I can't test this for a while. I probably won't post again today unless I get done quicker than expected. Either way, I'll post back and let you know how it went. Hopefully won't be too many hiccups :) Thanks for all your help today, it's much appreciated.

KReed92
08 Aug 2013, 16:40
*sigh* it's no good. I can't get it to work at all. :( I've uploaded the game files to Mediafire. I figured you'd be able to work out the problem if you had everything there. It's probably a bit of a mess because some bits are unfinished (no descriptions etc.) but just ignore that for now.

Just in case you get lost if you try to play it, talk to Lotte twice, until your character offers to look for someone, then it will more or less point you were to go. Go into the bedroom and "look at" the mirror, that's where I've tried to get the key-mashing going.

http://www.mediafire.com/download/k6wz9 ... _Tower.rar

jaynabonne
08 Aug 2013, 20:37
You inserted the function I gave you inside your own function. I was just giving an example. Just take the single line:

  game.keycount = game.keycount+1


for the inside of your function.

(BTW, I got to the point where the floor collapsed while I was on the balcony, and I can't seem to go anywhere. I also got stuck in the beginning because you had said "talk to lotte", and I was using the mouse, so I clicked on her name and the verb there was "Speak to"... which seemed like talking. So I clicked that, and it kept saying "She says nothing.", which wasn't helpful. Finally, after much back and forth getting nowhere, I typed exactly "talk to lotte" and it worked. You might want to fix that... lol)

KReed92
08 Aug 2013, 22:37
When you head back into the foyer and realize the others are gone, the two doorways in the small corridor become accessable if you go back in there :) At least they should be. If not I might have not programmed that in there yet... oopsie, lol.

As for the speaking thing, that's really odd because that 'speak to' verb isn't something I programmed :S since it's there already I'll copy the stuff from the 'talk to' command into that one so that either command/verb works :)

I'll work on the above tomorrow but if it's just a case of me mucking up the function then hopefully it should work alright after I tweak that :) Thanks again.

KReed92
09 Aug 2013, 09:16
I tested out and I did make those links so yeah if you go back into the small hallway after the floor collapses, you can go down the hall into a longer one. First door is intentionally blocked (as it leads to a room that I didn't want to work on yet as I wanted to focus on the hazardous room) so go to the second door and 'look at' the mirror for fun times.

Or at least, SHOULD be fun times... I still can't get the button mashing to work. My recent test was saying I lost when I know I pressed the key enough times which means the game either isn't initiating the key mashing script or it's not adding +1 to the keypress attribute when I DO press a key. Kinda starting to regret to keymashing idea :( I really like it originally but now I wanna mash keys in frustration lol x)

Here's the latest version: http://www.mediafire.com/download/0m3cz ... _Tower.rar

EDIT: .... you want something to chuckle at? The reason it said I lost was because I got my > and < muddled...

Timer SHOULD havd been "if game.keypress more than 5 then you win else you lose." but I had it saying 'less than' instead lol... I'm such a goof lately. BUT after tweaking that and testing it, it WORKED which means the keymashing as a whole works. Hallelujah! Thank you very very much. I didn't think that one would be possible but wow, I can now get on with making the rest of the game :D

jaynabonne
09 Aug 2013, 13:49
I'm glad it's working. :) Yep, those pesky inequality operators. lol

jaynabonne
09 Aug 2013, 23:44
I discovered something just now which explains an error you had before (I think).

If you have an attribute like this with no type:

<text>This is some text</text>

then it defaults to being a string with that value. But if you reduce the string down to nothing:

<text></text>

or

<text/>

then Quest turns it into a Boolean! So that might explain before when you had that error about comparing to a Boolean value - if you had an empty attribute, it will do that. That's new to me... I think I know why it does it, but I don't agree with the inconsistency. :)