#ifdef
is shorthand for #if defined([macro])
In this case, you don’t want “if macro is defined” you want to compare values, so just #if [macro] < 2
#ifdef
is shorthand for #if defined([macro])
In this case, you don’t want “if macro is defined” you want to compare values, so just #if [macro] < 2
The function PlayPolyphonic(…)
returns a (bool?) indicating being able to successfully play the sound (I.e. “it exists).
What NoSloppy’s code does:
Is tries to play the blaster mode sound (but ofc this applies for all of them), and then if it cannot (and the function returns false) then it plays the beep instead.
So in your code:
This would try to play the blaster mode sound twice, and the second call is unecessary (unless you really want to hear it twice).
No I only want to hear it once.
So like this:
case PropMode::BLASTER:
if (!hybrid_font.PlayPolyphonic(&SFX_blastermode)) {
else
beeper.Beep(0.05, 2000);
beeper.Silence(0.05);
beeper.Beep(0.05, 2000);
}
Blaster::SB_Effect(effect, location);
break;
...
? Or is it just without the else
?
Also, if the compiler ProffieOS is using supports them (I don’t know off the top of my head), this would be a pretty decent place for a C++ lambda or anonymous function. The reasons for using anonymous functions instead of normal ones are numerous, for both convenience and reasons of scoping and/or just code readability.
Under the assumption they are supported by the compiler, you could do something like this right before the switch statement:
auto playSwitchSound{[&hybrid_font, &beeper](auto *sound) -> void {
if (!hybrid_font.PlayPolyphonic(sound)) {
beeper.Beep(0.05, 2000);
beeper.Silence(0.05);
beeper.Beep(0.05, 2000);
}
}};
And then just call it like a normal function inside the switch:
playSwitchSound(&SFX_[mode]);
If you know what type the sound effects are, you can replace the auto parameter for clarity, but it shouldn’t much matter here.
Alternatively, you could just add:
auto beep{[&beeper]() -> void {
beeper.Beep(0.05, 2000);
beeper.Silence(0.05);
beeper.Beep(0.05, 2000);
}};
And then you’d have a bit less hidden in the lambda, (if that’s desirable) and could just do the following in the switch statement):
if (!hybrid_font.PlayPolyphonic(&SFX_[mode]) beep();
No, you’ve a random “else” keyword inside your if now that you don’t want.
(But besides that it’s correct)
Ok, so I remove the else
.
Thanks
It would have been better if I had written the logic most readable instead of the somewhat shorthand version first. I only recently realized it could be combined into one conditional check like that. I see why you feel the else is missing.
This is doing the same thing, but “showing” the else:
if (SFX_blastermode) {
hybrid_font.PlayPolyphonic(&SFX_blastermode);
} else {
beeper.Beep(0.05, 2000);
beeper.Silence(0.05);
beeper.Beep(0.05, 2000);
}
In English “if blastermode exists, play it, otherwise beep”
The other way
if (!hybrid_font.PlayPolyphonic(&SFX_blastermode)) {
beeper.Beep(0.05, 2000);
beeper.Silence(0.05);
beeper.Beep(0.05, 2000);
}
Is “try to play blastermode. If you can, play it, but if you can’t because it doesn’t exist, then just beep.”
You are going to make a programmer out of me.
Thanks.
I will add your suggestion. Also, and I am just guessing, this will make the prop file smaller and save on memory ?
30 years ago, I did a bit of programming in my Industrial Engineering course (but I had to drop-out after 2 years because the aviation school had just re-opened after being closed for 3 years due lack of funding - and aviation was always what I wanted to do). I programmed in Pascal and in RPL on my HP48 calculator.
It was always (if I remember correctly) if, then, end or if, then, else, end with some basic bolean (sorry don’t know how to spell it) like “and” “or” “xor” so yes C++ is a huge step-up.
Thanks again for all your help & patience with me.
Probably not. If at all, it’d be a completely negligible amount. Little reorganization things like that probably won’t affect the generated program much if at all (and thus won’t much affect the size), they’re purely for organization and readability.
There is no need to capture hybrid_font & beeper since they are global variables. And this is not an anonymous function, since it has a name.
I’m not sure if this syntax will actually work, I think the normal way to write local functions is this:
auto playSwitchSound = [](Effect* sound) -> void {
These types of local functions have been a part of C++ since C+±11, so they should work fine, but I’m not really a fan of using them, for a few reasons:
So, my conclusion is to generally stay away from lambdas unless they provide some tangible benefit. Usually this comes from being able to capture variables, which can lead to much shorter code in some cases.
Gotcha, was just freehanding, good to know!
As I’ve understood it, it’s creating a variable essentially to maintain a reference to the anonymous function? Very possible I’m wrong, but that’s how I’ve understood it. The function/lambda itself doesn’t have a name, but there’s a variable with a name that you can use to reference it?
EDIT: I’ve confused terms. This is list initialization, and it
The “lambda initialization” as it’s called (I’ve looked into why and I don’t think it ever much made sense to me, but that’s what they call it… you can use it for most things, not just lambda variables), works as so:
typename varname{initializer};
It’s a stylistic thing that I prefer using it for initialization instead of an =
I believe this is because of the bindings… maybe there’s other reasons too and they’re just slower in general. I’ve not heavily profiled them in various cases to know.
I would agree, the syntax is different. Though it’s fairly comparable to
auto functionName(params) -> rettype {}
(Which I’ve noticed you use in ProffieOS in a number of places, that’s why I point to that specific example)
And the captures make sense as they’re basically just parameters that never change. of course, it’s easy for me to say they make sense since I use them all the time.
That’s a fair criticism. I find them to be far more elegant than an external function that only has a purpose inside the current one and is only a few lines (And for my uses often are aided by the ability to capture).
Essentially, I like using it where it allows me to see what code is running virtually inline of where it’s actually being ran, but still be able to remove code duplication.
That said, I understand how it could be seen as cluttered depending on perspective.
I don’t like this syntax at all, but I’m forced to use it in a bunch of places in the style code. Later versions of C++ lets you use “auto” without the “-> rettype” part, which is much nicer. However, I also try to use “auto” as little as possible; in most cases, spelling out the type makes the code easier to read, which is important.
So there is this section of code in dual_prop.h:
uint32_t map_button(uint32_t b) {
switch (b) {
#if NUM_BUTTONS == 3
case BUTTON_AUX: return BUTTON_FIRE;
case BUTTON_AUX2: return BUTTON_MODE_SELECT;
#else
case BUTTON_POWER: return BUTTON_FIRE;
case BUTTON_AUX: return BUTTON_MODE_SELECT;
#endif
default: return b; } }
uint32_t reverse_map_button(uint32_t b) {
switch (b) {
#if NUM_BUTTONS == 3
case BUTTON_FIRE: return BUTTON_AUX;
case BUTTON_MODE_SELECT: return BUTTON_AUX2;
#else
case BUTTON_FIRE: return BUTTON_POWER;
case BUTTON_MODE_SELECT: return BUTTON_AUX;
#endif
default: return b; } }
I understand it changes the mapping of the buttons for 3 or more buttons setup but I do not understand why is it helpfull or why is it desired ? Also I read in the forum that 3 buttons sabers are rare.
Is this part needed in multi_prop.h ?
Should I add to it for the other props (Detonator & Jetpack - in progress) that I have added to multi_prop.h ?
Thank you for your time.
The config will have CONFIG_BUTTONS where you define what they do.
For a saber, you’d have POWER and AUX (and/or AUX2).
This code maps those into the appropriate buttons (fire and mode).
In the case that it’s a 3 button prop, it maps button 3 to mode instead of button 2.
That’s all that’s happening here.
It’s required as the blaster prop looks for FIRE and MODE, not POWER and AUX.
Ok I think I understand,
I need to add #if PropMode::BLASTER:
and #if !PropMode::BLASTER:
That doesn’t work.
#if
is a preprocessor thing and doesn’t know anything about templates, and thus cannot evaluate “PropMode::BLASTER”.
So, do I need to change anything to that code ? How does the prop (Saber, Blaster, Detonator, Jetpack, …) “knows” to use map_button or reverse_map_button ?
Or how does multi_prop “knows” or “tells” when map_button or reverse_map_button is in use ?
And another question.
Is it possible to have different presets
#ifdef CONFIG_PRESETS
Preset presets[] = {
Depending if using a blade, a blaster, a detonator, …
The SaberBlasterProp assumes that the Blaster prop needs key mapping to work properly.
You can see that by checking where map_button & reverse_map_button is called.
You can’t use #if
, but you can use if()
.
If you don’t know the difference, I suggest this might be a good time to read up on C++ before proceeding.
Yes. The easy way is to override the id() function and then trigger FindBladeAgain() when you switch mode. Note that this will interfere with blade id unless you add some additional trickery.
Ah, ok, so SaberBlasterProp switches key mapping at each Prop change. That code makes more sense now.
I absolutely didn’t know there was a difference between #if
and ìf()` so tank you for pointing this out. But now that I know there is a difference, I will go find out about it.
Once again thank you for your time.