Toggleable Sound
#7 posted by Mike Woodham on 2007/08/09 00:01:20
The music in FMB_bdg is toggleable and plays everywhere. Being a looped sound, it would play forever if not switched off by the player (by operating the music button) or when the player unwittingly moves through an off-trigger.
It doesn't play from a savegame even if it was playing when the game was saved. But the savegame must be recording the state of the entity because you have to operate the music trigger twice after a savegame if you want the music to play - the first time turns the music off even though you can't hear it, and the second time turns it back on, and you then hear it.
I created the entity following an idea by Preach.
// if the player has not touched the 'toggle-music' button then this must be
// a triggered event, which means....
if (mechanism.classname != "func_button") etc...
Could this be developed to check the state of the entity when opening a saved game and play the sound if TRUE? Or am I completely off-track understanding what you want to do?
Mike:
#8 posted by metlslime on 2007/08/09 00:33:33
well, it sounds like preach's save game code would fix your problem, but I have a second problem that you don't have, which is that the sound won't play at all if you are too far away at the time it is first triggered. Your music is always audible, so there's no worry about being too far from the emitter at the time that it starts up.
Model Import
#9 posted by Lunaran on 2007/08/09 05:18:15
I started messing with the quake model gen source to make it parse ascii files instead of .TRI, so that I could export to text from my modeler of choice (ie maya). I got all that working fine as far as I can tell, but the .mdl that gets written out crashes Fitzquake and every model editor I've found to try. Stepping through the exporter in debug doesn't really seem to show anything wrong, as the data is all seemingly correct before it gets written.
I took a break bashing my head against this a long time ago (like the end of 2006 now that I think about it :( ), so if I started poking at it now it might become obvious to me, but does anyone have any tips or suggestions? Are there any quake ports or other bits of software that I can try to load a model in that will actually tell me what part of the file is horked rather than just pooping?
Model Import
#10 posted by Preach on 2007/08/09 12:59:25
A good starting place would be:
http://tfc.duke.free.fr/coding/mdl-specs-en.html
This gives you a big chunk of c code that will read a mdl file. You can skip the chunk about rendering it and just write a quick function that prints out the header data once it's loaded it, to check whether that's been written correct or not.
You might also want to look at
http://people.pwf.cam.ac.uk/~ajd70/mdl_export.py
it's an export script for blender written in python. I wish I could remember what I did to make it work though, I had the same problems as you are and spent a few hours staring at a hex editor to find out what went wrong. If anything jogs my memory I'll let you know. Shame I never got round to writing the corresponding import script, it'd probably be good for diagnosing the problem...
Yeah
#11 posted by Lunaran on 2007/08/09 18:12:03
I've looked over all that in the quake and modelgen sources, but I'm not very confident in writing a new piece of software to check why the last piece of software I wrote doesn't work, because clearly there's no guarantees the new one's not going to be fucked in some tiny significant way also, especially if they're both doing the same things to the same data structures. I'm just a simian level designer.
Part of the problem is that I had to do so much to get the thing to a testable state - .bmp import for the skin and then my ascii reader thing, because there's no program left on earth to write TRI files and there's no program left on earth that'll write whatever silly-ass image format modelgen looks for.
Hmm
#12 posted by Preach on 2007/08/09 18:35:02
Well, upload an example model that the tool exports and I'll take a look at it, try and figure out what's wrong with it.
Okay...
#13 posted by metlslime on 2007/08/10 07:17:30
The steam jet sound problems seem to be solved.
First, I play the looping sound whenever the object is turned on, and the "fade out" sound whenever it is turned off. This was the original naive implementation.
Second, to deal with the problem of steam jets turning on when you're far away, I re-trigger the sound every 0.1 seconds when you are between 300 and 350 units away. The clipping sound artifact is there, but since it's so quiet at that distance, you barely hear it. When you get closer, it stops re-triggering it so you can hear a perfectly looped sound.
Third, I used Preach's loadgame callback idea to retrigger all sounds in case you are standing within 300 units when you save and reload the game.
Problem solved! Thanks for the help preach.
Oh Wow
#14 posted by Lunaran on 2007/08/11 02:34:17
thanks Preach! It might take me a bit to gather all the code and stuff back up and actually produce one, but I'll hit that this weekend.
Pointers Anyone?
#15 posted by Mike Woodham on 2007/08/11 23:46:40
So I thought I would try Preach's code from above and simply put a call to my music_play_tune routine for any savegame but got this super message from aguirRe's engine.
This Onion
CDAudio: drive not ready
CL_SignonReply: 1
CL_SignonReply: 2
INDIRECT 28(self)entity 0 481(distance).distance 21507(?]
STORE_V 28(self)entity 0 4(?]
STORE_V 323(CHAN_VOICE) 2.0 7(?]
STORE_V 21505(?] 10(?]
STORE_V 21506(?] 13(?]
STORE_V 21507(?] 16(?]
CALL5 489(sound)sound()
ADDRESS 28(self)entity 0 147(use).use 21508(?]
play_music.qc : music_play_tune : statement 51
world.qc : LoadGame : statement 0
world.qc : StartFrame : statement 16
PR_ExecuteProgram: assignment to world entity
Host_Error: Program error
The idea was to play whichever tune was currently set. Clearly, I am not understanding qc here.
In
#16 posted by aguirRe on 2007/08/12 00:18:44
function music_play_tune in file play_music.qc, there's an entity propery ("use" I think) that you're assigning some value at statement 51.
This entity is world (= 0) at the reported occasion and this is not allowed, you may not change the world's properties.
It's probably an un-initialized entity variable that causes this issue. If I saw the corresponding QC code, it'd be easier to explain.
Hehe
#17 posted by aguirRe on 2007/08/12 00:21:15
Does this mean you're working on "This Onion II - The Sequel"? ;)
AguirRe
#18 posted by Mike Woodham on 2007/08/12 12:45:15
Does that mean I would have to intialise my music sounds in world.qc instead of calling the function play_music where they are usually precached? I can get around the "use" statement.
Oh, and according to my publicist, I have to give a "no comment" to your last question :-)
From The
#19 posted by aguirRe on 2007/08/12 13:18:58
debug output above, it's a
self.use = something
statement that's run when self == world which is not allowed. It's not the precaching that's at fault here.
Since the function is called from StartFrame initially, I'd assume that the world is indeed self at that point.
Music_play_tune is normally the think function for the play_music entity, you can't call that directly from another entity's (here: world) think code. The sound calls are also invalid then.
I'd guess you'll have to trigger the play_music entity's think function somehow from StartFrame.
Thanks
#20 posted by Mike Woodham on 2007/08/12 13:26:48
I'll play a little more with this to see if I can figure out a workaround.
No, I Can't Figure It Out And I'm Going Round In Circles
#21 posted by Mike Woodham on 2007/08/12 18:43:01
I thought I could set up a flag to say whether or not the music was playing at the time of the savegame (state = TRUE/FALSE). I know the piece of music playing by tracking it with a variable (cnt = 1/3/5/7, for 4 set pieces of music). I know both of these are saved in the savegame file (actually FALSE appears not to be saved), so presumably are loaded with loadgame.
But world.qc baulks at everything I try, usually with a 'types function and field not allowed'. So I cannot figure out how to either read the entitie's 'state' and 'cnt' and make use of them; or how to call the 'music_play_tune' function from world.qc.
Do you think I am trying to do the impossible or is it just that the logic is beyond me?
This Might Not
#22 posted by aguirRe on 2007/08/12 19:10:17
be a very good idea, but just to make the music_play_tune "callable" from StartFrame, you could assign a global entity var music_entity the value of self in play_music.
In StartFrame, you'd then just set music_entity.nextthink = time to make it execute as soon as possible. You should probably add a check for music_entity being not-world, i.e.:
if (music_entity)
music_entity.nextthink = time;
Maybe someone else can suggest a better way to actually achieve whatever you're trying to do.
Btw
#23 posted by aguirRe on 2007/08/12 19:13:50
savegame files don't contain vars that are 0 (= FALSE), so that might be why it's "not saved".
I Don't Think It's Impossible
#24 posted by necros on 2007/08/12 19:20:54
are you waiting long enough for all the entities to be spawned before you go searching for the music entity?
it should just be a matter of using a while loop to .chain through your entities until you find your music ent, checking the entity fields and then giving it a .nextthink and .think to call it's function.
music_play_tune likely has stuff with self in it, so that's why you'd need to do musicent.think = music_play_tune; instead of directly calling music_play_tune();.
or am i misunderstanding the problem?
?
#25 posted by necros on 2007/08/12 19:26:34
savegame files don't contain vars that are 0 (= FALSE), so that might be why it's "not saved".
false = 0, and i'm pretty sure variables in quake are automatically initialized to 0 if they have no value, so technically, they are 'saved' whether it's actually in the save file or not.
OK
#26 posted by Mike Woodham on 2007/08/12 20:19:16
I didn't have a problem not seeing 'state = 0' in the savegame because I would have been looking for 'state = 1' to tell me if the music was playing at the time of the savegame.
No, my "problem" is that I cannot get a compile with any statement that uses something like 'musicent.think = music_play_tune;' in world.qc as I get an error of "Types function and field not allowed". I don't know how to copy one entity into another so that the world.qc can use it.
The reason I am having difficulty is that I am only an occaisional user of QC and don't really have enough depth of knowledge about the language or protocols in use. I get by, by reading other people's code and adapting it to my use or by plain old trial and error. But I don't think we have had music in Quake in the way in which I have implemented it, so nobody has yet written the code for me to adapt, and all my trials (Lord, soon be over) have ended in failure. Well, at least I'm consistent ;-)
If someone wants to take this on, I would have no problem passing my play-music code on. It's not a work of art but it does work.
And, "at the end of the day" I am only trying to tidy up something I have already finished.
Didn't
#27 posted by aguirRe on 2007/08/12 20:46:30
my suggestion work? To copy self in play_music, you just have a new global var
entity music_entity;
and assign self to it:
music_entity = self;
Then you set
music_entity.nextthink = time;
in e.g. StartFrame. You shouldn't set the think function, that's AFAIK already set in play_music.
You only make sure music_entity's think function will be run as soon as possible (you can't control exactly when, though).
AguirRe
#28 posted by Mike Woodham on 2007/08/12 22:54:23
No, it didn't work.
If I place the 'entity music_entity;' outside of world.qc I get a compile error "world.qc(359):error: unknown value 'music_entity'".
Line 359 is where 'music_entity.nextthink = time;' sits.
So I place it in world.qc immediately following the line, 'nosave float loadflag;'
I've added 'music_entity = self;' inside play_music, thinking that it needs to be there otherwise the new entity doesn't know who 'self' is.
Finally, 'music_entity.nextthink = time;' is in LoadGame, which is called from StartFrame.
Ah, but... I have just re-read everything and added '+ 3' to 'music_entity.nextthink = time;' and now it works. I had written a note in play_music that the sound will not play for one second - I read that somewhere but don't know why it is so.
Cool! Lookin' good!
Thanks.
Now I can get to work on checking which piece should play (or not). Watch this space!
Thanks again.
Long Standing Bug?
#29 posted by Preach on 2007/08/12 23:10:12
Is this, in the eyes of those present here, a bug? (and if so, one worth fixing?)
self.th_pain (attacker, take);
// nightmare mode monsters don't go into pain frames often
if (skill == 3)
self.pain_finished = time + 5;
You might expect that this piece of code makes sure that there is a minimum 5 seconds between each pain animation on nightmare, in the same way that self.pain_finished = time + 2; in the pain function puts a minimum of two seconds gap. But this isn't quite right.
You see, most pain functions only set pain_finished times once they've already concluded that pain_finished < time. Otherwise they'd constantly set pain_finished further into the future as long as the monster kept taking damage within the pain_finished period. Nightmare mode is, in effect, doing exactly that. You have to go 5 seconds without damaging the monster at all, rather than 5 seconds since you last caused it to go into pain.
So you end up with very odd behavior. If you pour nail after nail into an ogre, it'll only go into pain on the first one, but if you spread each nail 5 seconds apart, it will go into pain from every single one. Of course, the bug doesn't manifest itself that noticably, as 5 seconds is about enough time to kill any monster if you're focusing exclusively on it. Still, it might becomes more important with new high hp enemies, like in Quoth or the like. So, thoughts?
Mike
#30 posted by aguirRe on 2007/08/12 23:32:25
The reason you get a compile error is because of the order in progs.src file. Since world.qc is before play_music.qc, the compiler needs to know what it is before you can use it.
You can get around this kind of problem by declaring the global var in defs.qc or another file that's early in progs.src.
Or just declare the var in all files that you use it in. It'll just be one var anyway, as you can't have two global vars with the same name.
Good that it works now.
Well
#31 posted by ijed on 2007/08/12 23:51:39
In Quake2 the enemies never went into a pain animation in NM - they just ignored the shots, feeling no pain.
And it felt right, they are cyborgs. In Quake it is a bit strange that I can always count on a Vore (for example) yowling on the first hit, and have enough time in the animation to throw four grenades (1 to cause it to go into pain, three more to kill it) without reprisal.
Is it possible to add a randfloat value to the factor for pain - with the skill number deducting from this? (Yeah, just exhausted my coding knowledge).
What I'm suggesting is recoding the monster pain sequence, which can most likely cause alot of headaches, but I can see:
Create random Variable 1-10, deduct (skill level).
Is Variable higher than 5? If yes, play pain animation.
Which should give the engine less to think about for each particular monster currently in combat, since they're not all accumulating delays. This could be useful if, for example, the player is spraying nails into a horde of Vorelings.
It could also gives an organic feel to the enemies, making them less predictable and robotic.
|