1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 /*
20 * $Source: r:/prj/cit/src/RCS/mfdgump.c $
21 * $Revision: 1.18 $
22 * $Author: dc $
23 * $Date: 1994/11/28 06:38:23 $
24 *
25 *
26 */
27
28 #include "mfdint.h"
29 #include "mfdext.h"
30 #include "mfddims.h"
31 #include "objapp.h"
32 #include "tools.h"
33 #include "gamestrn.h"
34 #include "objuse.h"
35 #include "objbit.h"
36 #include "input.h"
37 #include "objprop.h"
38 #include "colors.h"
39 #include "objload.h"
40 #include "fullscrn.h"
41 #include "cit2d.h"
42 #include "gr2ss.h"
43
44 #include "cybstrng.h"
45 #include "mfdart.h"
46 #include "gamescr.h"
47
48 // ============================================================
49 // MFD CONTAINER GUMPS
50 // ============================================================
51
52 /* This is the MFD for buttons that zoom into the MFD. */
53
54 // -------
55 // DEFINES
56 // -------
57
58 #define MFD_GUMP_FUNC 23
59
60 #define NUM_CONTENTS 4
61 #define Y_STEP 15
62 #define FIRST_ITEM_Y 15
63 #define LEFT_MARGIN 5
64 #define CONTENTS_WID ((MFD_VIEW_WID - 2 * LEFT_MARGIN) / 2)
65 #define CONTENTS_HGT ((MFD_VIEW_HGT - FIRST_ITEM_Y - 5) / 2)
66 extern char container_extract(ObjID *pidlist, int d1, int d2);
67 extern void container_stuff(ObjID *pidlist, int numobjs, int *d1, int *d2);
68 extern uchar is_container(ObjID id, int **d1, int **d2);
69
70 #define LAST_INPUT_ROW (player_struct.mfd_func_data[MFD_GUMP_FUNC][0])
71 #define LAST_DOUBLE (player_struct.mfd_func_data[MFD_GUMP_FUNC][1])
72
73 // -------
74 // GLOBALS
75 // -------
76 ObjID gump_idlist[NUM_CONTENTS];
77 uchar gump_num_objs;
78
79 // -----------
80 // PROTOTYPES
81 // -----------
82 void mfd_gump_expose(MFD *mfd, ubyte control);
83 void gump_clear(void);
84 uchar gump_pickup(byte row);
85 uchar gump_get_useful(bool shifted);
86 uchar mfd_gump_handler(MFD *m, uiEvent *uie);
87
88 // ---------------
89 // EXPOSE FUNCTION
90 // ---------------
91
92 /* This gets called whenever the MFD needs to redraw or
93 undraw.
94 The control value is a bitmask with the following bits:
95 MFD_EXPOSE: Update the mfd, if MFD_EXPOSE_FULL is not set,
96 update incrementally.
97 MFD_EXPOSE_FULL: Fully redraw the mfd, implies MFD_EXPOSE
98
99 if no bits are set, the mfd is being "unexposed;" its display
100 being pulled off the screen to make room for a different func.
101 */
102
103 extern void check_panel_ref(uchar punt);
104
mfd_gump_expose(MFD * mfd,ubyte control)105 void mfd_gump_expose(MFD *mfd, ubyte control) {
106 uchar full = control & MFD_EXPOSE_FULL;
107 if (control == 0) // MFD is drawing stuff
108 {
109 panel_ref_unexpose(mfd->id, MFD_GUMP_FUNC);
110 return;
111 }
112 if (control & MFD_EXPOSE) // Time to draw stuff
113 {
114 extern void mfd_item_micro_expose(uchar full, int triple);
115 ObjID id = player_struct.panel_ref;
116 uchar i;
117
118 // clear update rects
119 mfd_clear_rects();
120 // set up canvas
121 gr_push_canvas(pmfd_canvas);
122 ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
123
124 // Clear the canvas by drawing the background bitmap
125 if (!full_game_3d)
126 ss_bitmap(&mfd_background, 0, 0);
127 // gr_bitmap(&mfd_background, 0, 0);
128 mfd_item_micro_expose(full, ID2TRIP(id));
129
130 if (full) {
131 int *d1, *d2;
132 is_container(id, &d1, &d2); // fill in d1 and d2;
133 gump_num_objs = container_extract(gump_idlist, *d1, (d2 != NULL) ? *d2 : 0);
134 for (i = gump_num_objs; i < sizeof(gump_idlist) / sizeof(gump_idlist[0]); i++)
135 gump_idlist[i] = OBJ_NULL;
136 LAST_INPUT_ROW = 0xFF;
137 }
138 gr_set_font(ResLock(MFD_FONT));
139 if (gump_num_objs == 0) {
140 short x, y;
141 char *s = get_temp_string(REF_STR_EmptyGump);
142 gr_string_size(s, &x, &y);
143 x = (MFD_VIEW_WID - x) / 2;
144 y = (MFD_VIEW_HGT - y) / 2;
145 mfd_draw_string(s, x, y, GREEN_YELLOW_BASE, TRUE);
146 } else
147 for (i = 0; i < gump_num_objs; i++) {
148 short x, y;
149 uchar r = i / 2, c = i % 2;
150 if (gump_idlist[i] != OBJ_NULL) {
151 grs_bitmap *bm = bitmaps_2d[OPNUM(gump_idlist[i])];
152 x = LEFT_MARGIN + ((c == 0) ? 0 : CONTENTS_WID) + (CONTENTS_WID - bm->w) / 2;
153 y = FIRST_ITEM_Y + ((r == 0) ? 0 : CONTENTS_HGT) + (CONTENTS_HGT - bm->h) / 2;
154 ss_bitmap(bm, x, y);
155 }
156 // the +1 in the last argument is to get
157 // mfd_add_rect to union adjacents...
158 }
159 mfd_add_rect(LEFT_MARGIN, FIRST_ITEM_Y, LEFT_MARGIN + 2 * CONTENTS_WID, FIRST_ITEM_Y + 2 * CONTENTS_HGT);
160 ResUnlock(MFD_FONT);
161 // on a full expose, make sure to draw everything
162
163 if (full)
164 mfd_add_rect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
165
166 // Pop the canvas
167 gr_pop_canvas();
168 // Now that we've popped the canvas, we can send the
169 // updated mfd to screen
170 mfd_update_rects(mfd);
171 }
172 }
173
174 // ----------------
175 // HANDLER FUNCTION
176 // ----------------
177 extern void mouse_unconstrain(void);
178
gump_clear(void)179 void gump_clear(void) {
180 int i;
181
182 for (i = 0; i < NUM_CONTENTS; i++)
183 gump_idlist[i] = OBJ_NULL;
184 }
185
gump_pickup(byte row)186 uchar gump_pickup(byte row) {
187 int *d1, *d2;
188 ObjID cont = player_struct.panel_ref;
189 extern void check_panel_ref(uchar puntme);
190
191 // KLC mouse_unconstrain();
192 if (row < 0 || row >= gump_num_objs || gump_idlist[row] == OBJ_NULL)
193 return FALSE;
194 push_cursor_object(gump_idlist[row]);
195 gump_idlist[row] = OBJ_NULL;
196 if (row == gump_num_objs - 1)
197 gump_num_objs--;
198 LAST_INPUT_ROW = 0xFF;
199 LAST_DOUBLE = FALSE;
200 // Here's where we update the container object
201 is_container(cont, &d1, &d2);
202 container_stuff(gump_idlist, gump_num_objs, d1, d2);
203
204 if (*d1 == 0 && (d2 == NULL || *d2 == 0))
205 check_panel_ref(TRUE); // punt empty gump
206 else
207 mfd_notify_func(MFD_GUMP_FUNC, MFD_ITEM_SLOT, FALSE, MFD_ACTIVE, FALSE);
208 return TRUE;
209 }
210
gump_get_useful(bool shifted)211 uchar gump_get_useful(bool shifted) {
212 int row;
213 uchar useless;
214 uchar obj_is_useless(ObjID oid);
215
216 for (useless = 0; useless <= 1; useless++) {
217 for (row = 0; row < gump_num_objs; row++) {
218 if (gump_idlist[row] && obj_is_useless(gump_idlist[row]) == useless) {
219 uchar result = gump_pickup(row);
220 if (result && shifted)
221 {
222 extern void absorb_object_on_cursor(ushort keycode, uint32_t context, intptr_t data); //see invent.c
223 absorb_object_on_cursor(0, 0, 0); //parameters unused
224 }
225 return result;
226 }
227 }
228 }
229 return FALSE;
230 }
231
mfd_gump_handler(MFD * m,uiEvent * e)232 uchar mfd_gump_handler(MFD *m, uiEvent *e) {
233 LGPoint pos = e->pos;
234 byte row;
235 short x, y;
236 grs_bitmap *bm;
237
238 pos.x -= m->rect.ul.x;
239 pos.y -= m->rect.ul.y;
240 row = (pos.y - FIRST_ITEM_Y) / CONTENTS_HGT;
241 row = 2 * row + (pos.x - LEFT_MARGIN) / CONTENTS_WID;
242
243 #ifdef RIGHT_BUTTON_GUMP_UI
244 if (LAST_INPUT_ROW != 0xFF && row != LAST_INPUT_ROW) {
245 if (e->mouse_data.buttons & (1 << MOUSE_RBUTTON)) {
246 return gump_pickup(LAST_INPUT_ROW);
247 }
248 }
249 #endif // RIGHT_BUTTON_GUMP_UI
250 if (row < 0 || row >= gump_num_objs)
251 return FALSE;
252 if (LAST_DOUBLE && (e->mouse_data.action & MOUSE_LUP)) {
253 return gump_pickup(row);
254 }
255 if (!(e->mouse_data.action & (MOUSE_LDOWN | UI_MOUSE_LDOUBLE)))
256 return FALSE;
257 #ifdef RIGHT_BUTTON_GUMP_UI
258 if (!(e->mouse_data.action & (MOUSE_LDOWN | MOUSE_RDOWN | UI_MOUSE_LDOUBLE)) && !(e->buttons & (1 << MOUSE_RBUTTON)))
259 return FALSE;
260 #endif // RIGHT_BUTTON_GUMP_UI
261 // Hey, this is a little extra work, but it gets the job done.
262 bm = bitmaps_2d[OPNUM(gump_idlist[row])];
263 x = LEFT_MARGIN + ((row % 2 == 0) ? 0 : CONTENTS_WID) + (CONTENTS_WID - bm->w) / 2;
264 y = FIRST_ITEM_Y + ((row / 2 == 0) ? 0 : CONTENTS_HGT) + (CONTENTS_HGT - bm->h) / 2;
265 if (pos.x >= x && pos.x < x + bm->w && pos.y >= y && pos.y < y + bm->h) {
266 if (e->mouse_data.action == UI_MOUSE_LDOUBLE) {
267 LAST_DOUBLE = TRUE;
268 return TRUE;
269 }
270 LAST_DOUBLE = FALSE;
271 if (e->mouse_data.action & MOUSE_LDOWN) {
272 if (gump_idlist[row] != OBJ_NULL) {
273 if (e->mouse_data.modifiers & 1) { //shifted click; see sdl_events.c
274 //try to pickup and absorb object
275 uchar result = gump_pickup(row);
276 if (result) {
277 extern void absorb_object_on_cursor(ushort keycode, uint32_t context, intptr_t data); //see invent.c
278 absorb_object_on_cursor(0, 0, 0); //parameters unused
279 }
280 return result;
281 }
282 else {
283 extern void look_at_object(ObjID);
284 look_at_object(gump_idlist[row]);
285 }
286 }
287 }
288 #ifdef RIGHT_BUTTON_GUMP_UI
289 if (e->action & MOUSE_RDOWN) {
290 // KLC mouse_constrain_xy(m->rect.ul.x,m->rect.ul.y,m->rect.lr.x-1,m->rect.lr.y-1);
291 LAST_INPUT_ROW = row;
292 return TRUE;
293 }
294 if (e->action & MOUSE_RUP)
295 return gump_pickup(row);
296 #endif // RIGHT_BUTTON_GUMP_UI
297 } else if (e->mouse_data.buttons & (1 << MOUSE_RBUTTON)) {
298 return gump_pickup(row);
299 }
300 LAST_DOUBLE = FALSE;
301 // KLC mouse_unconstrain();
302 return FALSE;
303 }
304