summaryrefslogtreecommitdiff
path: root/npc/031-4/gambler.txt
blob: d523f710becabf03331b15b5c0709cfb5d0ac59b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// TMW2 Scripts
// Author:
//    Jesusalva
// Description:
//    Gambler: Will next card be better or worse?
//    $XAN_BETS: How many victories all players already had (for propaganda :3)

031-4,92,84,0	script	Gambler#031-4	NPC_PLAYER,{
    function deal;
    function cardname {
        switch (getarg(0)) {
        case 1:
            return "A"; break;
        case 11:
            return "J"; break;
        case 12:
            return "Q"; break;
        case 13:
            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 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;
    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,
        rif(countitem(CasinoCoins) >= 2, l("Make it a quick game!")), L_Short,
        l("Information"), L_Info,
        l("Leave"), L_Quit;

L_Info:
    mes "";
    mesc l("Rules:");
    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("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.");
    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:
    clear;
    img("cards/cardBack_green");
    mesc l("I'll draw your hand now!");
    next;
    delitem CasinoCoins, 1;
    .@myRank = deal();
    mesc l("You scored a(n) %s!", b(playname(.@myRank)));
    next;
    clear;
    img("cards/cardBack_red");
    mesc l("I'll draw my hand now!");
    next;
    .@aiRank = deal();
    mesc l("I scored a(n) %s!", b(playname(.@aiRank)));
    next;
    clear;

L_Tally:
    if (.@aiRank == .@myRank) {
        getitem CasinoCoins, 1;
        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;
        }
        X24Event(X24_POKER);
    }
    dnext;
    goto L_Menu;

L_Short:
    delitem CasinoCoins, 1;
    clear;
    img("cards/cardBack_green");
    .@myRank = deal();
    img("cards/cardBack_red");
    .@aiRank = deal();
    mes "";
    mesc l("You scored a(n) %s!", b(playname(.@myRank)));
    mesc l("I scored a(n) %s!", b(playname(.@aiRank)));
    dnext;
    clear;
    mesc l("You scored a(n) %s!", b(playname(.@myRank)));
    mesc l("I scored a(n) %s!", b(playname(.@aiRank)));
    mes "";
    goto L_Tally;

// 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
    }
    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)) {
        if ($@GM_OVERRIDE) {
            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:
    .sex = G_MALE;
    .distance = 4;
    .@npcId = getnpcid(.name$);
    setunitdata(.@npcId, UDT_HEADTOP,    TopHat);
    setunitdata(.@npcId, UDT_HEADMIDDLE, Bathrobe);
    setunitdata(.@npcId, UDT_HEADBOTTOM, JeansShorts);
    npcsit;
    end;

}