diff options
author | Jesusaves <cpntb1@ymail.com> | 2024-07-29 20:30:32 -0300 |
---|---|---|
committer | Jesusaves <cpntb1@ymail.com> | 2024-07-29 20:30:32 -0300 |
commit | b9d9ca30323376fbf85d2c3b343ac55442037eaf (patch) | |
tree | a11b3e2be9a26258bd5691839d20f5248fbd4d18 | |
parent | be589c38427860db867114afe0809f581a7a46fc (diff) | |
download | serverdata-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.txt | 298 | ||||
-rw-r--r-- | npc/functions/array.txt | 50 |
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 |