Linux makefiles
[canaan.git] / prj / cam / src / deepc / engfeat / dpcfsys.cpp
blobc3e1f33fe890271cefa9658b42e61e3468e43bbf
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 #include <string.h>
8 #include <mprintf.h>
9 #include <config.h>
10 #include <cfgdbg.h>
12 #include <label.h>
13 #include <objtype.h>
14 #include <property.h>
15 //#include <frobbase.h>
16 #include <frobctrl.h>
17 #include <frobprop.h>
19 //#include <frobsys.h>
20 #include <scrptapi.h>
21 #include <playrobj.h>
22 #include <gamestr.h>
24 #include <appagg.h>
26 #include <resapi.h>
28 #include <netman.h>
29 #include <iobjnet.h>
30 #include <netmsg.h>
31 #include <phnet.h>
33 #include <linkman.h>
34 #include <relation.h>
36 #include <schema.h>
37 #include <psnd.h>
38 #include <appsfx.h>
39 #include <command.h>
40 #include <physapi.h>
41 #include <rendprop.h>
43 #include <combprop.h>
45 #include <contain.h>
46 #include <prcniter.h>
48 #include <dpcgame.h>
49 //#include <dpcscrpt.h>
50 #include <dpcpfiid.h>
51 #include <dpcovrly.h>
52 #include <dpcplayr.h>
53 #include <dpcinv.h>
54 #include <dpccurm.h>
55 #include <dpcutils.h>
56 #include <dpcnet.h>
57 #include <dpcfrob.h>
58 #include <dpcovcst.h>
59 #include <dpciface.h>
60 #include <dpccont.h>
61 #include <dpcprop.h>
62 #include <dpcobjst.h>
64 #include <physcast.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
72 // host.
73 static int gFrobsPending;
75 // Returns TRUE iff we are waiting for the host to respond to some
76 // frobs:
77 BOOL DPCFrobPending()
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)
86 gFrobsPending--;
89 //////////
91 // Networking Code
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
99 // in LoadCursor...
100 if (o == OBJ_NULL) {
101 ClearCursor();
102 DPC_cursor_mode = SCM_NORMAL;
103 } else {
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.
117 BOOL isAutoPickup;
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
122 // object...
123 char temp[255],temp2[64], text[255];
124 cStr str;
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)
132 int count;
133 if (gStackCountProp->Get(o,&count))
134 sprintf(temp2,str,count);
135 else
136 strcpy(temp2,str);
138 else
139 DPCStringFetch(temp2,sizeof(temp2),"NameUnresearched","research");
140 sprintf(text,temp,temp2);
141 DPCOverlayAddText(text,DEFAULT_MSG_TIME);
142 // Now pick it up...
143 DPCInvAddObj(PlayerObject(), o);
144 } else {
145 // It's an ordinary object
146 DPC_cursor_mode = SCM_NORMAL;
147 DPCInvLoadCursor(o);
150 // snap any "tripwire" links to the object
151 IRelation *pRel;
152 LinkID lid;
153 AutoAppIPtr(LinkManager);
154 pRel = pLinkManager->GetRelationNamed("Tripwire");
155 if (pRel->AnyLinks(LINKOBJ_WILDCARD,o))
157 lid = pRel->GetSingleLink(LINKOBJ_WILDCARD, o);
158 pRel->Remove(lid);
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 =
171 kNMF_None,
172 "FrobPickup",
173 "Frob Pickup Obj",
174 NULL,
175 handleFrobPickup,
176 // Can't have the assert here, because the object could be
177 // OBJ_NULL:
178 {{kNMPT_SenderObjID, kNMPF_AllowObjNull, "Obj"},
179 {kNMPT_GlobalObjID, kNMPF_AllowObjNull, "Container"},
180 {kNMPT_End}}
184 // Tell the client to put the given object onto its cursor
185 // Host code
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);
198 //////////
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!",
213 o, fromPlayer);
215 // Add feedback *before* picking it up, because picking the
216 // object up can potentially destroy it, if it's a combinable
217 // object...
218 char temp[255], text[255];
219 AutoAppIPtr(NetManager);
220 const char *fromName = pNetManager->GetPlayerName(fromPlayer);
221 const char *myName = pNetManager->GetPlayerName(PlayerObject());
222 char objName[128];
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);
231 // Now pick it up...
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);
240 } else {
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 =
252 kNMF_AppendSenderID,
253 "DPCGiveObj",
254 "Give Object To Player",
255 NULL,
256 handleGiveObjToPlayer,
257 {{kNMPT_ReceiverObjID, kNMPF_None, "Object"},
258 {kNMPT_End}}
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!",
266 obj);
268 if (obj == OBJ_NULL)
270 Warning(("Trying to give away OBJ_NULL!\n"));
271 return;
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));
280 return;
282 pObjectNetworking->ObjGiveWithoutObjID(obj, targetPlayer);
283 g_pGiveObjToPlayerMsg->Send(targetPlayer, obj);
285 // And now we're no longer holding it:
286 ClearCursor();
289 //////////
291 #define MAX_RAYCAST_OBJ 512
292 void DPCDoFrob(bool in_inv)
294 if (!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))
300 Location hit;
301 ObjID hit_obj;
302 ObjPos *p1, *p2;
303 int result;
304 ObjID objlist[MAX_RAYCAST_OBJ];
305 int n;
306 ObjID obj;
307 BOOL propval;
309 p1 = ObjPosGet(PlayerObject());
310 p2 = ObjPosGet(frobWorldSelectObj);
312 if ((p1 != NULL) && (p2 != NULL))
314 cConcreteIter iter(gPropBlockFrob);
315 n = 0;
316 iter.Start();
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))
323 objlist[n] = obj;
324 n++;
325 if (n == MAX_RAYCAST_OBJ)
327 Warning(("DPCDoFrob: Raycast obj limit exceeded!\n"));
328 break;
332 iter.Stop();
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);
357 sFrobActivate sfa;
358 sfa.frobber = PlayerObject();
359 sfa.ms_down = 100; // fakes
360 sfa.flags = 0;
361 sfa.src_obj = OBJ_NULL;
363 // support for inv-inv frobbing should go here
364 if (DPC_cursor_mode == SCM_DRAGOBJ) // USEOBJ)
366 // object on cursor
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);
373 else
375 sfa.dst_obj = frobInvSelectObj;
376 sfa.dst_loc = kFrobLocWorld;
377 sfa.src_obj = drag_obj;
378 sfa.src_loc = kFrobLocInv;
381 else
383 // normal world frob
384 sfa.dst_obj = OBJ_NULL;
385 if (in_inv)
387 sfa.src_obj = frobInvSelectObj;
388 sfa.src_loc = kFrobLocInv;
390 else
392 if (frobWorldSelectObj != OBJ_NULL)
393 sfa.src_obj = frobWorldSelectObj;
394 else
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
404 return;
407 if (FrobWouldPickup(&sfa)) {
408 // FrobInstantExecute will send two acks:
409 gFrobsPending += 2;
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)
421 return(TRUE);
423 ObjID victim = o;
424 int x,y;
426 if (DPCInvFindObjSlot(victim, &x, &y))
427 DPCInvForceObj(x,y,OBJ_NULL);
429 IObjectSystem* pOS = AppGetObj(IObjectSystem);
430 pOS->Destroy(victim);
431 SafeRelease(pOS);
433 return TRUE;
437 // for MOVE from world, puts obj on cursor
438 // Host code
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?
450 if (!ObjHasRefs(o))
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);
457 return(FALSE);
461 AutoAppIPtr(ObjectNetworking);
462 AutoAppIPtr(NetManager);
463 if (pNetManager->Networking() && !pObjectNetworking->ObjHostedHere(o))
465 DPCSendFrobPickup(OBJ_NULL, owner, OBJ_NULL);
466 return(FALSE);
469 // If we've borrowed this object from the world, stop worrying about
470 // that. Otherwise, deregistering it will return the object
471 // automatically:
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);
482 return(TRUE);
485 // for MOVE from inv
486 // not a supported notion in Deep Cover
487 BOOL DPCInvThrowBackToWorld(ObjID o, ObjID src)
489 return(TRUE);
492 // when the object should be used as a tool cursor
493 BOOL DPCInvToolCursor(ObjID o)
495 return(TRUE);
498 void DPCFrobsysInit(void)
500 frobInvRemObj = DPCInvRemObj;
501 frobInvTakeObjFromWorld = DPCInvTakeObjFromWorld;
502 frobInvThrowBackToWorld = DPCInvThrowBackToWorld;
503 frobInvToolCursor = DPCInvToolCursor;
504 frobAcknowledge = DPCFrobAcknowledge;
505 gFrobsPending = 0;
506 g_pFrobPickupMsg = new cNetMsg(&sFrobPickupDesc);
507 g_pGiveObjToPlayerMsg = new cNetMsg(&sGiveObjToPlayerDesc);
510 void DPCFrobsysTerm(void)
512 delete g_pFrobPickupMsg;
513 delete g_pGiveObjToPlayerMsg;