2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
15 //#include <frobbase.h>
19 //#include <frobsys.h>
49 //#include <dpcscrpt.h>
66 BOOL
DPCInvThrowBackToWorld(ObjID o
, ObjID src
);
67 BOOL
DPCInvTakeObjFromWorld(ObjID o
, ObjID src
);
68 BOOL
DPCInvRemObj(ObjID o
);
69 BOOL
DPCInvToolCursor(ObjID o
);
71 // The number of requests for frob-pickup that are outstanding to the
73 static int gFrobsPending
;
75 // Returns TRUE iff we are waiting for the host to respond to some
79 return (gFrobsPending
> 0);
82 // This will get called by the frob system when it finishes with a frob
83 // that we requested a receipt for (which is things we are picking up):
84 void DPCFrobAcknowledge(ObjID o
)
94 static cNetMsg
*g_pFrobPickupMsg
= NULL
;
96 static void handleFrobPickup(ObjID o
, ObjID oldCont
)
98 // This test shouldn't be necessary, but OBJ_NULL isn't handled right
102 DPC_cursor_mode
= SCM_NORMAL
;
104 AutoAppIPtr(NetManager
);
105 if (pNetManager
->Networking()) {
106 AutoAppIPtr(ObjectNetworking
);
107 pObjectNetworking
->ObjTakeOver(o
);
110 // If the thing used to be in a container, tell everyone to take
111 // it out. This must happen before we put it in our inventory:
112 DPCBroadcastRemoveContainee(o
, oldCont
);
114 // At this point, we have two choices. If the object is auto-pickup,
115 // then we just put it into the player's inventory. Otherwise, pick
116 // it up and put it on their cursor.
118 if (gPropAutoPickup
->Get(o
, &isAutoPickup
) && isAutoPickup
) {
119 // It's an auto-pickup object
120 // Add feedback *before* picking it up, because picking the
121 // object up can potentially destroy it, if it's a combinable
123 char temp
[255],temp2
[64], text
[255];
125 eObjState st
= ObjGetObjState(o
);
126 AutoAppIPtr(GameStrings
);
127 DPCStringFetch(temp
, sizeof(temp
), "PickupString", "misc");
128 str
= pGameStrings
->FetchObjString(o
,PROP_OBJSHORTNAME_NAME
);
130 if (st
!= kObjStateUnresearched
)
133 if (gStackCountProp
->Get(o
,&count
))
134 sprintf(temp2
,str
,count
);
139 DPCStringFetch(temp2
,sizeof(temp2
),"NameUnresearched","research");
140 sprintf(text
,temp
,temp2
);
141 DPCOverlayAddText(text
,DEFAULT_MSG_TIME
);
143 DPCInvAddObj(PlayerObject(), o
);
145 // It's an ordinary object
146 DPC_cursor_mode
= SCM_NORMAL
;
150 // snap any "tripwire" links to the object
153 AutoAppIPtr(LinkManager
);
154 pRel
= pLinkManager
->GetRelationNamed("Tripwire");
155 if (pRel
->AnyLinks(LINKOBJ_WILDCARD
,o
))
157 lid
= pRel
->GetSingleLink(LINKOBJ_WILDCARD
, o
);
161 // Current theory: the pickup sound is local to the client doing
162 // the pickup, so we're not networking it...
163 //sfx_parm parm={0,0,0,0,100,0,0,0,NULL,NULL};
164 //g_pPropSnd->GenerateSound("pickup", &parm);
165 SchemaPlay((Label
*)"pickup_item",NULL
);
169 static sNetMsgDesc sFrobPickupDesc
=
176 // Can't have the assert here, because the object could be
178 {{kNMPT_SenderObjID
, kNMPF_AllowObjNull
, "Obj"},
179 {kNMPT_GlobalObjID
, kNMPF_AllowObjNull
, "Container"},
184 // Tell the client to put the given object onto its cursor
187 void DPCSendFrobPickup(ObjID o
, ObjID player
, ObjID oldCont
)
189 AutoAppIPtr(NetManager
);
190 if (pNetManager
->Networking()) {
191 // Make sure we're not sending heartbeats for this thing any more
192 PhysNetSetSleep(o
, TRUE
);
194 // If player is the host, then this will just loopback:
195 g_pFrobPickupMsg
->Send(player
, o
, oldCont
);
200 // Give item to another player
203 static cNetMsg
*g_pGiveObjToPlayerMsg
= NULL
;
205 // Receiver's side -- deal with this object
206 // Assumes that we have already received ownership of the object, due to
207 // the low-level Give that should have just happened.
208 static void handleGiveObjToPlayer(ObjID o
, ObjID fromPlayer
)
210 AutoAppIPtr(ObjectNetworking
);
211 AssertMsg2(pObjectNetworking
->ObjHostedHere(o
),
212 "Received possession, but not ownership, of %d from %d!",
215 // Add feedback *before* picking it up, because picking the
216 // object up can potentially destroy it, if it's a combinable
218 char temp
[255], text
[255];
219 AutoAppIPtr(NetManager
);
220 const char *fromName
= pNetManager
->GetPlayerName(fromPlayer
);
221 const char *myName
= pNetManager
->GetPlayerName(PlayerObject());
223 ObjGetObjShortNameSubst(o
, objName
, sizeof(objName
));
225 if (DPCStringFetch(temp
, sizeof(temp
), "ReceiveString", "misc"))
227 sprintf(text
, temp
, objName
, fromName
);
228 DPCOverlayAddText(text
,DEFAULT_MSG_TIME
);
232 if (DPCInvAddObj(PlayerObject(), o
))
234 // Tell the other player that we succeeded
235 if (DPCStringFetch(temp
, sizeof(temp
), "GiveawayString", "misc"))
237 sprintf(text
, temp
, objName
, myName
);
238 DPCSendAddText(fromPlayer
, text
);
241 // Tell the other player that we failed to take it
242 if (DPCStringFetch(temp
, sizeof(temp
), "GivefailString", "misc"))
244 sprintf(text
, temp
, objName
, myName
);
245 DPCSendAddText(fromPlayer
, text
);
250 static sNetMsgDesc sGiveObjToPlayerDesc
=
254 "Give Object To Player",
256 handleGiveObjToPlayer
,
257 {{kNMPT_ReceiverObjID
, kNMPF_None
, "Object"},
261 // Giver's side -- hand the object off
262 static void GiveAwayObject(ObjID targetPlayer
, ObjID obj
)
264 AssertMsg1(targetPlayer
!= PlayerObject(),
265 "Trying to give object %d to myself!",
270 Warning(("Trying to give away OBJ_NULL!\n"));
274 // Hand off ownership, and then the object itself, to the target;
275 // it's his problem now:
276 AutoAppIPtr(ObjectNetworking
);
277 if (!pObjectNetworking
->ObjHostedHere(obj
))
279 Warning(("Trying to give away unowned object %d!\n", obj
));
282 pObjectNetworking
->ObjGiveWithoutObjID(obj
, targetPlayer
);
283 g_pGiveObjToPlayerMsg
->Send(targetPlayer
, obj
);
285 // And now we're no longer holding it:
291 #define MAX_RAYCAST_OBJ 512
292 void DPCDoFrob(bool in_inv
)
296 // make sure we can actually reach the object
297 // maybe we need to special case containers?
298 if ((frobWorldSelectObj
!= OBJ_NULL
) && ObjHasRefs(frobWorldSelectObj
))
304 ObjID objlist
[MAX_RAYCAST_OBJ
];
309 p1
= ObjPosGet(PlayerObject());
310 p2
= ObjPosGet(frobWorldSelectObj
);
312 if ((p1
!= NULL
) && (p2
!= NULL
))
314 cConcreteIter
iter(gPropBlockFrob
);
317 while (iter
.Next(&obj
))
319 gPropBlockFrob
->Get(obj
, &propval
);
320 // make sure it is concrete, matches our target BlockFrob, and derives from physical (to exclude traps)
321 if (propval
&& OBJ_IS_CONCRETE(obj
))
325 if (n
== MAX_RAYCAST_OBJ
)
327 Warning(("DPCDoFrob: Raycast obj limit exceeded!\n"));
334 PhysRaycastSetObjlist(objlist
, n
);
335 result
= PhysRaycast(p1
->loc
, p2
->loc
, &hit
, &hit_obj
, 0.0, kCollideAllPhys
);
336 PhysRaycastClearObjlist();
337 if (result
!= kCollideNone
)
339 if (hit_obj
!= frobWorldSelectObj
)
340 return; // maybe needs feedback?
345 if (FrobSoundIsRelevant(frobWorldSelectObj
))
347 SchemaPlay(FrobSoundGet(frobWorldSelectObj
),NULL
);
349 if (gPropUseMessage
->IsRelevant(frobWorldSelectObj
))
351 AutoAppIPtr(GameStrings
);
352 cStr str
= pGameStrings
->FetchObjString(frobWorldSelectObj
, PROP_USEMESSAGE_NAME
);
353 DPCOverlayAddText(str
,DEFAULT_MSG_TIME
);
358 sfa
.frobber
= PlayerObject();
359 sfa
.ms_down
= 100; // fakes
361 sfa
.src_obj
= OBJ_NULL
;
363 // support for inv-inv frobbing should go here
364 if (DPC_cursor_mode
== SCM_DRAGOBJ
) // USEOBJ)
367 if (IsAPlayer(frobInvSelectObj
))
369 // It's been dragged onto another player, so try giving it to them.
370 // This sorta goes around frob.
371 GiveAwayObject(frobInvSelectObj
, drag_obj
);
375 sfa
.dst_obj
= frobInvSelectObj
;
376 sfa
.dst_loc
= kFrobLocWorld
;
377 sfa
.src_obj
= drag_obj
;
378 sfa
.src_loc
= kFrobLocInv
;
384 sfa
.dst_obj
= OBJ_NULL
;
387 sfa
.src_obj
= frobInvSelectObj
;
388 sfa
.src_loc
= kFrobLocInv
;
392 if (frobWorldSelectObj
!= OBJ_NULL
)
393 sfa
.src_obj
= frobWorldSelectObj
;
395 sfa
.src_obj
= g_ifaceFocusObj
;
396 sfa
.src_loc
= kFrobLocWorld
;
400 // more sure our src obj has a frobinfo prop
401 if (!pFrobInfoProp
->IsRelevant(sfa
.src_obj
))
403 // we don't? bail out
407 if (FrobWouldPickup(&sfa
)) {
408 // FrobInstantExecute will send two acks:
410 // Ask frob to tell us when it's done:
411 sfa
.flags
|= FROBFLG_RETURN_RECEIPT
;
413 if (sfa
.src_obj
!= OBJ_NULL
) {
414 FrobInstantExecute(&sfa
);
418 // for DELETE frob bit
419 BOOL
DPCInvRemObj(ObjID o
)
426 if (DPCInvFindObjSlot(victim, &x, &y))
427 DPCInvForceObj(x,y,OBJ_NULL);
429 IObjectSystem* pOS = AppGetObj(IObjectSystem);
430 pOS->Destroy(victim);
437 // for MOVE from world, puts obj on cursor
439 BOOL
DPCInvTakeObjFromWorld(ObjID o
, ObjID owner
)
441 AutoAppIPtr(ContainSys
);
442 ObjID container
= pContainSys
->GetContainer(o
);
443 if (IsAPlayer(container
)) {
444 // We don't count players as containers for frob purposes
445 container
= OBJ_NULL
;
448 // Check for raceway conditions: has someone else already picked up this
449 // object, or otherwise taken it over?
452 // Make sure it's not contained by something
453 if (container
== OBJ_NULL
)
455 // The object isn't ours to give away...
456 DPCSendFrobPickup(OBJ_NULL
, owner
, OBJ_NULL
);
461 AutoAppIPtr(ObjectNetworking
);
462 AutoAppIPtr(NetManager
);
463 if (pNetManager
->Networking() && !pObjectNetworking
->ObjHostedHere(o
))
465 DPCSendFrobPickup(OBJ_NULL
, owner
, OBJ_NULL
);
469 // If we've borrowed this object from the world, stop worrying about
470 // that. Otherwise, deregistering it will return the object
472 PhysNetDiscardBorrow(o
);
473 ObjSetHasRefs(o
,FALSE
);
474 PhysDeregisterModel(o
);
475 DPCSendFrobPickup(o
, owner
, container
);
477 // Finally, remove the thing from the container locally, so that we
478 // will decline any further attempts to frob it:
479 if (container
!= OBJ_NULL
)
480 pContainSys
->Remove(container
, o
);
486 // not a supported notion in Deep Cover
487 BOOL
DPCInvThrowBackToWorld(ObjID o
, ObjID src
)
492 // when the object should be used as a tool cursor
493 BOOL
DPCInvToolCursor(ObjID o
)
498 void DPCFrobsysInit(void)
500 frobInvRemObj
= DPCInvRemObj
;
501 frobInvTakeObjFromWorld
= DPCInvTakeObjFromWorld
;
502 frobInvThrowBackToWorld
= DPCInvThrowBackToWorld
;
503 frobInvToolCursor
= DPCInvToolCursor
;
504 frobAcknowledge
= DPCFrobAcknowledge
;
506 g_pFrobPickupMsg
= new cNetMsg(&sFrobPickupDesc
);
507 g_pGiveObjToPlayerMsg
= new cNetMsg(&sGiveObjToPlayerDesc
);
510 void DPCFrobsysTerm(void)
512 delete g_pFrobPickupMsg
;
513 delete g_pGiveObjToPlayerMsg
;