Linux makefiles
[canaan.git] / prj / cam / src / shock / shkhrm.cpp
bloba2d95c6566bd197e69903bbe4df3c15145854772
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/shock/shkhrm.cpp,v 1.55 2000/02/19 13:25:26 toml Exp $
8 #include <2d.h>
9 #include <appagg.h>
10 #include <mprintf.h>
11 #include <math.h>
13 #include <resapi.h>
14 #include <appsfx.h>
15 #include <playrobj.h>
16 #include <gamestr.h>
17 #include <rand.h>
18 #include <schema.h>
19 #include <scrptapi.h>
20 #include <simtime.h>
21 #include <cfgdbg.h>
22 #include <contain.h>
24 #include <shkhrm.h>
25 #include <shkscrm.h>
26 #include <shkovrly.h>
27 #include <shkovcst.h>
28 #include <shkutils.h>
29 #include <shkplayr.h>
30 #include <shkplcst.h>
31 #include <shktrcst.h>
32 #include <shktrait.h>
33 #include <shkimcst.h>
34 #include <shkprop.h>
35 #include <shkinv.h>
36 #include <shkobjst.h>
37 #include <gunapi.h>
38 #include <gunprop.h>
39 //#include <shkgun.h>
40 #include <shkmfddm.h>
41 #include <shkiftul.h>
42 #include <shkparam.h>
43 #include <shkpsapi.h>
44 #include <shktrcst.h>
45 #include <shkincst.h>
46 #include <shkplprp.h>
47 #include <shkpsipr.h>
49 // ui library not C++ ized properly yet
50 extern "C" {
51 #include <event.h>
52 #include <gadbox.h>
53 #include <gadblist.h>
54 #include <gadbutt.h>
55 #include <memall.h>
56 #include <dbmem.h> // must be last header!
59 #define NUM_HRM_MODES 3
61 static IRes *gBackHnd[3];
62 static IRes *gNodeHnd[4];
63 static IRes *gModeHnd[4][3];
64 static IRes *gBarHnd[2];
66 static Rect full_rect = {{LMFD_X, LMFD_Y}, {LMFD_X + LMFD_W, LMFD_Y + LMFD_H}};
67 static Rect close_rect = {{163,8},{163 + 20, 8 + 21}};
69 static LGadButton close_button;
70 static DrawElement close_elem;
71 static IRes *close_handles[2];
72 static grs_bitmap *close_bitmaps[4];
74 #define DOIT_X 157
75 #define DOIT_Y 232
77 static Rect doit_rect = {{157,232},{157 + 19, 232 + 55}};
78 static LGadButton doit_button;
79 static DrawElement doit_elem;
80 static IRes *doit_handles[2];
81 static grs_bitmap *doit_bitmaps[4];
83 static IRes *reset_handle;
85 static int gHRMMode = 0;
87 static uint gHRMFlags = 0;
89 #define MAX_JARGON_LINES 12
90 static char gJargonLines[MAX_JARGON_LINES][255];
91 static char gJargonText[1024];
92 static int gJargonNum;
93 static int gJargonTeletype;
94 static tSimTime gJargonTime;
96 #define MATRIX_X 5
97 #define MATRIX_Y 4
99 typedef enum
101 kHRMModeNormal,
102 kHRMModeLose,
103 kHRMModeWin,
104 kHRMModeUnpaid,
105 kHRMModeUnwinnable,
106 } eHRMGameMode;
108 eHRMGameMode gHRMGameMode;
110 typedef enum
112 kHRMStateFree = 0,
113 kHRMStateLit = 1,
114 kHRMStateDead = 2,
115 kHRMStateMine = 3,
116 kHRMStateEmpty = 4,
117 } eHRMState;
119 static char *nodenames[] = { "", "hrmon","hrmburn","hrmmine" };
120 static char *postfixes[] = { "H","R","M" };
121 static char *modenames[] = { "lose","win","pay","fail" };
122 static char *backnames[] = { "hack", "repair", "modify", };
123 static char *barnames[] = { "hrmbarh", "hrmbarv", };
125 static eHRMState gHRMState[MATRIX_X][MATRIX_Y];
127 static int gHRMBoards[NUM_HRM_MODES][MATRIX_Y][MATRIX_X] =
129 // hack
131 {4, 4, 0, 0, 0,},
132 {0, 0, 0, 4, 0,},
133 {0, 4, 0, 0, 0,},
134 {0, 0, 0, 4, 4,},
137 // repair
139 {4, 0, 0, 0, 4,},
140 {4, 0, 0, 0, 4,},
141 {4, 0, 0, 0, 4,},
142 {4, 0, 0, 0, 4,},
145 // modify
147 {4, 0, 0, 0, 0,},
148 {4, 0, 4, 0, 4,},
149 {4, 0, 4, 0, 4,},
150 {0, 0, 0, 0, 4,},
154 // okay, I admit this is getting hideous
155 BOOL gHRMPsi = FALSE;
156 int gHRMBonus = 0;
158 static ITechInfoProperty *hrm_props[NUM_HRM_MODES];
160 typedef enum
162 kHRMFlagNone = 0x0,
163 kHRMFlagUseINT = 0x1,
164 } eHRMFlags;
166 typedef enum
168 kHRMResultNone = 0x0,
169 kHRMResultWin = 0x1,
170 kHRMResultLoss = 0x2,
171 } eHRMResult;
173 #define TEXT_X 15
174 #define TEXT_Y 12 // goal
175 #define TEXT_Y2 180 // jargon
176 #define TEXT_W 137
177 #define JARGON_H 100
178 #define TELETYPE_SPEED 10
180 //--------------------------------------------------------------------------------------
181 void JargonClear()
183 int i;
184 for (i=0; i < MAX_JARGON_LINES; i++)
186 strcpy(gJargonLines[i],"");
188 strcpy(gJargonText,"");
189 gJargonNum = 0;
190 gJargonTime = 0;
192 //--------------------------------------------------------------------------------------
193 void JargonAdd(char *text)
195 BOOL reorg = FALSE;
196 int i,h;
198 h = gr_font_string_height(gShockFont, gJargonText);
199 while ((gJargonNum == MAX_JARGON_LINES) || (h > JARGON_H))
201 //ConfigSpew("hrm_spew",("removing old line\n"));
202 reorg = TRUE;
203 // copy everything down by one
204 for (i=0; i < MAX_JARGON_LINES - 1; i++)
205 strcpy(gJargonLines[i],gJargonLines[i+1]);
207 // reset pointer back one
208 gJargonNum--;
210 strcpy(gJargonText,"");
211 for (i=0; i < gJargonNum; i++)
213 strcat(gJargonText,gJargonLines[i]);
215 gr_font_string_wrap(gShockFont, gJargonText, TEXT_W);
216 h = gr_font_string_height(gShockFont, gJargonText);
219 tSimTime simtime = GetSimTime();
220 if (gJargonTime == 0)
222 gJargonTime = simtime - (strlen(gJargonText) * TELETYPE_SPEED);
223 //ConfigSpew("hrm_spew",("resetting jargontime to %d\n",gJargonTime));
226 strcpy(gJargonLines[gJargonNum],text);
227 gJargonNum++;
228 ConfigSpew("hrm_spew",("adding text: %s",text));
230 // reassemble main text
231 gr_font_string_unwrap(gJargonText);
232 strcat(gJargonText,gJargonLines[gJargonNum-1]);
233 gr_font_string_wrap(gShockFont, gJargonText, TEXT_W);
235 //--------------------------------------------------------------------------------------
236 static void ResetBoard(void)
238 int x,y;
239 for (x = 0; x < MATRIX_X; x++)
241 for (y = 0; y < MATRIX_Y; y++)
243 gHRMState[x][y] = (eHRMState)gHRMBoards[gHRMMode][y][x]; // yes, this is reversed!
247 //--------------------------------------------------------------------------------------
248 // actually resolve the effect!
250 static void ShockHRMTriggerEffect(eHRMResult result)
252 uint flags = kHRMFlagNone;
254 ObjID o = ShockOverlayGetObj();
255 ObjID plr = PlayerObject();
257 AutoAppIPtr(ShockPlayer);
258 AutoAppIPtr(ScriptMan);
260 char temp[255];
261 char name[255];
262 sprintf(name,"%sResult",backnames[gHRMMode]);
263 ShockStringFetch(temp,sizeof(temp),name,"hrm",result);
264 if (strlen(temp) > 0)
265 ShockOverlayAddText(temp,DEFAULT_MSG_TIME);
267 // no effect, then just reset the board
268 // maybe this should just lock out input and
269 // force the player to reset the board?
270 if (result == kHRMResultNone)
272 //ResetBoard();
273 gHRMGameMode = kHRMModeUnwinnable;
274 // feedback
275 //SchemaPlay((Label *)"login",NULL);
276 return;
279 switch (gHRMMode)
281 case 0: // hack
282 if (result == kHRMResultWin)
284 // send a "done hacking" message to the object
285 sScrMsg msg(o,"HackSuccess");
286 // We want to run this script locally, even if we're a client:
287 msg.flags |= kSMF_MsgSendToProxy;
288 pScriptMan->SendMessage(&msg);
289 SchemaPlay((Label *)"hack_success",NULL);
291 else
293 ObjSetObjState(o,kObjStateBroken);
294 SchemaPlay((Label *)"hack_critical",NULL);
296 // break it
297 sScrMsg msg(o,"HackCritfail");
298 msg.flags |= kSMF_MsgPostToOwner;
299 pScriptMan->SendMessage(&msg);
302 break;
303 case 1: // repair
304 if (result == kHRMResultWin)
306 ObjSetObjState(o,kObjStateNormal);
308 // improve it's condition as well, if it is a weapon
309 if (ObjHasGunState(o))
311 float cond = GunGetCondition(o);
312 cond = cond + 10;
313 if (cond > 100) cond = 100;
314 GunSetCondition(o,cond);
317 SchemaPlay((Label *)"hack_success",NULL);
319 else
321 // destroy it!!
323 // okay, is this an equipped item? If so, we need to unequip it
324 AutoAppIPtr(ContainSys);
325 eContainType ctype = pContainSys->IsHeld(PlayerObject(),o);
326 if (ctype != ECONTAIN_NULL)
328 pShockPlayer->Equip(PlayerObject(),(ePlayerEquip)(ctype - SHOCKCONTAIN_PDOLLBASE), OBJ_NULL, FALSE);
331 //ObjSetObjState(o,kObjStateDestroyed);
332 AutoAppIPtr(ObjectSystem);
333 pObjectSystem->Destroy(o);
336 SchemaPlay((Label *)"hack_critical",NULL);
338 break;
339 case 2: // modify
340 if (result == kHRMResultWin)
342 int modlevel = GunGetModification(o);
343 if (modlevel < 2)
345 GunSetModification(o, modlevel + 1);
346 SchemaPlay((Label *)"hack_success",NULL);
349 else
351 // break it
352 ObjSetObjState(o,kObjStateBroken);
353 ShockInvRefresh();
354 SchemaPlay((Label *)"hack_critical",NULL);
356 break;
359 ShockInvRefresh();
361 if (result == kHRMResultWin)
362 gHRMGameMode = kHRMModeWin;
363 else
364 gHRMGameMode = kHRMModeLose;
366 //--------------------------------------------------------------------------------------
367 static eTechSkills FindSkill()
369 eTechSkills useskill;
370 switch(gHRMMode)
372 case 0: useskill = kTechHacking; break;
373 case 1: useskill = kTechRepair; break;
374 case 2: useskill = kTechModify; break;
375 default:
376 Warning(("FindSkill: invalid HRM mode %d!\n",gHRMMode));
377 useskill = kTechHacking;
378 break;
380 return(useskill);
382 //--------------------------------------------------------------------------------------
383 #define BASE_COST 1
384 static int FindCost()
386 sTechInfo *ti;
387 float retval;
388 float factor;
389 ObjID o = ShockOverlayGetObj();
391 if (!hrm_props[gHRMMode]->Get(o,&ti))
392 factor = 1.0;
393 else
394 factor = ti->m_cost;
396 retval = BASE_COST * factor;
398 AutoAppIPtr(ShockPlayer);
399 if ((gHRMMode == 2) && pShockPlayer->HasTrait(PlayerObject(),kTraitTinker))
400 retval = retval / 2;
403 // psi only costs half as much
404 // this removed 6/17/99 as retuning -- Xemu
405 if (gHRMPsi)
406 retval = retval / 2;
409 if (retval < 1)
410 retval = 1;
412 return(retval);
414 //--------------------------------------------------------------------------------------
415 static bool PayNanites()
417 int cost;
418 ObjID plr = PlayerObject();
419 AutoAppIPtr(ShockPlayer);
421 BOOL pay = TRUE;
423 if (pay)
425 cost = FindCost();
426 if (!gHRMPsi)
428 if (ShockInvNaniteTotal() < cost)
430 SchemaPlay((Label *)"login",NULL);
432 char temp[255];
433 ShockStringFetch(temp,sizeof(temp),"NoNoNanites","misc");
434 ShockOverlayAddText(temp,DEFAULT_MSG_TIME);
435 return(FALSE);
438 ShockInvPayNanites(cost);
440 else
442 AutoAppIPtr(PlayerPsi);
443 int psipoints = pPlayerPsi->GetPoints();
445 if (psipoints < cost)
447 char temp[255];
448 ShockStringFetch(temp,sizeof(temp),"NoNoPsi","misc");
449 ShockOverlayAddText(temp,DEFAULT_MSG_TIME);
450 return(FALSE);
453 pPlayerPsi->SetPoints(psipoints - cost);
457 return(TRUE);
459 //--------------------------------------------------------------------------------------
460 int FindSoftLevel()
462 ObjID soft;
463 AutoAppIPtr(ShockPlayer);
465 switch(FindSkill())
467 case kTechHacking: soft = pShockPlayer->GetEquip(PlayerObject(), kEquipHack); break;
468 case kTechRepair: soft = pShockPlayer->GetEquip(PlayerObject(), kEquipRepair); break;
469 case kTechModify: soft = pShockPlayer->GetEquip(PlayerObject(), kEquipModify); break;
472 int softlevel = 0;
473 if (soft != OBJ_NULL)
474 gPropSoftwareLevel->Get(soft, &softlevel);
475 return(softlevel);
478 //--------------------------------------------------------------------------------------
479 static int HRMSkill()
481 int skillval, softlevel;
483 AutoAppIPtr(ShockPlayer);
484 if (gHRMPsi)
486 skillval = pShockPlayer->GetStat(kStatPsi);
487 if (PsiOverloaded(PlayerObject(),kPsiCyberHack))
488 skillval = skillval + 2;
489 skillval = (skillval + 1) / 2; // the +1 for rounding up
491 else
492 skillval = pShockPlayer->GetTechSkill(FindSkill());
493 // if (skillval >= MAX_SKILL_VAL)
494 // skillval = MAX_SKILL_VAL - 1;
495 if (pShockPlayer->HasImplant(PlayerObject(), kImplantTech) && !gHRMPsi)
496 skillval += 1;
498 if (!gHRMPsi)
500 softlevel = FindSoftLevel();
501 skillval = skillval + (softlevel);
503 skillval = skillval + gHRMBonus;
504 return(skillval);
507 //--------------------------------------------------------------------------------------
508 static int HRMStat()
510 AutoAppIPtr(ShockPlayer);
511 int statval;
512 if (gHRMPsi)
514 statval = pShockPlayer->GetStat(kStatPsi);
515 if (PsiOverloaded(PlayerObject(),kPsiCyberHack))
516 statval = statval + 2;
517 statval = (statval + 1) / 2;
519 else
520 statval = pShockPlayer->GetStat(kStatCyber);
521 return(statval);
525 if (!hrm_props[gHRMMode]->Get(o,&ti))
526 return;
528 *succeed = ti->m_success;
529 *critfail = ti->m_critfail;
531 AutoAppIPtr(ShockPlayer);
533 // relevant skill
534 skillval = HRMSkill();
535 statval = HRMStat();
537 //--------------------------------------------------------------------------------------
538 int FindChance(sTechInfo *ti)
540 int chance;
541 sHRMParams *params;
542 params = GetHRMParams();
544 chance = ti->m_success +
545 (HRMSkill() * params->m_skillSuccessBonus) +
546 (HRMStat() * params->m_statSuccessBonus);
547 if (chance > 85)
548 chance = 85;
549 return(chance);
551 //--------------------------------------------------------------------------------------
552 int FindMines(sTechInfo *ti)
554 int num_mines;
555 sHRMParams *params;
556 params = GetHRMParams();
558 num_mines = ti->m_critfail
559 - (HRMSkill() * params->m_skillCritfailBonus)
560 - (HRMStat() * params->m_statCritfailBonus);
561 return(num_mines);
563 static int BoardValue(int x, int y)
565 if ((x < 0) || (y < 0) || (x >= MATRIX_X) || (y >= MATRIX_Y))
566 return(0);
568 if (gHRMState[x][y] == kHRMStateLit)
569 return(1);
571 return(0);
573 //--------------------------------------------------------------------------------------
574 // board has changed at location X, see whether this causes a win
575 // or an un-winnable situation
576 static void EvaluateBoard(Point loc)
578 int x,y;
579 int num_free;
580 BOOL win = FALSE;
582 x = loc.x;
583 y = loc.y;
585 // this is kind of retarded, I admit
586 if (BoardValue(x-2,y) + BoardValue(x-1,y) + BoardValue(x,y) == 3)
587 win = TRUE;
588 if (BoardValue(x-1,y) + BoardValue(x,y) + BoardValue(x+1,y) == 3)
589 win = TRUE;
590 if (BoardValue(x,y) + BoardValue(x+1,y) + BoardValue(x+2,y) == 3)
591 win = TRUE;
592 if (BoardValue(x,y-2) + BoardValue(x,y-1) + BoardValue(x,y) == 3)
593 win = TRUE;
594 if (BoardValue(x,y-1) + BoardValue(x,y) + BoardValue(x,y+1) == 3)
595 win = TRUE;
596 if (BoardValue(x,y) + BoardValue(x,y+1) + BoardValue(x,y+2) == 3)
597 win = TRUE;
599 if (win)
601 // hey, yay, we win
602 ShockHRMTriggerEffect(kHRMResultWin);
604 char temp[255];
605 ShockStringFetch(temp,sizeof(temp),"JargonWin","jargon",gHRMMode);
606 JargonAdd(temp);
607 return;
610 // now count open squares
611 num_free = 0;
612 for (x=0; x < MATRIX_X; x++)
614 for (y = 0; y < MATRIX_Y; y++)
616 if ((gHRMState[x][y] == kHRMStateFree) || (gHRMState[x][y] == kHRMStateMine))
617 num_free++;
621 // if none left, game is unwinnable
622 if (num_free == 0)
624 ShockHRMTriggerEffect(kHRMResultNone);
627 //--------------------------------------------------------------------------------------
628 static void PlaceMines()
630 int i, num_mines, num_free, r;
631 int x,y,n;
632 BOOL placed;
633 sTechInfo *ti;
634 ObjID o = ShockOverlayGetObj();
636 if (!hrm_props[gHRMMode]->Get(o,&ti))
637 return;
639 // figure out how many mines to place
640 num_mines = FindMines(ti);
642 // how many blank spaces do we have?
643 num_free = 0;
644 for (x=0; x < MATRIX_X; x++)
646 for (y = 0; y < MATRIX_Y; y++)
648 if (gHRMState[x][y] == kHRMStateFree)
649 num_free++;
652 ConfigSpew("hrm_spew",("%d free spaces on board, %d mines\n",num_free,num_mines));
654 for (i=0; (i < num_mines) && (num_free > 0); i++)
656 // choose a random location
657 // try it
658 // if we have tried too many times, bail out
659 r = (Rand() % num_free) + 1;
660 num_free--;
662 // count up until we find the Nth free spot
663 // turn it into a mine square
664 n = 0;
665 placed = FALSE;
666 for (x=0; !placed && (x < MATRIX_X); x++)
668 for (y=0; !placed && (y < MATRIX_Y); y++)
670 if (gHRMState[x][y] == kHRMStateFree)
671 n++;
672 if (n == r)
674 ConfigSpew("hrm_spew",("Placing mine at %d, %d\n",x,y));
675 gHRMState[x][y] = kHRMStateMine;
676 placed = TRUE;
682 //--------------------------------------------------------------------------------------
683 static void PlayPiece(Point loc)
685 eHRMState state;
686 BOOL mined;
687 float diceval,chance;
688 sTechInfo *ti;
689 ObjID o;
690 char temp[255];
691 int r;
693 o = ShockOverlayGetObj();
695 state = gHRMState[loc.x][loc.y];
696 if ((state == kHRMStateLit) || (state == kHRMStateDead) || (state == kHRMStateEmpty))
698 // not a valid play, give feedback
699 SchemaPlay((Label *)"login",NULL);
700 return;
703 // are we playing on a "mine" square?
704 mined = (state == kHRMStateMine);
706 diceval = (Rand() % 10000) / 100.0F;
708 if (!hrm_props[gHRMMode]->Get(o,&ti))
709 return;
711 chance = FindChance(ti);
713 ConfigSpew("hrm_spew",("diceval %g vs success %g\n",diceval,chance));
715 if (diceval <= chance)
717 gHRMState[loc.x][loc.y] = kHRMStateLit;
718 if (!mined)
720 r = Rand() % 5;
721 ShockStringFetch(temp,sizeof(temp),"JargonLit","jargon",((r+1) * 10) + gHRMMode);
723 else
724 ShockStringFetch(temp,sizeof(temp),"JargonMineLit","jargon", gHRMMode);
725 JargonAdd(temp);
726 EvaluateBoard(loc);
728 else
730 if (mined)
732 ShockStringFetch(temp,sizeof(temp),"JargonMineBurnt","jargon", gHRMMode);
733 JargonAdd(temp);
734 ShockHRMTriggerEffect(kHRMResultLoss);
736 else
738 r = Rand() % 5;
739 ShockStringFetch(temp,sizeof(temp),"JargonBurnt","jargon",((r+1) * 10) + gHRMMode);
740 JargonAdd(temp);
742 gHRMState[loc.x][loc.y] = kHRMStateDead;
743 EvaluateBoard(loc);
748 //--------------------------------------------------------------------------------------
749 #define BOARD_X 16
750 #define BOARD_Y 48
751 #define BOARD_DX 30
752 #define BOARD_DY 36
753 #define MODE_X 13
754 #define MODE_Y 42
756 static Rect board_rect = {{BOARD_X,BOARD_Y},{BOARD_X + (BOARD_DX * MATRIX_X),BOARD_Y + (BOARD_DY * MATRIX_Y)}};
758 static void DrawBoard()
760 int x,y;
761 Point draw;
762 eHRMState state;
763 Rect r = ShockOverlayGetRect(kOverlayHRM);
765 for (x=0 ; x < MATRIX_X; x++)
767 for (y=0; y < MATRIX_Y; y++)
769 state = gHRMState[x][y];
770 if ((state != kHRMStateEmpty) && (state != kHRMStateFree))
772 draw.x = BOARD_X + (x * BOARD_DX) + r.ul.x;
773 draw.y = BOARD_Y + (y * BOARD_DY) + r.ul.y;
774 DrawByHandle(gNodeHnd[state],draw);
776 if (state == kHRMStateLit)
778 // are we right-connected?
779 if (x < MATRIX_X - 1)
781 if (gHRMState[x+1][y] == kHRMStateLit)
782 DrawByHandle(gBarHnd[0],draw);
784 if (y < MATRIX_Y - 1)
786 if (gHRMState[x][y+1] == kHRMStateLit)
787 DrawByHandle(gBarHnd[1],draw);
793 //--------------------------------------------------------------------------------------
794 static ePlayerEquip g_softslots[] = { kEquipHack, kEquipRepair, kEquipModify };
795 static ePlayerEquip FindSoftSlot()
797 int usemode;
798 if ((gHRMMode < 0) || (gHRMMode > 2))
800 Warning(("FindSoftSlot: asked for invalid slot %d!\n",gHRMMode));
801 usemode = 0;
803 else
804 usemode = gHRMMode;
805 return(g_softslots[usemode]);
807 //--------------------------------------------------------------------------------------
808 void ShockHRMInit(int )
810 int i,j;
811 char temp[255];
813 for (i=1; i < 4; i++)
815 sprintf(temp,"%s",nodenames[i]);
816 gNodeHnd[i] = LoadPCX(temp);
819 for (i=0; i < 2; i++)
821 gBarHnd[i] = LoadPCX(barnames[i]);
824 for (i=0; i < 4; i++)
826 for (j=0; j < 3; j++)
828 sprintf(temp,"%s%s",modenames[i],postfixes[j]);
829 gModeHnd[i][j] = LoadPCX(temp);
833 close_handles[0] = LoadPCX("closeoff"); // LoadPCX(temp);
834 close_handles[1] = LoadPCX("Closeon"); // LoadPCX(temp);
835 close_bitmaps[0] = (grs_bitmap *) close_handles[0]->Lock();
836 close_bitmaps[1] = (grs_bitmap *) close_handles[1]->Lock();
837 for (i = 2; i < 4; i++)
839 close_bitmaps[i] = close_bitmaps[0];
842 sprintf(temp,"start0");
843 doit_handles[0] = LoadPCX(temp);
844 sprintf(temp,"start1");
845 doit_handles[1] = LoadPCX(temp);
846 doit_bitmaps[0] = (grs_bitmap *) doit_handles[0]->Lock();
847 doit_bitmaps[1] = (grs_bitmap *) doit_handles[1]->Lock();
848 for (i = 2; i < 4; i++)
850 doit_bitmaps[i] = doit_bitmaps[0];
853 for (i=0; i < 3; i++)
854 gBackHnd[i] = LoadPCX(backnames[i]);
856 hrm_props[0] = gPropHackDiff;
857 hrm_props[1] = gPropRepairDiff;
858 hrm_props[2] = gPropModifyDiff;
860 reset_handle = LoadPCX("reset0");
862 SetLeftMFDRect(kOverlayHRM, full_rect);
865 //--------------------------------------------------------------------------------------
866 void ShockHRMTerm(void)
868 int i,j;
870 for (i=0; i < 3; i++)
871 SafeFreeHnd(&gBackHnd[i]);
873 for (i=0; i < 2; i++)
874 SafeFreeHnd(&gBarHnd[i]);
876 for (i=0; i < 4; i++)
878 SafeFreeHnd(&gNodeHnd[i]);
881 for (i=0; i < 4; i++)
882 for (j=0; j < 3; j++)
883 SafeFreeHnd(&gModeHnd[i][j]);
885 close_handles[0]->Unlock();
886 close_handles[1]->Unlock();
887 SafeFreeHnd(&close_handles[0]);
888 SafeFreeHnd(&close_handles[1]);
889 doit_handles[0]->Unlock();
890 doit_handles[1]->Unlock();
891 SafeFreeHnd(&doit_handles[0]);
892 SafeFreeHnd(&doit_handles[1]);
894 SafeFreeHnd(&reset_handle);
897 //--------------------------------------------------------------------------------------
898 static Rect help_rects[] = {
899 {{13,31},{48,65}},
900 {{49,31},{83,65}},
901 {{84,31},{118,65}},
902 {{119,31},{154,65}},
903 {{-1,-1},{-1,-1}}, //{{159,149},{159 + 19, 149 + 140}},
904 {{13,271},{154,288}},
905 {{13,248},{154,266}},
908 #define NUM_HELP_RECTS (sizeof(help_rects)/sizeof(Rect))
910 static void DrawHelpText(Point mpt)
912 //int i;
913 char temp[1024];
914 cStr str;
915 ObjID o,plr;
916 int modlevel;
917 //BOOL allow;
918 Rect r = ShockOverlayGetRect(kOverlayHRM);
920 o = ShockOverlayGetObj();
921 plr = PlayerObject();
922 AutoAppIPtr(GameStrings);
923 AutoAppIPtr(ShockPlayer);
925 strcpy(temp,"");
928 for (i=0; i < NUM_HELP_RECTS; i++)
930 if (RectTestPt(&help_rects[i], mpt))
932 allow = TRUE;
933 if (allow)
934 ShockStringFetch(temp,sizeof(temp),"HRMHelp","hrm",i);
935 break;
940 // also display the effect of the tech op
941 switch (gHRMMode)
943 case 0: // hack
944 str = pGameStrings->FetchObjString(o, PROP_HACKTEXT_NAME);
945 strcpy(temp,str);
946 break;
947 case 1: // repair
948 ShockStringFetch(temp,sizeof(temp),"RepairText","hrm");
949 break;
950 case 2: // modify
951 modlevel = GunGetModification(o);
952 // adjust if we've just won
953 if (gHRMGameMode == kHRMModeWin)
954 modlevel -= 1;
956 switch (modlevel)
958 case 0:
959 str = pGameStrings->FetchObjString(o, PROP_MODIFY1TEXT_NAME);
960 strcpy(temp,str);
961 break;
962 case 1:
963 str = pGameStrings->FetchObjString(o, PROP_MODIFY2TEXT_NAME);
964 strcpy(temp,str);
965 break;
966 case 2:
967 ShockStringFetch(temp,sizeof(temp),"ModifyResult3","misc");
968 break;
972 gr_font_string_wrap(gShockFont, temp, TEXT_W);
973 gr_set_fcolor(gShockTextColor);
974 gr_font_string(gShockFont, temp, TEXT_X + r.ul.x, TEXT_Y + r.ul.y);
976 // display jargon
977 tSimTime simtime = GetSimTime();
979 if (gJargonTime == 0)
981 gJargonTeletype = strlen(gJargonText);
983 else
985 gJargonTeletype = (simtime - gJargonTime) / TELETYPE_SPEED;
986 if (gJargonTeletype > strlen(gJargonText))
987 gJargonTime = 0;
990 //ConfigSpew("hrm_spew",("JargonTeletype = %d, strlen = %d\n",gJargonTeletype,strlen(gJargonText)));
991 strcpy(temp,gJargonText);
992 temp[gJargonTeletype] = '\0';
993 gr_font_string(gShockFont, temp, TEXT_X + r.ul.x, TEXT_Y2 + r.ul.y);
995 int chance;
996 sTechInfo *ti;
997 if (hrm_props[gHRMMode]->Get(o,&ti))
999 chance = FindChance(ti);
1000 sprintf(temp,"%d%%",100 - chance);
1001 gr_font_string(gShockFont, temp, 14 + r.ul.x, 49 + r.ul.y);
1004 //--------------------------------------------------------------------------------------
1005 #define COST_X 128
1006 #define COST_Y 161
1007 #define COST_W 48
1008 #define NANITE_X 90
1009 #define NANITE_Y 274
1010 #define NAME_X 15
1011 #define NAME_Y 13
1013 void ShockHRMDraw(void)
1015 Rect r = ShockOverlayGetRect(kOverlayHRM);
1016 ObjID plr;
1017 char temp[255]; // ,fmtstr[64];
1018 ObjID o = ShockOverlayGetObj();
1019 Point drawpt;
1021 AutoAppIPtr(ShockPlayer);
1022 AutoAppIPtr(GameStrings);
1023 plr = PlayerObject();
1025 // background
1026 DrawByHandle(gBackHnd[gHRMMode],r.ul);
1028 // draw the board state
1029 DrawBoard();
1030 if (gHRMGameMode != kHRMModeNormal)
1032 drawpt.x = MODE_X + r.ul.x;
1033 drawpt.y = MODE_Y + r.ul.y;
1034 DrawByHandle(gModeHnd[gHRMGameMode - 1][gHRMMode], drawpt);
1037 // draw in the main text
1038 Point mpt;
1039 mouse_get_xy(&mpt.x,&mpt.y);
1040 mpt.x -= r.ul.x;
1041 mpt.y -= r.ul.y;
1042 DrawHelpText(mpt);
1045 // short name up top
1046 if (ObjHasObjShortName(o))
1048 cStr str;
1049 str = pGameStrings->FetchObjString(o,PROP_OBJSHORTNAME_NAME);
1050 strcpy(temp,str);
1051 gr_font_string(gShockFont,temp,r.ul.x + NAME_X, r.ul.y + NAME_Y);
1054 // and how many nanites we actually have
1055 if (gHRMPsi)
1056 strcpy(temp,"0");
1057 else
1058 sprintf(temp,"%d",ShockInvNaniteTotal());
1060 gr_font_string(gShockFont,temp,NANITE_X + r.ul.x, NANITE_Y + r.ul.y);
1063 // draw in the cost at the bottom
1064 //ShockStringFetch(fmtstr,sizeof(fmtstr),"Cost","hrm");
1065 sprintf(temp,"%d",FindCost());
1066 short w;
1067 w = gr_font_string_width(gShockFont, temp);
1068 gr_font_string(gShockFont,temp,COST_X + r.ul.x + ((COST_W - w) / 2),COST_Y + r.ul.y);
1070 // draw in the reset button
1071 if ((gHRMGameMode != kHRMModeWin) && (gHRMGameMode != kHRMModeLose))
1073 //LGadDrawBox(VB(&doit_button), NULL);
1074 Point pt;
1075 pt.x = r.ul.x + DOIT_X;
1076 pt.y = r.ul.y + DOIT_Y;
1077 if (gHRMGameMode == kHRMModeUnpaid)
1078 DrawByHandle(doit_handles[0],pt);
1079 else
1080 DrawByHandle(reset_handle,pt);
1083 // close button
1084 LGadDrawBox(VB(&close_button),NULL);
1086 //--------------------------------------------------------------------------------------
1087 bool ShockHRMHandleMouse(Point pt)
1089 float x,y;
1090 Point loc;
1091 if (RectTestPt(&board_rect, pt))
1093 // all these casts are probably excessive, but better safe than sorry
1094 x = (float)(pt.x - board_rect.ul.x) / (float)BOARD_DX;
1095 y = (float)(pt.y - board_rect.ul.y) / (float)BOARD_DY;
1096 // okay, now "round" so that we get the closest hit
1097 // the zany constant is because the node itself takes up about half the
1098 // size, so the remaining intervening space wants to be split in half
1099 loc.x = floor(x + 0.25);
1100 loc.y = floor(y + 0.25);
1101 ConfigSpew("hrm_spew",("piece loc %d, %d\n",loc.x,loc.y));
1102 if ((loc.x < 0) || (loc.y < 0) || (loc.x >= MATRIX_X) || (loc.y >= MATRIX_Y))
1103 return(TRUE);
1105 if (gHRMGameMode == kHRMModeNormal)
1107 SchemaPlay((Label *)"hacking",NULL);
1108 PlayPiece(loc);
1111 return(TRUE);
1113 //--------------------------------------------------------------------------------------
1114 void ShockHRMDisplay(ObjID o, int mode, BOOL use_psi, int bonus)
1116 if (ShockOverlayCheck(kOverlayHRM))
1117 ShockOverlayChange(kOverlayHRM, kOverlayModeOff);
1119 gHRMMode = mode;
1120 gHRMPsi = use_psi;
1121 gHRMBonus = bonus;
1122 gHRMGameMode = kHRMModeUnpaid;
1124 // check for skill zero and terminate
1125 int skillval;
1126 ObjID plr;
1127 AutoAppIPtr(ShockPlayer);
1128 plr = PlayerObject();
1130 if (!gHRMPsi)
1132 skillval = pShockPlayer->GetTechSkill(FindSkill());
1135 if (skillval == 0)
1137 char errmsg[255];
1138 ShockStringFetch(errmsg, sizeof(errmsg), "notechskill", "hrm", mode);
1139 ShockOverlayAddText(errmsg, DEFAULT_MSG_TIME);
1140 return; // dont even open the MFD
1144 sTechSkills *req;
1145 int reqval;
1146 if (g_ReqTechProperty->Get(o,&req))
1147 reqval = req->m_tech[FindSkill()];
1148 else
1149 reqval = 1;
1150 if (gHRMMode == kTechModify)
1152 int modlevel = GunGetModification(o);
1153 // second modification is harder
1154 if (modlevel == 1)
1155 reqval = reqval + 2;
1157 if (skillval < reqval)
1159 char errmsg[255],temp[255];
1160 ShockStringFetch(errmsg, sizeof(errmsg), "techminskill", "hrm", mode);
1161 sprintf(temp,errmsg,reqval);
1162 ShockOverlayAddText(temp, DEFAULT_MSG_TIME);
1163 return; // dont even open the MFD
1166 // don't require softs anymore
1168 ObjID softobj;
1169 softobj = pShockPlayer->GetEquip(plr, FindSoftSlot());
1170 if (softobj == OBJ_NULL)
1172 char errmsg[255];
1173 ShockStringFetch(errmsg, sizeof(errmsg), "notechsoft", "hrm", mode);
1174 ShockOverlayAddText(errmsg, DEFAULT_MSG_TIME);
1175 return; // dont even open the MFD
1180 // if we are modifying but our weapon is already at max modification,
1181 // just give some feedback text
1182 if (gHRMMode == 2)
1184 int modlevel = GunGetModification(o);
1185 char errmsg[255];
1186 switch (modlevel)
1188 case 2:
1189 ShockStringFetch(errmsg, sizeof(errmsg), "ModifyResult3", "hrm");
1190 ShockOverlayAddText(errmsg, DEFAULT_MSG_TIME);
1191 return; // dont even open the MFD
1193 // these cases handle poking in the right difficulty property
1194 case 1:
1195 hrm_props[2] = gPropModify2Diff;
1196 break;
1197 case 0:
1198 hrm_props[2] = gPropModifyDiff;
1199 break;
1203 if (gHRMPsi)
1204 ShockOverlaySetDist(kOverlayHRM, FALSE);
1205 else
1206 ShockOverlaySetDist(kOverlayHRM, TRUE);
1208 // okay, we've qualified so open the darned MFD
1209 ShockOverlayChange(kOverlayHRM, kOverlayModeOn);
1210 ShockOverlaySetObj(kOverlayHRM, o);
1212 // reset the board
1213 ResetBoard();
1214 // place the mines
1215 PlaceMines();
1217 // set up the initial jargon
1218 JargonClear();
1220 char temp[255],temp2[255];
1221 int r;
1222 int statval, softval;
1223 int basediff,chance,mines;
1224 int bonusval;
1225 sTechInfo *ti;
1227 if (!hrm_props[gHRMMode]->Get(o,&ti))
1228 return;
1230 r = Rand() % 3;
1232 sHRMParams *param;
1233 param = GetHRMParams();
1235 // base & final difficulty
1236 ShockStringFetch(temp2,sizeof(temp2),"JargonBaseDiff","jargon", gHRMMode);
1237 basediff = 100 - ti->m_success;
1238 sprintf(temp,temp2,basediff);
1239 JargonAdd(temp);
1242 if (!gHRMPsi)
1244 ShockStringFetch(temp2,sizeof(temp2),"JargonSkill","jargon", gHRMMode);
1245 skillval = pShockPlayer->GetTechSkill(FindSkill());
1246 bonusval = skillval * param->m_skillSuccessBonus;
1247 sprintf(temp,temp2,skillval,bonusval);
1248 JargonAdd(temp);
1250 ShockStringFetch(temp2,sizeof(temp2),"JargonStat","jargon", gHRMMode);
1251 statval = pShockPlayer->GetStat(kStatCyber);
1252 bonusval = statval * param->m_statSuccessBonus;
1253 sprintf(temp,temp2,statval,bonusval);
1254 JargonAdd(temp);
1256 ShockStringFetch(temp2,sizeof(temp2),"JargonSoft","jargon", gHRMMode);
1257 softval = FindSoftLevel();
1258 if (softval > 0)
1260 bonusval = (softval) * param->m_skillSuccessBonus;
1261 sprintf(temp,temp2,softval,bonusval);
1262 JargonAdd(temp);
1265 if (pShockPlayer->HasImplant(PlayerObject(), kImplantTech) && !gHRMPsi)
1267 ShockStringFetch(temp2,sizeof(temp),"JargonImplant","jargon", gHRMMode);
1268 bonusval = param->m_skillSuccessBonus;
1269 sprintf(temp,temp2,bonusval);
1270 JargonAdd(temp);
1273 if (gHRMBonus != 0)
1275 ShockStringFetch(temp2,sizeof(temp2),"JargonBonus","jargon", gHRMMode);
1276 bonusval = gHRMBonus * param->m_skillSuccessBonus;
1277 sprintf(temp,temp2,bonusval);
1278 JargonAdd(temp);
1281 else
1283 ShockStringFetch(temp2,sizeof(temp2),"JargonSkill","jargon", gHRMMode);
1284 skillval = HRMSkill();
1285 bonusval = skillval * param->m_skillSuccessBonus;
1286 sprintf(temp,temp2,skillval,bonusval);
1287 JargonAdd(temp);
1289 ShockStringFetch(temp2,sizeof(temp2),"JargonStat","jargon", gHRMMode);
1290 statval = HRMStat(); // pShockPlayer->GetStat(kStatPsi);
1291 bonusval = statval * param->m_statSuccessBonus;
1292 sprintf(temp,temp2,statval,bonusval);
1293 JargonAdd(temp);
1296 ShockStringFetch(temp2,sizeof(temp2),"JargonPsiBonus","jargon", gHRMMode);
1297 sprintf(temp,temp2,gHRMBonus);
1298 JargonAdd(temp);
1302 ShockStringFetch(temp2,sizeof(temp2),"JargonFinalDiff","jargon", gHRMMode);
1303 chance = 100 - FindChance(ti);
1304 sprintf(temp,temp2,chance);
1305 JargonAdd(temp);
1307 // mines
1308 mines = FindMines(ti);
1309 if (mines < 0)
1310 mines = 0;
1311 if (mines == 1)
1312 ShockStringFetch(temp2,sizeof(temp2),"JargonMinesOne","jargon", gHRMMode);
1313 else
1314 ShockStringFetch(temp2,sizeof(temp2),"JargonMines","jargon", gHRMMode);
1315 sprintf(temp,temp2,mines);
1316 JargonAdd(temp);
1318 //--------------------------------------------------------------------------------------
1319 static bool reset_cb(short action, void* data, LGadBox* vb)
1321 if (action != BUTTONGADG_LCLICK)
1322 return(FALSE);
1324 if ((gHRMGameMode == kHRMModeWin) || (gHRMGameMode == kHRMModeLose))
1325 return(TRUE);
1327 if (PayNanites())
1329 SchemaPlay((Label *)"start_hack",NULL);
1331 // reset the state of the board
1332 ResetBoard();
1333 // place the mines
1334 PlaceMines();
1335 gHRMGameMode = kHRMModeNormal;
1338 return(TRUE);
1341 //--------------------------------------------------------------------------------------
1342 static bool close_cb(short action, void* data, LGadBox* vb)
1344 if (action == BUTTONGADG_LCLICK)
1346 uiDefer(DeferOverlayClose,(void *)kOverlayHRM);
1348 return(TRUE);
1350 //--------------------------------------------------------------------------------------
1351 static void BuildInterfaceButtons(void)
1353 Rect r = ShockOverlayGetRect(kOverlayHRM);
1355 close_elem.draw_type = DRAWTYPE_BITMAPOFFSET;
1356 close_elem.draw_data = close_bitmaps;
1357 close_elem.draw_data2 = (void *)4; // should be 2 but hackery required
1359 LGadCreateButtonArgs(&close_button, LGadCurrentRoot(), close_rect.ul.x + r.ul.x, close_rect.ul.y + r.ul.y,
1360 RectWidth(&close_rect), RectHeight(&close_rect), &close_elem, close_cb, 0);
1362 doit_elem.draw_type = DRAWTYPE_BITMAPOFFSET;
1363 doit_elem.draw_data = doit_bitmaps;
1364 doit_elem.draw_data2 = (void *)4; // should be 2 but hackery required
1366 LGadCreateButtonArgs(&doit_button, LGadCurrentRoot(), doit_rect.ul.x + r.ul.x, doit_rect.ul.y + r.ul.y,
1367 RectWidth(&doit_rect), RectHeight(&doit_rect), &doit_elem, reset_cb, 0);
1370 //--------------------------------------------------------------------------------------
1371 static void DestroyInterfaceButtons(void)
1373 LGadDestroyBox(VB(&close_button),FALSE);
1374 LGadDestroyBox(VB(&doit_button),FALSE);
1376 //--------------------------------------------------------------------------------------
1377 void ShockHRMStateChange(int which)
1379 if (ShockOverlayCheck(which))
1381 // take down any plug-in that got us here
1382 ShockOverlayChange(kOverlayHRMPlug, kOverlayModeOff);
1383 BuildInterfaceButtons();
1385 else
1387 DestroyInterfaceButtons();
1390 //--------------------------------------------------------------------------------------
1391 int ShockFindTechType(ObjID obj)
1393 if (ObjGetObjState(obj) == kObjStateUnresearched)
1394 return(kTechResearch);
1396 if ((ObjGetObjState(obj) == kObjStateBroken) && (gPropRepairDiff->IsRelevant(obj)))
1397 return(kTechRepair);
1399 if (IsPlayerGun(obj) && gPropModifyDiff->IsRelevant(obj))
1400 return(kTechModify);
1402 if (gPropHackDiff->IsRelevant(obj))
1403 return(kTechHacking);
1405 return(-1);
1407 //--------------------------------------------------------------------------------------
1408 sOverlayFunc OverlayHRM = {
1409 ShockHRMDraw, // draw
1410 ShockHRMInit, // init
1411 ShockHRMTerm, // term
1412 ShockHRMHandleMouse, // mouse
1413 NULL, // dclick (really use)
1414 NULL, // dragdrop
1415 NULL, // key
1416 NULL, // bitmap
1417 "", // upschema
1418 "subpanel_cl", // downschema
1419 ShockHRMStateChange, // state
1420 NULL, // transparency
1421 TRUE, // distance
1422 TRUE, // needmouse
1423 0, // alpha
1424 NULL, // update func
1425 TRUE, // check contains?