summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesusaves <cpntb1@ymail.com>2024-07-29 20:30:32 -0300
committerJesusaves <cpntb1@ymail.com>2024-07-29 20:30:32 -0300
commitb9d9ca30323376fbf85d2c3b343ac55442037eaf (patch)
treea11b3e2be9a26258bd5691839d20f5248fbd4d18
parentbe589c38427860db867114afe0809f581a7a46fc (diff)
downloadserverdata-b9d9ca30323376fbf85d2c3b343ac55442037eaf.tar.gz
serverdata-b9d9ca30323376fbf85d2c3b343ac55442037eaf.tar.bz2
serverdata-b9d9ca30323376fbf85d2c3b343ac55442037eaf.tar.xz
serverdata-b9d9ca30323376fbf85d2c3b343ac55442037eaf.zip
Poker NPC. My least favorite one.
-rw-r--r--npc/031-4/gambler.txt298
-rw-r--r--npc/functions/array.txt50
2 files changed, 261 insertions, 87 deletions
diff --git a/npc/031-4/gambler.txt b/npc/031-4/gambler.txt
index c0357486b..60da552d2 100644
--- a/npc/031-4/gambler.txt
+++ b/npc/031-4/gambler.txt
@@ -6,39 +6,66 @@
// $XAN_BETS: How many victories all players already had (for propaganda :3)
031-4,92,84,0 script Gambler#031-4 NPC_PLAYER,{
- function cardname{
+ function deal;
+ function cardname {
switch (getarg(0)) {
- case 0:
+ case 1:
return "A"; break;
- case 10:
- return "J"; break;
case 11:
- return "Q"; break;
+ return "J"; break;
case 12:
- return "K"; break;
+ return "Q"; break;
case 13:
- return l("Joker"); break;
+ return "K"; break;
+ default:
+ return str(getarg(0));
+ }
+ }
+ function suitname {
+ switch (getarg(0)) {
+ case 0:
+ return "Clubs"; break;
+ case 1:
+ return "Hearts"; break;
+ case 2:
+ return "Spades"; break;
+ case 3:
+ return "Diamonds"; break;
default:
- return getarg(0)+1;
+ return sprintf("%dERROR", getarg(0));
+ }
+ }
+ function playname {
+ switch (getarg(0)) {
+ case 23: return l("Royal Straight Flush"); break;
+ case 22: return l("Royal Straight"); break;
+ case 21: return l("Straight Flush"); break;
+ case 20: return l("Four of a Kind"); break;
+ case 19: return l("Full House"); break;
+ case 18: return l("Flush"); break;
+ case 17: return l("Straight"); break;
+ case 16: return l("Three of a Kind"); break;
+ case 15: return l("Two Pairs"); break;
+ case 14: return l("One Pair"); break;
+ default: return l("%s High", cardname(getarg(0))); break;
}
}
+ .@showMenu = true;
goto L_Menu;
L_Menu:
showavatar;
- mesn;
- mesc ("I'll futurely play Poker with you, but as I cannot show images side by side, showing your hand would take a LOT of space. So not available.");
- mesc ("The prize of an Axe Hat cannot be obtained, and thus, slot machine cannot be used.");
- if (!is_admin()) close;
- // Rank is CardNo / 13, and No is CardNo % 13
- // CardNo = 1+rand2(54)
- // Clubs, Diamonds, Hearts, Spades
- // cardJoker, use rand2(53) if you remove it
- //cardBack_{red,green,blue} / cardBack{1,2,3}
-
- mesc l("If a tie happens, I'll give your coin back.");
- next;
+ if (.@showMenu) {
+ mesn;
+ mesc l("Hey, do you want to play my card game?");
+ mesc l("It's essentially poker: I'll deal you five cards, then determine what you got. After that, I'll deal myself five cards, then determine what I got.");
+ mesc l("If your hand beats mine, you win. If my hand beats your, I win. Wanna play?");
+
+ mesc l("If a tie happens, I'll give your coin back.");
+ next;
+ .@showMenu=false;
+ }
menu
rif(countitem(CasinoCoins) >= 1, l("Let's play!")), L_Spin,
l("Information"), L_Info,
@@ -47,90 +74,187 @@ L_Menu:
L_Info:
mes "";
mesc l("Rules:");
- mesc l("A card will be flipped, you'll need to decide if next flip will be HIGHER or LOWER.");
- mesc l("Cards are ranked on this priority: A - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - J - Q - K - Joker");
+ mesc l("You'll be given five cards. The winning hand is the one with highest combo.");
+ mesc l("Combos are ranked on this priority: Royal Straight Flush > Straight Flush > Four of a Kind > Full House > Flush > Straight > Three of a Kind > Two Pairs > One Pair > Card");
+ mesc l("Cards are ranked on this priority: A - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - J - Q - K");
next;
mesc l("Prizes:");
- mesc l("If you're right, you'll get at least 80 GP!");
- mesc l("You'll also get half of the GP as Monster Points!");
+ //mesc("If you beat my hand, you'll win 110 GP!");
+ mesc l("If you beat my hand, you'll win some GP!");
+ mesc l("You'll also get a %s!", getitemlink(MaggotSlime));
+ mesc l("* Slime not included if you didn't got any combo.");
mesc l("If a tie happens, you'll get your coin back.");
- mesc l("If you're wrong, your winning streak is reset.");
- mesc l("Winning Streak is also reset on logout or when you leave the Inn.");
- next;
- mesc l("Winning Strike Prizes:");
- mesc l("If you get 10 successive right guesses, you'll get a %s!", getitemlink(SantaHat));
- mesc l("Every seven successive right guesses, you'll get a %s!", getitemlink(BronzeGift)); // 7.14%
- mesc l("Every fifteen successive right guesses, you'll get a @@!", getitemlink(SilverGift)); // 3.33%
- mesc l("Every fifty successive right guesses, you'll get a @@!", getitemlink(GoldenGift)); // 1.00%
- mesc l("Every 101 successive right guesses, you'll get a @@!", getitemlink(PrismGift)); // 0.50%
+ mes "";
+ mesc l("If you get a %s, you'll also get a %s.", playname(23), getitemlink(SupremeGift)); // Royal Straight Flush, 1:100, 0.00015%
+ mesc l("If you get a %s, you'll also get a %s.", playname(21), getitemlink(PrismGift)); // Straight Flush, 1:50, 0.0014%
+ mesc l("If you get a %s, you'll also get a %s.", playname(20), getitemlink(AxeHat)); // Four of a Kind, 1:20, 0.024%
+ mesc l("If you get a %s, you'll also get a %s.", playname(19), getitemlink(BronzeGift)); // Full House, 1:7, 0.10%
+ mesc l("If you get a %s, you'll also get a %s.", playname(18), getitemlink(MintDonut)); // Flush, 1:5, 0.2%
+ mesc l("If you get a %s, you'll also get a %s.", playname(17), getitemlink(StrangeCoin)); // Straight, 1:4, 0.4%
+ // 3oK 1:3 2%, 2P 1:2 5%, Pair 1:1 42%
+ // No pair has 50.25% chance and has no payout (1:0)
+ mesc l("You need to beat the Dealer's hand to get those prizes."), 1;
+ mesc l("If you don't have a %s, you'll receive it instead of the %s.", getitemlink(AxeHat), getitemlink(PrismGift)), 1;
+ // Source: Encyclopedia Britannica
next;
goto L_Menu;
L_Spin:
- showavatar AVATAR_CARD_COVER;
- mesc l("I'll draw a card now!");
+ clear;
+ img("cards/cardBack_green");
+ mesc l("I'll draw your hand now!");
next;
delitem CasinoCoins, 1;
- // First card will never be an edge card (Ace or Joker), so you can ALWAYS guess wrong.
- .@card1=rand(1, 12);
- showavatar 1000+.@card1;
- mesn;
- mesc l("It's a @@!", cardname(.@card1));
- mesc l("Will next draw be HIGHER or LOWER?!");
+ .@myRank = deal();
+ mesc l("You scored a(n) %s!", b(playname(.@myRank)));
next;
- mesc l("Cards are ranked on this priority: A - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - J - Q - K - Joker");
- select
- l("HIGHER!"),
- l("LOWER!");
- mes "";
-
- // Flip Flop!
- .@card2=rand(0, 13);
- showavatar 1000+.@card2;
- mesn;
- mesc l("It's a @@!", cardname(.@card2));
+ clear;
+ img("cards/cardBack_red");
+ mesc l("I'll draw my hand now!");
+ next;
+ delitem CasinoCoins, 1;
+ .@aiRank = deal();
+ mesc l("I scored a(n) %s!", b(playname(.@aiRank)));
+ next;
+ clear;
- if (.@card1 == .@card2) {
- mesc l("It's a tie!");
+ if (.@aiRank == .@myRank) {
getitem CasinoCoins, 1;
- .@bypass=1;
- } else if (.@card2 < .@card1 && @menu == 2) {
- mesc l("It's lower! That's right!");
- Zeny=Zeny+80;
- @gambler_winstreak=@gambler_winstreak+1;
- } else if (.@card2 > .@card1 && @menu == 1) {
- mesc l("It's higher! That's right!");
- Zeny=Zeny+80;
- @gambler_winstreak=@gambler_winstreak+1;
- } else {
- mesc l("You were wrong!");
- @gambler_winstreak=0;
+ img("cards/cardBack_blue");
+ mesc l("It's a tie! You get your coin back!"), 3;
+ } else if (.@aiRank > .@myRank) {
+ img("cards/cardBack_red");
+ mesc l("It looks like I won! Better luck next time!"), 1;
+ } else if (.@myRank > .@aiRank) {
+ img("cards/cardBack_green");
+ mesc l("Ahahah, I concede defeat! Here's your prize!"), 2;
+ .@gp = 40 + 110 * .@myRank / 18;
+ getexp .@gp, .@myRank;
+ switch (.@myRank) {
+ case 23: getitem SupremeGift, 1; break;
+ case 21:
+ if (countitem(AxeHat))
+ getitem PrismGift, 1;
+ else
+ getitem AxeHat, 1;
+ break;
+ case 20: getitem AxeHat, 1; break;
+ case 19: getitem BronzeGift, 1; break;
+ case 18: getitem MintDonut, 1; break;
+ case 17: getitem StrangeCoin, 1; break;
+ case 16:
+ case 15:
+ case 14:
+ getitem MaggotSlime, 1;
+ // FALLTHROUGH
+ default:
+ Zeny += .@gp;
+ break;
+ }
}
+ dnext;
+ goto L_Menu;
- // Winning Streak
- if (!.@bypass && @gambler_winstreak) {
- if (@gambler_winstreak % 7 == 0)
- getitem BronzeGift, 1;
- if (@gambler_winstreak % 15 == 0)
- getitem SilverGift, 1;
- if (@gambler_winstreak % 50 == 0)
- getitem GoldenGift, 1;
- if (@gambler_winstreak % 101 == 0)
- getitem PrismGift, 1;
- if (@gambler_winstreak == 10)
- getitem SantaHat, 1;
- mesc l("Your current win streak is @@!", @gambler_winstreak);
- $XAN_BETS=$XAN_BETS+1;
- Zeny+=min((@gambler_winstreak*2), 40);
- Mobpt+=40+min(@gambler_winstreak, 20);
- } else {
- .@bypass=0;
+// deal(show=True), returns score
+function deal {
+ // Give you 5 cards
+ // We cannot "give 7 cards ask to chose 5" because "chose 5" is NOT OK
+ freeloop(true);
+ while (getarraysize(.@cards) < 5) {
+ .@tmp = rand2(52);
+ if (.@tmp >= 52 || .@tmp < 0) Exception("Poker - Division by zero: "+str(.@tmp), RB_DEBUGMES|RB_IRCBROADCAST|RB_ISFATAL);
+ if (array_find(.@cards, .@tmp) == -1)
+ array_push(.@cards, .@tmp);
+ freeloop(true); // array_find can unset it
}
- next;
- goto L_Menu;
+ freeloop(false);
+
+ // Get their rank (err... suit) and number (err... actual rank)
+ // The order doesn't matter, so everything is in an array
+ .@r[0] = .@cards[0] / 13;
+ .@n[0] = .@cards[0] % 13 + 1;
+ .@r[1] = .@cards[1] / 13;
+ .@n[1] = .@cards[1] % 13 + 1;
+ .@r[2] = .@cards[2] / 13;
+ .@n[2] = .@cards[2] % 13 + 1;
+ .@r[3] = .@cards[3] / 13;
+ .@n[3] = .@cards[3] % 13 + 1;
+ .@r[4] = .@cards[4] / 13;
+ .@n[4] = .@cards[4] % 13 + 1;
+
+ // Display the cards? Do it now, before we modify the data
+ if (getarg(0, true)) {
+ debugmes sprintf("cards/card%s%d", suitname(.@r[0]), .@n[0]);
+ debugmes sprintf("cards/card%s%d", suitname(.@r[1]), .@n[1]);
+ debugmes sprintf("cards/card%s%d", suitname(.@r[2]), .@n[2]);
+ debugmes sprintf("cards/card%s%d", suitname(.@r[3]), .@n[3]);
+ debugmes sprintf("cards/card%s%d", suitname(.@r[4]), .@n[4]);
+ img(sprintf("cards/card%s%d", suitname(.@r[0]), .@n[0]));
+ img(sprintf("cards/card%s%d", suitname(.@r[1]), .@n[1]));
+ img(sprintf("cards/card%s%d", suitname(.@r[2]), .@n[2]));
+ img(sprintf("cards/card%s%d", suitname(.@r[3]), .@n[3]));
+ img(sprintf("cards/card%s%d", suitname(.@r[4]), .@n[4]));
+ }
+
+ // Essentially, we don't care if the card number and suit is changed
+ array_sort_asc(.@n);
+
+ // Calculations related to the card number
+ // FIXME: The array is sorted, do we need O(n²) complexity?
+ .@t = 0; // Mode Number (from the three M operations = Average, Mode, Median)
+ .@c = 0; // Count of it
+ .@p = 0; // Last pair
+ for (.@i=0;.@i <= 13;.@i++) {
+ .@tmp = array_count(.@n, .@i);
+ // An unique pair for Full House and Two Pairs
+ if (.@tmp == 2 && .@p != .@i)
+ .@p = .@i;
+ // More than what we remember
+ if (.@tmp > .@c) {
+ .@t = .@i;
+ .@c = .@tmp;
+ }
+ }
+ // Shorthandlers
+ .@straight = (.@n[0]+1 == .@n[1] && .@n[1]+1 == .@n[2] && .@n[2]+1 == .@n[3] && .@n[3]+1 == .@n[4]);
+ .@royal = (.@n[0] == 1 && .@n[1] == 10 && .@n[2] == 11 && .@n[3] == 12 && .@n[4] == 13);
+ .@flush = (array_count(.@r, 0) == 5 || array_count(.@r, 1) == 5 || array_count(.@r, 2) == 5 || array_count(.@r, 3) == 5);
+ .@paires = (.@p > 0 && .@p != .@t);
+
+ // Complex logic like this one is avoided by sorting
+ //if (array_find(.@n, 1) && array_find(.@n, 10) && array_find(.@n, 11) && array_find(.@n, 12) && array_find(.@n, 13))
+
+ // Determine the result of your hand
+ // Note that it goes up to 13 (card high), then pair is at 14
+ if (.@royal && .@flush)
+ .@result = 23; // Royal Straight Flush
+ //else if (.@royal) // TODO: Should this be just a straight then?
+ // .@result = 22; // Royal Straight
+ else if (.@straight && .@flush)
+ .@result = 21; // Straight Flush
+ else if (.@c == 4)
+ .@result = 20; // Four of a kind
+ else if (.@c == 3 && .@p > 0)
+ .@result = 19; // Full house
+ else if (.@flush)
+ .@result = 18; // Flush
+ else if (.@straight)
+ .@result = 17; // Straight
+ else if (.@c == 3)
+ .@result = 16; // Three of a kind
+ else if (.@c == 2 && .@paires)
+ .@result = 15; // Two pairs
+ else if (.@c == 2)
+ .@result = 14; // One pair
+ else
+ .@result = .@n[4]; // Nothing special
+
+ return .@result;
+}
L_Quit:
+ closeclientdialog;
close;
OnInit:
@@ -138,7 +262,7 @@ OnInit:
.distance = 4;
.@npcId = getnpcid(.name$);
setunitdata(.@npcId, UDT_HEADTOP, TopHat);
- setunitdata(.@npcId, UDT_HEADMIDDLE, CreasedShirt);
+ setunitdata(.@npcId, UDT_HEADMIDDLE, Bathrobe);
setunitdata(.@npcId, UDT_HEADBOTTOM, JeansShorts);
npcsit;
end;
diff --git a/npc/functions/array.txt b/npc/functions/array.txt
index 48bafff3e..d9fc43bab 100644
--- a/npc/functions/array.txt
+++ b/npc/functions/array.txt
@@ -163,6 +163,56 @@ function script array_remove {
+// array_sort_asc(<array>)
+// sorts the array. Index always 0
+
+function script array_sort_asc {
+ .@asc = getarg(1, true);
+ .@size = getarraysize(getarg(0));
+
+ freeloop(true);
+
+ for (.@i = 0; .@i < .@size; .@i++) {
+ .@min = .@i;
+ // Complexity O(n²)
+ for (.@j = .@i+1; .@j < .@size; .@j++) {
+ if (getelementofarray(getarg(0), .@j) < getelementofarray(getarg(0), .@min))
+ .@min = .@j;
+ }
+ swap(getelementofarray(getarg(0), .@min), getelementofarray(getarg(0), .@i));
+ }
+
+ freeloop(false);
+ return true;
+}
+
+
+
+// array_sort_desc(<array>)
+// sorts the array. Index always 0
+
+function script array_sort_dessc {
+ .@asc = getarg(1, true);
+ .@size = getarraysize(getarg(0));
+
+ freeloop(true);
+
+ for (.@i = 0; .@i < .@size; .@i++) {
+ .@min = .@i;
+ // Complexity O(n²)
+ for (.@j = .@i+1; .@j < .@size; .@j++) {
+ if (getelementofarray(getarg(0), .@j) > getelementofarray(getarg(0), .@min))
+ .@min = .@j;
+ }
+ swap(getelementofarray(getarg(0), .@min), getelementofarray(getarg(0), .@i));
+ }
+
+ freeloop(false);
+ return true;
+}
+
+
+
// array_reverse(<array>)
// reverses the array