2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/shock/shkinv.cpp,v 1.108 1999/11/19 14:57:42 adurant Exp $
62 //#include <gunbase.h>
69 // ui library not C++ ized properly yet
77 // Must be last header
81 static IRes
*gBlockHnd
= NULL
;
83 static eContainType gLastLoc
;
85 #define INV_ICON_X (4)
86 #define INV_ICON_Y (17)
90 Rect inv_icon_rect
= { {INV_ICON_X
, INV_ICON_Y
}, {INV_ICON_X
+ 523,INV_ICON_Y
+ 98} };
93 static Rect close_rect = {{5,10},{5 + 20, 10 + 21}};
94 static LGadButton close_button;
95 static DrawElement close_elem;
96 static IRes *close_handles[2];
97 static grs_bitmap *close_bitmaps[4];
100 // Shock inventory system stuff
102 ObjID inv_array
[MAX_INV_ITEMS
];
103 static Rect inv_rect
= {{INV_X
,INV_Y
},{INV_X
+ 636, INV_Y
+ 121}};
104 //Point player_inv_dims = {INV_COLUMNS,INV_ROWS};
105 Point gPlayerMaxInv
= {15,3};
107 bool InvCheckSpace(Point space
, ObjID obj
, int loc
);
108 BOOL
ShockInvPlayerContainsListener(eContainsEvent event
, ObjID container
, ObjID containee
, eContainType ctype
, ContainCBData
);
110 grs_canvas gInvCanvas
;
111 grs_bitmap
*gInvBitmap
;
114 //--------------------------------------------------------------------------------------
115 void ShockInvClear(void)
118 //if (shock_cursor_mode == SCM_NORMAL)
119 //ShockInvLoadCursor(OBJ_NULL);
120 for (i
=0;i
< MAX_INV_ITEMS
; i
++)
121 inv_array
[i
] = OBJ_NULL
;
123 //--------------------------------------------------------------------------------------
124 // reassembles inv_array from containment links to the player
125 void ShockInvReset(void)
127 if (PlayerObjectExists())
129 ShockInvComputeObjArray(PlayerObject(), inv_array
);
133 //--------------------------------------------------------------------------------------
134 void ShockInvInit(int which
)
137 gHndInv
= LoadPCX("invback");
138 gBlockHnd
= LoadPCX("block");
142 close_handles[0] = LoadPCX("CloseOff");
143 close_handles[1] = LoadPCX("CloseOn");
144 close_bitmaps[0] = (grs_bitmap *) close_handles[0]->Lock();
145 close_bitmaps[1] = (grs_bitmap *) close_handles[1]->Lock();
146 for (i = 2; i < 4; i++)
148 close_bitmaps[i] = close_bitmaps[0];
158 w
= RectWidth(&inv_rect
);
159 h
= RectHeight(&inv_rect
);
160 use_rect
.ul
.x
= (smode
.w
- w
) / 2;
161 use_rect
.ul
.y
= inv_rect
.ul
.y
;
162 use_rect
.lr
.x
= use_rect
.ul
.x
+ w
;
163 use_rect
.lr
.y
= use_rect
.ul
.y
+ h
;
164 //mprintf("use_rect = %d,%d %d,%d\n",use_rect.ul.x,use_rect.ul.y,use_rect.lr.x,use_rect.lr.y);
165 ShockOverlaySetRect(which
,use_rect
);
169 //grs_bitmap *bmp = (grs_bitmap *) gHndInv->Lock();
170 gInvBitmap
= gr_alloc_bitmap(BMT_FLAT16
, 0, w
, h
); // BMF_TRANS
171 //gInvBitmap->align = bmp->align;
172 gr_make_canvas(gInvBitmap
, &gInvCanvas
);
176 //--------------------------------------------------------------------------------------
177 void ShockInvTerm(void)
179 SafeFreeHnd(&gHndInv
);
180 SafeFreeHnd(&gBlockHnd
);
184 close_handles[0]->Unlock();
185 close_handles[1]->Unlock();
186 SafeFreeHnd(&close_handles[0]);
187 SafeFreeHnd(&close_handles[1]);
191 //--------------------------------------------------------------------------------------
192 void ShockInvListenInit()
194 AutoAppIPtr(ContainSys
);
195 pContainSys
->Listen(gPlayerObj
,ShockInvPlayerContainsListener
,NULL
);
198 //--------------------------------------------------------------------------------------
199 #define ANIM_DUR 250.0F
201 static Rect equip_rects
[kEquipMax
] = {
202 {{529,16},{562,116}}, // kEquipWeapon
203 {{-1,-1}, {-1,-1}}, // kEquipWeaponAlt
204 {{563,16},{632,83}}, // kEquipArmor
205 {{564,84},{596,117}}, // kEquipSpecial
206 {{599,84},{632,117}}, // kEquipSpecial2
209 void ShockInvDrawCore(void)
211 Point size
, drawloc
, drawpt
;
213 Rect r2
= ShockOverlayGetRect(kOverlayInv
);
215 tSimTime currTime
= GetSimTime();
221 r
.lr
.x
= RectWidth(&r2
);
222 r
.lr
.y
= RectHeight(&r2
);
224 AutoAppIPtr(ShockPlayer
);
226 size
= ContainDimsGetSize(PlayerObject());
227 drawloc
.x
= r
.ul
.x
+ INV_ICON_X
;
228 drawloc
.y
= r
.ul
.y
+ INV_ICON_Y
;
232 DrawByHandle(gHndInv
,drawpt
);
233 //drawloc.y = drawloc.y + (drawpt.y - inv_rect.ul.y);
234 ShockInvDrawObjArray(size
, gPlayerMaxInv
, inv_array
, drawloc
);
236 //LGadDrawBox(VB(&close_button),NULL);
238 mouse_get_xy(&rawpt
.x
,&rawpt
.y
);
239 mpt
.x
= rawpt
.x
- r2
.ul
.x
;
240 mpt
.y
= rawpt
.y
- r2
.ul
.y
;
242 // look for mouseover in-inv objects
243 if (RectTestPt(&r2
,rawpt
))
245 o
= ShockInvFindObject(mpt
);
248 ShockInterfaceMouseOver(o
);
254 // draw the quickbind overlay
255 for (i=0; i < MAX_BIND; i++)
261 loc = ShockBindVal(i);
262 if ((loc != -1) && (loc < BIND_PSIBASE))
266 sprintf(temp,"F%d",i+1);
267 dx = r.ul.x + INV_ICON_X + (x * INV_ICON_WIDTH);
268 dy = r.ul.y + INV_ICON_Y + (y * INV_ICON_HEIGHT);
269 gr_font_string(gShockFont, temp, dx, dy);
274 // draw equipped items
275 ObjID player
= PlayerObject();
277 for (i
=0; i
<= kEquipSpecial2
; i
++)
279 // only one hand of weapons these days
280 if (i
== kEquipWeaponAlt
)
283 if (i
== kEquipSpecial2
)
285 if (!pShockPlayer
->HasTrait(player
,kTraitCybernetic
))
287 drawpt
= equip_rects
[i
].ul
;
289 drawpt
.y
+= 1 + r
.ul
.y
;
290 DrawByHandle(gBlockHnd
, drawpt
);
295 o
= pShockPlayer
->GetEquip(player
, (ePlayerEquip
)i
);
297 if (RectTestPt(&equip_rects
[i
],mpt
))
299 ShockInterfaceMouseOver(o
);
304 dx
= r
.ul
.x
+ equip_rects
[i
].ul
.x
+ 1;
305 dy
= r
.ul
.y
+ equip_rects
[i
].ul
.y
+ 1;
306 ShockInvObjDraw(o
,dx
,dy
);
308 if (i
== kEquipArmor
)
310 // draw in some stats for effectiveness of armor
312 char format
[128], temp
[128];
316 dy
= r
.ul
.y
+ equip_rects
[i
].ul
.y
+ 14;
317 for (j
=0; j
< 3; j
++)
322 case 0: val
= pArmor
->m_combat
; break;
323 case 1: val
= pArmor
->m_radiation
; break;
324 case 2: val
= pArmor
->m_toxic
; break;
329 ShockStringFetch(format
,sizeof(format
),"Armor","misc",j
+1);
330 sprintf(temp
,format
,val
);
331 w
= gr_font_string_width(gShockFont
,temp
);
332 h
= gr_font_string_height(gShockFont
,temp
);
333 dx
= r
.ul
.x
+ equip_rects
[i
].ul
.x
+ ((RectWidth(&equip_rects
[i
]) - w
) / 2);
334 gr_font_string(gShockFont
,temp
,dx
,dy
);
343 //--------------------------------------------------------------------------------------
344 void ShockInvDraw(void)
346 Rect r
= ShockOverlayGetRect(kOverlayInv
);
349 gr_push_canvas(&gInvCanvas
);
356 // determine what is under the mouse
360 AutoAppIPtr(ShockPlayer
);
362 mouse_get_xy(&rawpt
.x
,&rawpt
.y
);
363 mpt
.x
= rawpt
.x
- r
.ul
.x
;
364 mpt
.y
= rawpt
.y
- r
.ul
.y
;
366 if ((shock_cursor_mode
== SCM_DRAGOBJ
) && (gLastLoc
!= ECONTAIN_NULL
))
370 dims
= ContainDimsGetSize(PlayerObject());
371 slot
= ShockInvFindObjSlot(dims
,rawpt
,drag_obj
);
372 if (slot
!= gLastLoc
)
373 gLastLoc
= ECONTAIN_NULL
;
376 // look for mouseover in-inv objects
377 if (RectTestPt(&r
,rawpt
))
379 o
= ShockInvFindObject(mpt
);
383 for (i
=0; (o
== OBJ_NULL
) && (i
<= kEquipSpecial2
); i
++)
385 // only one hand of weapons these days
386 if (i
== kEquipWeaponAlt
)
389 if (RectTestPt(&equip_rects
[i
],mpt
))
392 o
= pShockPlayer
->GetEquip(PlayerObject(), (ePlayerEquip
)i
);
399 ShockInterfaceMouseOver(o
);
402 else if (inrect
&& (i
<= kEquipSpecial2
))
404 if ((i
!= kEquipSpecial2
) || pShockPlayer
->HasTrait(PlayerObject(),kTraitCybernetic
))
405 ShockStringFetch(gHelpString
,sizeof(gHelpString
),"MouseHelpInv","misc",i
);
408 gr_bitmap(gInvBitmap
, r
.ul
.x
, r
.ul
.y
);
410 //--------------------------------------------------------------------------------------
411 void ShockInvObjDraw(ObjID o
, int dx
, int dy
)
418 // get the right bitmap
419 if (ObjGetObjIcon(o
,&lp
))
422 hnd
= LoadPCX(lp
->text
,"objicon\\");//);
426 bmp
= (grs_bitmap
*) hnd
->Lock();
427 gr_bitmap(bmp
, dx
, dy
);
434 if (ShockObjGetQuantity(o
,temp
))
436 //w = gr_font_string_width(gShockFont,temp);
437 //gr_set_fcolor(gShockTextColor);
438 gr_font_string(gShockFont
, temp
, dx
+ 3 , dy
+ 3);
442 //--------------------------------------------------------------------------------------
443 BOOL
ShockObjGetQuantity(ObjID o
, char *temp
)
446 int drawquan
= 0; // from the book of draw'quan
449 if (IProperty_IsRelevant(gStackCountProp
,o
))
451 gStackCountProp
->Get(o
,&quan
);
454 // ammo overlay on weapons
455 else if (ObjHasGunState(o
)) // IsGun(o))
458 g_pWeaponTypeProperty
->Get(o
,&wpntype
);
460 if (wpntype
!=kWeaponPsiAmp
)
462 quan
= GunStateGetAmmo(o
);
467 else if (gPropEnergy
->IsRelevant(o
))
470 gPropEnergy
->Get(o
, &energy
);
480 sprintf(temp
,"%d^",quan
);
483 sprintf(temp
,"%d",quan
);
488 return(drawquan
> 0);
490 //--------------------------------------------------------------------------------------
491 void ShockInvDrawObjArray(Point dims
, Point maxdims
, ObjID
*objarr
, Point startloc
)
500 drawn
= (bool *)Malloc(sizeof(bool) * dims
.x
* dims
.y
);
501 for (i
=0; i
< dims
.x
* dims
.y
; i
++)
504 for (y
=0; y
< maxdims
.y
; y
++)
506 for (x
=0; x
< maxdims
.x
; x
++)
508 dx
= startloc
.x
+ (INV_ICON_WIDTH
* x
);
509 dy
= startloc
.y
+ (INV_ICON_HEIGHT
* y
);
511 // draw in any "unavailable" blocks
512 if ((y
>= dims
.y
) || (x
>= dims
.x
))
517 DrawByHandle(gBlockHnd
, drawpt
);
521 // okay, proceed along normally
524 // nothing to draw if empty, or already drawn previously
525 if ((o
== OBJ_NULL
) || drawn
[c
])
530 ShockInvObjDraw(o
,dx
,dy
);
532 // mark it and all of its slots as drawn
533 w
= InvDimsGetWidth(o
);
534 h
= InvDimsGetHeight(o
);
535 for (i
= x
; i
< x
+ w
; i
++)
537 for (j
= y
; j
< y
+ h
; j
++)
539 int loc
= i
+ (dims
.x
* j
);
540 if (loc
< dims
.x
* dims
.y
)
543 Warning(("Trying to draw obj %d (%d x %d) at %d, %d!\n",o
,w
,h
,x
,y
));
547 // move on to next obj
554 //--------------------------------------------------------------------------------------
555 // For the user-interface level, a request to put the object at this location in a container
556 bool SetInvObj(ObjID container
, int x
, int y
, ObjID obj
)
559 dims
= ContainDimsGetSize(container
);
560 int ul
= (y
* dims
.x
) + x
;
561 return(SetInvObj(container
, ul
,obj
));
563 //--------------------------------------------------------------------------------------
564 // For the user-interface level, a request to put the object at this location in a container
565 bool SetInvObj(ObjID container
, int ul
, int obj
)
571 ObjID prevobj
= OBJ_NULL
;
575 dims
= ContainDimsGetSize(container
);
579 if (!InvCheckSpace(dims
, obj
, ul
))
581 Warning(("Obj %d does not fit at %d,%d (%d) !\n",obj
,x
,y
,ul
));
585 w
= InvDimsGetWidth(obj
);
586 h
= InvDimsGetHeight(obj
);
587 objarr
= (ObjID
*)Malloc(sizeof(ObjID
) * (dims
.x
* dims
.y
));
588 ShockInvComputeObjArray(container
,objarr
);
590 // find objects "underneath" this location
591 AutoAppIPtr(ContainSys
);
592 bool keepgoing
= TRUE
;
593 for (x1
= x
; keepgoing
&& (x1
< x
+ w
); x1
++)
595 for (y1
= y
; keepgoing
&& (y1
< y
+ h
); y1
++)
597 i
= (y1
* dims
.x
) + x1
;
598 //mprintf("analyzing %d at loc %d\n",objarr[i],i);
599 if (objarr
[i
] != OBJ_NULL
)
602 // check for combinability
603 HRESULT res
= pContainSys
->CombineTry(objarr
[i
], obj
, i
);
606 // okay, we've merged in our object so we're basically done
607 ShockInvLoadCursor(OBJ_NULL
);
612 // do we already have a cursor swap candidate? if not, make this the one
613 // if so, then too bad we can't resolve this case
614 if (prevobj
== OBJ_NULL
)
620 if (prevobj
!= objarr
[i
])
630 if (keepgoing
) // ie, we didn't abort, so put this obj in the inventory
632 ShockInvLoadCursor(OBJ_NULL
);
633 pContainSys
->Add(container
, obj
, ul
, CTF_NONE
);
637 //mprintf("prevobj is %d\n",prevobj);
638 if (prevobj
!= OBJ_NULL
)
640 // remove it from the inventory
641 pContainSys
->Remove(container
,prevobj
);
642 ShockInvLoadCursor(prevobj
);
648 //--------------------------------------------------------------------------------------
649 // do the simple geometry to find what slot is being clicked on, given objid on the cursor
650 int ShockInvFindObjSlot(Point dims
, Point mpos
, ObjID objid
)
652 if (!ShockOverlayCheck(kOverlayInv
))
654 return(ShockInvFindObjSlotPos(dims
,mpos
,&inv_icon_rect
,objid
));
657 //--------------------------------------------------------------------------------------
658 // same as above, but more general
659 int ShockInvFindObjSlotPos(Point dims
, Point mpos
, Rect
*pRect
, ObjID objid
)
664 //mprintf("mpos = %d, %d\n",mpos.x,mpos.y);
665 if (RectTestPt(pRect
, mpos
))
667 if (objid
== OBJ_NULL
)
674 // This is kind of ugly. An attempt to deal with issues of mapping the hotspot
675 // of the cursor to the upper left objslot of where it wants to go.
677 w
= InvDimsGetWidth(objid
);
678 h
= InvDimsGetHeight(objid
);
679 offset
.x
= (((float)w
/ 2) - 0.5F
) * INV_ICON_WIDTH
;
680 offset
.y
= (((float)h
/ 2) - 0.5F
) * INV_ICON_HEIGHT
;
683 x
= (mpos
.x
- offset
.x
- pRect
->ul
.x
) / INV_ICON_WIDTH
;
684 y
= (mpos
.y
- offset
.y
- pRect
->ul
.y
) / INV_ICON_HEIGHT
;
685 if ((x
>= dims
.x
) || (y
>= dims
.y
))
688 return ((y
* dims
.x
) + x
);
692 //--------------------------------------------------------------------------------------
693 ObjID
ShockInvFindObject(int slot
)
695 return (inv_array
[slot
]);
697 //--------------------------------------------------------------------------------------
698 ObjID
ShockInvFindObject(Point mpos
)
703 dims
= ContainDimsGetSize(PlayerObject());
705 if (RectTestPt(&inv_icon_rect
, mpos
)) /// || RectTestPt(&gunslot_rect, mpos))
707 slot
= ShockInvFindObjSlot(dims
, mpos
);
717 //--------------------------------------------------------------------------------------
718 bool ShockInvLoadCursor(int o
)
729 Warning(("ShockInvLoadCursor: not in cursor mode!\n"));
737 //mprintf("loading cursor with obj %d\n",o);
746 if (ObjGetObjIcon(o
, &lp
) && (shock_cursor_mode
== SCM_NORMAL
))
748 hnd
= LoadPCX(lp
->text
,"objicon\\");
749 if (SetCursorByHandle(hnd
))
752 shock_cursor_mode
= SCM_DRAGOBJ
;
760 //--------------------------------------------------------------------------------------
761 static int gThrowAudioHnd
= -1; // = SFX_NO_HND;
762 static void SchemaDoneCallback(int /*hSchema*/, ObjID
/*schemaID*/, void* /*pData*/)
766 //--------------------------------------------------------------------------------------
767 // put an object in the first open slot in the inventory
768 bool ShockInvAddObj(ObjID container
, ObjID obj
)
770 AutoAppIPtr(ContainSys
);
777 // Don't do anything if it's already in the inventory; this can
778 // cause duplicate links, which wreak merry hell on networking.
779 if (pContainSys
->Contains(container
, obj
))
782 dims
= ContainDimsGetSize(container
);
783 arr
= (ObjID
*)Malloc(sizeof(ObjID
) * dims
.x
* dims
.y
);
784 ShockInvComputeObjArray(container
,arr
);
785 space
=ShockInvFindSpace(arr
, dims
, obj
, &loc
);
788 AutoAppIPtr(ShockPlayer
);
790 // if we are armor, and armor equip slot is free, then wear it
791 if (ObjHasArmor(obj
) && (pShockPlayer
->GetEquip(container
,kEquipArmor
) == OBJ_NULL
))
794 equipped
= pShockPlayer
->Equip(container
,kEquipArmor
,obj
,FALSE
);
799 // okay, lets just put it the everyday joe inventory
802 // first, check for autocombine if we are auto-adding
803 if (!pContainSys
->CanCombineContainer(PlayerObject(), obj
, -1))
805 // no space, so chuck object back into world
806 ThrowObj(obj
, PlayerObject()); // maybe should be from container obj?
807 // this line removed since ThrowObj is guaranteed to set the cursor to OBJ_NULL
808 // if it is the cursor obj anyways
809 //ShockInvLoadCursor(OBJ_NULL);
811 // play an error SFX too
812 if (gThrowAudioHnd
== -1)
814 sSchemaCallParams schParams
;
815 memset (&schParams
, 0, sizeof (schParams
));;
816 schParams
.flags
= SCH_SET_CALLBACK
;
817 schParams
.sourceID
= OBJ_NULL
;
818 schParams
.callback
= SchemaDoneCallback
;
820 gThrowAudioHnd
= SchemaPlay((Label
*)"bb11",&schParams
);
822 //gThrowAudioHnd = SchemaPlay((Label *)"bb11",NULL);
827 result
= pContainSys
->Add(container
,obj
,loc
,CTF_COMBINE
);
831 ShockInvLoadCursor(OBJ_NULL
);
837 //--------------------------------------------------------------------------------------
838 bool ShockInvFindSpace(ObjID
*arr
, Point dims
, ObjID obj
, int *slot
)
847 Warning(("Object %d does not have a valid container dimension!\n",obj
));
852 for (x
= 0; x
< dims
.x
; x
++)
854 for (y
=0; y
< dims
.y
; y
++)
856 i
= x
+ (y
* dims
.x
);
857 if (arr
[i
] == OBJ_NULL
)
859 // is there enough room here?
861 w
= InvDimsGetWidth(obj
);
862 h
= InvDimsGetHeight(obj
);
863 // are we too close to the edges?
864 if ((x
+ w
> dims
.x
) || (y
+ h
> dims
.y
))
866 // now check for enough clear slots
867 for (x1
= x
; space
&& (x1
< x
+ w
); x1
++)
869 for (y1
= y
; space
&& (y1
< y
+ h
); y1
++)
871 if (arr
[x1
+ (y1
* dims
.x
)] != OBJ_NULL
)
886 //--------------------------------------------------------------------------------------
887 bool ShockInvPayNanites(int quan
)
889 AutoAppIPtr(ContainSys
);
890 AutoAppIPtr(ObjectSystem
);
893 ObjID arch
= pObjectSystem
->GetObjectNamed("Nanites");
894 res
= pContainSys
->CombineAdd(PlayerObject(),arch
,-quan
);
900 //--------------------------------------------------------------------------------------
901 int ShockInvNaniteTotal(void)
904 AutoAppIPtr(ContainSys
);
905 AutoAppIPtr(ObjectSystem
);
906 ObjID arch
= pObjectSystem
->GetObjectNamed("Nanites");
907 retval
= pContainSys
->CombineCount(PlayerObject(),arch
);
910 //--------------------------------------------------------------------------------------
912 static bool close_cb(short action, void* data, LGadBox* vb)
914 if (action == BUTTONGADG_LCLICK) // || (action == BUTTONGADG_RCLICK))
916 uiDefer(DeferOverlayClose,(void *)kOverlayInv);
917 //SchemaPlay((Label *)"subpanel_cl",NULL);
922 //--------------------------------------------------------------------------------------
923 static void BuildInterfaceButtons(void)
927 r = ShockOverlayGetRect(kOverlayInv);
929 // set up the continue button
930 close_elem.draw_type = DRAWTYPE_BITMAPOFFSET;
931 close_elem.draw_data = close_bitmaps;
932 close_elem.draw_data2 = (void *)4; // should be 2 but hackery required
934 LGadCreateButtonArgs(&close_button, LGadCurrentRoot(), close_rect.ul.x + r.ul.x, close_rect.ul.y + r.ul.y,
935 RectWidth(&close_rect), RectHeight(&close_rect), &close_elem, close_cb, 0);
939 //--------------------------------------------------------------------------------------
940 static void DestroyInterfaceButtons(void)
942 //LGadDestroyBox(VB(&close_button),FALSE);
944 //--------------------------------------------------------------------------------------
945 void ShockInvStateChange(int which
)
948 if (ShockOverlayCheck(which
))
949 BuildInterfaceButtons(); // just got put up
951 DestroyInterfaceButtons(); // just got taken down
953 //--------------------------------------------------------------------------------------
954 // Check for transparency in the source art
955 //--------------------------------------------------------------------------------------
956 bool ShockInvCheckTransp(Point pt
)
958 // for now, always return false so we don't get tricked by the transparency
959 // in the interlacing.
965 r = ShockOverlayGetRect(kOverlayInv);
969 pix = HandleGetPix(gHndInv,p);
973 //mprintf("SICT: %d (%d)\n",retval,pix);
977 //--------------------------------------------------------------------------------------
978 // Basic interface handling.
979 //--------------------------------------------------------------------------------------
980 //EXTERN int hack_for_kbd_state(void);
981 //#define CTRL_STATES (KBM_LCTRL|KBM_RCTRL)
982 bool ShockInvHandleMouse(Point pos
)
986 //bool retval = TRUE;
988 o = ShockInvFindObject(pos);
989 mprintf("SIHM = %d, %d, obj = %d\n",pos.x,pos.y,o);
991 switch (shock_cursor_mode)
996 AutoAppIPtr(PlayerPsi);
997 pPlayerPsi->PsiTarget(o);
1007 //--------------------------------------------------------------------------------------
1008 bool ShockInvDoubleClick(Point pos
)
1012 if (shock_cursor_mode
== SCM_NORMAL
)
1016 // mprintf("double click!\n");
1017 o
= ShockInvFindObject(pos
);
1021 AutoAppIPtr(ShockPlayer
);
1022 for (i
=0; i
< kEquipMax
; i
++)
1024 if (RectTestPt(&equip_rects
[i
],pos
))
1026 ePlayerEquip slot
= (ePlayerEquip
)i
;
1028 o
= pShockPlayer
->GetEquip(PlayerObject(), slot
);
1034 // direct in-inv usage
1035 frobInvSelectObj
= o
;
1037 //mprintf("inv frobbing objid %d\n",o);
1042 //--------------------------------------------------------------------------------------
1043 void ShockInvTakeMe(ObjID obj
)
1045 ShockInvLoadCursor(obj
);
1046 AutoAppIPtr(ContainSys
);
1047 pContainSys
->Remove(PlayerObject(),obj
);
1048 SchemaPlay((Label
*)"select_item",NULL
);
1050 //--------------------------------------------------------------------------------------
1051 // user has down-alt-clicked on a stack
1052 // if it isn't stackable, just put it on the cursor
1053 // if it is stackable, but the increment is the whole stack, put it on the cursor
1054 // otherwise, put on the cursor an increment's worth, and leave the rest in place.
1055 // If leaveEmpty is TRUE, then an empty stack will be left behind if
1057 void ShockSplitStack(ObjID obj
, BOOL leaveEmpty
)
1059 if (obj
== OBJ_NULL
)
1062 AutoAppIPtr(ObjectSystem
);
1064 maxobj
= pObjectSystem
->MaxObjID();
1065 currobj
= pObjectSystem
->ActiveObjects();
1066 if (currobj
> maxobj
* 9 / 10)
1069 ShockStringFetch(temp
,sizeof(temp
),"TooManyObjs","misc");
1070 ShockOverlayAddText(temp
,DEFAULT_MSG_TIME
);
1078 gPropStackIncrem
->Get(obj
,&increm
);
1080 // the case where we take all and leave nothing behind
1081 if (!gStackCountProp
->Get(obj
,&num
) || (num
<= increm
))
1087 // Just take the whole stack
1088 ShockInvTakeMe(obj
);
1093 // okay, we are actually splitting
1095 AutoAppIPtr(ContainSys
);
1097 // this will create a new object as well
1099 newobj
= pContainSys
->RemoveFromStack(obj
, kStackRemoveLeaveEmpty
, increm
);
1101 newobj
= pContainSys
->RemoveFromStack(obj
, 0, increm
);
1102 ObjSetHasRefs(newobj
,FALSE
);
1103 PhysDeregisterModel(newobj
);
1105 // put it on our cursor, voila!
1106 ShockInvLoadCursor(newobj
);
1108 //--------------------------------------------------------------------------------------
1109 bool ShockInvDragDrop(Point pos
, BOOL start
)
1113 ObjID player
= PlayerObject();
1114 AutoAppIPtr(ShockPlayer
);
1118 // first off, are we over an equip slot?
1119 for (i
=0; i
< kEquipMax
; i
++)
1121 if (RectTestPt(&equip_rects
[i
],pos
))
1123 ePlayerEquip slot
= (ePlayerEquip
)i
;
1125 prevobj
= pShockPlayer
->GetEquip(player
, slot
);
1126 switch (shock_cursor_mode
)
1130 // don't do anything on downs with something on the cursor
1137 BOOL place_item
= FALSE
;
1138 if (prevobj
== OBJ_NULL
)
1140 if ((gLastLoc
== ECONTAIN_NULL
) || (gLastLoc
!= slot
))
1145 // inv-inv tool usage
1146 frobInvSelectObj
= prevobj
;
1149 if (ShockScriptAllowSwap())
1154 if (pShockPlayer
->Equip(player
, slot
,drag_obj
,TRUE
))
1155 ShockInvLoadCursor(OBJ_NULL
);
1157 prevobj
= OBJ_NULL
; // leave the old obj in place
1167 pShockPlayer
->Equip(player
, slot
,OBJ_NULL
,TRUE
);
1175 if (prevobj
!= OBJ_NULL
)
1176 ShockLookPopup(prevobj
);
1178 // leave equipped obj in place
1185 if (prevobj
!= OBJ_NULL
)
1187 AutoAppIPtr(PlayerPsi
);
1188 pPlayerPsi
->PsiTarget(prevobj
);
1191 // leave equipped obj in place
1196 if (prevobj
!= OBJ_NULL
)
1198 // handle combinables
1199 AutoAppIPtr(ContainSys
);
1200 // agh, clean this up
1201 if (pContainSys
->CombineTry(pShockPlayer
->GetEquip(player
, slot
),prevobj
,SHOCKCONTAIN_PDOLLBASE
+ slot
) == S_OK
)
1202 ShockInvLoadCursor(OBJ_NULL
);
1204 ShockInvLoadCursor(prevobj
);
1209 // otherwise, do the normal thing
1211 o
= ShockInvFindObject(pos
);
1213 switch (shock_cursor_mode
)
1219 BOOL place_item
= FALSE
;
1222 dims
= ContainDimsGetSize(PlayerObject());
1223 slot
= ShockInvFindObjSlot(dims
,pos
,drag_obj
);
1226 if ((gLastLoc
== ECONTAIN_NULL
) || (gLastLoc
!= slot
))
1231 // inv-inv tool usage
1232 frobInvSelectObj
= o
; // since this is the "target" of the tool frob
1234 //mprintf("tool frobbing objid %d with %d\n",o,drag_obj); // shock_cursor_useobj);
1236 if (ShockScriptAllowSwap())
1239 gLastLoc
= ECONTAIN_NULL
;
1244 // make the contains system request
1245 // automagically handles swapping and combining
1246 SchemaPlay((Label
*)"place_item", NULL
);
1247 SetInvObj(PlayerObject(),slot
,drag_obj
);
1258 AutoAppIPtr(ContainSys
);
1259 gLastLoc
= pContainSys
->IsHeld(PlayerObject(),o
);
1265 if ((o
!= OBJ_NULL
) && !start
)
1272 if ((o
!= OBJ_NULL
) && !start
)
1274 AutoAppIPtr(PlayerPsi
);
1275 pPlayerPsi
->PsiTarget(o
);
1284 ShockSplitStack(o
, FALSE
);
1291 //--------------------------------------------------------------------------------------
1292 void ShockInvFillObjPos(ObjID o
, ObjID
*arr
, int ctpos
, Point dims
)
1294 // assumes object will fit!
1296 // filter out objects that are contained by not in standard object array space
1297 if (ctpos
>= SHOCKCONTAIN_PDOLLBASE
)
1302 // simple conversion, may become more complex?
1303 x1
= ctpos
% dims
.x
;
1304 y1
= ctpos
/ dims
.x
;
1305 w
= InvDimsGetWidth(o
);
1306 h
= InvDimsGetHeight(o
);
1307 for (x
= x1
; x
< x1
+ w
; x
++)
1308 for (y
= y1
; y
< y1
+ h
; y
++)
1309 arr
[x
+ (dims
.x
* y
)] = o
;
1312 //--------------------------------------------------------------------------------------
1313 void ShockInvComputeObjArray(ObjID o
, ObjID
*arr
)
1315 AutoAppIPtr(ContainSys
);
1317 sContainIter
*piter
;
1323 dims
= ContainDimsGetSize(o
);
1324 if ((dims
.x
== 0) || (dims
.y
== 0))
1326 Warning(("ShockInvComputeObjArray:: dims is zero!\n"));
1329 piter
= pContainSys
->IterStart(o
);
1330 for (i
=0; i
< dims
.x
* dims
.y
; i
++)
1332 while (!piter
->finished
)
1334 if (piter
->type
< SHOCKCONTAIN_PDOLLBASE
)
1335 ShockInvFillObjPos(piter
->containee
,arr
,piter
->type
,dims
);
1336 pContainSys
->IterNext(piter
);
1338 pContainSys
->IterEnd(piter
);
1340 //--------------------------------------------------------------------------------------
1341 static bool InvCheckSpace(Point space
, ObjID obj
, int loc
)
1344 w
= InvDimsGetWidth(obj
);
1345 h
= InvDimsGetHeight(obj
);
1349 // okay, double-check that we fit
1350 if ((x
+ w
- 1 >= space
.x
) || (y
+ h
- 1 >= space
.y
))
1355 //--------------------------------------------------------------------------------------
1356 static bool InvCheckSpace(Point space
, ObjID obj
, int x
, int y
)
1359 w
= InvDimsGetWidth(obj
);
1360 h
= InvDimsGetHeight(obj
);
1362 // okay, double-check that we fit
1363 if ((x
+ w
- 1 >= space
.x
) || (y
+ h
- 1 >= space
.y
))
1368 //--------------------------------------------------------------------------------------
1369 // really only for use by the listener
1370 void InvClearObj(int objid
, ObjID
*invarr
)
1372 // finds all object slots that are equal to objid
1375 for (i
=0; i
< MAX_INV_ITEMS
; i
++)
1377 if (invarr
[i
] == objid
)
1379 invarr
[i
] = OBJ_NULL
;
1383 //--------------------------------------------------------------------------------------
1384 BOOL
ShockInvPlayerContainsListener(eContainsEvent event
, ObjID container
, ObjID containee
, eContainType ctype
, ContainCBData
)
1386 if (container
!= PlayerObject()) {
1387 // This actually gets called for any containment change, but we
1388 // only care about the player:
1395 dims
= ContainDimsGetSize(container
);
1399 loc
= ctype
; // simple conversion, eh?
1404 if (loc
< SHOCKCONTAIN_PDOLLBASE
)
1406 //mprintf("trying to place obj %d at loc %d\n",containee,loc);
1407 if (InvCheckSpace(dims
,containee
,loc
))
1408 ShockInvFillObjPos(containee
, inv_array
, loc
, dims
);
1414 case kContainRemove
:
1416 if (loc >= SHOCKCONTAIN_PDOLLBASE)
1418 AutoAppIPtr(ShockPlayer);
1419 pShockPlayer->Equip(container, (ePlayerEquip)loc,OBJ_NULL);
1422 InvClearObj(containee
, inv_array
);
1428 //--------------------------------------------------------------------------------------
1435 void ShockInvResize(ObjID obj
, sContainDims
*olddims
, sContainDims
*dims
)
1440 sContainIter
*piter
;
1441 AutoAppIPtr(ContainSys
);
1445 // rearrange the inventory values to accomodate the new size,
1446 // while not appearing to move at all.
1448 // note that we have to gather the data in one pass, and set
1449 // the data in a second pass to avoid modifying the data we
1450 // are iterating over.
1451 cSimpleDList
<sResizeData
> contents
;
1453 piter
= pContainSys
->IterStart(obj
);
1454 while (!piter
->finished
)
1458 rsd
.obj
= piter
->containee
;
1459 rsd
.loc
= piter
->type
;
1460 contents
.Append(rsd
);
1462 pContainSys
->IterNext(piter
);
1464 pContainSys
->IterEnd(piter
);
1468 // now that we have assembled a list of data, go poke
1469 // in the new locations for everything
1470 cSimpleDList
<ObjID
> objlist
;
1471 cSimpleDList
<sResizeData
>::cIter iter
;
1472 for (iter
= contents
.Iter(); !iter
.Done(); iter
.Next())
1476 if (rsd
.loc
< SHOCKCONTAIN_PDOLLBASE
)
1478 oldpt
.x
= rsd
.loc
% olddims
->m_width
;
1479 oldpt
.y
= rsd
.loc
/ olddims
->m_width
;
1481 newloc
= (oldpt
.y
* dims
->m_width
) + oldpt
.x
;
1483 // if the object is now in an invalid space, pitch it
1484 invdims
.x
= dims
->m_width
;
1485 invdims
.y
= dims
->m_height
;
1486 // compare the old location to the new dimensions
1487 if (InvCheckSpace(invdims
,rsd
.obj
, oldpt
.x
,oldpt
.y
))
1489 pContainSys
->SetContainType(obj
,rsd
.obj
, newloc
);
1490 ShockInvFillObjPos(rsd
.obj
, inv_array
, newloc
, invdims
);
1494 // make a list of stuff to try and re-place in the inventory
1495 pContainSys
->Remove(obj
,rsd
.obj
);
1496 objlist
.Append(rsd
.obj
);
1501 // note if we have anything on the cursor
1502 ObjID save_obj
= drag_obj
;
1504 // try to replace the misfits
1505 cSimpleDList
<ObjID
>::cIter objiter
;
1506 for (objiter
= objlist
.Iter(); !objiter
.Done(); objiter
.Next())
1509 o
= objiter
.Value();
1510 ShockInvAddObj(obj
,o
);
1513 // restore the cursor if necessary
1514 if (save_obj
!= OBJ_NULL
)
1516 ShockInvLoadCursor(save_obj
);
1520 //--------------------------------------------------------------------------------------
1521 void ShockInvDestroyCursorObj(void)
1523 if (drag_obj
== OBJ_NULL
)
1526 IObjectSystem
* pOS
= AppGetObj(IObjectSystem
);
1527 pOS
->Destroy(drag_obj
);
1530 ShockInvLoadCursor(OBJ_NULL
);
1532 //--------------------------------------------------------------------------------------
1534 int ShockInvQuickbind(void)
1537 Rect r = ShockOverlayGetRect(kOverlayInv);
1538 eContainType retval;
1541 // look around for an object under the cursor to bind.
1542 mouse_get_xy(&rawpt.x,&rawpt.y);
1543 mpt.x = rawpt.x - r.ul.x;
1544 mpt.y = rawpt.y - r.ul.y;
1545 o = ShockInvFindObject(mpt);
1547 // return its containtype
1548 AutoAppIPtr(ContainSys);
1549 retval = pContainSys->IsHeld(PlayerObject(), o);
1550 if (retval == ECONTAIN_NULL)
1557 void ShockInvRefresh(void)
1562 //--------------------------------------------------------------------------------------
1563 // the area at the bottom that holds your dedicated inventory slots
1564 //--------------------------------------------------------------------------------------
1571 static Rect ticker_rect
= {{0,0},{0,0}};
1572 #define BUTTON_RECT(x,y) {{x,y},{x + INV_ICON_WIDTH, y + INV_ICON_HEIGHT}}
1573 Rect fake_rects
[4] = {
1574 BUTTON_RECT(BIO_X
+ 183, BIO_Y
+ 21),
1575 BUTTON_RECT(BIO_X
+ 222, BIO_Y
+ 21),
1576 BUTTON_RECT(AMMO_X
+ 5, AMMO_Y
+ 20),
1577 BUTTON_RECT(AMMO_X
+ 44, AMMO_Y
+ 20),
1579 //--------------------------------------------------------------------------------------
1580 void ShockTickerInit(int which
)
1585 ScrnModeGet(&smode
);
1588 use_rect
.ul
.x
= ticker_rect
.ul
.x
;
1589 use_rect
.ul
.y
= ticker_rect
.ul
.y
;
1593 use_rect
.ul
.x
= (smode
.w
- 640);
1594 use_rect
.ul
.y
= (smode
.h
- 480);
1597 ShockOverlaySetRect(which
,use_rect
);
1600 //--------------------------------------------------------------------------------------
1601 void ShockTickerTerm(void)
1605 //--------------------------------------------------------------------------------------
1606 void ShockTickerDraw(void)
1608 Rect r
= ShockOverlayGetRect(kOverlayTicker
);
1611 Point mpt
; // rawpt,drawpt,
1613 //DrawByHandle(gTickerHnd,r.ul);
1614 AutoAppIPtr(ShockPlayer
);
1617 mouse_get_xy(&rawpt.x,&rawpt.y);
1618 mpt.x = rawpt.x - r.ul.x;
1619 mpt.y = rawpt.y - r.ul.y;
1621 mouse_get_xy(&mpt
.x
,&mpt
.y
);
1623 for (i
=kEquipFakeNanites
; i
<= kEquipFakeKeys
; i
++)
1625 o
= pShockPlayer
->GetEquip(PlayerObject(), (ePlayerEquip
)i
);
1626 // special case for 2-handed weapons
1629 if (i
>= kEquipFakeLogs
)
1639 RectOffsettedRect(&fake_rects
[i
-kEquipFakeNanites
], offset
, &userect
);
1641 if (RectTestPt(&userect
,mpt
))
1643 ShockInterfaceMouseOver(o
);
1644 g_ifaceFocusObj
= o
;
1649 drawpt.x = fake_rects[i - kEquipFakeNanites].ul.x + 1;
1650 if (i >= kEquipFakeLogs)
1652 drawpt.y = r.ul.y + fake_rects[i - kEquipFakeNanites].ul.y + 1;
1654 ShockInvObjDraw(o
,userect
.ul
.x
,userect
.ul
.y
); // drawpt.x,drawpt.y);
1658 //--------------------------------------------------------------------------------------
1659 EXTERN
bool ShockTickerHandleMouse(Point pos
)
1663 //--------------------------------------------------------------------------------------
1664 // puts cursor in look-at mode
1665 void ShockSplitCursor(void)
1670 shock_cursor_mode
= SCM_SPLIT
;
1671 //mprintf("SLC!\n");
1672 hnd
= LoadPCX("splitcur","iface\\");
1673 SetCursorByHandle(hnd
);
1676 //--------------------------------------------------------------------------------------
1677 sOverlayFunc OverlayInv
= {
1678 ShockInvDraw
, // draw
1679 ShockInvInit
, // init
1680 ShockInvTerm
, // term
1681 ShockInvHandleMouse
, // mouse
1682 ShockInvDoubleClick
, // dclick (really use)
1683 ShockInvDragDrop
, // dragdrop
1688 ShockInvStateChange
, // state
1689 ShockInvCheckTransp
, // transparency
1694 sOverlayFunc OverlayTicker
= {
1695 ShockTickerDraw
, // draw
1696 ShockTickerInit
, // init
1697 ShockTickerTerm
, // term
1698 ShockTickerHandleMouse
, // mouse
1699 NULL
, // dclick (really use)
1706 NULL
, // transparency