Drawing cards simultanously while not losing the game
This is the result of trying to fix Prosperity. It has (hopefully soon had) the issue that the active player loses the game even If both players run out of cards which should end in a draw. I fixed it easily but then you throw in cards like Laboratory Maniac and suddenly things become interesting… so the idea was to write a more general function both_players_draw() for Wheel of Fortune and similar cards that takes this issue into account.
What we want is something like this:
I understand that there is a LOSE_GAME event in Shandalar that we could (ab)use but up to my knowledge there is no such thing in Manalink. Lacking an alternative that is more in line with the game mechanics I came up with something else. I know that this is the proverbial sledgehammer to crack a nut so suggestions how to solve this issue differently are welcome.
The code now looks like this:
I didn‘t want to use a global variable as I need some functionality around this mutex and also some access control. Which is why it is implemented the way it is, namely a so-called Singleton (https://en.wikipedia.org/wiki/Singleton_pattern). My previous comment about a better world with less Singletons applies accordingly.
The next issue is coming back from lose_the_game while recording calls. We need to go back to the initial caller, here draw_cards, but we don‘t know how we got there. draw_cards might call lose_the_game directly or the Laboratory Manic or some other card might have done so. So we need to take all the previous calls from the call stack, otherwise we end up in a mess. If we want to stay within C longjmp() is the only way I know, basically a goto command across functions (goto is something that usually makes people green in the face but there are legitimate uses…). I want to stay within C as I don‘t know what calls go through the exe and what happens there. C++ would offer a more elegant solution with try/catch, basically throwing an exception instead of calling longjmp and doing nothing after the catch, but I don‘t know how the exe behaves when a exception passes by as there is probably no code to handle it (which in turn might introduce various new hard-to-track bugs).
Note that Laboratory Maniac is just an example for some card that changes the outcome of lose_the_game and adds to the call stack. You could also introduce Jace, Wielder of Mysteries or other cards that do something similar.
A toy example implementing this is attached. Since it is more future-proof than checking for the existence of individual cards (my current hack) the plan is to implement this in Manalink and see what happens.
What do you think?
What we want is something like this:
- Code: Select all
int both_players_draw(player_t player, int amount) {
loseGameStartsRecordingIncomingCalls();
draw_cards(player, amount);
draw_cards(1-player, amount); // opposite player as player is always 0 or 1
loseGameStopsRecordingIncomingCallsAndEvaluateResult();
// If both players had enough cards we end up here, otherwise the game ends beforehand.
return 0;
}
I understand that there is a LOSE_GAME event in Shandalar that we could (ab)use but up to my knowledge there is no such thing in Manalink. Lacking an alternative that is more in line with the game mechanics I came up with something else. I know that this is the proverbial sledgehammer to crack a nut so suggestions how to solve this issue differently are welcome.
The code now looks like this:
- Code: Select all
static jmp_buf buf;
int both_players_draw_better(player_t player, int amount) {
loseGameRecorder::instance().startRecording();
if (!setjmp(buf)) {
draw_cards(player, amount);
}
if (!setjmp(buf)) {
draw_cards(1-player, amount);
}
loseGameRecorder::instance().stopRecording();
return 0;
}
I didn‘t want to use a global variable as I need some functionality around this mutex and also some access control. Which is why it is implemented the way it is, namely a so-called Singleton (https://en.wikipedia.org/wiki/Singleton_pattern). My previous comment about a better world with less Singletons applies accordingly.
The next issue is coming back from lose_the_game while recording calls. We need to go back to the initial caller, here draw_cards, but we don‘t know how we got there. draw_cards might call lose_the_game directly or the Laboratory Manic or some other card might have done so. So we need to take all the previous calls from the call stack, otherwise we end up in a mess. If we want to stay within C longjmp() is the only way I know, basically a goto command across functions (goto is something that usually makes people green in the face but there are legitimate uses…). I want to stay within C as I don‘t know what calls go through the exe and what happens there. C++ would offer a more elegant solution with try/catch, basically throwing an exception instead of calling longjmp and doing nothing after the catch, but I don‘t know how the exe behaves when a exception passes by as there is probably no code to handle it (which in turn might introduce various new hard-to-track bugs).
Note that Laboratory Maniac is just an example for some card that changes the outcome of lose_the_game and adds to the call stack. You could also introduce Jace, Wielder of Mysteries or other cards that do something similar.
A toy example implementing this is attached. Since it is more future-proof than checking for the existence of individual cards (my current hack) the plan is to implement this in Manalink and see what happens.
What do you think?