1 /**
2 * @file inv.cpp
3 *
4 * Implementation of player inventory.
5 */
6 #include "all.h"
7 #include "options.h"
8
9 DEVILUTION_BEGIN_NAMESPACE
10
11 BOOL invflag;
12 BYTE *pInvCels;
13 BOOL drawsbarflag;
14 int sgdwLastTime; // check name
15
16 /**
17 * Maps from inventory slot to screen position. The inventory slots are
18 * arranged as follows:
19 * 00 01
20 * 02 03 06
21 * 07 08 19 20 13 14
22 * 09 10 21 22 15 16
23 * 11 12 23 24 17 18
24 * 04 05
25 * 25 26 27 28 29 30 31 32 33 34
26 * 35 36 37 38 39 40 41 42 43 44
27 * 45 46 47 48 49 50 51 52 53 54
28 * 55 56 57 58 59 60 61 62 63 64
29 * 65 66 67 68 69 70 71 72
30 * @see graphics/inv/inventory.png
31 */
32 const InvXY InvRect[] = {
33 // clang-format off
34 // X, Y
35 { 132, 31 }, // helmet
36 { 160, 31 }, // helmet
37 { 132, 59 }, // helmet
38 { 160, 59 }, // helmet
39 { 45, 205 }, // left ring
40 { 247, 205 }, // right ring
41 { 204, 59 }, // amulet
42 { 17, 104 }, // left hand
43 { 46, 104 }, // left hand
44 { 17, 132 }, // left hand
45 { 46, 132 }, // left hand
46 { 17, 160 }, // left hand
47 { 46, 160 }, // left hand
48 { 247, 104 }, // right hand
49 { 276, 104 }, // right hand
50 { 247, 132 }, // right hand
51 { 276, 132 }, // right hand
52 { 247, 160 }, // right hand
53 { 276, 160 }, // right hand
54 { 132, 104 }, // chest
55 { 160, 104 }, // chest
56 { 132, 132 }, // chest
57 { 160, 132 }, // chest
58 { 132, 160 }, // chest
59 { 160, 160 }, // chest
60 { 17, 250 }, // inv row 1
61 { 46, 250 }, // inv row 1
62 { 75, 250 }, // inv row 1
63 { 104, 250 }, // inv row 1
64 { 133, 250 }, // inv row 1
65 { 162, 250 }, // inv row 1
66 { 191, 250 }, // inv row 1
67 { 220, 250 }, // inv row 1
68 { 249, 250 }, // inv row 1
69 { 278, 250 }, // inv row 1
70 { 17, 279 }, // inv row 2
71 { 46, 279 }, // inv row 2
72 { 75, 279 }, // inv row 2
73 { 104, 279 }, // inv row 2
74 { 133, 279 }, // inv row 2
75 { 162, 279 }, // inv row 2
76 { 191, 279 }, // inv row 2
77 { 220, 279 }, // inv row 2
78 { 249, 279 }, // inv row 2
79 { 278, 279 }, // inv row 2
80 { 17, 308 }, // inv row 3
81 { 46, 308 }, // inv row 3
82 { 75, 308 }, // inv row 3
83 { 104, 308 }, // inv row 3
84 { 133, 308 }, // inv row 3
85 { 162, 308 }, // inv row 3
86 { 191, 308 }, // inv row 3
87 { 220, 308 }, // inv row 3
88 { 249, 308 }, // inv row 3
89 { 278, 308 }, // inv row 3
90 { 17, 337 }, // inv row 4
91 { 46, 337 }, // inv row 4
92 { 75, 337 }, // inv row 4
93 { 104, 337 }, // inv row 4
94 { 133, 337 }, // inv row 4
95 { 162, 337 }, // inv row 4
96 { 191, 337 }, // inv row 4
97 { 220, 337 }, // inv row 4
98 { 249, 337 }, // inv row 4
99 { 278, 337 }, // inv row 4
100 { 205, 33 }, // belt
101 { 234, 33 }, // belt
102 { 263, 33 }, // belt
103 { 292, 33 }, // belt
104 { 321, 33 }, // belt
105 { 350, 33 }, // belt
106 { 379, 33 }, // belt
107 { 408, 33 } // belt
108 // clang-format on
109 };
110
111 /* data */
112 /** Specifies the starting inventory slots for placement of 2x2 items. */
113 int AP2x2Tbl[10] = { 8, 28, 6, 26, 4, 24, 2, 22, 0, 20 };
114
FreeInvGFX()115 void FreeInvGFX()
116 {
117 MemFreeDbg(pInvCels);
118 }
119
InitInv()120 void InitInv()
121 {
122 if (plr[myplr]._pClass == PC_WARRIOR) {
123 pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL);
124 } else if (plr[myplr]._pClass == PC_ROGUE) {
125 pInvCels = LoadFileInMem("Data\\Inv\\Inv_rog.CEL", NULL);
126 } else if (plr[myplr]._pClass == PC_SORCERER) {
127 pInvCels = LoadFileInMem("Data\\Inv\\Inv_Sor.CEL", NULL);
128 } else if (plr[myplr]._pClass == PC_MONK) {
129 if (!gbIsSpawn)
130 pInvCels = LoadFileInMem("Data\\Inv\\Inv_Sor.CEL", NULL);
131 else
132 pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL);
133 } else if (plr[myplr]._pClass == PC_BARD) {
134 pInvCels = LoadFileInMem("Data\\Inv\\Inv_rog.CEL", NULL);
135 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
136 pInvCels = LoadFileInMem("Data\\Inv\\Inv.CEL", NULL);
137 }
138
139 invflag = FALSE;
140 drawsbarflag = FALSE;
141 }
142
InvDrawSlotBack(CelOutputBuffer out,int X,int Y,int W,int H)143 static void InvDrawSlotBack(CelOutputBuffer out, int X, int Y, int W, int H)
144 {
145 BYTE *dst;
146
147 dst = out.at(X, Y);
148
149 int wdt, hgt;
150 BYTE pix;
151
152 for (hgt = H; hgt; hgt--, dst -= out.pitch() + W) {
153 for (wdt = W; wdt; wdt--) {
154 pix = *dst;
155 if (pix >= PAL16_BLUE) {
156 if (pix <= PAL16_BLUE + 15)
157 pix -= PAL16_BLUE - PAL16_BEIGE;
158 else if (pix >= PAL16_GRAY)
159 pix -= PAL16_GRAY - PAL16_BEIGE;
160 }
161 *dst++ = pix;
162 }
163 }
164 }
165
DrawInv(CelOutputBuffer out)166 void DrawInv(CelOutputBuffer out)
167 {
168 BOOL invtest[NUM_INV_GRID_ELEM];
169 int frame, frame_width, color, screen_x, screen_y, i, j, ii;
170
171 CelDrawTo(out, RIGHT_PANEL_X, 351, pInvCels, 1, SPANEL_WIDTH);
172
173 if (!plr[myplr].InvBody[INVLOC_HEAD].isEmpty()) {
174 InvDrawSlotBack(out, RIGHT_PANEL_X + 133, 59, 2 * INV_SLOT_SIZE_PX, 2 * INV_SLOT_SIZE_PX);
175
176 frame = plr[myplr].InvBody[INVLOC_HEAD]._iCurs + CURSOR_FIRSTITEM;
177 frame_width = InvItemWidth[frame];
178
179 if (pcursinvitem == INVITEM_HEAD) {
180 color = ICOL_WHITE;
181 if (plr[myplr].InvBody[INVLOC_HEAD]._iMagical != ITEM_QUALITY_NORMAL) {
182 color = ICOL_BLUE;
183 }
184 if (!plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag) {
185 color = ICOL_RED;
186 }
187 if (frame <= 179) {
188 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 133, 59, pCursCels, frame, frame_width, false);
189 } else {
190 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 133, 59, pCursCels2, frame - 179, frame_width, false);
191 }
192 }
193
194 if (plr[myplr].InvBody[INVLOC_HEAD]._iStatFlag) {
195 if (frame <= 179) {
196 CelClippedDrawTo(out, RIGHT_PANEL_X + 133, 59, pCursCels, frame, frame_width);
197 } else {
198 CelClippedDrawTo(out, RIGHT_PANEL_X + 133, 59, pCursCels2, frame - 179, frame_width);
199 }
200 } else {
201 if (frame <= 179) {
202 CelDrawLightRedTo(out, RIGHT_PANEL_X + 133, 59, pCursCels, frame, frame_width, 1);
203 } else {
204 CelDrawLightRedTo(out, RIGHT_PANEL_X + 133, 59, pCursCels2, frame - 179, frame_width, 1);
205 }
206 }
207 }
208
209 if (!plr[myplr].InvBody[INVLOC_RING_LEFT].isEmpty()) {
210 InvDrawSlotBack(out, RIGHT_PANEL_X + 48, 205, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX);
211
212 frame = plr[myplr].InvBody[INVLOC_RING_LEFT]._iCurs + CURSOR_FIRSTITEM;
213 frame_width = InvItemWidth[frame];
214
215 if (pcursinvitem == INVITEM_RING_LEFT) {
216 color = ICOL_WHITE;
217 if (plr[myplr].InvBody[INVLOC_RING_LEFT]._iMagical != ITEM_QUALITY_NORMAL) {
218 color = ICOL_BLUE;
219 }
220 if (!plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag) {
221 color = ICOL_RED;
222 }
223 if (frame <= 179) {
224 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 48, 205, pCursCels, frame, frame_width, false);
225 } else {
226 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 48, 205, pCursCels2, frame - 179, frame_width, false);
227 }
228 }
229
230 if (plr[myplr].InvBody[INVLOC_RING_LEFT]._iStatFlag) {
231 if (frame <= 179) {
232 CelClippedDrawTo(out, RIGHT_PANEL_X + 48, 205, pCursCels, frame, frame_width);
233 } else {
234 CelClippedDrawTo(out, RIGHT_PANEL_X + 48, 205, pCursCels2, frame - 179, frame_width);
235 }
236 } else {
237 if (frame <= 179) {
238 CelDrawLightRedTo(out, RIGHT_PANEL_X + 48, 205, pCursCels, frame, frame_width, 1);
239 } else {
240 CelDrawLightRedTo(out, RIGHT_PANEL_X + 48, 205, pCursCels2, frame - 179, frame_width, 1);
241 }
242 }
243 }
244
245 if (!plr[myplr].InvBody[INVLOC_RING_RIGHT].isEmpty()) {
246 InvDrawSlotBack(out, RIGHT_PANEL_X + 249, 205, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX);
247
248 frame = plr[myplr].InvBody[INVLOC_RING_RIGHT]._iCurs + CURSOR_FIRSTITEM;
249 frame_width = InvItemWidth[frame];
250
251 if (pcursinvitem == INVITEM_RING_RIGHT) {
252 color = ICOL_WHITE;
253 if (plr[myplr].InvBody[INVLOC_RING_RIGHT]._iMagical != ITEM_QUALITY_NORMAL) {
254 color = ICOL_BLUE;
255 }
256 if (!plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag) {
257 color = ICOL_RED;
258 }
259 if (frame <= 179) {
260 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 249, 205, pCursCels, frame, frame_width, false);
261 } else {
262 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 249, 205, pCursCels2, frame - 179, frame_width, false);
263 }
264 }
265
266 if (plr[myplr].InvBody[INVLOC_RING_RIGHT]._iStatFlag) {
267 if (frame <= 179) {
268 CelClippedDrawTo(out, RIGHT_PANEL_X + 249, 205, pCursCels, frame, frame_width);
269 } else {
270 CelClippedDrawTo(out, RIGHT_PANEL_X + 249, 205, pCursCels2, frame - 179, frame_width);
271 }
272 } else {
273 if (frame <= 179) {
274 CelDrawLightRedTo(out, RIGHT_PANEL_X + 249, 205, pCursCels, frame, frame_width, 1);
275 } else {
276 CelDrawLightRedTo(out, RIGHT_PANEL_X + 249, 205, pCursCels2, frame - 179, frame_width, 1);
277 }
278 }
279 }
280
281 if (!plr[myplr].InvBody[INVLOC_AMULET].isEmpty()) {
282 InvDrawSlotBack(out, RIGHT_PANEL_X + 205, 60, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX);
283
284 frame = plr[myplr].InvBody[INVLOC_AMULET]._iCurs + CURSOR_FIRSTITEM;
285 frame_width = InvItemWidth[frame];
286
287 if (pcursinvitem == INVITEM_AMULET) {
288 color = ICOL_WHITE;
289 if (plr[myplr].InvBody[INVLOC_AMULET]._iMagical != ITEM_QUALITY_NORMAL) {
290 color = ICOL_BLUE;
291 }
292 if (!plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag) {
293 color = ICOL_RED;
294 }
295 if (frame <= 179) {
296 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 205, 60, pCursCels, frame, frame_width, false);
297 } else {
298 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 205, 60, pCursCels2, frame - 179, frame_width, false);
299 }
300 }
301
302 if (plr[myplr].InvBody[INVLOC_AMULET]._iStatFlag) {
303 if (frame <= 179) {
304 CelClippedDrawTo(out, RIGHT_PANEL_X + 205, 60, pCursCels, frame, frame_width);
305 } else {
306 CelClippedDrawTo(out, RIGHT_PANEL_X + 205, 60, pCursCels2, frame - 179, frame_width);
307 }
308 } else {
309 if (frame <= 179) {
310 CelDrawLightRedTo(out, RIGHT_PANEL_X + 205, 60, pCursCels, frame, frame_width, 1);
311 } else {
312 CelDrawLightRedTo(out, RIGHT_PANEL_X + 205, 60, pCursCels2, frame - 179, frame_width, 1);
313 }
314 }
315 }
316
317 if (!plr[myplr].InvBody[INVLOC_HAND_LEFT].isEmpty()) {
318 InvDrawSlotBack(out, RIGHT_PANEL_X + 17, 160, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX);
319
320 frame = plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCurs + CURSOR_FIRSTITEM;
321 frame_width = InvItemWidth[frame];
322 // calc item offsets for weapons smaller than 2x3 slots
323 screen_x = frame_width == INV_SLOT_SIZE_PX ? (RIGHT_PANEL_X + 31) : (RIGHT_PANEL_X + 17);
324 screen_y = InvItemHeight[frame] == (3 * INV_SLOT_SIZE_PX) ? (160) : (146);
325
326 if (pcursinvitem == INVITEM_HAND_LEFT) {
327 color = ICOL_WHITE;
328 if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMagical != ITEM_QUALITY_NORMAL) {
329 color = ICOL_BLUE;
330 }
331 if (!plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
332 color = ICOL_RED;
333 }
334 if (frame <= 179) {
335 CelBlitOutlineTo(out, color, screen_x, screen_y, pCursCels, frame, frame_width, false);
336 } else {
337 CelBlitOutlineTo(out, color, screen_x, screen_y, pCursCels2, frame - 179, frame_width, false);
338 }
339 }
340
341 if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iStatFlag) {
342 if (frame <= 179) {
343 CelClippedDrawTo(out, screen_x, screen_y, pCursCels, frame, frame_width);
344 } else {
345 CelClippedDrawTo(out, screen_x, screen_y, pCursCels2, frame - 179, frame_width);
346 }
347 } else {
348 if (frame <= 179) {
349 CelDrawLightRedTo(out, screen_x, screen_y, pCursCels, frame, frame_width, 1);
350 } else {
351 CelDrawLightRedTo(out, screen_x, screen_y, pCursCels2, frame - 179, frame_width, 1);
352 }
353 }
354
355 if (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iLoc == ILOC_TWOHAND) {
356 if (plr[myplr]._pClass != PC_BARBARIAN
357 || (plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_SWORD
358 && plr[myplr].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_MACE)) {
359 InvDrawSlotBack(out, RIGHT_PANEL_X + 248, 160, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX);
360 light_table_index = 0;
361 cel_transparency_active = TRUE;
362
363 const int dst_x = RIGHT_PANEL_X + (frame_width == INV_SLOT_SIZE_PX ? 261 : 247);
364 const int dst_y = 160;
365 if (frame <= 179) {
366 CelClippedBlitLightTransTo(out, dst_x, dst_y, pCursCels, frame, frame_width);
367 } else {
368 CelClippedBlitLightTransTo(out, dst_x, dst_y, pCursCels2, frame - 179, frame_width);
369 }
370
371 cel_transparency_active = FALSE;
372 }
373 }
374 }
375 if (!plr[myplr].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
376 InvDrawSlotBack(out, RIGHT_PANEL_X + 248, 160, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX);
377
378 frame = plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iCurs + CURSOR_FIRSTITEM;
379 frame_width = InvItemWidth[frame];
380 // calc item offsets for weapons smaller than 2x3 slots
381 screen_x = frame_width == INV_SLOT_SIZE_PX ? (RIGHT_PANEL_X + 261) : (RIGHT_PANEL_X + 249);
382 screen_y = InvItemHeight[frame] == 3 * INV_SLOT_SIZE_PX ? (160) : (146);
383
384 if (pcursinvitem == INVITEM_HAND_RIGHT) {
385 color = ICOL_WHITE;
386 if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iMagical != ITEM_QUALITY_NORMAL) {
387 color = ICOL_BLUE;
388 }
389 if (!plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
390 color = ICOL_RED;
391 }
392 if (frame <= 179) {
393 CelBlitOutlineTo(out, color, screen_x, screen_y, pCursCels, frame, frame_width, false);
394 } else {
395 CelBlitOutlineTo(out, color, screen_x, screen_y, pCursCels2, frame - 179, frame_width, false);
396 }
397 }
398
399 if (plr[myplr].InvBody[INVLOC_HAND_RIGHT]._iStatFlag) {
400 if (frame <= 179) {
401 CelClippedDrawTo(out, screen_x, screen_y, pCursCels, frame, frame_width);
402 } else {
403 CelClippedDrawTo(out, screen_x, screen_y, pCursCels2, frame - 179, frame_width);
404 }
405 } else {
406 if (frame <= 179) {
407 CelDrawLightRedTo(out, screen_x, screen_y, pCursCels, frame, frame_width, 1);
408 } else {
409 CelDrawLightRedTo(out, screen_x, screen_y, pCursCels2, frame - 179, frame_width, 1);
410 }
411 }
412 }
413
414 if (!plr[myplr].InvBody[INVLOC_CHEST].isEmpty()) {
415 InvDrawSlotBack(out, RIGHT_PANEL_X + 133, 160, 2 * INV_SLOT_SIZE_PX, 3 * INV_SLOT_SIZE_PX);
416
417 frame = plr[myplr].InvBody[INVLOC_CHEST]._iCurs + CURSOR_FIRSTITEM;
418 frame_width = InvItemWidth[frame];
419
420 if (pcursinvitem == INVITEM_CHEST) {
421 color = ICOL_WHITE;
422 if (plr[myplr].InvBody[INVLOC_CHEST]._iMagical != ITEM_QUALITY_NORMAL) {
423 color = ICOL_BLUE;
424 }
425 if (!plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag) {
426 color = ICOL_RED;
427 }
428 if (frame <= 179) {
429 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 133, 160, pCursCels, frame, frame_width, false);
430 } else {
431 CelBlitOutlineTo(out, color, RIGHT_PANEL_X + 133, 160, pCursCels2, frame - 179, frame_width, false);
432 }
433 }
434
435 if (plr[myplr].InvBody[INVLOC_CHEST]._iStatFlag) {
436 if (frame <= 179) {
437 CelClippedDrawTo(out, RIGHT_PANEL_X + 133, 160, pCursCels, frame, frame_width);
438 } else {
439 CelClippedDrawTo(out, RIGHT_PANEL_X + 133, 160, pCursCels2, frame - 179, frame_width);
440 }
441 } else {
442 if (frame <= 179) {
443 CelDrawLightRedTo(out, RIGHT_PANEL_X + 133, 160, pCursCels, frame, frame_width, 1);
444 } else {
445 CelDrawLightRedTo(out, RIGHT_PANEL_X + 133, 160, pCursCels2, frame - 179, frame_width, 1);
446 }
447 }
448 }
449
450 for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
451 invtest[i] = FALSE;
452 if (plr[myplr].InvGrid[i] != 0) {
453 InvDrawSlotBack(
454 out,
455 InvRect[i + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
456 InvRect[i + SLOTXY_INV_FIRST].Y - 1,
457 INV_SLOT_SIZE_PX,
458 INV_SLOT_SIZE_PX);
459 }
460 }
461
462 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
463 if (plr[myplr].InvGrid[j] > 0) // first slot of an item
464 {
465 ii = plr[myplr].InvGrid[j] - 1;
466
467 invtest[j] = TRUE;
468
469 frame = plr[myplr].InvList[ii]._iCurs + CURSOR_FIRSTITEM;
470 frame_width = InvItemWidth[frame];
471 if (pcursinvitem == ii + INVITEM_INV_FIRST) {
472 color = ICOL_WHITE;
473 if (plr[myplr].InvList[ii]._iMagical != ITEM_QUALITY_NORMAL) {
474 color = ICOL_BLUE;
475 }
476 if (!plr[myplr].InvList[ii]._iStatFlag) {
477 color = ICOL_RED;
478 }
479 if (frame <= 179) {
480 CelBlitOutlineTo(
481 out,
482 color,
483 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
484 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
485 pCursCels, frame, frame_width,
486 false);
487 } else {
488 CelBlitOutlineTo(
489 out,
490 color,
491 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
492 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
493 pCursCels2, frame - 179, frame_width,
494 false);
495 }
496 }
497
498 if (plr[myplr].InvList[ii]._iStatFlag) {
499 if (frame <= 179) {
500 CelClippedDrawTo(
501 out,
502 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
503 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
504 pCursCels, frame, frame_width);
505 } else {
506 CelClippedDrawTo(
507 out,
508 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
509 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
510 pCursCels2, frame - 179, frame_width);
511 }
512 } else {
513 if (frame <= 179) {
514 CelDrawLightRedTo(
515 out,
516 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
517 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
518 pCursCels, frame, frame_width, 1);
519 } else {
520 CelDrawLightRedTo(
521 out,
522 InvRect[j + SLOTXY_INV_FIRST].X + RIGHT_PANEL_X,
523 InvRect[j + SLOTXY_INV_FIRST].Y - 1,
524 pCursCels2, frame - 179, frame_width, 1);
525 }
526 }
527 }
528 }
529 }
530
DrawInvBelt(CelOutputBuffer out)531 void DrawInvBelt(CelOutputBuffer out)
532 {
533 int i, frame, frame_width, color;
534 BYTE fi, ff;
535
536 if (talkflag) {
537 return;
538 }
539
540 DrawPanelBox(out, 205, 21, 232, 28, PANEL_X + 205, PANEL_Y + 5);
541
542 for (i = 0; i < MAXBELTITEMS; i++) {
543 if (plr[myplr].SpdList[i].isEmpty()) {
544 continue;
545 }
546
547 InvDrawSlotBack(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, INV_SLOT_SIZE_PX, INV_SLOT_SIZE_PX);
548 frame = plr[myplr].SpdList[i]._iCurs + CURSOR_FIRSTITEM;
549 frame_width = InvItemWidth[frame];
550
551 if (pcursinvitem == i + INVITEM_BELT_FIRST) {
552 color = ICOL_WHITE;
553 if (plr[myplr].SpdList[i]._iMagical)
554 color = ICOL_BLUE;
555 if (!plr[myplr].SpdList[i]._iStatFlag)
556 color = ICOL_RED;
557 if (!sgbControllerActive || invflag) {
558 if (frame <= 179)
559 CelBlitOutlineTo(out, color, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels, frame, frame_width, false);
560 else
561 CelBlitOutlineTo(out, color, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels2, frame - 179, frame_width, false);
562 }
563 }
564
565 if (plr[myplr].SpdList[i]._iStatFlag) {
566 if (frame <= 179)
567 CelClippedDrawTo(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels, frame, frame_width);
568 else
569 CelClippedDrawTo(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels2, frame - 179, frame_width);
570 } else {
571 if (frame <= 179)
572 CelDrawLightRedTo(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels, frame, frame_width, 1);
573 else
574 CelDrawLightRedTo(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X, InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, pCursCels2, frame - 179, frame_width, 1);
575 }
576
577 if (AllItemsList[plr[myplr].SpdList[i].IDidx].iUsable
578 && plr[myplr].SpdList[i]._iStatFlag
579 && plr[myplr].SpdList[i]._itype != ITYPE_GOLD) {
580 fi = i + 49;
581 ff = fontframe[gbFontTransTbl[fi]];
582 PrintChar(out, InvRect[i + SLOTXY_BELT_FIRST].X + PANEL_X + INV_SLOT_SIZE_PX - fontkern[ff], InvRect[i + SLOTXY_BELT_FIRST].Y + PANEL_Y - 1, ff, COL_WHITE);
583 }
584 }
585 }
586
587 /**
588 * @brief Gets the size, in inventory cells, of the given item.
589 * @param item The item whose size is to be determined.
590 * @return The size, in inventory cells, of the item.
591 */
GetInventorySize(const ItemStruct & item)592 InvXY GetInventorySize(const ItemStruct &item)
593 {
594 int itemSizeIndex = item._iCurs + CURSOR_FIRSTITEM;
595
596 return {
597 InvItemWidth[itemSizeIndex] / INV_SLOT_SIZE_PX,
598 InvItemHeight[itemSizeIndex] / INV_SLOT_SIZE_PX,
599 };
600 }
601
602 /**
603 * @brief Checks whether the given item can fit in a belt slot (i.e. the item's size in inventory cells is 1x1).
604 * @param item The item to be checked.
605 * @return 'True' in case the item can fit a belt slot and 'False' otherwise.
606 */
FitsInBeltSlot(const ItemStruct & item)607 bool FitsInBeltSlot(const ItemStruct &item)
608 {
609 InvXY size = GetInventorySize(item);
610
611 return size.X == 1 && size.Y == 1;
612 }
613
614 /**
615 * @brief Checks whether the given item can be placed on the belt. Takes item size as well as characteristics into account. Items
616 * that cannot be placed on the belt have to be placed in the inventory instead.
617 * @param item The item to be checked.
618 * @return 'True' in case the item can be placed on the belt and 'False' otherwise.
619 */
CanBePlacedOnBelt(const ItemStruct & item)620 bool CanBePlacedOnBelt(const ItemStruct &item)
621 {
622 return FitsInBeltSlot(item)
623 && item._itype != ITYPE_GOLD
624 && item._iStatFlag
625 && AllItemsList[item.IDidx].iUsable;
626 }
627
628 /**
629 * @brief Checks whether the given item can be placed on the specified player's belt. Returns 'True' when the item can be placed
630 * on belt slots and the player has at least one empty slot in his belt.
631 * If 'persistItem' is 'True', the item is also placed in the belt.
632 * @param playerNumber The player number on whose belt will be checked.
633 * @param item The item to be checked.
634 * @param persistItem Pass 'True' to actually place the item in the belt. The default is 'False'.
635 * @return 'True' in case the item can be placed on the player's belt and 'False' otherwise.
636 */
AutoPlaceItemInBelt(int playerNumber,const ItemStruct & item,bool persistItem=false)637 bool AutoPlaceItemInBelt(int playerNumber, const ItemStruct &item, bool persistItem = false)
638 {
639 if (!CanBePlacedOnBelt(item)) {
640 return false;
641 }
642
643 for (int i = 0; i < MAXBELTITEMS; i++) {
644 if (plr[playerNumber].SpdList[i].isEmpty()) {
645 if (persistItem) {
646 plr[playerNumber].SpdList[i] = item;
647 CalcPlrScrolls(playerNumber);
648 drawsbarflag = TRUE;
649 }
650
651 return true;
652 }
653 }
654
655 return false;
656 }
657
658 /**
659 * @brief Checks whether the given item can be equipped. Since this overload doesn't take player information, it only considers
660 * general aspects about the item, like if its requirements are met and if the item's target location is valid for the body.
661 * @param item The item to check.
662 * @return 'True' in case the item could be equipped in a player, and 'False' otherwise.
663 */
CanEquip(const ItemStruct & item)664 bool CanEquip(const ItemStruct &item)
665 {
666 return item.isEquipment()
667 && item._iStatFlag;
668 }
669
670 /**
671 * @brief A specialized version of 'CanEquip(int, ItemStruct&, int)' that specifically checks whether the item can be equipped
672 * in one/both of the player's hands.
673 * @param playerNumber The player number whose inventory will be checked for compatibility with the item.
674 * @param item The item to check.
675 * @return 'True' if the player can currently equip the item in either one of his hands (i.e. the required hands are empty and
676 * allow the item), and 'False' otherwise.
677 */
CanWield(int playerNumber,const ItemStruct & item)678 bool CanWield(int playerNumber, const ItemStruct &item)
679 {
680 if (!CanEquip(item) || (item._iLoc != ILOC_ONEHAND && item._iLoc != ILOC_TWOHAND))
681 return false;
682
683 PlayerStruct &player = plr[playerNumber];
684 ItemStruct &leftHandItem = player.InvBody[INVLOC_HAND_LEFT];
685 ItemStruct &rightHandItem = player.InvBody[INVLOC_HAND_RIGHT];
686
687 if (leftHandItem.isEmpty() && rightHandItem.isEmpty()) {
688 return true;
689 }
690
691 if (!leftHandItem.isEmpty() && !rightHandItem.isEmpty()) {
692 return false;
693 }
694
695 ItemStruct &occupiedHand = !leftHandItem.isEmpty() ? leftHandItem : rightHandItem;
696
697 // Barbarian can wield two handed swords and maces in one hand, so we allow equiping any sword/mace as long as his occupied
698 // hand has a shield (i.e. no dual wielding allowed)
699 if (player._pClass == PC_BARBARIAN) {
700 if (occupiedHand._itype == ITYPE_SHIELD && (item._itype == ITYPE_SWORD || item._itype == ITYPE_MACE))
701 return true;
702 }
703
704 // Bard can dual wield swords and maces, so we allow equiping one-handed weapons in her free slot as long as her occupied
705 // slot is another one-handed weapon.
706 if (player._pClass == PC_BARD) {
707 bool occupiedHandIsOneHandedSwordOrMace = occupiedHand._iLoc == ILOC_ONEHAND
708 && (occupiedHand._itype == ITYPE_SWORD || occupiedHand._itype == ITYPE_MACE);
709
710 bool weaponToEquipIsOneHandedSwordOrMace = item._iLoc == ILOC_ONEHAND
711 && (item._itype == ITYPE_SWORD || item._itype == ITYPE_MACE);
712
713 if (occupiedHandIsOneHandedSwordOrMace && weaponToEquipIsOneHandedSwordOrMace) {
714 return true;
715 }
716 }
717
718 return item._iLoc == ILOC_ONEHAND
719 && occupiedHand._iLoc == ILOC_ONEHAND
720 && item._iClass != occupiedHand._iClass;
721 }
722
723 /**
724 * @brief Checks whether the specified item can be equipped in the desired body location on the player.
725 * @param playerNumber The player number whose inventory will be checked for compatibility with the item.
726 * @param item The item to check.
727 * @param bodyLocation The location in the inventory to be checked against. Can be one of 'inv_body_loc' members.
728 * @return 'True' if the player can currently equip the item in the specified body location (i.e. the body location is empty and
729 * allows the item), and 'False' otherwise.
730 */
CanEquip(int playerNumber,const ItemStruct & item,int bodyLocation)731 bool CanEquip(int playerNumber, const ItemStruct &item, int bodyLocation)
732 {
733 PlayerStruct &player = plr[playerNumber];
734 if (!CanEquip(item) || player._pmode > PM_WALK3 || !player.InvBody[bodyLocation].isEmpty()) {
735 return false;
736 }
737
738 switch (bodyLocation) {
739 case INVLOC_AMULET:
740 return item._iLoc == ILOC_AMULET;
741
742 case INVLOC_CHEST:
743 return item._iLoc == ILOC_ARMOR;
744
745 case INVLOC_HAND_LEFT:
746 case INVLOC_HAND_RIGHT:
747 return CanWield(playerNumber, item);
748
749 case INVLOC_HEAD:
750 return item._iLoc == ILOC_HELM;
751
752 case INVLOC_RING_LEFT:
753 case INVLOC_RING_RIGHT:
754 return item._iLoc == ILOC_RING;
755
756 default:
757 return false;
758 }
759 }
760
761 /**
762 * @brief Automatically attempts to equip the specified item in a specific location in the player's body.
763 * @note On success, this will broadcast an equipment_change event to let other players know about the equipment change.
764 * @param playerNumber The player number whose inventory will be checked for compatibility with the item.
765 * @param item The item to equip.
766 * @param bodyLocation The location in the inventory where the item should be equipped. Can be one of 'inv_body_loc' members.
767 * @param persistItem Indicates whether or not the item should be persisted in the player's body. Pass 'False' to check
768 * whether the player can equip the item but you don't want the item to actually be equipped. 'True' by default.
769 * @return 'True' if the item was equipped and 'False' otherwise.
770 */
AutoEquip(int playerNumber,const ItemStruct & item,int bodyLocation,bool persistItem)771 bool AutoEquip(int playerNumber, const ItemStruct &item, int bodyLocation, bool persistItem)
772 {
773 if (!CanEquip(playerNumber, item, bodyLocation)) {
774 return false;
775 }
776
777 if (persistItem) {
778 plr[playerNumber].InvBody[bodyLocation] = item;
779
780 if (sgOptions.Audio.bAutoEquipSound && playerNumber == myplr) {
781 PlaySFX(ItemInvSnds[ItemCAnimTbl[item._iCurs]]);
782 }
783
784 NetSendCmdChItem(FALSE, bodyLocation);
785 CalcPlrInv(playerNumber, TRUE);
786 }
787
788 return true;
789 }
790
791 /**
792 * @brief Automatically attempts to equip the specified item in the most appropriate location in the player's body.
793 * @note On success, this will broadcast an equipment_change event to let other players know about the equipment change.
794 * @param playerNumber The player number whose inventory will be checked for compatibility with the item.
795 * @param item The item to equip.
796 * @param persistItem Indicates whether or not the item should be persisted in the player's body. Pass 'False' to check
797 * whether the player can equip the item but you don't want the item to actually be equipped. 'True' by default.
798 * @return 'True' if the item was equipped and 'False' otherwise.
799 */
AutoEquip(int playerNumber,const ItemStruct & item,bool persistItem)800 bool AutoEquip(int playerNumber, const ItemStruct &item, bool persistItem)
801 {
802 if (!CanEquip(item)) {
803 return false;
804 }
805
806 for (int bodyLocation = INVLOC_HEAD; bodyLocation < NUM_INVLOC; bodyLocation++) {
807 if (AutoEquip(playerNumber, item, bodyLocation, persistItem)) {
808 return true;
809 }
810 }
811
812 return false;
813 }
814
815 /**
816 * @brief Checks whether or not auto-equipping behavior is enabled for the given player and item.
817 * @param player The player to check.
818 * @param item The item to check.
819 * @return 'True' if auto-equipping behavior is enabled for the player and item and 'False' otherwise.
820 */
AutoEquipEnabled(const PlayerStruct & player,const ItemStruct & item)821 bool AutoEquipEnabled(const PlayerStruct &player, const ItemStruct &item)
822 {
823 if (item.isWeapon()) {
824 // Monk can use unarmed attack as an encouraged option, thus we do not automatically equip weapons on him so as to not
825 // annoy players who prefer that playstyle.
826 return player._pClass != PC_MONK && sgOptions.Gameplay.bAutoEquipWeapons;
827 }
828
829 if (item.isArmor()) {
830 return sgOptions.Gameplay.bAutoEquipArmor;
831 }
832
833 if (item.isHelm()) {
834 return sgOptions.Gameplay.bAutoEquipHelms;
835 }
836
837 if (item.isShield()) {
838 return sgOptions.Gameplay.bAutoEquipShields;
839 }
840
841 if (item.isJewelry()) {
842 return sgOptions.Gameplay.bAutoEquipJewelry;
843 }
844
845 return true;
846 }
847
848 /**
849 * @brief Checks whether the given item can be placed on the specified player's inventory.
850 * If 'persistItem' is 'True', the item is also placed in the inventory.
851 * @param playerNumber The player number on whose inventory will be checked.
852 * @param item The item to be checked.
853 * @param persistItem Pass 'True' to actually place the item in the inventory. The default is 'False'.
854 * @return 'True' in case the item can be placed on the player's inventory and 'False' otherwise.
855 */
AutoPlaceItemInInventory(int playerNumber,const ItemStruct & item,bool persistItem=false)856 bool AutoPlaceItemInInventory(int playerNumber, const ItemStruct &item, bool persistItem = false)
857 {
858 InvXY itemSize = GetInventorySize(item);
859 bool done = false;
860
861 if (itemSize.X == 1 && itemSize.Y == 1) {
862 for (int i = 30; i <= 39 && !done; i++) {
863 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
864 }
865
866 for (int i = 20; i <= 29 && !done; i++) {
867 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
868 }
869
870 for (int i = 10; i <= 19 && !done; i++) {
871 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
872 }
873
874 for (int i = 0; i <= 9 && !done; i++) {
875 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
876 }
877 }
878
879 if (itemSize.X == 1 && itemSize.Y == 2) {
880 for (int i = 29; i >= 20 && !done; i--) {
881 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
882 }
883
884 for (int i = 9; i >= 0 && !done; i--) {
885 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
886 }
887
888 for (int i = 19; i >= 10 && !done; i--) {
889 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
890 }
891 }
892
893 if (itemSize.X == 1 && itemSize.Y == 3) {
894 for (int i = 0; i < 20 && !done; i++) {
895 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
896 }
897 }
898
899 if (itemSize.X == 2 && itemSize.Y == 2) {
900 for (int i = 0; i < 10 && !done; i++) {
901 done = AutoPlace(playerNumber, AP2x2Tbl[i], itemSize.X, itemSize.Y, persistItem);
902 }
903
904 for (int i = 21; i < 29 && !done; i += 2) {
905 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
906 }
907
908 for (int i = 1; i < 9 && !done; i += 2) {
909 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
910 }
911
912 for (int i = 10; i < 19 && !done; i++) {
913 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
914 }
915 }
916
917 if (itemSize.X == 2 && itemSize.Y == 3) {
918 for (int i = 0; i < 9 && !done; i++) {
919 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
920 }
921
922 for (int i = 10; i < 19 && !done; i++) {
923 done = AutoPlace(playerNumber, i, itemSize.X, itemSize.Y, persistItem);
924 }
925 }
926
927 return done;
928 }
929
AutoPlace(int pnum,int ii,int sx,int sy,BOOL saveflag)930 BOOL AutoPlace(int pnum, int ii, int sx, int sy, BOOL saveflag)
931 {
932 int i, j, xx, yy;
933 BOOL done;
934
935 done = TRUE;
936 yy = 10 * (ii / 10);
937 if (yy < 0) {
938 yy = 0;
939 }
940 for (j = 0; j < sy && done; j++) {
941 if (yy >= NUM_INV_GRID_ELEM) {
942 done = FALSE;
943 }
944 xx = ii % 10;
945 if (xx < 0) {
946 xx = 0;
947 }
948 for (i = 0; i < sx && done; i++) {
949 if (xx >= 10) {
950 done = FALSE;
951 } else {
952 done = plr[pnum].InvGrid[xx + yy] == 0;
953 }
954 xx++;
955 }
956 yy += 10;
957 }
958 if (done && saveflag) {
959 plr[pnum].InvList[plr[pnum]._pNumInv] = plr[pnum].HoldItem;
960 plr[pnum]._pNumInv++;
961 yy = 10 * (ii / 10);
962 if (yy < 0) {
963 yy = 0;
964 }
965 for (j = 0; j < sy; j++) {
966 xx = ii % 10;
967 if (xx < 0) {
968 xx = 0;
969 }
970 for (i = 0; i < sx; i++) {
971 if (i != 0 || j != sy - 1) {
972 plr[pnum].InvGrid[xx + yy] = -plr[pnum]._pNumInv;
973 } else {
974 plr[pnum].InvGrid[xx + yy] = plr[pnum]._pNumInv;
975 }
976 xx++;
977 }
978 yy += 10;
979 }
980 CalcPlrScrolls(pnum);
981 }
982 return done;
983 }
984
SpecialAutoPlace(int pnum,int ii,const ItemStruct & item)985 BOOL SpecialAutoPlace(int pnum, int ii, const ItemStruct &item)
986 {
987 int i, j, xx, yy;
988 BOOL done;
989
990 done = TRUE;
991 yy = 10 * (ii / 10);
992 if (yy < 0) {
993 yy = 0;
994 }
995
996 InvXY itemSize = GetInventorySize(item);
997 for (j = 0; j < itemSize.Y && done; j++) {
998 if (yy >= NUM_INV_GRID_ELEM) {
999 done = FALSE;
1000 }
1001 xx = ii % 10;
1002 if (xx < 0) {
1003 xx = 0;
1004 }
1005 for (i = 0; i < itemSize.X && done; i++) {
1006 if (xx >= 10) {
1007 done = FALSE;
1008 } else {
1009 done = plr[pnum].InvGrid[xx + yy] == 0;
1010 }
1011 xx++;
1012 }
1013 yy += 10;
1014 }
1015 if (!done) {
1016 done = AutoPlaceItemInBelt(pnum, item);
1017 }
1018
1019 return done;
1020 }
1021
GoldAutoPlace(int pnum)1022 BOOL GoldAutoPlace(int pnum)
1023 {
1024 bool done = false;
1025
1026 for (int i = 0; i < plr[pnum]._pNumInv && !done; i++) {
1027 if (plr[pnum].InvList[i]._itype != ITYPE_GOLD)
1028 continue;
1029 if (plr[pnum].InvList[i]._ivalue >= MaxGold)
1030 continue;
1031
1032 plr[pnum].InvList[i]._ivalue += plr[pnum].HoldItem._ivalue;
1033 if (plr[pnum].InvList[i]._ivalue > MaxGold) {
1034 plr[pnum].HoldItem._ivalue = plr[pnum].InvList[i]._ivalue - MaxGold;
1035 SetPlrHandGoldCurs(&plr[pnum].HoldItem);
1036 plr[pnum].InvList[i]._ivalue = MaxGold;
1037 if (gbIsHellfire)
1038 GetPlrHandSeed(&plr[pnum].HoldItem);
1039 } else {
1040 plr[pnum].HoldItem._ivalue = 0;
1041 done = true;
1042 }
1043
1044 SetPlrHandGoldCurs(&plr[pnum].InvList[i]);
1045 plr[pnum]._pGold = CalculateGold(pnum);
1046 }
1047
1048 for (int i = 39; i >= 0 && !done; i--) {
1049 int yy = 10 * (i / 10);
1050 int xx = i % 10;
1051 if (plr[pnum].InvGrid[xx + yy] == 0) {
1052 int ii = plr[pnum]._pNumInv;
1053 plr[pnum].InvList[ii] = plr[pnum].HoldItem;
1054 plr[pnum]._pNumInv = plr[pnum]._pNumInv + 1;
1055 plr[pnum].InvGrid[xx + yy] = plr[pnum]._pNumInv;
1056 GetPlrHandSeed(&plr[pnum].InvList[ii]);
1057 int gold = plr[pnum].HoldItem._ivalue;
1058 if (gold > MaxGold) {
1059 gold -= MaxGold;
1060 plr[pnum].HoldItem._ivalue = gold;
1061 GetPlrHandSeed(&plr[pnum].HoldItem);
1062 plr[pnum].InvList[ii]._ivalue = MaxGold;
1063 } else {
1064 plr[pnum].HoldItem._ivalue = 0;
1065 done = true;
1066 plr[pnum]._pGold = CalculateGold(pnum);
1067 SetCursor_(CURSOR_HAND);
1068 }
1069 }
1070 }
1071
1072 return done;
1073 }
1074
WeaponAutoPlace(int pnum)1075 BOOL WeaponAutoPlace(int pnum)
1076 {
1077 if (plr[pnum]._pClass == PC_MONK)
1078 return FALSE;
1079 if (plr[pnum].HoldItem._iLoc != ILOC_TWOHAND
1080 || (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].HoldItem._itype == ITYPE_SWORD || plr[pnum].HoldItem._itype == ITYPE_MACE))) {
1081 if (plr[pnum]._pClass != PC_BARD) {
1082 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON)
1083 return FALSE;
1084 if (!plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON)
1085 return FALSE;
1086 }
1087
1088 if (plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty()) {
1089 NetSendCmdChItem(TRUE, INVLOC_HAND_LEFT);
1090 plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem;
1091 return TRUE;
1092 }
1093 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND) {
1094 NetSendCmdChItem(TRUE, INVLOC_HAND_RIGHT);
1095 plr[pnum].InvBody[INVLOC_HAND_RIGHT] = plr[pnum].HoldItem;
1096 return TRUE;
1097 }
1098 } else if (plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
1099 NetSendCmdChItem(TRUE, INVLOC_HAND_LEFT);
1100 plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem;
1101 return TRUE;
1102 }
1103
1104 return FALSE;
1105 }
1106
SwapItem(ItemStruct * a,ItemStruct * b)1107 int SwapItem(ItemStruct *a, ItemStruct *b)
1108 {
1109 ItemStruct h;
1110
1111 h = *a;
1112 *a = *b;
1113 *b = h;
1114
1115 return h._iCurs + CURSOR_FIRSTITEM;
1116 }
1117
CheckInvPaste(int pnum,int mx,int my)1118 void CheckInvPaste(int pnum, int mx, int my)
1119 {
1120 int r, sx, sy;
1121 int i, j, xx, yy, ii;
1122 BOOL done, done2h;
1123 int il, cn, it, iv, ig, gt;
1124 ItemStruct tempitem;
1125
1126 SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
1127 i = mx + (icursW >> 1);
1128 j = my + (icursH >> 1);
1129 sx = icursW28;
1130 sy = icursH28;
1131 done = FALSE;
1132 for (r = 0; (DWORD)r < NUM_XY_SLOTS && !done; r++) {
1133 int xo = RIGHT_PANEL;
1134 int yo = 0;
1135 if (r >= SLOTXY_BELT_FIRST) {
1136 xo = PANEL_LEFT;
1137 yo = PANEL_TOP;
1138 }
1139
1140 if (i >= InvRect[r].X + xo && i < InvRect[r].X + xo + INV_SLOT_SIZE_PX) {
1141 if (j >= InvRect[r].Y + yo - INV_SLOT_SIZE_PX - 1 && j < InvRect[r].Y + yo) {
1142 done = TRUE;
1143 r--;
1144 }
1145 }
1146 if (r == SLOTXY_CHEST_LAST) {
1147 if ((sx & 1) == 0)
1148 i -= 14;
1149 if ((sy & 1) == 0)
1150 j -= 14;
1151 }
1152 if (r == SLOTXY_INV_LAST && (sy & 1) == 0)
1153 j += 14;
1154 }
1155 if (!done)
1156 return;
1157 il = ILOC_UNEQUIPABLE;
1158 if (r >= SLOTXY_HEAD_FIRST && r <= SLOTXY_HEAD_LAST)
1159 il = ILOC_HELM;
1160 if (r >= SLOTXY_RING_LEFT && r <= SLOTXY_RING_RIGHT)
1161 il = ILOC_RING;
1162 if (r == SLOTXY_AMULET)
1163 il = ILOC_AMULET;
1164 if (r >= SLOTXY_HAND_LEFT_FIRST && r <= SLOTXY_HAND_RIGHT_LAST)
1165 il = ILOC_ONEHAND;
1166 if (r >= SLOTXY_CHEST_FIRST && r <= SLOTXY_CHEST_LAST)
1167 il = ILOC_ARMOR;
1168 if (r >= SLOTXY_BELT_FIRST && r <= SLOTXY_BELT_LAST)
1169 il = ILOC_BELT;
1170 done = FALSE;
1171 if (plr[pnum].HoldItem._iLoc == il)
1172 done = TRUE;
1173 if (il == ILOC_ONEHAND && plr[pnum].HoldItem._iLoc == ILOC_TWOHAND) {
1174 if (plr[pnum]._pClass == PC_BARBARIAN
1175 && (plr[pnum].HoldItem._itype == ITYPE_SWORD || plr[pnum].HoldItem._itype == ITYPE_MACE))
1176 il = ILOC_ONEHAND;
1177 else
1178 il = ILOC_TWOHAND;
1179 done = TRUE;
1180 }
1181 if (plr[pnum].HoldItem._iLoc == ILOC_UNEQUIPABLE && il == ILOC_BELT) {
1182 if (sx == 1 && sy == 1) {
1183 done = TRUE;
1184 if (!AllItemsList[plr[pnum].HoldItem.IDidx].iUsable)
1185 done = FALSE;
1186 if (!plr[pnum].HoldItem._iStatFlag)
1187 done = FALSE;
1188 if (plr[pnum].HoldItem._itype == ITYPE_GOLD)
1189 done = FALSE;
1190 }
1191 }
1192
1193 if (il == ILOC_UNEQUIPABLE) {
1194 done = TRUE;
1195 it = 0;
1196 ii = r - SLOTXY_INV_FIRST;
1197 if (plr[pnum].HoldItem._itype == ITYPE_GOLD) {
1198 yy = 10 * (ii / 10);
1199 xx = ii % 10;
1200 if (plr[pnum].InvGrid[xx + yy] != 0) {
1201 iv = plr[pnum].InvGrid[xx + yy];
1202 if (iv > 0) {
1203 if (plr[pnum].InvList[iv - 1]._itype != ITYPE_GOLD) {
1204 it = iv;
1205 }
1206 } else {
1207 it = -iv;
1208 }
1209 }
1210 } else {
1211 yy = 10 * ((ii / 10) - ((sy - 1) >> 1));
1212 if (yy < 0)
1213 yy = 0;
1214 for (j = 0; j < sy && done; j++) {
1215 if (yy >= NUM_INV_GRID_ELEM)
1216 done = FALSE;
1217 xx = (ii % 10) - ((sx - 1) >> 1);
1218 if (xx < 0)
1219 xx = 0;
1220 for (i = 0; i < sx && done; i++) {
1221 if (xx >= 10) {
1222 done = FALSE;
1223 } else {
1224 if (plr[pnum].InvGrid[xx + yy] != 0) {
1225 iv = plr[pnum].InvGrid[xx + yy];
1226 if (iv < 0)
1227 iv = -iv;
1228 if (it != 0) {
1229 if (it != iv)
1230 done = FALSE;
1231 } else
1232 it = iv;
1233 }
1234 }
1235 xx++;
1236 }
1237 yy += 10;
1238 }
1239 }
1240 }
1241
1242 if (!done)
1243 return;
1244
1245 if (il != ILOC_UNEQUIPABLE && il != ILOC_BELT && !plr[pnum].HoldItem._iStatFlag) {
1246 done = FALSE;
1247 if (plr[pnum]._pClass == PC_WARRIOR)
1248 PlaySFX(PS_WARR13);
1249 else if (plr[pnum]._pClass == PC_ROGUE)
1250 PlaySFX(PS_ROGUE13);
1251 else if (plr[pnum]._pClass == PC_SORCERER)
1252 PlaySFX(PS_MAGE13);
1253 else if (plr[pnum]._pClass == PC_MONK)
1254 PlaySFX(PS_MONK13);
1255 else if (plr[pnum]._pClass == PC_BARD)
1256 PlaySFX(PS_ROGUE13);
1257 else if (plr[pnum]._pClass == PC_BARBARIAN)
1258 PlaySFX(PS_MAGE13);
1259 }
1260
1261 if (!done)
1262 return;
1263
1264 if (pnum == myplr)
1265 PlaySFX(ItemInvSnds[ItemCAnimTbl[plr[pnum].HoldItem._iCurs]]);
1266
1267 cn = CURSOR_HAND;
1268 switch (il) {
1269 case ILOC_HELM:
1270 NetSendCmdChItem(FALSE, INVLOC_HEAD);
1271 if (plr[pnum].InvBody[INVLOC_HEAD].isEmpty())
1272 plr[pnum].InvBody[INVLOC_HEAD] = plr[pnum].HoldItem;
1273 else
1274 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HEAD], &plr[pnum].HoldItem);
1275 break;
1276 case ILOC_RING:
1277 if (r == SLOTXY_RING_LEFT) {
1278 NetSendCmdChItem(FALSE, INVLOC_RING_LEFT);
1279 if (plr[pnum].InvBody[INVLOC_RING_LEFT].isEmpty())
1280 plr[pnum].InvBody[INVLOC_RING_LEFT] = plr[pnum].HoldItem;
1281 else
1282 cn = SwapItem(&plr[pnum].InvBody[INVLOC_RING_LEFT], &plr[pnum].HoldItem);
1283 } else {
1284 NetSendCmdChItem(FALSE, INVLOC_RING_RIGHT);
1285 if (plr[pnum].InvBody[INVLOC_RING_RIGHT].isEmpty())
1286 plr[pnum].InvBody[INVLOC_RING_RIGHT] = plr[pnum].HoldItem;
1287 else
1288 cn = SwapItem(&plr[pnum].InvBody[INVLOC_RING_RIGHT], &plr[pnum].HoldItem);
1289 }
1290 break;
1291 case ILOC_AMULET:
1292 NetSendCmdChItem(FALSE, INVLOC_AMULET);
1293 if (plr[pnum].InvBody[INVLOC_AMULET].isEmpty())
1294 plr[pnum].InvBody[INVLOC_AMULET] = plr[pnum].HoldItem;
1295 else
1296 cn = SwapItem(&plr[pnum].InvBody[INVLOC_AMULET], &plr[pnum].HoldItem);
1297 break;
1298 case ILOC_ONEHAND:
1299 if (r <= SLOTXY_HAND_LEFT_LAST) {
1300 if (plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty()) {
1301 if ((plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty() || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass != plr[pnum].HoldItem._iClass)
1302 || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON)) {
1303 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1304 plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem;
1305 } else {
1306 NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT);
1307 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem);
1308 }
1309 break;
1310 }
1311 if ((plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty() || plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass != plr[pnum].HoldItem._iClass)
1312 || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON)) {
1313 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1314 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem);
1315 break;
1316 }
1317
1318 NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT);
1319 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem);
1320 break;
1321 }
1322 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
1323 if ((plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() || plr[pnum].InvBody[INVLOC_HAND_LEFT]._iLoc != ILOC_TWOHAND)
1324 || (plr[pnum]._pClass == PC_BARBARIAN && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE))) {
1325 if ((plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() || plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass != plr[pnum].HoldItem._iClass)
1326 || (plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON)) {
1327 NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT);
1328 plr[pnum].InvBody[INVLOC_HAND_RIGHT] = plr[pnum].HoldItem;
1329 break;
1330 }
1331 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1332 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem);
1333 break;
1334 }
1335 NetSendCmdDelItem(FALSE, INVLOC_HAND_LEFT);
1336 NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT);
1337 SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].InvBody[INVLOC_HAND_LEFT]);
1338 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem);
1339 break;
1340 }
1341
1342 if ((!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == plr[pnum].HoldItem._iClass)
1343 && !(plr[pnum]._pClass == PC_BARD && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iClass == ICLASS_WEAPON && plr[pnum].HoldItem._iClass == ICLASS_WEAPON)) {
1344 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1345 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem);
1346 break;
1347 }
1348 NetSendCmdChItem(FALSE, INVLOC_HAND_RIGHT);
1349 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_RIGHT], &plr[pnum].HoldItem);
1350 break;
1351 case ILOC_TWOHAND:
1352 NetSendCmdDelItem(FALSE, INVLOC_HAND_RIGHT);
1353 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() && !plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
1354 tempitem = plr[pnum].HoldItem;
1355 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD)
1356 plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_RIGHT];
1357 else
1358 plr[pnum].HoldItem = plr[pnum].InvBody[INVLOC_HAND_LEFT];
1359 if (pnum == myplr)
1360 SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
1361 else
1362 SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
1363 done2h = FALSE;
1364 for (i = 0; i < NUM_INV_GRID_ELEM && !done2h; i++)
1365 done2h = AutoPlace(pnum, i, icursW28, icursH28, TRUE);
1366 plr[pnum].HoldItem = tempitem;
1367 if (pnum == myplr)
1368 SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
1369 else
1370 SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
1371 if (!done2h)
1372 return;
1373
1374 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD)
1375 plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE;
1376 else
1377 plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE;
1378 }
1379
1380 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() || !plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
1381 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1382 if (plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty())
1383 SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].InvBody[INVLOC_HAND_RIGHT]);
1384 cn = SwapItem(&plr[pnum].InvBody[INVLOC_HAND_LEFT], &plr[pnum].HoldItem);
1385 } else {
1386 NetSendCmdChItem(FALSE, INVLOC_HAND_LEFT);
1387 plr[pnum].InvBody[INVLOC_HAND_LEFT] = plr[pnum].HoldItem;
1388 }
1389 if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_STAFF && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell != SPL_NULL && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) {
1390 plr[pnum]._pRSpell = plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell;
1391 plr[pnum]._pRSplType = RSPLTYPE_CHARGES;
1392 force_redraw = 255;
1393 }
1394 break;
1395 case ILOC_ARMOR:
1396 NetSendCmdChItem(FALSE, INVLOC_CHEST);
1397 if (plr[pnum].InvBody[INVLOC_CHEST].isEmpty())
1398 plr[pnum].InvBody[INVLOC_CHEST] = plr[pnum].HoldItem;
1399 else
1400 cn = SwapItem(&plr[pnum].InvBody[INVLOC_CHEST], &plr[pnum].HoldItem);
1401 break;
1402 case ILOC_UNEQUIPABLE:
1403 if (plr[pnum].HoldItem._itype == ITYPE_GOLD && it == 0) {
1404 ii = r - SLOTXY_INV_FIRST;
1405 yy = 10 * (ii / 10);
1406 xx = ii % 10;
1407 if (plr[pnum].InvGrid[yy + xx] > 0) {
1408 il = plr[pnum].InvGrid[yy + xx];
1409 il--;
1410 gt = plr[pnum].InvList[il]._ivalue;
1411 ig = plr[pnum].HoldItem._ivalue + gt;
1412 if (ig <= MaxGold) {
1413 plr[pnum].InvList[il]._ivalue = ig;
1414 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1415 SetPlrHandGoldCurs(&plr[pnum].InvList[il]);
1416 } else {
1417 ig = MaxGold - gt;
1418 plr[pnum]._pGold += ig;
1419 plr[pnum].HoldItem._ivalue -= ig;
1420 plr[pnum].InvList[il]._ivalue = MaxGold;
1421 plr[pnum].InvList[il]._iCurs = ICURS_GOLD_LARGE;
1422 // BUGFIX: incorrect values here are leftover from beta (fixed)
1423 cn = GetGoldCursor(plr[pnum].HoldItem._ivalue);
1424 cn += CURSOR_FIRSTITEM;
1425 }
1426 } else {
1427 il = plr[pnum]._pNumInv;
1428 plr[pnum].InvList[il] = plr[pnum].HoldItem;
1429 plr[pnum]._pNumInv++;
1430 plr[pnum].InvGrid[yy + xx] = plr[pnum]._pNumInv;
1431 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1432 SetPlrHandGoldCurs(&plr[pnum].InvList[il]);
1433 }
1434 } else {
1435 if (it == 0) {
1436 plr[pnum].InvList[plr[pnum]._pNumInv] = plr[pnum].HoldItem;
1437 plr[pnum]._pNumInv++;
1438 it = plr[pnum]._pNumInv;
1439 } else {
1440 il = it - 1;
1441 if (plr[pnum].HoldItem._itype == ITYPE_GOLD)
1442 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1443 cn = SwapItem(&plr[pnum].InvList[il], &plr[pnum].HoldItem);
1444 if (plr[pnum].HoldItem._itype == ITYPE_GOLD)
1445 plr[pnum]._pGold = CalculateGold(pnum);
1446 for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
1447 if (plr[pnum].InvGrid[i] == it)
1448 plr[pnum].InvGrid[i] = 0;
1449 if (plr[pnum].InvGrid[i] == -it)
1450 plr[pnum].InvGrid[i] = 0;
1451 }
1452 }
1453 ii = r - SLOTXY_INV_FIRST;
1454 yy = 10 * (ii / 10 - ((sy - 1) >> 1));
1455 if (yy < 0)
1456 yy = 0;
1457 for (j = 0; j < sy; j++) {
1458 xx = (ii % 10 - ((sx - 1) >> 1));
1459 if (xx < 0)
1460 xx = 0;
1461 for (i = 0; i < sx; i++) {
1462 if (i != 0 || j != sy - 1)
1463 plr[pnum].InvGrid[xx + yy] = -it;
1464 else
1465 plr[pnum].InvGrid[xx + yy] = it;
1466 xx++;
1467 }
1468 yy += 10;
1469 }
1470 }
1471 break;
1472 case ILOC_BELT:
1473 ii = r - SLOTXY_BELT_FIRST;
1474 if (plr[pnum].HoldItem._itype == ITYPE_GOLD) {
1475 if (!plr[pnum].SpdList[ii].isEmpty()) {
1476 if (plr[pnum].SpdList[ii]._itype == ITYPE_GOLD) {
1477 i = plr[pnum].HoldItem._ivalue + plr[pnum].SpdList[ii]._ivalue;
1478 if (i <= MaxGold) {
1479 plr[pnum].SpdList[ii]._ivalue = i;
1480 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1481 SetPlrHandGoldCurs(&plr[pnum].SpdList[ii]);
1482 } else {
1483 i = MaxGold - plr[pnum].SpdList[ii]._ivalue;
1484 plr[pnum]._pGold += i;
1485 plr[pnum].HoldItem._ivalue -= i;
1486 plr[pnum].SpdList[ii]._ivalue = MaxGold;
1487 plr[pnum].SpdList[ii]._iCurs = ICURS_GOLD_LARGE;
1488
1489 // BUGFIX: incorrect values here are leftover from beta (fixed)
1490 cn = GetGoldCursor(plr[pnum].HoldItem._ivalue);
1491 cn += CURSOR_FIRSTITEM;
1492 }
1493 } else {
1494 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1495 cn = SwapItem(&plr[pnum].SpdList[ii], &plr[pnum].HoldItem);
1496 }
1497 } else {
1498 plr[pnum].SpdList[ii] = plr[pnum].HoldItem;
1499 plr[pnum]._pGold += plr[pnum].HoldItem._ivalue;
1500 }
1501 } else if (plr[pnum].SpdList[ii].isEmpty()) {
1502 plr[pnum].SpdList[ii] = plr[pnum].HoldItem;
1503 } else {
1504 cn = SwapItem(&plr[pnum].SpdList[ii], &plr[pnum].HoldItem);
1505 if (plr[pnum].HoldItem._itype == ITYPE_GOLD)
1506 plr[pnum]._pGold = CalculateGold(pnum);
1507 }
1508 drawsbarflag = TRUE;
1509 break;
1510 }
1511 CalcPlrInv(pnum, TRUE);
1512 if (pnum == myplr) {
1513 if (cn == CURSOR_HAND)
1514 SetCursorPos(MouseX + (cursW >> 1), MouseY + (cursH >> 1));
1515 SetCursor_(cn);
1516 }
1517 }
1518
CheckInvSwap(int pnum,BYTE bLoc,int idx,WORD wCI,int seed,BOOL bId,uint32_t dwBuff)1519 void CheckInvSwap(int pnum, BYTE bLoc, int idx, WORD wCI, int seed, BOOL bId, uint32_t dwBuff)
1520 {
1521 PlayerStruct *p;
1522
1523 memset(&item[MAXITEMS], 0, sizeof(*item));
1524 RecreateItem(MAXITEMS, idx, wCI, seed, 0, (dwBuff & CF_HELLFIRE) != 0);
1525
1526 p = &plr[pnum];
1527 p->HoldItem = item[MAXITEMS];
1528
1529 if (bId) {
1530 p->HoldItem._iIdentified = TRUE;
1531 }
1532
1533 if (bLoc < NUM_INVLOC) {
1534 p->InvBody[bLoc] = p->HoldItem;
1535
1536 if (bLoc == INVLOC_HAND_LEFT && p->HoldItem._iLoc == ILOC_TWOHAND) {
1537 p->InvBody[INVLOC_HAND_RIGHT]._itype = ITYPE_NONE;
1538 } else if (bLoc == INVLOC_HAND_RIGHT && p->HoldItem._iLoc == ILOC_TWOHAND) {
1539 p->InvBody[INVLOC_HAND_LEFT]._itype = ITYPE_NONE;
1540 }
1541 }
1542
1543 CalcPlrInv(pnum, TRUE);
1544 }
1545
CheckInvCut(int pnum,int mx,int my,bool automaticMove)1546 void CheckInvCut(int pnum, int mx, int my, bool automaticMove)
1547 {
1548 int r;
1549 BOOL done;
1550 char ii;
1551 int iv, i, j, offs, ig;
1552 PlayerStruct &player = plr[pnum];
1553
1554 if (player._pmode > PM_WALK3) {
1555 return;
1556 }
1557
1558 if (dropGoldFlag) {
1559 dropGoldFlag = FALSE;
1560 dropGoldValue = 0;
1561 }
1562
1563 done = FALSE;
1564
1565 for (r = 0; (DWORD)r < NUM_XY_SLOTS && !done; r++) {
1566 int xo = RIGHT_PANEL;
1567 int yo = 0;
1568 if (r >= SLOTXY_BELT_FIRST) {
1569 xo = PANEL_LEFT;
1570 yo = PANEL_TOP;
1571 }
1572
1573 // check which inventory rectangle the mouse is in, if any
1574 if (mx >= InvRect[r].X + xo
1575 && mx < InvRect[r].X + xo + (INV_SLOT_SIZE_PX + 1)
1576 && my >= InvRect[r].Y + yo - (INV_SLOT_SIZE_PX + 1)
1577 && my < InvRect[r].Y + yo) {
1578 done = TRUE;
1579 r--;
1580 }
1581 }
1582
1583 if (!done) {
1584 // not on an inventory slot rectangle
1585 return;
1586 }
1587
1588 ItemStruct &holdItem = player.HoldItem;
1589 holdItem._itype = ITYPE_NONE;
1590
1591 bool automaticallyMoved = false;
1592 bool automaticallyEquipped = false;
1593 bool automaticallyUnequip = false;
1594
1595 ItemStruct &headItem = player.InvBody[INVLOC_HEAD];
1596 if (r >= SLOTXY_HEAD_FIRST && r <= SLOTXY_HEAD_LAST && !headItem.isEmpty()) {
1597 holdItem = headItem;
1598 if (automaticMove) {
1599 automaticallyUnequip = true;
1600 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1601 }
1602
1603 if (!automaticMove || automaticallyMoved) {
1604 NetSendCmdDelItem(FALSE, INVLOC_HEAD);
1605 headItem._itype = ITYPE_NONE;
1606 }
1607 }
1608
1609 ItemStruct &leftRingItem = player.InvBody[INVLOC_RING_LEFT];
1610 if (r == SLOTXY_RING_LEFT && !leftRingItem.isEmpty()) {
1611 holdItem = leftRingItem;
1612 if (automaticMove) {
1613 automaticallyUnequip = true;
1614 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1615 }
1616
1617 if (!automaticMove || automaticallyMoved) {
1618 NetSendCmdDelItem(FALSE, INVLOC_RING_LEFT);
1619 leftRingItem._itype = ITYPE_NONE;
1620 }
1621 }
1622
1623 ItemStruct &rightRingItem = player.InvBody[INVLOC_RING_RIGHT];
1624 if (r == SLOTXY_RING_RIGHT && !rightRingItem.isEmpty()) {
1625 holdItem = rightRingItem;
1626 if (automaticMove) {
1627 automaticallyUnequip = true;
1628 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1629 }
1630
1631 if (!automaticMove || automaticallyMoved) {
1632 NetSendCmdDelItem(FALSE, INVLOC_RING_RIGHT);
1633 rightRingItem._itype = ITYPE_NONE;
1634 }
1635 }
1636
1637 ItemStruct &amuletItem = player.InvBody[INVLOC_AMULET];
1638 if (r == SLOTXY_AMULET && !amuletItem.isEmpty()) {
1639 holdItem = amuletItem;
1640 if (automaticMove) {
1641 automaticallyUnequip = true;
1642 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1643 }
1644
1645 if (!automaticMove || automaticallyMoved) {
1646 NetSendCmdDelItem(FALSE, INVLOC_AMULET);
1647 amuletItem._itype = ITYPE_NONE;
1648 }
1649 }
1650
1651 ItemStruct &leftHandItem = player.InvBody[INVLOC_HAND_LEFT];
1652 if (r >= SLOTXY_HAND_LEFT_FIRST && r <= SLOTXY_HAND_LEFT_LAST && !leftHandItem.isEmpty()) {
1653 holdItem = leftHandItem;
1654 if (automaticMove) {
1655 automaticallyUnequip = true;
1656 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1657 }
1658
1659 if (!automaticMove || automaticallyMoved) {
1660 NetSendCmdDelItem(FALSE, INVLOC_HAND_LEFT);
1661 leftHandItem._itype = ITYPE_NONE;
1662 }
1663 }
1664
1665 ItemStruct &rightHandItem = player.InvBody[INVLOC_HAND_RIGHT];
1666 if (r >= SLOTXY_HAND_RIGHT_FIRST && r <= SLOTXY_HAND_RIGHT_LAST && !rightHandItem.isEmpty()) {
1667 holdItem = rightHandItem;
1668 if (automaticMove) {
1669 automaticallyUnequip = true;
1670 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1671 }
1672
1673 if (!automaticMove || automaticallyMoved) {
1674 NetSendCmdDelItem(FALSE, INVLOC_HAND_RIGHT);
1675 rightHandItem._itype = ITYPE_NONE;
1676 }
1677 }
1678
1679 ItemStruct &chestItem = player.InvBody[INVLOC_CHEST];
1680 if (r >= SLOTXY_CHEST_FIRST && r <= SLOTXY_CHEST_LAST && !chestItem.isEmpty()) {
1681 holdItem = chestItem;
1682 if (automaticMove) {
1683 automaticallyUnequip = true;
1684 automaticallyMoved = automaticallyEquipped = AutoPlaceItemInInventory(pnum, holdItem, true);
1685 }
1686
1687 if (!automaticMove || automaticallyMoved) {
1688 NetSendCmdDelItem(FALSE, INVLOC_CHEST);
1689 chestItem._itype = ITYPE_NONE;
1690 }
1691 }
1692
1693 if (r >= SLOTXY_INV_FIRST && r <= SLOTXY_INV_LAST) {
1694 ig = r - SLOTXY_INV_FIRST;
1695 ii = player.InvGrid[ig];
1696 if (ii != 0) {
1697 iv = ii;
1698 if (ii <= 0) {
1699 iv = -ii;
1700 }
1701
1702 holdItem = player.InvList[iv - 1];
1703 if (automaticMove) {
1704 if (CanBePlacedOnBelt(holdItem)) {
1705 automaticallyMoved = AutoPlaceItemInBelt(pnum, holdItem, true);
1706 } else {
1707 automaticallyMoved = automaticallyEquipped = AutoEquip(pnum, holdItem);
1708 }
1709 }
1710
1711 if (!automaticMove || automaticallyMoved) {
1712 for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
1713 if (player.InvGrid[i] == iv || player.InvGrid[i] == -iv) {
1714 player.InvGrid[i] = 0;
1715 }
1716 }
1717
1718 iv--;
1719
1720 player._pNumInv--;
1721
1722 if (player._pNumInv > 0 && player._pNumInv != iv) {
1723 player.InvList[iv] = player.InvList[player._pNumInv];
1724
1725 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
1726 if (player.InvGrid[j] == player._pNumInv + 1) {
1727 player.InvGrid[j] = iv + 1;
1728 }
1729 if (player.InvGrid[j] == -(player._pNumInv + 1)) {
1730 player.InvGrid[j] = -iv - 1;
1731 }
1732 }
1733 }
1734 }
1735 }
1736 }
1737
1738 if (r >= SLOTXY_BELT_FIRST) {
1739 ItemStruct &beltItem = player.SpdList[r - SLOTXY_BELT_FIRST];
1740 if (!beltItem.isEmpty()) {
1741 holdItem = beltItem;
1742 if (automaticMove) {
1743 automaticallyMoved = AutoPlaceItemInInventory(pnum, holdItem, true);
1744 }
1745
1746 if (!automaticMove || automaticallyMoved) {
1747 beltItem._itype = ITYPE_NONE;
1748 drawsbarflag = TRUE;
1749 }
1750 }
1751 }
1752
1753 if (!holdItem.isEmpty()) {
1754 if (holdItem._itype == ITYPE_GOLD) {
1755 player._pGold = CalculateGold(pnum);
1756 }
1757
1758 CalcPlrInv(pnum, TRUE);
1759 CheckItemStats(pnum);
1760
1761 if (pnum == myplr) {
1762 if (automaticallyEquipped) {
1763 PlaySFX(ItemInvSnds[ItemCAnimTbl[holdItem._iCurs]]);
1764 } else if (!automaticMove || automaticallyMoved) {
1765 PlaySFX(IS_IGRAB);
1766 }
1767
1768 if (automaticMove) {
1769 if (!automaticallyMoved) {
1770 if (CanBePlacedOnBelt(holdItem) || automaticallyUnequip) {
1771 switch (player._pClass) {
1772 case PC_WARRIOR:
1773 case PC_BARBARIAN:
1774 PlaySFX(PS_WARR15, false);
1775 break;
1776 case PC_ROGUE:
1777 case PC_BARD:
1778 PlaySFX(PS_ROGUE15, false);
1779 break;
1780 case PC_SORCERER:
1781 PlaySFX(PS_MAGE15, false);
1782 break;
1783 case PC_MONK:
1784 PlaySFX(PS_MONK15, false);
1785 break;
1786 case NUM_CLASSES:
1787 break;
1788 }
1789 } else {
1790 switch (player._pClass) {
1791 case PC_WARRIOR:
1792 case PC_BARBARIAN:
1793 PlaySFX(PS_WARR37, false);
1794 break;
1795 case PC_ROGUE:
1796 case PC_BARD:
1797 PlaySFX(PS_ROGUE37, false);
1798 break;
1799 case PC_SORCERER:
1800 PlaySFX(PS_MAGE37, false);
1801 break;
1802 case PC_MONK:
1803 PlaySFX(PS_MONK37, false);
1804 break;
1805 case NUM_CLASSES:
1806 break;
1807 }
1808 }
1809 }
1810
1811 holdItem._itype = ITYPE_NONE;
1812 } else {
1813 SetCursor_(holdItem._iCurs + CURSOR_FIRSTITEM);
1814 SetCursorPos(mx - (cursW >> 1), MouseY - (cursH >> 1));
1815 }
1816 }
1817 }
1818 }
1819
inv_update_rem_item(int pnum,BYTE iv)1820 void inv_update_rem_item(int pnum, BYTE iv)
1821 {
1822 if (iv < NUM_INVLOC) {
1823 plr[pnum].InvBody[iv]._itype = ITYPE_NONE;
1824 }
1825
1826 if (plr[pnum]._pmode != PM_DEATH) {
1827 CalcPlrInv(pnum, TRUE);
1828 } else {
1829 CalcPlrInv(pnum, FALSE);
1830 }
1831 }
1832
RemoveInvItem(int pnum,int iv)1833 void RemoveInvItem(int pnum, int iv)
1834 {
1835 int i, j;
1836
1837 iv++;
1838
1839 for (i = 0; i < NUM_INV_GRID_ELEM; i++) {
1840 if (plr[pnum].InvGrid[i] == iv || plr[pnum].InvGrid[i] == -iv) {
1841 plr[pnum].InvGrid[i] = 0;
1842 }
1843 }
1844
1845 iv--;
1846 plr[pnum]._pNumInv--;
1847
1848 if (plr[pnum]._pNumInv > 0 && plr[pnum]._pNumInv != iv) {
1849 plr[pnum].InvList[iv] = plr[pnum].InvList[plr[pnum]._pNumInv];
1850
1851 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
1852 if (plr[pnum].InvGrid[j] == plr[pnum]._pNumInv + 1) {
1853 plr[pnum].InvGrid[j] = iv + 1;
1854 }
1855 if (plr[pnum].InvGrid[j] == -(plr[pnum]._pNumInv + 1)) {
1856 plr[pnum].InvGrid[j] = -(iv + 1);
1857 }
1858 }
1859 }
1860
1861 CalcPlrScrolls(pnum);
1862 }
1863
RemoveSpdBarItem(int pnum,int iv)1864 void RemoveSpdBarItem(int pnum, int iv)
1865 {
1866 plr[pnum].SpdList[iv]._itype = ITYPE_NONE;
1867
1868 CalcPlrScrolls(pnum);
1869 force_redraw = 255;
1870 }
1871
CheckInvItem(bool isShiftHeld)1872 void CheckInvItem(bool isShiftHeld)
1873 {
1874 if (pcurs >= CURSOR_FIRSTITEM) {
1875 CheckInvPaste(myplr, MouseX, MouseY);
1876 } else {
1877 CheckInvCut(myplr, MouseX, MouseY, isShiftHeld);
1878 }
1879 }
1880
1881 /**
1882 * Check for interactions with belt
1883 */
CheckInvScrn(bool isShiftHeld)1884 void CheckInvScrn(bool isShiftHeld)
1885 {
1886 if (MouseX > 190 + PANEL_LEFT && MouseX < 437 + PANEL_LEFT
1887 && MouseY > PANEL_TOP && MouseY < 33 + PANEL_TOP) {
1888 CheckInvItem(isShiftHeld);
1889 }
1890 }
1891
CheckItemStats(int pnum)1892 void CheckItemStats(int pnum)
1893 {
1894 PlayerStruct *p = &plr[pnum];
1895
1896 p->HoldItem._iStatFlag = FALSE;
1897
1898 if (p->_pStrength >= p->HoldItem._iMinStr
1899 && p->_pMagic >= p->HoldItem._iMinMag
1900 && p->_pDexterity >= p->HoldItem._iMinDex) {
1901 p->HoldItem._iStatFlag = TRUE;
1902 }
1903 }
1904
CheckBookLevel(int pnum)1905 void CheckBookLevel(int pnum)
1906 {
1907 int slvl;
1908
1909 if (plr[pnum].HoldItem._iMiscId == IMISC_BOOK) {
1910 plr[pnum].HoldItem._iMinMag = spelldata[plr[pnum].HoldItem._iSpell].sMinInt;
1911 slvl = plr[pnum]._pSplLvl[plr[pnum].HoldItem._iSpell];
1912 while (slvl != 0) {
1913 plr[pnum].HoldItem._iMinMag += 20 * plr[pnum].HoldItem._iMinMag / 100;
1914 slvl--;
1915 if (plr[pnum].HoldItem._iMinMag + 20 * plr[pnum].HoldItem._iMinMag / 100 > 255) {
1916 plr[pnum].HoldItem._iMinMag = -1;
1917 slvl = 0;
1918 }
1919 }
1920 }
1921 }
1922
CheckQuestItem(int pnum)1923 void CheckQuestItem(int pnum)
1924 {
1925 if (plr[pnum].HoldItem.IDidx == IDI_OPTAMULET && quests[Q_BLIND]._qactive == QUEST_ACTIVE)
1926 quests[Q_BLIND]._qactive = QUEST_DONE;
1927 if (plr[pnum].HoldItem.IDidx == IDI_MUSHROOM && quests[Q_MUSHROOM]._qactive == QUEST_ACTIVE && quests[Q_MUSHROOM]._qvar1 == QS_MUSHSPAWNED) {
1928 sfxdelay = 10;
1929 if (plr[pnum]._pClass == PC_WARRIOR) { // BUGFIX: Voice for this quest might be wrong in MP
1930 sfxdnum = PS_WARR95;
1931 } else if (plr[pnum]._pClass == PC_ROGUE) {
1932 sfxdnum = PS_ROGUE95;
1933 } else if (plr[pnum]._pClass == PC_SORCERER) {
1934 sfxdnum = PS_MAGE95;
1935 } else if (plr[pnum]._pClass == PC_MONK) {
1936 sfxdnum = PS_MONK95;
1937 } else if (plr[pnum]._pClass == PC_BARD) {
1938 sfxdnum = PS_ROGUE95;
1939 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
1940 sfxdnum = PS_WARR95;
1941 }
1942 quests[Q_MUSHROOM]._qvar1 = QS_MUSHPICKED;
1943 }
1944 if (plr[pnum].HoldItem.IDidx == IDI_ANVIL && quests[Q_ANVIL]._qactive != QUEST_NOTAVAIL) {
1945 if (quests[Q_ANVIL]._qactive == QUEST_INIT) {
1946 quests[Q_ANVIL]._qactive = QUEST_ACTIVE;
1947 quests[Q_ANVIL]._qvar1 = 1;
1948 }
1949 if (quests[Q_ANVIL]._qlog == TRUE) {
1950 sfxdelay = 10;
1951 if (plr[myplr]._pClass == PC_WARRIOR) {
1952 sfxdnum = PS_WARR89;
1953 } else if (plr[myplr]._pClass == PC_ROGUE) {
1954 sfxdnum = PS_ROGUE89;
1955 } else if (plr[myplr]._pClass == PC_SORCERER) {
1956 sfxdnum = PS_MAGE89;
1957 } else if (plr[myplr]._pClass == PC_MONK) {
1958 sfxdnum = PS_MONK89;
1959 } else if (plr[myplr]._pClass == PC_BARD) {
1960 sfxdnum = PS_ROGUE89;
1961 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1962 sfxdnum = PS_WARR89;
1963 }
1964 }
1965 }
1966 if (plr[pnum].HoldItem.IDidx == IDI_GLDNELIX && quests[Q_VEIL]._qactive != QUEST_NOTAVAIL) {
1967 sfxdelay = 30;
1968 if (plr[myplr]._pClass == PC_WARRIOR) {
1969 sfxdnum = PS_WARR88;
1970 } else if (plr[myplr]._pClass == PC_ROGUE) {
1971 sfxdnum = PS_ROGUE88;
1972 } else if (plr[myplr]._pClass == PC_SORCERER) {
1973 sfxdnum = PS_MAGE88;
1974 } else if (plr[myplr]._pClass == PC_MONK) {
1975 sfxdnum = PS_MONK88;
1976 } else if (plr[myplr]._pClass == PC_BARD) {
1977 sfxdnum = PS_ROGUE88;
1978 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1979 sfxdnum = PS_WARR88;
1980 }
1981 }
1982 if (plr[pnum].HoldItem.IDidx == IDI_ROCK && quests[Q_ROCK]._qactive != QUEST_NOTAVAIL) {
1983 if (quests[Q_ROCK]._qactive == QUEST_INIT) {
1984 quests[Q_ROCK]._qactive = QUEST_ACTIVE;
1985 quests[Q_ROCK]._qvar1 = 1;
1986 }
1987 if (quests[Q_ROCK]._qlog == TRUE) {
1988 sfxdelay = 10;
1989 if (plr[myplr]._pClass == PC_WARRIOR) {
1990 sfxdnum = PS_WARR87;
1991 } else if (plr[myplr]._pClass == PC_ROGUE) {
1992 sfxdnum = PS_ROGUE87;
1993 } else if (plr[myplr]._pClass == PC_SORCERER) {
1994 sfxdnum = PS_MAGE87;
1995 } else if (plr[myplr]._pClass == PC_MONK) {
1996 sfxdnum = PS_MONK87;
1997 } else if (plr[myplr]._pClass == PC_BARD) {
1998 sfxdnum = PS_ROGUE87;
1999 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
2000 sfxdnum = PS_WARR87;
2001 }
2002 }
2003 }
2004 if (plr[pnum].HoldItem.IDidx == IDI_ARMOFVAL && quests[Q_BLOOD]._qactive == QUEST_ACTIVE) {
2005 quests[Q_BLOOD]._qactive = QUEST_DONE;
2006 sfxdelay = 20;
2007 if (plr[myplr]._pClass == PC_WARRIOR) {
2008 sfxdnum = PS_WARR91;
2009 } else if (plr[myplr]._pClass == PC_ROGUE) {
2010 sfxdnum = PS_ROGUE91;
2011 } else if (plr[myplr]._pClass == PC_SORCERER) {
2012 sfxdnum = PS_MAGE91;
2013 } else if (plr[myplr]._pClass == PC_MONK) {
2014 sfxdnum = PS_MONK91;
2015 } else if (plr[myplr]._pClass == PC_BARD) {
2016 sfxdnum = PS_ROGUE91;
2017 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
2018 sfxdnum = PS_WARR91;
2019 }
2020 }
2021 if (plr[pnum].HoldItem.IDidx == IDI_MAPOFDOOM) {
2022 quests[Q_GRAVE]._qlog = FALSE;
2023 quests[Q_GRAVE]._qactive = QUEST_ACTIVE;
2024 quests[Q_GRAVE]._qvar1 = 1;
2025 sfxdelay = 10;
2026 if (plr[myplr]._pClass == PC_WARRIOR) {
2027 sfxdnum = PS_WARR79;
2028 } else if (plr[myplr]._pClass == PC_ROGUE) {
2029 sfxdnum = PS_ROGUE79;
2030 } else if (plr[myplr]._pClass == PC_SORCERER) {
2031 sfxdnum = PS_MAGE79;
2032 } else if (plr[myplr]._pClass == PC_MONK) {
2033 sfxdnum = PS_MONK79;
2034 } else if (plr[myplr]._pClass == PC_BARD) {
2035 sfxdnum = PS_ROGUE79;
2036 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
2037 sfxdnum = PS_WARR79;
2038 }
2039 }
2040 if (plr[pnum].HoldItem.IDidx == IDI_NOTE1 || plr[pnum].HoldItem.IDidx == IDI_NOTE2 || plr[pnum].HoldItem.IDidx == IDI_NOTE3) {
2041 int mask, idx, item_num;
2042 int n1, n2, n3;
2043 ItemStruct tmp;
2044 mask = 0;
2045 idx = plr[pnum].HoldItem.IDidx;
2046 if (PlrHasItem(pnum, IDI_NOTE1, &n1) || idx == IDI_NOTE1)
2047 mask = 1;
2048 if (PlrHasItem(pnum, IDI_NOTE2, &n2) || idx == IDI_NOTE2)
2049 mask |= 2;
2050 if (PlrHasItem(pnum, IDI_NOTE3, &n3) || idx == IDI_NOTE3)
2051 mask |= 4;
2052 if (mask == 7) {
2053 sfxdelay = 10;
2054 if (plr[myplr]._pClass == PC_WARRIOR) {
2055 sfxdnum = PS_WARR46;
2056 } else if (plr[myplr]._pClass == PC_ROGUE) {
2057 sfxdnum = PS_ROGUE46;
2058 } else if (plr[myplr]._pClass == PC_SORCERER) {
2059 sfxdnum = PS_MAGE46;
2060 } else if (plr[myplr]._pClass == PC_MONK) {
2061 sfxdnum = PS_MONK46;
2062 } else if (plr[myplr]._pClass == PC_BARD) {
2063 sfxdnum = PS_ROGUE46;
2064 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
2065 sfxdnum = PS_WARR46;
2066 }
2067 switch (idx) {
2068 case IDI_NOTE1:
2069 PlrHasItem(pnum, IDI_NOTE2, &n2);
2070 RemoveInvItem(pnum, n2);
2071 PlrHasItem(pnum, IDI_NOTE3, &n3);
2072 RemoveInvItem(pnum, n3);
2073 break;
2074 case IDI_NOTE2:
2075 PlrHasItem(pnum, IDI_NOTE1, &n1);
2076 RemoveInvItem(pnum, n1);
2077 PlrHasItem(pnum, IDI_NOTE3, &n3);
2078 RemoveInvItem(pnum, n3);
2079 break;
2080 case IDI_NOTE3:
2081 PlrHasItem(pnum, IDI_NOTE1, &n1);
2082 RemoveInvItem(pnum, n1);
2083 PlrHasItem(pnum, IDI_NOTE2, &n2);
2084 RemoveInvItem(pnum, n2);
2085 break;
2086 }
2087 item_num = itemactive[0];
2088 tmp = item[item_num];
2089 memset(&item[item_num], 0, sizeof(*item));
2090 GetItemAttrs(item_num, IDI_FULLNOTE, 16);
2091 SetupItem(item_num);
2092 plr[pnum].HoldItem = item[item_num];
2093 item[item_num] = tmp;
2094 }
2095 }
2096 }
2097
CleanupItems(int ii)2098 void CleanupItems(int ii)
2099 {
2100 dItem[item[ii]._ix][item[ii]._iy] = 0;
2101
2102 if (currlevel == 21 & item[ii]._ix == CornerStone.x && item[ii]._iy == CornerStone.y) {
2103 CornerStone.item._itype = ITYPE_NONE;
2104 CornerStone.item._iSelFlag = 0;
2105 CornerStone.item._ix = 0;
2106 CornerStone.item._iy = 0;
2107 CornerStone.item._iAnimFlag = FALSE;
2108 CornerStone.item._iIdentified = FALSE;
2109 CornerStone.item._iPostDraw = FALSE;
2110 }
2111
2112 int i = 0;
2113 while (i < numitems) {
2114 if (itemactive[i] == ii) {
2115 DeleteItem(itemactive[i], i);
2116 i = 0;
2117 continue;
2118 }
2119
2120 i++;
2121 }
2122 }
2123
InvGetItem(int pnum,int ii)2124 void InvGetItem(int pnum, int ii)
2125 {
2126 if (dropGoldFlag) {
2127 dropGoldFlag = FALSE;
2128 dropGoldValue = 0;
2129 }
2130
2131 if (dItem[item[ii]._ix][item[ii]._iy] == 0)
2132 return;
2133
2134 if (myplr == pnum && pcurs >= CURSOR_FIRSTITEM)
2135 NetSendCmdPItem(TRUE, CMD_SYNCPUTITEM, plr[myplr]._px, plr[myplr]._py);
2136
2137 item[ii]._iCreateInfo &= ~CF_PREGEN;
2138 plr[pnum].HoldItem = item[ii];
2139 CheckQuestItem(pnum);
2140 CheckBookLevel(pnum);
2141 CheckItemStats(pnum);
2142 bool cursor_updated = false;
2143 if (plr[pnum].HoldItem._itype == ITYPE_GOLD && GoldAutoPlace(pnum))
2144 cursor_updated = true;
2145 CleanupItems(ii);
2146 pcursitem = -1;
2147 if (!cursor_updated)
2148 SetCursor_(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
2149 }
2150
AutoGetItem(int pnum,int ii)2151 void AutoGetItem(int pnum, int ii)
2152 {
2153 int i, idx;
2154 int w, h;
2155 BOOL done;
2156
2157 if (pcurs != CURSOR_HAND) {
2158 return;
2159 }
2160
2161 if (dropGoldFlag) {
2162 dropGoldFlag = FALSE;
2163 dropGoldValue = 0;
2164 }
2165
2166 if (dItem[item[ii]._ix][item[ii]._iy] == 0)
2167 return;
2168
2169 item[ii]._iCreateInfo &= ~CF_PREGEN;
2170 plr[pnum].HoldItem = item[ii]; /// BUGFIX: overwrites cursor item, allowing for belt dupe bug
2171 CheckQuestItem(pnum);
2172 CheckBookLevel(pnum);
2173 CheckItemStats(pnum);
2174 SetICursor(plr[pnum].HoldItem._iCurs + CURSOR_FIRSTITEM);
2175 if (plr[pnum].HoldItem._itype == ITYPE_GOLD) {
2176 done = GoldAutoPlace(pnum);
2177 if (!done) {
2178 item[ii]._ivalue = plr[pnum].HoldItem._ivalue;
2179 SetPlrHandGoldCurs(&item[ii]);
2180 }
2181 } else {
2182 done = AutoEquipEnabled(plr[pnum], plr[pnum].HoldItem) && AutoEquip(pnum, plr[pnum].HoldItem);
2183 if (!done) {
2184 done = AutoPlaceItemInBelt(pnum, plr[pnum].HoldItem, true);
2185 }
2186 if (!done) {
2187 done = AutoPlaceItemInInventory(pnum, plr[pnum].HoldItem, TRUE);
2188 }
2189 }
2190
2191 if (done) {
2192 CleanupItems(ii);
2193 return;
2194 }
2195
2196 if (pnum == myplr) {
2197 if (plr[pnum]._pClass == PC_WARRIOR) {
2198 PlaySFX(random_(0, 3) + PS_WARR14);
2199 } else if (plr[pnum]._pClass == PC_ROGUE) {
2200 PlaySFX(random_(0, 3) + PS_ROGUE14);
2201 } else if (plr[pnum]._pClass == PC_SORCERER) {
2202 PlaySFX(random_(0, 3) + PS_MAGE14);
2203 } else if (plr[pnum]._pClass == PC_MONK) {
2204 PlaySFX(random_(0, 3) + PS_MONK14);
2205 } else if (plr[pnum]._pClass == PC_BARD) {
2206 PlaySFX(random_(0, 3) + PS_ROGUE14);
2207 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
2208 PlaySFX(random_(0, 3) + PS_WARR14);
2209 }
2210 }
2211 plr[pnum].HoldItem = item[ii];
2212 RespawnItem(ii, TRUE);
2213 NetSendCmdPItem(TRUE, CMD_RESPAWNITEM, item[ii]._ix, item[ii]._iy);
2214 plr[pnum].HoldItem._itype = ITYPE_NONE;
2215 }
2216
FindGetItem(int idx,WORD ci,int iseed)2217 int FindGetItem(int idx, WORD ci, int iseed)
2218 {
2219 if (numitems <= 0)
2220 return -1;
2221
2222 int ii;
2223 int i = 0;
2224 while (1) {
2225 ii = itemactive[i];
2226 if (item[ii].IDidx == idx && item[ii]._iSeed == iseed && item[ii]._iCreateInfo == ci)
2227 break;
2228
2229 i++;
2230
2231 if (i >= numitems)
2232 return -1;
2233 }
2234
2235 return ii;
2236 }
2237
SyncGetItem(int x,int y,int idx,WORD ci,int iseed)2238 void SyncGetItem(int x, int y, int idx, WORD ci, int iseed)
2239 {
2240 int i, ii;
2241
2242 if (dItem[x][y]) {
2243 ii = dItem[x][y] - 1;
2244 if (item[ii].IDidx == idx
2245 && item[ii]._iSeed == iseed
2246 && item[ii]._iCreateInfo == ci) {
2247 FindGetItem(idx, ci, iseed);
2248 } else {
2249 ii = FindGetItem(idx, ci, iseed);
2250 }
2251 } else {
2252 ii = FindGetItem(idx, ci, iseed);
2253 }
2254
2255 if (ii == -1)
2256 return;
2257
2258 CleanupItems(ii);
2259 assert(FindGetItem(idx, ci, iseed) == -1);
2260 }
2261
CanPut(int x,int y)2262 BOOL CanPut(int x, int y)
2263 {
2264 char oi, oi2;
2265
2266 if (dItem[x][y])
2267 return FALSE;
2268 if (nSolidTable[dPiece[x][y]])
2269 return FALSE;
2270
2271 if (dObject[x][y] != 0) {
2272 if (object[dObject[x][y] > 0 ? dObject[x][y] - 1 : -(dObject[x][y] + 1)]._oSolidFlag)
2273 return FALSE;
2274 }
2275
2276 oi = dObject[x + 1][y + 1];
2277 if (oi > 0 && object[oi - 1]._oSelFlag != 0) {
2278 return FALSE;
2279 }
2280 if (oi < 0 && object[-(oi + 1)]._oSelFlag != 0) {
2281 return FALSE;
2282 }
2283
2284 oi = dObject[x + 1][y];
2285 if (oi > 0) {
2286 oi2 = dObject[x][y + 1];
2287 if (oi2 > 0 && object[oi - 1]._oSelFlag != 0 && object[oi2 - 1]._oSelFlag != 0)
2288 return FALSE;
2289 }
2290
2291 if (currlevel == 0 && dMonster[x][y] != 0)
2292 return FALSE;
2293 if (currlevel == 0 && dMonster[x + 1][y + 1] != 0)
2294 return FALSE;
2295
2296 return TRUE;
2297 }
2298
TryInvPut()2299 BOOL TryInvPut()
2300 {
2301 int dir;
2302
2303 if (numitems >= MAXITEMS)
2304 return FALSE;
2305
2306 dir = GetDirection(plr[myplr]._px, plr[myplr]._py, cursmx, cursmy);
2307 if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) {
2308 return TRUE;
2309 }
2310
2311 dir = (dir - 1) & 7;
2312 if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) {
2313 return TRUE;
2314 }
2315
2316 dir = (dir + 2) & 7;
2317 if (CanPut(plr[myplr]._px + offset_x[dir], plr[myplr]._py + offset_y[dir])) {
2318 return TRUE;
2319 }
2320
2321 return CanPut(plr[myplr]._px, plr[myplr]._py);
2322 }
2323
DrawInvMsg(const char * msg)2324 void DrawInvMsg(const char *msg)
2325 {
2326 DWORD dwTicks;
2327
2328 dwTicks = SDL_GetTicks();
2329 if (dwTicks - sgdwLastTime >= 5000) {
2330 sgdwLastTime = dwTicks;
2331 ErrorPlrMsg(msg);
2332 }
2333 }
2334
InvPutItem(int pnum,int x,int y)2335 int InvPutItem(int pnum, int x, int y)
2336 {
2337 BOOL done;
2338 int d;
2339 int i, j, l;
2340 int xx, yy;
2341 int xp, yp;
2342
2343 if (numitems >= MAXITEMS)
2344 return -1;
2345
2346 d = GetDirection(plr[pnum]._px, plr[pnum]._py, x, y);
2347 xx = x - plr[pnum]._px;
2348 yy = y - plr[pnum]._py;
2349 if (abs(xx) > 1 || abs(yy) > 1) {
2350 x = plr[pnum]._px + offset_x[d];
2351 y = plr[pnum]._py + offset_y[d];
2352 }
2353 if (!CanPut(x, y)) {
2354 d = (d - 1) & 7;
2355 x = plr[pnum]._px + offset_x[d];
2356 y = plr[pnum]._py + offset_y[d];
2357 if (!CanPut(x, y)) {
2358 d = (d + 2) & 7;
2359 x = plr[pnum]._px + offset_x[d];
2360 y = plr[pnum]._py + offset_y[d];
2361 if (!CanPut(x, y)) {
2362 done = FALSE;
2363 for (l = 1; l < 50 && !done; l++) {
2364 for (j = -l; j <= l && !done; j++) {
2365 yp = j + plr[pnum]._py;
2366 for (i = -l; i <= l && !done; i++) {
2367 xp = i + plr[pnum]._px;
2368 if (CanPut(xp, yp)) {
2369 done = TRUE;
2370 x = xp;
2371 y = yp;
2372 }
2373 }
2374 }
2375 }
2376 if (!done)
2377 return -1;
2378 }
2379 }
2380 }
2381
2382 if (currlevel == 0) {
2383 yp = cursmy;
2384 xp = cursmx;
2385 if (plr[pnum].HoldItem._iCurs == ICURS_RUNE_BOMB && xp >= 79 && xp <= 82 && yp >= 61 && yp <= 64) {
2386 NetSendCmdLocParam2(0, CMD_OPENHIVE, plr[pnum]._px, plr[pnum]._py, xx, yy);
2387 quests[Q_FARMER]._qactive = 3;
2388 if (gbIsMultiplayer) {
2389 NetSendCmdQuest(TRUE, Q_FARMER);
2390 return -1;
2391 }
2392 return -1;
2393 }
2394 if (plr[pnum].HoldItem.IDidx == IDI_MAPOFDOOM && xp >= 35 && xp <= 38 && yp >= 20 && yp <= 24) {
2395 NetSendCmd(FALSE, CMD_OPENCRYPT);
2396 quests[Q_GRAVE]._qactive = 3;
2397 if (gbIsMultiplayer) {
2398 NetSendCmdQuest(TRUE, Q_GRAVE);
2399 }
2400 return -1;
2401 }
2402 }
2403
2404 assert(CanPut(x, y));
2405
2406 int ii = AllocateItem();
2407
2408 dItem[x][y] = ii + 1;
2409 item[ii] = plr[pnum].HoldItem;
2410 item[ii]._ix = x;
2411 item[ii]._iy = y;
2412 RespawnItem(ii, TRUE);
2413
2414 if (currlevel == 21 && x == CornerStone.x && y == CornerStone.y) {
2415 CornerStone.item = item[ii];
2416 InitQTextMsg(TEXT_CORNSTN);
2417 quests[Q_CORNSTN]._qlog = 0;
2418 quests[Q_CORNSTN]._qactive = QUEST_DONE;
2419 }
2420
2421 NewCursor(CURSOR_HAND);
2422 return ii;
2423 }
2424
SyncPutItem(int pnum,int x,int y,int idx,WORD icreateinfo,int iseed,int Id,int dur,int mdur,int ch,int mch,int ivalue,DWORD ibuff,int to_hit,int max_dam,int min_str,int min_mag,int min_dex,int ac)2425 int SyncPutItem(int pnum, int x, int y, int idx, WORD icreateinfo, int iseed, int Id, int dur, int mdur, int ch, int mch, int ivalue, DWORD ibuff, int to_hit, int max_dam, int min_str, int min_mag, int min_dex, int ac)
2426 {
2427 BOOL done;
2428 int d;
2429 int i, j, l;
2430 int xx, yy;
2431 int xp, yp;
2432
2433 if (numitems >= MAXITEMS)
2434 return -1;
2435
2436 d = GetDirection(plr[pnum]._px, plr[pnum]._py, x, y);
2437 xx = x - plr[pnum]._px;
2438 yy = y - plr[pnum]._py;
2439 if (abs(xx) > 1 || abs(yy) > 1) {
2440 x = plr[pnum]._px + offset_x[d];
2441 y = plr[pnum]._py + offset_y[d];
2442 }
2443 if (!CanPut(x, y)) {
2444 d = (d - 1) & 7;
2445 x = plr[pnum]._px + offset_x[d];
2446 y = plr[pnum]._py + offset_y[d];
2447 if (!CanPut(x, y)) {
2448 d = (d + 2) & 7;
2449 x = plr[pnum]._px + offset_x[d];
2450 y = plr[pnum]._py + offset_y[d];
2451 if (!CanPut(x, y)) {
2452 done = FALSE;
2453 for (l = 1; l < 50 && !done; l++) {
2454 for (j = -l; j <= l && !done; j++) {
2455 yp = j + plr[pnum]._py;
2456 for (i = -l; i <= l && !done; i++) {
2457 xp = i + plr[pnum]._px;
2458 if (CanPut(xp, yp)) {
2459 done = TRUE;
2460 x = xp;
2461 y = yp;
2462 }
2463 }
2464 }
2465 }
2466 if (!done)
2467 return -1;
2468 }
2469 }
2470 }
2471
2472 CanPut(x, y);
2473
2474 int ii = AllocateItem();
2475
2476 dItem[x][y] = ii + 1;
2477
2478 if (idx == IDI_EAR) {
2479 RecreateEar(ii, icreateinfo, iseed, Id, dur, mdur, ch, mch, ivalue, ibuff);
2480 } else {
2481 RecreateItem(ii, idx, icreateinfo, iseed, ivalue, (ibuff & CF_HELLFIRE) != 0);
2482 if (Id)
2483 item[ii]._iIdentified = TRUE;
2484 item[ii]._iDurability = dur;
2485 item[ii]._iMaxDur = mdur;
2486 item[ii]._iCharges = ch;
2487 item[ii]._iMaxCharges = mch;
2488 item[ii]._iPLToHit = to_hit;
2489 item[ii]._iMaxDam = max_dam;
2490 item[ii]._iMinStr = min_str;
2491 item[ii]._iMinMag = min_mag;
2492 item[ii]._iMinDex = min_dex;
2493 item[ii]._iAC = ac;
2494 item[ii].dwBuff = ibuff;
2495 }
2496
2497 item[ii]._ix = x;
2498 item[ii]._iy = y;
2499 RespawnItem(ii, TRUE);
2500
2501 if (currlevel == 21 && x == CornerStone.x && y == CornerStone.y) {
2502 CornerStone.item = item[ii];
2503 InitQTextMsg(TEXT_CORNSTN);
2504 quests[Q_CORNSTN]._qlog = 0;
2505 quests[Q_CORNSTN]._qactive = QUEST_DONE;
2506 }
2507 return ii;
2508 }
2509
CheckInvHLight()2510 char CheckInvHLight()
2511 {
2512 int r, ii, nGold;
2513 ItemStruct *pi;
2514 PlayerStruct *p;
2515 char rv;
2516
2517 for (r = 0; (DWORD)r < NUM_XY_SLOTS; r++) {
2518 int xo = RIGHT_PANEL;
2519 int yo = 0;
2520 if (r >= SLOTXY_BELT_FIRST) {
2521 xo = PANEL_LEFT;
2522 yo = PANEL_TOP;
2523 }
2524
2525 if (MouseX >= InvRect[r].X + xo
2526 && MouseX < InvRect[r].X + xo + (INV_SLOT_SIZE_PX + 1)
2527 && MouseY >= InvRect[r].Y + yo - (INV_SLOT_SIZE_PX + 1)
2528 && MouseY < InvRect[r].Y + yo) {
2529 break;
2530 }
2531 }
2532
2533 if ((DWORD)r >= NUM_XY_SLOTS)
2534 return -1;
2535
2536 rv = -1;
2537 infoclr = COL_WHITE;
2538 pi = NULL;
2539 p = &plr[myplr];
2540 ClearPanel();
2541 if (r >= SLOTXY_HEAD_FIRST && r <= SLOTXY_HEAD_LAST) {
2542 rv = INVLOC_HEAD;
2543 pi = &p->InvBody[rv];
2544 } else if (r == SLOTXY_RING_LEFT) {
2545 rv = INVLOC_RING_LEFT;
2546 pi = &p->InvBody[rv];
2547 } else if (r == SLOTXY_RING_RIGHT) {
2548 rv = INVLOC_RING_RIGHT;
2549 pi = &p->InvBody[rv];
2550 } else if (r == SLOTXY_AMULET) {
2551 rv = INVLOC_AMULET;
2552 pi = &p->InvBody[rv];
2553 } else if (r >= SLOTXY_HAND_LEFT_FIRST && r <= SLOTXY_HAND_LEFT_LAST) {
2554 rv = INVLOC_HAND_LEFT;
2555 pi = &p->InvBody[rv];
2556 } else if (r >= SLOTXY_HAND_RIGHT_FIRST && r <= SLOTXY_HAND_RIGHT_LAST) {
2557 pi = &p->InvBody[INVLOC_HAND_LEFT];
2558 if (pi->isEmpty() || pi->_iLoc != ILOC_TWOHAND
2559 || (p->_pClass == PC_BARBARIAN && (p->InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SWORD || p->InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_MACE))) {
2560 rv = INVLOC_HAND_RIGHT;
2561 pi = &p->InvBody[rv];
2562 } else {
2563 rv = INVLOC_HAND_LEFT;
2564 }
2565 } else if (r >= SLOTXY_CHEST_FIRST && r <= SLOTXY_CHEST_LAST) {
2566 rv = INVLOC_CHEST;
2567 pi = &p->InvBody[rv];
2568 } else if (r >= SLOTXY_INV_FIRST && r <= SLOTXY_INV_LAST) {
2569 r = abs(p->InvGrid[r - SLOTXY_INV_FIRST]);
2570 if (r == 0)
2571 return -1;
2572 ii = r - 1;
2573 rv = ii + INVITEM_INV_FIRST;
2574 pi = &p->InvList[ii];
2575 } else if (r >= SLOTXY_BELT_FIRST) {
2576 r -= SLOTXY_BELT_FIRST;
2577 drawsbarflag = TRUE;
2578 pi = &p->SpdList[r];
2579 if (pi->isEmpty())
2580 return -1;
2581 rv = r + INVITEM_BELT_FIRST;
2582 }
2583
2584 if (pi->isEmpty())
2585 return -1;
2586
2587 if (pi->_itype == ITYPE_GOLD) {
2588 nGold = pi->_ivalue;
2589 sprintf(infostr, "%i gold %s", nGold, get_pieces_str(nGold));
2590 } else {
2591 if (pi->_iMagical == ITEM_QUALITY_MAGIC) {
2592 infoclr = COL_BLUE;
2593 } else if (pi->_iMagical == ITEM_QUALITY_UNIQUE) {
2594 infoclr = COL_GOLD;
2595 }
2596 strcpy(infostr, pi->_iName);
2597 if (pi->_iIdentified) {
2598 strcpy(infostr, pi->_iIName);
2599 PrintItemDetails(pi);
2600 } else {
2601 PrintItemDur(pi);
2602 }
2603 }
2604
2605 return rv;
2606 }
2607
RemoveScroll(int pnum)2608 void RemoveScroll(int pnum)
2609 {
2610 int i;
2611
2612 for (i = 0; i < plr[pnum]._pNumInv; i++) {
2613 if (!plr[pnum].InvList[i].isEmpty()
2614 && (plr[pnum].InvList[i]._iMiscId == IMISC_SCROLL || plr[pnum].InvList[i]._iMiscId == IMISC_SCROLLT)
2615 && plr[pnum].InvList[i]._iSpell == plr[pnum]._pRSpell) {
2616 RemoveInvItem(pnum, i);
2617 CalcPlrScrolls(pnum);
2618 return;
2619 }
2620 }
2621 for (i = 0; i < MAXBELTITEMS; i++) {
2622 if (!plr[pnum].SpdList[i].isEmpty()
2623 && (plr[pnum].SpdList[i]._iMiscId == IMISC_SCROLL || plr[pnum].SpdList[i]._iMiscId == IMISC_SCROLLT)
2624 && plr[pnum].SpdList[i]._iSpell == plr[pnum]._pSpell) {
2625 RemoveSpdBarItem(pnum, i);
2626 CalcPlrScrolls(pnum);
2627 return;
2628 }
2629 }
2630 }
2631
UseScroll()2632 BOOL UseScroll()
2633 {
2634 int i;
2635
2636 if (pcurs != CURSOR_HAND)
2637 return FALSE;
2638 if (leveltype == DTYPE_TOWN && !spelldata[plr[myplr]._pRSpell].sTownSpell)
2639 return FALSE;
2640
2641 for (i = 0; i < plr[myplr]._pNumInv; i++) {
2642 if (!plr[myplr].InvList[i].isEmpty()
2643 && (plr[myplr].InvList[i]._iMiscId == IMISC_SCROLL || plr[myplr].InvList[i]._iMiscId == IMISC_SCROLLT)
2644 && plr[myplr].InvList[i]._iSpell == plr[myplr]._pRSpell) {
2645 return TRUE;
2646 }
2647 }
2648 for (i = 0; i < MAXBELTITEMS; i++) {
2649 if (!plr[myplr].SpdList[i].isEmpty()
2650 && (plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLL || plr[myplr].SpdList[i]._iMiscId == IMISC_SCROLLT)
2651 && plr[myplr].SpdList[i]._iSpell == plr[myplr]._pRSpell) {
2652 return TRUE;
2653 }
2654 }
2655
2656 return FALSE;
2657 }
2658
UseStaffCharge(int pnum)2659 void UseStaffCharge(int pnum)
2660 {
2661 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty()
2662 && (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_STAFF
2663 || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE // BUGFIX: myplr->pnum
2664 )
2665 && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iSpell == plr[pnum]._pRSpell
2666 && plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) {
2667 plr[pnum].InvBody[INVLOC_HAND_LEFT]._iCharges--;
2668 CalcPlrStaff(pnum);
2669 }
2670 }
2671
UseStaff()2672 BOOL UseStaff()
2673 {
2674 if (pcurs == CURSOR_HAND) {
2675 if (!plr[myplr].InvBody[INVLOC_HAND_LEFT].isEmpty()
2676 && (plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_STAFF || plr[myplr].InvBody[INVLOC_HAND_LEFT]._iMiscId == IMISC_UNIQUE)
2677 && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iSpell == plr[myplr]._pRSpell
2678 && plr[myplr].InvBody[INVLOC_HAND_LEFT]._iCharges > 0) {
2679 return TRUE;
2680 }
2681 }
2682
2683 return FALSE;
2684 }
2685
StartGoldDrop()2686 void StartGoldDrop()
2687 {
2688 initialDropGoldIndex = pcursinvitem;
2689 if (pcursinvitem <= INVITEM_INV_LAST)
2690 initialDropGoldValue = plr[myplr].InvList[pcursinvitem - INVITEM_INV_FIRST]._ivalue;
2691 else
2692 initialDropGoldValue = plr[myplr].SpdList[pcursinvitem - INVITEM_BELT_FIRST]._ivalue;
2693 dropGoldFlag = TRUE;
2694 dropGoldValue = 0;
2695 if (talkflag)
2696 control_reset_talk();
2697 }
2698
UseInvItem(int pnum,int cii)2699 BOOL UseInvItem(int pnum, int cii)
2700 {
2701 int c, idata;
2702 ItemStruct *Item;
2703 BOOL speedlist;
2704
2705 if (plr[pnum]._pInvincible && plr[pnum]._pHitPoints == 0 && pnum == myplr)
2706 return TRUE;
2707 if (pcurs != CURSOR_HAND)
2708 return TRUE;
2709 if (stextflag != STORE_NONE)
2710 return TRUE;
2711 if (cii < INVITEM_INV_FIRST)
2712 return FALSE;
2713
2714 if (cii <= INVITEM_INV_LAST) {
2715 c = cii - INVITEM_INV_FIRST;
2716 Item = &plr[pnum].InvList[c];
2717 speedlist = FALSE;
2718 } else {
2719 if (talkflag)
2720 return TRUE;
2721 c = cii - INVITEM_BELT_FIRST;
2722 Item = &plr[pnum].SpdList[c];
2723 speedlist = TRUE;
2724 }
2725
2726 switch (Item->IDidx) {
2727 case IDI_MUSHROOM:
2728 sfxdelay = 10;
2729 if (plr[pnum]._pClass == PC_WARRIOR) {
2730 sfxdnum = PS_WARR95;
2731 } else if (plr[pnum]._pClass == PC_ROGUE) {
2732 sfxdnum = PS_ROGUE95;
2733 } else if (plr[pnum]._pClass == PC_SORCERER) {
2734 sfxdnum = PS_MAGE95;
2735 } else if (plr[pnum]._pClass == PC_MONK) {
2736 sfxdnum = PS_MONK95;
2737 } else if (plr[pnum]._pClass == PC_BARD) {
2738 sfxdnum = PS_ROGUE95;
2739 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
2740 sfxdnum = PS_WARR95;
2741 }
2742 return TRUE;
2743 case IDI_FUNGALTM:
2744 PlaySFX(IS_IBOOK);
2745 sfxdelay = 10;
2746 if (plr[pnum]._pClass == PC_WARRIOR) {
2747 sfxdnum = PS_WARR29;
2748 } else if (plr[pnum]._pClass == PC_ROGUE) {
2749 sfxdnum = PS_ROGUE29;
2750 } else if (plr[pnum]._pClass == PC_SORCERER) {
2751 sfxdnum = PS_MAGE29;
2752 } else if (plr[pnum]._pClass == PC_MONK) {
2753 sfxdnum = PS_MONK29;
2754 } else if (plr[pnum]._pClass == PC_BARD) {
2755 sfxdnum = PS_ROGUE29;
2756 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
2757 sfxdnum = PS_WARR29;
2758 }
2759 return TRUE;
2760 }
2761
2762 if (!AllItemsList[Item->IDidx].iUsable)
2763 return FALSE;
2764
2765 if (!Item->_iStatFlag) {
2766 if (plr[pnum]._pClass == PC_WARRIOR) {
2767 PlaySFX(PS_WARR13);
2768 } else if (plr[pnum]._pClass == PC_ROGUE) {
2769 PlaySFX(PS_ROGUE13);
2770 } else if (plr[pnum]._pClass == PC_SORCERER) {
2771 PlaySFX(PS_MAGE13);
2772 } else if (plr[pnum]._pClass == PC_MONK) {
2773 PlaySFX(PS_MONK13);
2774 } else if (plr[pnum]._pClass == PC_BARD) {
2775 PlaySFX(PS_ROGUE13);
2776 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
2777 PlaySFX(PS_WARR13);
2778 }
2779 return TRUE;
2780 }
2781
2782 if (Item->_iMiscId == IMISC_NONE && Item->_itype == ITYPE_GOLD) {
2783 StartGoldDrop();
2784 return TRUE;
2785 }
2786
2787 if (dropGoldFlag) {
2788 dropGoldFlag = FALSE;
2789 dropGoldValue = 0;
2790 }
2791
2792 if (Item->_iMiscId == IMISC_SCROLL && currlevel == 0 && !spelldata[Item->_iSpell].sTownSpell) {
2793 return TRUE;
2794 }
2795
2796 if (Item->_iMiscId == IMISC_SCROLLT && currlevel == 0 && !spelldata[Item->_iSpell].sTownSpell) {
2797 return TRUE;
2798 }
2799
2800 if (Item->_iMiscId > IMISC_RUNEFIRST && Item->_iMiscId < IMISC_RUNELAST && currlevel == 0) {
2801 return TRUE;
2802 }
2803
2804 idata = ItemCAnimTbl[Item->_iCurs];
2805 if (Item->_iMiscId == IMISC_BOOK)
2806 PlaySFX(IS_RBOOK);
2807 else if (pnum == myplr)
2808 PlaySFX(ItemInvSnds[idata]);
2809
2810 UseItem(pnum, Item->_iMiscId, Item->_iSpell);
2811
2812 if (speedlist) {
2813 if (plr[pnum].SpdList[c]._iMiscId == IMISC_NOTE) {
2814 InitQTextMsg(TEXT_BOOK9);
2815 invflag = FALSE;
2816 return TRUE;
2817 }
2818 RemoveSpdBarItem(pnum, c);
2819 return TRUE;
2820 } else {
2821 if (plr[pnum].InvList[c]._iMiscId == IMISC_MAPOFDOOM)
2822 return TRUE;
2823 if (plr[pnum].InvList[c]._iMiscId == IMISC_NOTE) {
2824 InitQTextMsg(TEXT_BOOK9);
2825 invflag = FALSE;
2826 return TRUE;
2827 }
2828 RemoveInvItem(pnum, c);
2829 }
2830 return TRUE;
2831 }
2832
DoTelekinesis()2833 void DoTelekinesis()
2834 {
2835 if (pcursobj != -1)
2836 NetSendCmdParam1(TRUE, CMD_OPOBJT, pcursobj);
2837 if (pcursitem != -1)
2838 NetSendCmdGItem(TRUE, CMD_REQUESTAGITEM, myplr, myplr, pcursitem);
2839 if (pcursmonst != -1 && !M_Talker(pcursmonst) && monster[pcursmonst].mtalkmsg == 0)
2840 NetSendCmdParam1(TRUE, CMD_KNOCKBACK, pcursmonst);
2841 NewCursor(CURSOR_HAND);
2842 }
2843
CalculateGold(int pnum)2844 int CalculateGold(int pnum)
2845 {
2846 int i, gold;
2847
2848 gold = 0;
2849 for (i = 0; i < MAXBELTITEMS; i++) {
2850 if (plr[pnum].SpdList[i]._itype == ITYPE_GOLD) {
2851 gold += plr[pnum].SpdList[i]._ivalue;
2852 force_redraw = 255;
2853 }
2854 }
2855 for (i = 0; i < plr[pnum]._pNumInv; i++) {
2856 if (plr[pnum].InvList[i]._itype == ITYPE_GOLD)
2857 gold += plr[pnum].InvList[i]._ivalue;
2858 }
2859
2860 return gold;
2861 }
2862
DropItemBeforeTrig()2863 BOOL DropItemBeforeTrig()
2864 {
2865 if (TryInvPut()) {
2866 NetSendCmdPItem(TRUE, CMD_PUTITEM, cursmx, cursmy);
2867 NewCursor(CURSOR_HAND);
2868 return TRUE;
2869 }
2870
2871 return FALSE;
2872 }
2873
2874 DEVILUTION_END_NAMESPACE
2875