1 /*
2 Copyright (C) 2000-2013 The Exult Team
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "game.h"
24 #include "gamewin.h"
25 #include "Gump_button.h"
26 #include "misc_buttons.h"
27 #include "Paperdoll_gump.h"
28 #include "contain.h"
29 #include "actors.h"
30 #include "objiter.h"
31 #include "cheat.h"
32 #include "miscinf.h"
33 #include "shapeid.h"
34 #include "ready.h"
35 #include "ammoinf.h"
36 #include "npcdollinf.h"
37 #include "objdollinf.h"
38 #include "weaponinf.h"
39 #include "ignore_unused_variable_warning.h"
40 #include "array_size.h"
41
42 #include <cstdio>
43
44 using std::size_t;
45
46 //#define SHOW_USECODE_CONTAINER
47 //#define SHOW_NONREADIED_OBJECTS
48
49 /*
50 *
51 * SERPENT ISLE PAPERDOLL GUMP
52 *
53 */
54
55 /*
56 * Statics:
57 */
58
59 // Paperdoll is completely different to Actor
60 Paperdoll_gump::Position Paperdoll_gump::disk = {123, 137};
61 Paperdoll_gump::Position Paperdoll_gump::heart = {97, 137};
62 Paperdoll_gump::Position Paperdoll_gump::combat = {51, 142};
63 Paperdoll_gump::Position Paperdoll_gump::cstat = {72, 137};
64 Paperdoll_gump::Position Paperdoll_gump::cmode = {75, 140};
65 Paperdoll_gump::Position Paperdoll_gump::halo = {123, 120};
66
67 Paperdoll_gump::Position Paperdoll_gump::coords[18] = {
68 {76, 20}, /* head */ {115, 27}, /* back */
69 {105, 65}, /* belt */ {38, 55}, /* lhand */
70 {55, 62}, /* lfinger */ {80, 80}, /* legs */
71 {84, 105}, /* feet */ {90, 50}, /* rfinger */
72 {117, 55}, /* rhand */ {45, 35}, /* torso */
73 {44, 26}, /* neck */ {69, 59}, /* ammo */
74 {59, 19}, /* back2 */ {94, 20}, /* back 3 (shield) */
75 {76, 26}, /* ears */ {76, 33}, /* cloak */
76 {73, 53}, /* gloves */ {0, 0} /* usecode container */
77 };
78 Paperdoll_gump::Position Paperdoll_gump::coords_blue[18] = {
79 {76, 20}, /* head */ {64, 27}, /* back */
80 {54, 56}, /* belt */ {30, 58}, /* lhand */
81 {55, 62}, /* lfinger */ {80, 80}, /* legs */
82 {84, 105}, /* feet */ {90, 50}, /* rfinger */
83 {68, 50}, /* rhand */ {45, 37}, /* torso */
84 {22, 26}, /* neck */ {69, 59}, /* ammo */
85 {59, 19}, /* back2 */ {94, 20}, /* back 3 (shield) */
86 {76, 26}, /* ears */ {76, 33}, /* cloak */
87 {73, 53}, /* gloves */ {0, 0} /* usecode container */
88 };
89 Paperdoll_gump::Position Paperdoll_gump::coords_hot[18] = {
90 {76, 20}, /* head */ {94, 27}, /* back */
91 {92, 61}, /* belt */ {38, 55}, /* lhand */
92 {55, 62}, /* lfinger */ {80, 80}, /* legs */
93 {84, 105}, /* feet */ {90, 50}, /* rfinger */
94 {117, 55}, /* rhand */ {83, 43}, /* torso */
95 {76, 41}, /* neck */ {69, 59}, /* ammo */
96 {59, 19}, /* back2 */ {94, 20}, /* back 3 (shield) */
97 {76, 26}, /* ears */ {76, 33}, /* cloak */
98 {73, 53}, /* gloves */ {0, 0} /* usecode container */
99 };
100
101
102
103 //
104 // Paperdoll Coords
105 //
106
107 Paperdoll_gump::Position Paperdoll_gump::body = {46, 33};
108 Paperdoll_gump::Position Paperdoll_gump::headp = {46, 22};
109
110 Paperdoll_gump::Position Paperdoll_gump::beltf = {58, 52};
111 Paperdoll_gump::Position Paperdoll_gump::neckf = {46, 47};
112 Paperdoll_gump::Position Paperdoll_gump::beltm = {57, 55};
113 Paperdoll_gump::Position Paperdoll_gump::neckm = {46, 44};
114
115 Paperdoll_gump::Position Paperdoll_gump::legsp = {57, 66};
116 Paperdoll_gump::Position Paperdoll_gump::feetp = {46, 99};
117
118 Paperdoll_gump::Position Paperdoll_gump::hands = {68, 44};
119 Paperdoll_gump::Position Paperdoll_gump::rhandp = {68, 44};
120 Paperdoll_gump::Position Paperdoll_gump::lhandp = {34, 65};
121
122 Paperdoll_gump::Position Paperdoll_gump::ahand = {28, 59};
123 Paperdoll_gump::Position Paperdoll_gump::ammo = {28, 59};
124
125 Paperdoll_gump::Position Paperdoll_gump::backf = {68, 28};
126 Paperdoll_gump::Position Paperdoll_gump::back2f = {34, 22};
127 Paperdoll_gump::Position Paperdoll_gump::backm = {68, 22};
128 Paperdoll_gump::Position Paperdoll_gump::back2m = {35, 22};
129 Paperdoll_gump::Position Paperdoll_gump::shieldf = {56, 25};
130 Paperdoll_gump::Position Paperdoll_gump::shieldm = {57, 22};
131
132
133 /*
134 * Find the index of the closest 'spot' to a mouse point.
135 *
136 * Output: Index, or -1 if unsuccessful.
137 */
138
find_closest(int mx,int my,int only_empty)139 int Paperdoll_gump::find_closest(
140 int mx, int my, // Mouse point in window.
141 int only_empty // Only allow empty spots.
142 ) {
143 mx -= x;
144 my -= y; // Get point rel. to us.
145 long closest_squared = 1000000; // Best distance squared.
146 int closest = -1; // Best index.
147
148 Actor *npc = container->as_actor();
149
150 for (size_t i = 0; i < array_size(coords_hot); i++) {
151 int spot = i;
152
153 int dx = mx - coords_hot[spot].x;
154 int dy = my - coords_hot[spot].y;
155 long dsquared = dx * dx + dy * dy;
156
157 // Map slots occupied by multi-slot items to the filled slot.
158 if ((i == back_shield || i == back_2h) && npc->is_scabbard_used())
159 spot = belt;
160 else if (i == cloak && npc->is_neck_used())
161 spot = amulet;
162 else if (i == rhand && npc->is_two_handed())
163 spot = lhand;
164 else if ((i == rfinger || i == gloves) && npc->is_two_fingered())
165 spot = lfinger;
166
167 // Better than prev and free if required.?
168 if (dsquared < closest_squared && !(only_empty && container->get_readied(spot))) {
169 closest_squared = dsquared;
170 closest = spot;
171 }
172 }
173
174 return closest;
175 }
176
177 /*
178 * Create the gump display for an actor.
179 */
180
Paperdoll_gump(Container_game_object * cont,int initx,int inity,int shnum)181 Paperdoll_gump::Paperdoll_gump(
182 Container_game_object *cont, // Container it represents.
183 int initx, int inity, // Coords. on screen.
184 int shnum // Shape #.
185 ) : Gump(cont, initx, inity, 123, SF_PAPERDOL_VGA) {
186 ignore_unused_variable_warning(shnum);
187 set_object_area(TileRect(26, 0, 104, 140), 6, 145);
188
189 // Create Heart button
190 heart_button = new Heart_button(this, heart.x, heart.y);
191 Actor *actor = cont->as_actor();
192 // Create Cstats button or Halo and Cmode
193 if (Game::get_game_type() == BLACK_GATE) {
194 if (actor->get_npc_num() == 0)
195 halo_button = new Halo_button(this, halo.x, halo.y,
196 actor);
197 else
198 halo_button = new Halo_button(this, disk.x, disk.y,
199 actor);
200
201 cmode_button = new Combat_mode_button(this, cmode.x, cmode.y,
202 actor);
203 cstats_button = nullptr;
204 } else {
205 cstats_button = new Cstats_button(this, cstat.x, cstat.y);
206 halo_button = nullptr;
207 cmode_button = nullptr;
208 }
209
210
211
212 // If Avatar create Disk Button
213 if (actor->get_npc_num() == 0)
214 disk_button = new Disk_button(this, disk.x, disk.y);
215 else
216 disk_button = nullptr;
217
218
219 // If Avatar create Combat Button
220 if (actor->get_npc_num() == 0)
221 combat_button = new Combat_button(this, combat.x, combat.y);
222 else
223 combat_button = nullptr;
224
225
226 // Put all the objects in the right place
227 for (size_t i = 0; i < array_size(coords); i++) {
228 Game_object *obj = container->get_readied(i);
229 if (obj)
230 set_to_spot(obj, i);
231 }
232 }
233
234 /*
235 * Delete actor display.
236 */
237
~Paperdoll_gump()238 Paperdoll_gump::~Paperdoll_gump(
239 ) {
240 delete heart_button;
241 delete disk_button;
242 delete combat_button;
243 delete cstats_button;
244 delete halo_button;
245 delete cmode_button;
246 }
247
248 /*
249 * Is a given screen point on one of our buttons?
250 *
251 * Output: ->button if so.
252 */
253
on_button(int mx,int my)254 Gump_button *Paperdoll_gump::on_button(
255 int mx, int my // Point in window.
256 ) {
257 Gump_button *btn = Gump::on_button(mx, my);
258 if (btn)
259 return btn;
260 else if (heart_button && heart_button->on_button(mx, my))
261 return heart_button;
262 else if (disk_button && disk_button->on_button(mx, my))
263 return disk_button;
264 else if (combat_button && combat_button->on_button(mx, my))
265 return combat_button;
266 else if (cstats_button && cstats_button->on_button(mx, my))
267 return cstats_button;
268 else if (halo_button && halo_button->on_button(mx, my))
269 return halo_button;
270 else if (cmode_button && cmode_button->on_button(mx, my))
271 return cmode_button;
272 return nullptr;
273 }
274
275 /*
276 * Add an object.
277 *
278 * Output: false if cannot add it.
279 */
280
add(Game_object * obj,int mx,int my,int sx,int sy,bool dont_check,bool combine)281 bool Paperdoll_gump::add(
282 Game_object *obj,
283 int mx, int my, // Screen location of mouse.
284 int sx, int sy, // Screen location of obj's hotspot.
285 bool dont_check, // Skip volume check.
286 bool combine // True to try to combine obj. MAY
287 // cause obj to be deleted.
288 ) {
289 ignore_unused_variable_warning(sx, sy);
290 do {
291 Game_object *cont = find_object(mx, my);
292
293 if (cont && cont->add(obj, false, combine))
294 break;
295
296 int index = find_closest(mx, my, 1);
297
298 if (index != -1 && container->add_readied(obj, index))
299 break;
300
301 if (container->add(obj, dont_check, combine))
302 break;
303
304 return false;
305 } while (false);
306
307 // Put all the objects in the right place
308 for (size_t i = 0; i < array_size(coords); i++) {
309 obj = container->get_readied(i);
310 if (obj) set_to_spot(obj, i);
311 }
312
313 return true;
314 }
315
316 /*
317 * Set object's coords. to given spot.
318 */
319
set_to_spot(Game_object * obj,int index)320 void Paperdoll_gump::set_to_spot(
321 Game_object *obj,
322 int index // Spot index.
323 ) {
324
325 // Get shape.
326 Shape_frame *shape = obj->get_shape();
327 //if (!shape) // Funny? Try frame 0.
328 // shape = gwin->get_shape(obj->get_shapenum(), 0);
329 if (!shape)
330 return;
331
332 // Height and width
333 int w = shape->get_width();
334 int h = shape->get_height();
335
336 // Set object's position.
337 obj->set_shape_pos(
338 coords[index].x + shape->get_xleft() - w / 2 - object_area.x,
339 coords[index].y + shape->get_yabove() - h / 2 - object_area.y);
340 }
341
342 /*
343 * Paint on screen.
344 */
345
paint()346 void Paperdoll_gump::paint(
347 ) {
348 const Game_object *obj;
349
350 // Paint Objects
351 TileRect box = object_area; // Paint objects inside.
352 box.shift(x, y); // Set box to screen location.
353
354 paint_shape(x, y);
355
356 // Paint red "checkmark".
357 paint_elems();
358
359 // Get the information required about ourself
360 Actor *actor = container->as_actor();
361 const Paperdoll_npc *info = actor->get_info().get_npc_paperdoll();
362
363 if (!info) {
364 const Shape_info &inf = ShapeID::get_info(actor->get_sexed_coloured_shape());
365 info = inf.get_npc_paperdoll();
366 }
367 if (!info) {
368 const Shape_info &inf = ShapeID::get_info(actor->get_shape_real());
369 info = inf.get_npc_paperdoll_safe(actor->get_type_flag(Actor::tf_sex));
370 }
371
372 // Spots that are female/male specific
373 Position shield;
374 Position back2;
375 Position back;
376 Position neck;
377 Position beltp;
378
379 if (actor->get_type_flag(Actor::tf_sex) || info->is_npc_female()) {
380 // Set the female spots
381 shield = shieldf;
382 back2 = back2f;
383 back = backf;
384 neck = neckf;
385 beltp = beltf;
386 } else { // Set the male spots
387 shield = shieldm;
388 back2 = back2m;
389 back = backm;
390 neck = neckm;
391 beltp = beltm;
392 }
393
394 // Now paint. Order is very specific
395
396
397 if (actor->is_scabbard_used()) {
398 paint_object(box, info, belt, shield.x, shield.y, 0, back_shield);
399 paint_object(box, info, belt, back2.x, back2.y, 0, back_2h);
400 } else {
401 paint_object(box, info, back_shield, shield.x, shield.y);
402 paint_object(box, info, back_2h, back2.x, back2.y);
403 }
404 paint_object(box, info, backpack, back.x, back.y);
405 if (actor->is_neck_used())
406 paint_object(box, info, amulet, body.x, body.y, 0, cloak);
407 else
408 paint_object(box, info, cloak, body.x, body.y);
409 paint_body(box, info);
410 paint_object(box, info, legs, legsp.x, legsp.y);
411 paint_object(box, info, feet, feetp.x, feetp.y);
412 paint_object(box, info, quiver, ammo.x, ammo.y, 0, -1);
413 paint_object(box, info, torso, body.x, body.y);
414 paint_belt(box, info);
415 paint_head(box, info);
416 if (actor->is_neck_used()) {
417 obj = container->get_readied(amulet);
418 const Paperdoll_item *item1;
419 const Paperdoll_item *item2;
420 if (obj) {
421 const Shape_info &inf = obj->get_info();
422 item1 = inf.get_item_paperdoll(obj->get_framenum(), cloak);
423 item2 = inf.get_item_paperdoll(obj->get_framenum(), cloak_clasp);
424 } else
425 item1 = item2 = nullptr;
426 if (!item1 && !item2)
427 paint_object(box, info, amulet, neck.x, neck.y);
428 } else
429 paint_object(box, info, amulet, neck.x, neck.y);
430 if (!actor->is_scabbard_used())
431 paint_object(box, info, belt, beltp.x, beltp.y);
432 paint_arms(box, info);
433 paint_object_arms(box, info, torso, body.x, body.y, 1, torso);
434 paint_object(box, info, earrings, headp.x, headp.y);
435 paint_object(box, info, head, headp.x, headp.y);
436 if (actor->is_neck_used())
437 paint_object(box, info, amulet, body.x, body.y, 0, cloak_clasp);
438 else
439 paint_object(box, info, cloak, body.x, body.y, 0, cloak_clasp);
440 paint_object_arms(box, info, rfinger, lhandp.x, lhandp.y, 0);
441 if (actor->is_two_fingered()) {
442 obj = container->get_readied(lfinger);
443 const Paperdoll_item *item1;
444 if (obj) {
445 const Shape_info &inf = obj->get_info();
446 item1 = inf.get_item_paperdoll(obj->get_framenum(), gloves);
447 } else
448 item1 = nullptr;
449 if (!item1)
450 paint_object_arms(box, info, lfinger, rhandp.x, rhandp.y);
451 else
452 paint_object_arms(box, info, lfinger, hands.x, hands.y, 0, gloves);
453 } else
454 paint_object_arms(box, info, lfinger, rhandp.x, rhandp.y, 0);
455 paint_object_arms(box, info, gloves, hands.x, hands.y, 0);
456 paint_object(box, info, lhand, lhandp.x, lhandp.y);
457 paint_object(box, info, quiver, ahand.x, ahand.y, 2, -1);
458 paint_object(box, info, rhand, rhandp.x, rhandp.y);
459
460 // if debugging show usecode container
461 #ifdef SHOW_USECODE_CONTAINER
462 paint_object(box, info, ucont, 20, 20);
463 #endif
464
465 #ifdef SHOW_NONREADIED_OBJECTS
466 Game_object *itm;
467 Object_iterator iter(actor->get_objects());
468 while ((itm = iter.get_next()) != nullptr)
469 if (actor->find_readied(itm) == -1)
470 itm->paint();
471 #endif
472
473
474 // Paint buttons.
475 if (heart_button) heart_button->paint();
476 if (disk_button) disk_button->paint();
477 if (combat_button) combat_button->paint();
478 if (cstats_button) cstats_button->paint();
479 if (halo_button) halo_button->paint();
480 if (cmode_button) cmode_button->paint();
481
482 // Show weight.
483 int max_weight = actor->get_max_weight();
484 int weight = actor->get_weight() / 10;
485 char text[20];
486 if (gwin->failed_copy_protection())
487 snprintf(text, 6, "Oink!");
488 else
489 snprintf(text, 20, "%d/%d", weight, max_weight);
490 int twidth = sman->get_text_width(2, text);
491 sman->paint_text(2, text, x + 84 - (twidth / 2), y + 114);
492 }
493
Get_ammo_frame(Game_object * obj,Container_game_object * container,int & frame)494 static inline bool Get_ammo_frame(
495 Game_object *obj,
496 Container_game_object *container,
497 int &frame
498 ) {
499 const Game_object *check = container->get_readied(lhand);
500 if (check) {
501 const Weapon_info *winf = check->get_info().get_weapon_info();
502 // frame == 2 for ammo held in hand, 0 for ammo in quiver.
503 if (!winf)
504 return frame != 2;
505 const Ammo_info *ainf = obj->get_info().get_ammo_info();
506 int family = ainf ? ainf->get_family_shape() : obj->get_shapenum();
507 bool infamily = winf->get_ammo_consumed() == family;
508 if (frame == 2 && !infamily)
509 return false;
510 else if (!frame)
511 frame++;
512 } else if (frame == 2) // No weapon means no ammo in hand.
513 return false;
514 return true;
515 }
516
517 /*
518 * Paint a generic object on screen
519 */
520
paint_object(const TileRect & box,const Paperdoll_npc * info,int spot,int sx,int sy,int frame,int itemtype)521 void Paperdoll_gump::paint_object(
522 const TileRect &box, // box
523 const Paperdoll_npc *info, // info
524 int spot, // belt
525 int sx, int sy, // back2x, back2y
526 int frame, // 0
527 int itemtype // back2h_spot
528 ) {
529 Game_object *obj = container->get_readied(spot);
530 if (!obj) return;
531
532 int old_it = itemtype;
533 if (itemtype == -1) itemtype = spot;
534
535 const Paperdoll_item *item = obj->get_info().get_item_paperdoll(obj->get_framenum(), itemtype);
536 if (!item || item->get_paperdoll_baseframe() == -1 ||
537 item->get_paperdoll_shape() == -1) {
538 if ((old_it != -1 && !item) || (spot == quiver && frame == 2)) return;
539 //if (!obj->get_tx() && !obj->get_ty()) return;
540
541 set_to_spot(obj, spot);
542
543 int shnum = Shapeinfo_lookup::GetBlueShapeData(spot);
544 ShapeID s(shnum, 0, SF_GUMPS_VGA);
545
546 s.paint_shape(box.x + coords_blue[spot].x,
547 box.y + coords_blue[spot].y);
548 int ox = box.x + obj->get_tx();
549 int oy = box.y + obj->get_ty();
550 obj->paint_shape(ox, oy);
551 if (cheat.is_selected(obj))
552 // Outline selected obj.
553 obj->ShapeID::paint_outline(ox, oy, HIT_PIXEL);
554
555 return;
556 } else if (spot == quiver && !Get_ammo_frame(obj, container, frame))
557 return;
558
559 int f = item->get_paperdoll_frame(frame);
560 if (item->is_gender_based() &&
561 (!container->as_actor()->get_type_flag(Actor::tf_sex) &&
562 !info->is_npc_female()))
563 f++;
564
565 ShapeID s(item->get_paperdoll_shape(), f, SF_PAPERDOL_VGA);
566 s.paint_shape(box.x + sx, box.y + sy, item->is_translucent());
567 if (cheat.is_selected(obj)) // Outline selected obj.
568 s.paint_outline(box.x + sx, box.y + sy, HIT_PIXEL);
569 }
570
571 /*
572 * Paint with arms frame
573 */
paint_object_arms(const TileRect & box,const Paperdoll_npc * info,int spot,int sx,int sy,int start,int itemtype)574 void Paperdoll_gump::paint_object_arms(
575 const TileRect &box,
576 const Paperdoll_npc *info,
577 int spot,
578 int sx, int sy,
579 int start,
580 int itemtype
581 ) {
582 paint_object(box, info, spot, sx, sy, start + get_arm_type(), itemtype);
583 }
584
585 /*
586 * Paint the body
587 */
paint_body(const TileRect & box,const Paperdoll_npc * info)588 void Paperdoll_gump::paint_body(
589 const TileRect &box,
590 const Paperdoll_npc *info
591 ) {
592 ShapeID s(info->get_body_shape(), info->get_body_frame(), SF_PAPERDOL_VGA);
593 s.paint_shape(box.x + body.x, box.y + body.y, info->is_translucent());
594 }
595
596 /*
597 * Paint the belt
598 */
paint_belt(const TileRect & box,const Paperdoll_npc * info)599 void Paperdoll_gump::paint_belt(
600 const TileRect &box,
601 const Paperdoll_npc *info
602 ) {
603 ShapeID s(10, 0, SF_PAPERDOL_VGA);
604 if (!container->as_actor()->get_type_flag(Actor::tf_sex) &&
605 !info->is_npc_female())
606 s.set_frame(1);
607 s.paint_shape(box.x + beltm.x, box.y + beltm.y, info->is_translucent());
608 }
609
610 /*
611 * Paint the head
612 */
paint_head(const TileRect & box,const Paperdoll_npc * info)613 void Paperdoll_gump::paint_head(
614 const TileRect &box,
615 const Paperdoll_npc *info
616 ) {
617 const Game_object *obj = container->get_readied(head);
618
619 const Paperdoll_item *item = nullptr;
620 if (obj)
621 item = obj->get_info().get_item_paperdoll(
622 obj->get_framenum(), head);
623
624 int f;
625 if (item && item->get_spot_frame())
626 f = info->get_head_frame_helm();
627 else
628 f = info->get_head_frame();
629
630 ShapeID s(info->get_head_shape(), f, SF_PAPERDOL_VGA);
631 s.paint_shape(box.x + headp.x, box.y + headp.y, info->is_translucent());
632 }
633
634 /*
635 * Paint the arms
636 */
paint_arms(const TileRect & box,const Paperdoll_npc * info)637 void Paperdoll_gump::paint_arms(
638 const TileRect &box,
639 const Paperdoll_npc *info
640 ) {
641 int frnum = info->get_arms_frame(get_arm_type());
642 ShapeID s(info->get_arms_shape(), frnum, SF_PAPERDOL_VGA);
643 s.paint_shape(box.x + body.x, box.y + body.y, info->is_translucent());
644 }
645
646
647 /*
648 * Gets which arm frame to use
649 */
650
get_arm_type()651 int Paperdoll_gump::get_arm_type() {
652 const Game_object *obj = container->get_readied(lhand);
653 if (!obj)
654 return 0; // Nothing in hand; normal arms.
655 const Shape_info &inf = obj->get_info();
656 if (inf.get_ready_type() != both_hands)
657 return 0; // Only two-handed weapons change arms.
658
659 const Paperdoll_item *item = inf.get_item_paperdoll(obj->get_framenum(), lhand);
660 return item ? item->get_spot_frame() : 0;
661 }
662
663
664 /*
665 * Find object a screen point is on.
666 *
667 * Output: Object found, or null.
668 */
669
find_object(int mx,int my)670 Game_object *Paperdoll_gump::find_object(
671 int mx, int my // Mouse pos. on screen.
672 ) {
673
674
675 // Check Objects
676 TileRect box = object_area; // Paint objects inside.
677 box.shift(x, y); // Set box to screen location.
678 mx -= box.x;
679 my -= box.y;
680
681 // Get the information required about ourself
682 const Actor *actor = container->as_actor();
683 const Paperdoll_npc *info = actor->get_info().get_npc_paperdoll();
684
685 if (!info) {
686 const Shape_info &inf = ShapeID::get_info(actor->get_sexed_coloured_shape());
687 info = inf.get_npc_paperdoll();
688 }
689 if (!info) {
690 const Shape_info &inf = ShapeID::get_info(actor->get_shape_real());
691 info = inf.get_npc_paperdoll_safe(actor->get_type_flag(Actor::tf_sex));
692 }
693
694 Position shield;
695 Position back2;
696 Position back;
697 Position neck;
698 Position beltp;
699
700 if (actor->get_type_flag(Actor::tf_sex) || info->is_npc_female()) {
701 shield = shieldf;
702 back2 = back2f;
703 back = backf;
704 neck = neckf;
705 beltp = beltf;
706 } else {
707 shield = shieldm;
708 back2 = back2m;
709 back = backm;
710 neck = neckm;
711 beltp = beltm;
712 }
713
714 Game_object *obj;
715
716 // if debugging show usecode container
717 #ifdef SHOW_USECODE_CONTAINER
718 if ((obj = check_object(mx, my, info, ucont, 20, 20)) != nullptr)
719 return obj;
720 #endif
721
722 // Must be done in this order (reverse of rendering)
723 if ((obj = check_object(mx, my, info, rhand, rhandp.x, rhandp.y)))
724 return obj;
725 if ((obj = check_object(mx, my, info, quiver, ahand.x, ahand.y, 2, -1)))
726 return obj;
727 if ((obj = check_object(mx, my, info, lhand, lhandp.x, lhandp.y)))
728 return obj;
729 if ((obj = check_object_arms(mx, my, info, gloves, hands.x, hands.y, 0)))
730 return obj;
731 if (actor->is_two_fingered()) {
732 obj = container->get_readied(lfinger);
733 const Paperdoll_item *item1;
734 if (obj) {
735 const Shape_info &inf = obj->get_info();
736 item1 = inf.get_item_paperdoll(obj->get_framenum(), gloves);
737 } else
738 item1 = nullptr;
739 if (!item1 && (obj = check_object_arms(mx, my, info, lfinger, rhandp.x, rhandp.y, 0)))
740 return obj;
741 else if ((obj = check_object_arms(mx, my, info, lfinger, hands.x, hands.y, 0, gloves)))
742 return obj;
743 } else if ((obj = check_object_arms(mx, my, info, lfinger, rhandp.x, rhandp.y, 0)))
744 return obj;
745
746 if ((obj = check_object_arms(mx, my, info, rfinger, lhandp.x, lhandp.y, 0)))
747 return obj;
748 if (actor->is_neck_used()) {
749 if ((obj = check_object(mx, my, info, amulet, body.x, body.y, 0, cloak_clasp)))
750 return obj;
751 } else {
752 if ((obj = check_object(mx, my, info, cloak, body.x, body.y, 0, cloak_clasp)))
753 return obj;
754 }
755 if ((obj = check_object(mx, my, info, head, headp.x, headp.y)))
756 return obj;
757 if ((obj = check_object(mx, my, info, earrings, headp.x, headp.y)))
758 return obj;
759 if ((obj = check_object_arms(mx, my, info, torso, body.x, body.y, 1, torso)))
760 return obj;
761 if (check_arms(mx, my, info))
762 return nullptr;
763 if (!actor->is_scabbard_used())
764 if ((obj = check_object(mx, my, info, belt, beltp.x, beltp.y)))
765 return obj;
766 if (actor->is_neck_used()) {
767 obj = container->get_readied(amulet);
768 const Paperdoll_item *item1;
769 const Paperdoll_item *item2;
770 if (obj) {
771 const Shape_info &inf = obj->get_info();
772 item1 = inf.get_item_paperdoll(obj->get_framenum(), cloak);
773 item2 = inf.get_item_paperdoll(obj->get_framenum(), cloak_clasp);
774 } else
775 item1 = item2 = nullptr;
776 if (!item1 && !item2 && (obj = check_object(mx, my, info, amulet, neck.x, neck.y)))
777 return obj;
778 } else if ((obj = check_object(mx, my, info, amulet, neck.x, neck.y)))
779 return obj;
780 if (check_head(mx, my, info))
781 return nullptr;
782 if (check_belt(mx, my, info))
783 return nullptr;
784 if ((obj = check_object(mx, my, info, torso, body.x, body.y)))
785 return obj;
786 if ((obj = check_object(mx, my, info, quiver, ammo.x, ammo.y, 0, -1)))
787 return obj;
788 if ((obj = check_object(mx, my, info, feet, feetp.x, feetp.y)))
789 return obj;
790 if ((obj = check_object(mx, my, info, legs, legsp.x, legsp.y)))
791 return obj;
792 if (check_body(mx, my, info))
793 return nullptr;
794 if (actor->is_neck_used()) {
795 if ((obj = check_object(mx, my, info, amulet, body.x, body.y, 0, cloak)))
796 return obj;
797 } else {
798 if ((obj = check_object(mx, my, info, cloak, body.x, body.y)))
799 return obj;
800 }
801 if ((obj = check_object(mx, my, info, backpack, back.x, back.y)))
802 return obj;
803 if (actor->is_scabbard_used()) {
804 if ((obj = check_object(mx, my, info, belt, back2.x, back2.y, 0, back_2h)))
805 return obj;
806 if ((obj = check_object(mx, my, info, belt, shield.x, shield.y, 0, back_shield)))
807 return obj;
808 } else {
809 if ((obj = check_object(mx, my, info, back_2h, back2.x, back2.y)))
810 return obj;
811 if ((obj = check_object(mx, my, info, back_shield, shield.x, shield.y)))
812 return obj;
813 }
814 return nullptr;
815 }
816
817 /*
818 * Checks for a generic object on screen
819 */
820
check_object(int mx,int my,const Paperdoll_npc * info,int spot,int sx,int sy,int frame,int itemtype)821 Game_object *Paperdoll_gump::check_object(
822 int mx, int my,
823 const Paperdoll_npc *info,
824 int spot,
825 int sx, int sy,
826 int frame,
827 int itemtype
828 ) {
829 Game_object *obj = container->get_readied(spot);
830 if (!obj) return nullptr;
831
832 int old_it = itemtype;
833 if (itemtype == -1) itemtype = spot;
834
835 const Paperdoll_item *item = obj->get_info().get_item_paperdoll(obj->get_framenum(), itemtype);
836 if (!item || item->get_paperdoll_baseframe() == -1 ||
837 item->get_paperdoll_shape() == -1) {
838 if ((old_it != -1 && !item) || (spot == quiver && frame == 2)) return nullptr;
839
840 if (!obj->get_tx() && !obj->get_ty()) set_to_spot(obj, spot);
841
842 if (check_shape(mx - obj->get_tx(), my - obj->get_ty(),
843 obj->get_shapenum(), obj->get_framenum(), obj->get_shapefile())) {
844 return obj;
845 }
846
847 return nullptr;
848 } else if (spot == quiver && !Get_ammo_frame(obj, container, frame))
849 return nullptr;
850
851
852 int f = item->get_paperdoll_frame(frame);
853 if (item->is_gender_based() && (!info->is_npc_female()
854 && !container->as_actor()->get_type_flag(Actor::tf_sex))) f++;
855
856 if (check_shape(mx - sx, my - sy, item->get_paperdoll_shape(), f, SF_PAPERDOL_VGA)) {
857 Shape_frame *shape = obj->get_shape();
858 int w = shape->get_width();
859 int h = shape->get_height();
860 // Set object's position.
861 obj->set_shape_pos(mx + shape->get_xleft() - w / 2,
862 my + shape->get_yabove() - h / 2);
863
864 return obj;
865 }
866
867 return nullptr;
868 }
869
870 /*
871 * Checks for object with arms frame
872 */
check_object_arms(int mx,int my,const Paperdoll_npc * info,int spot,int sx,int sy,int start,int itemtype)873 Game_object *Paperdoll_gump::check_object_arms(
874 int mx, int my,
875 const Paperdoll_npc *info,
876 int spot,
877 int sx, int sy,
878 int start,
879 int itemtype
880 ) {
881 return check_object(mx, my, info, spot, sx, sy, start + get_arm_type(), itemtype);
882 }
883
884 /*
885 * Checks for the body
886 */
check_body(int mx,int my,const Paperdoll_npc * info)887 bool Paperdoll_gump::check_body(
888 int mx, int my,
889 const Paperdoll_npc *info
890 ) {
891 return check_shape(mx - body.x, my - body.y, info->get_body_shape(),
892 info->get_body_frame(), SF_PAPERDOL_VGA);
893 }
894
895 /*
896 * Checks for the belt
897 */
check_belt(int mx,int my,const Paperdoll_npc * info)898 bool Paperdoll_gump::check_belt(
899 int mx, int my,
900 const Paperdoll_npc *info
901 ) {
902 if (info->is_npc_female() || container->as_actor()->get_type_flag(Actor::tf_sex))
903 return check_shape(mx - beltf.x, my - beltf.y, 10, 0, SF_PAPERDOL_VGA);
904 else
905 return check_shape(mx - beltm.x, my - beltm.y, 10, 1, SF_PAPERDOL_VGA);
906
907 return false;
908 }
909
910 /*
911 * Checks for the head
912 */
check_head(int mx,int my,const Paperdoll_npc * info)913 bool Paperdoll_gump::check_head(
914 int mx, int my,
915 const Paperdoll_npc *info
916 ) {
917 const Game_object *obj = container->get_readied(head);
918
919 const Paperdoll_item *item = nullptr;
920 if (obj)
921 item = obj->get_info().get_item_paperdoll(
922 obj->get_framenum(), head);
923
924 int f;
925 if (item && item->get_spot_frame())
926 f = info->get_head_frame_helm();
927 else
928 f = info->get_head_frame();
929
930 return check_shape(mx - headp.x, my - headp.y,
931 info->get_head_shape(), f, SF_PAPERDOL_VGA);
932 }
933
934 /*
935 * Checks for the arms
936 */
check_arms(int mx,int my,const Paperdoll_npc * info)937 bool Paperdoll_gump::check_arms(
938 int mx, int my,
939 const Paperdoll_npc *info
940 ) {
941 int frnum = info->get_arms_frame(get_arm_type());
942 return check_shape(mx - body.x, my - body.y,
943 info->get_arms_shape(), frnum, SF_PAPERDOL_VGA);
944 }
945
946 /*
947 * Generic Shaper checking
948 */
check_shape(int px,int py,int shape,int frame,ShapeFile file)949 bool Paperdoll_gump::check_shape(
950 int px, int py,
951 int shape, int frame,
952 ShapeFile file
953 ) {
954 ShapeID sid(shape, frame, file);
955 Shape_frame *s = sid.get_shape();
956
957 // If no shape, return
958 if (!s) return false;
959
960 TileRect r = gwin->get_shape_rect(s, 0, 0);
961
962 // If point not in rectangle, return
963 if (!r.has_point(px, py)) return false;
964
965 // If point not in shape, return
966 if (!s->has_point(px, py)) return false;
967
968 return true;
969 }
970
find_actor(int mx,int my)971 Container_game_object *Paperdoll_gump::find_actor(int mx, int my) {
972 ignore_unused_variable_warning(mx, my);
973 return container;
974 }
975
get_npc_paperdoll_safe(bool sex) const976 const Paperdoll_npc *Shape_info::get_npc_paperdoll_safe(bool sex) const {
977 if (npcpaperdoll)
978 return npcpaperdoll;
979 int shape = sex ? Shapeinfo_lookup::GetFemaleAvShape() :
980 Shapeinfo_lookup::GetMaleAvShape();
981 const Shape_info &inf = ShapeID::get_info(shape);
982 return inf.get_npc_paperdoll();
983 }
984