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