1 /*
2 Copyright (C) 2000 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 "Actor_gump.h"
24 #include "actors.h"
25 #include "array_size.h"
26 #include "gamewin.h"
27 #include "misc_buttons.h"
28 #include "ignore_unused_variable_warning.h"
29
30 #include <cstdio>
31
32 using std::size_t;
33
34 #define TWO_HANDED_BROWN_SHAPE 48
35 #define TWO_HANDED_BROWN_FRAME 0
36 #define TWO_FINGER_BROWN_SHAPE 48
37 #define TWO_FINGER_BROWN_FRAME 1
38
39 /*
40 * Statics:
41 */
42
43 Actor_gump::Position Actor_gump::disk = {124, 115};
44 Actor_gump::Position Actor_gump::heart = {124, 132};
45 Actor_gump::Position Actor_gump::combat = {52, 100};
46 Actor_gump::Position Actor_gump::halo = {47, 110};
47 Actor_gump::Position Actor_gump::cmode = {48, 132};
48 Actor_gump::Position Actor_gump::coords[12] = {
49 {114, 10}, /* head */ {115, 24}, /* back */
50 {115, 37}, /* belt */ {115, 55}, /* lhand */
51 {115, 71}, /* lfinger */ {114, 85}, /* legs */
52 {76, 98}, /* feet */ {35, 70}, /* rfinger */
53 {37, 56}, /* rhand */ {37, 37}, /* torso */
54 {37, 24}, /* neck */ {37, 11} /* ammo */
55 };
56
57 /*
58 * Find the index of the closest 'spot' to a mouse point.
59 *
60 * Output: Index, or -1 if unsuccessful.
61 */
62
find_closest(int mx,int my,int only_empty)63 int Actor_gump::find_closest(
64 int mx, int my, // Mouse point in window.
65 int only_empty // Only allow empty spots.
66 ) {
67 mx -= x;
68 my -= y; // Get point rel. to us.
69 long closest_squared = 1000000; // Best distance squared.
70 int closest = -1; // Best index.
71 for (size_t i = 0; i < array_size(coords); i++) {
72 int dx = mx - coords[i].x;
73 int dy = my - coords[i].y;
74 long dsquared = dx * dx + dy * dy;
75 // Better than prev.?
76 if (dsquared < closest_squared && (!only_empty ||
77 !container->get_readied(i))) {
78 closest_squared = dsquared;
79 closest = i;
80 }
81 }
82 return closest;
83 }
84
85 /*
86 * Create the gump display for an actor.
87 */
88
Actor_gump(Container_game_object * cont,int initx,int inity,int shnum)89 Actor_gump::Actor_gump(
90 Container_game_object *cont, // Container it represents. MUST
91 // be an Actor.
92 int initx, int inity, // Coords. on screen.
93 int shnum // Shape #.
94 ) : Gump(cont, initx, inity, shnum) {
95 set_object_area(TileRect(26, 0, 104, 132), 6, 136);
96 Actor *npc = cont->as_actor();
97 add_elem(new Heart_button(this, heart.x, heart.y));
98 if (npc->get_npc_num() == 0) {
99 add_elem(new Disk_button(this, disk.x, disk.y));
100 add_elem(new Combat_button(this, combat.x, combat.y));
101 }
102 add_elem(new Halo_button(this, halo.x, halo.y, npc));
103 add_elem(new Combat_mode_button(this, cmode.x, cmode.y, npc));
104
105 for (size_t i = 0; i < array_size(coords); i++) {
106 // Set object coords.
107 Game_object *obj = container->get_readied(i);
108 if (obj)
109 set_to_spot(obj, i);
110 }
111 }
112
113 /*
114 * Add an object.
115 *
116 * Output: false if cannot add it.
117 */
118
add(Game_object * obj,int mx,int my,int sx,int sy,bool dont_check,bool combine)119 bool Actor_gump::add(
120 Game_object *obj,
121 int mx, int my, // Screen location of mouse.
122 int sx, int sy, // Screen location of obj's hotspot.
123 bool dont_check, // Skip volume check.
124 bool combine // True to try to combine obj. MAY
125 // cause obj to be deleted.
126 )
127 {
128 ignore_unused_variable_warning(sx, sy);
129 Game_object *cont = find_object(mx, my);
130
131 if (cont && cont->add(obj, false, combine))
132 return true;
133
134 int index = find_closest(mx, my, 1);
135
136 if (index != -1 && container->add_readied(obj, index))
137 return true;
138
139 if (container->add(obj, dont_check, combine))
140 return true;
141
142 return false;
143 }
144
145 /*
146 * Set object's coords. to given spot.
147 */
148
set_to_spot(Game_object * obj,int index)149 void Actor_gump::set_to_spot(
150 Game_object *obj,
151 int index // Spot index.
152 ) {
153 // Get shape info.
154 Shape_frame *shape = obj->get_shape();
155 if (!shape)
156 return; // Not much we can do.
157 int w = shape->get_width();
158 int h = shape->get_height();
159 // Set object's position.
160 obj->set_shape_pos(
161 coords[index].x + shape->get_xleft() - w / 2 - object_area.x,
162 coords[index].y + shape->get_yabove() - h / 2 - object_area.y);
163 // Shift if necessary.
164 int x0 = obj->get_tx() - shape->get_xleft();
165 int y0 = obj->get_ty() - shape->get_yabove();
166 int newcx = obj->get_tx();
167 int newcy = obj->get_ty();
168 if (x0 < 0)
169 newcx -= x0;
170 if (y0 < 0)
171 newcy -= y0;
172 int x1 = x0 + w;
173 int y1 = y0 + h;
174 if (x1 > object_area.w)
175 newcx -= x1 - object_area.w;
176 if (y1 > object_area.h)
177 newcy -= y1 - object_area.h;
178 obj->set_shape_pos(newcx, newcy);
179 }
180
181 /*
182 * Paint on screen.
183 */
184
paint()185 void Actor_gump::paint(
186 ) {
187 // Watch for any newly added objs.
188 for (size_t i = 0; i < array_size(coords); i++) {
189 // Set object coords.
190 Game_object *obj = container->get_readied(i);
191 if (obj)//&& !obj->get_tx() && !obj->get_ty())
192 set_to_spot(obj, i);
193 }
194
195 Gump::paint(); // Paint gump & objects.
196
197 // Paint over blue lines for 2 handed
198 Actor *actor = container->as_actor();
199 if (actor) {
200 if (actor->is_two_fingered()) {
201 int sx = x + 36;
202 int // Note this is the right finger slot shifted slightly
203 sy = y + 70;
204 ShapeID sid(TWO_FINGER_BROWN_SHAPE, TWO_FINGER_BROWN_FRAME, SF_GUMPS_VGA);
205 sid.paint_shape(sx, sy);
206 }
207 if (actor->is_two_handed()) {
208 int sx = x + 36;
209 int // Note this is the right hand slot shifted slightly
210 sy = y + 55;
211 ShapeID sid(TWO_HANDED_BROWN_SHAPE, TWO_HANDED_BROWN_FRAME, SF_GUMPS_VGA);
212 sid.paint_shape(sx, sy);
213 }
214 }
215 // Show weight.
216 int max_weight = container->get_max_weight();
217 int weight = container->get_weight() / 10;
218 char text[20];
219 snprintf(text, 20, "%d/%d", weight, max_weight);
220 int twidth = sman->get_text_width(2, text);
221 const int boxw = 102;
222 sman->paint_text(2, text, x + 28 + (boxw - twidth) / 2, y + 120);
223 }
224
find_actor(int mx,int my)225 Container_game_object *Actor_gump::find_actor(int mx, int my) {
226 ignore_unused_variable_warning(mx, my);
227 return container;
228 }
229