home *** CD-ROM | disk | FTP | other *** search
- /* Main combat routines for Dungeon Master's Familiar
- by James Gary
-
- Modification history:
-
- 6-26-88 Fixed size determination error in damage calculation
- 7-1-88 Added saving throws
- 7-1-88 Changed Attacker/Defender from temp records to cursors
- Previously editor changes not effective untill re-selection.
- 7-9-88 Changed saving throws from gadgets to Inovatools 1 pop-up
- menus
- 7-9-88 Added turning to pop-up menu
- 7-12-88 Modified message handler for new roller functions
- (See roller.c for more detail)
- */
-
- #include <exec/types.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <libraries/dos.h>
- #include <intuition/intuition.h>
- #include <clib/macros.h>
- #include "character.h"
- #include "dmf.h"
-
- extern struct Character characters[];
- int Attacker=0,Defender=0; /* cursors to att. & def. */
- struct Window *wG; /* Main combat window */
- struct MsgPort *MyPort; /* Use this because handling input from
- multiple windows */
-
- /* Cleric combat table */
- int ClericTable[21][8] = {
- {25, 23, 21, 20, 20, 20, 19 },
- {24, 22, 20, 20, 20, 19, 18 },
- {23, 21, 20, 20, 20, 18, 17 },
- {22, 20, 20, 20, 19, 17, 16 },
- {21, 20, 20, 20, 18, 16, 15 },
- {20, 20, 20, 19, 17, 15, 14 },
- {20, 20, 20, 18, 16, 14, 13 },
- {20, 20, 19, 17, 15, 13, 12 },
- {20, 20, 18, 16, 14, 12, 11 },
- {20, 19, 17, 15, 13, 11, 10 },
- {20, 18, 16, 14, 12, 10, 9 },
- {19, 17, 15, 13, 11, 9, 8 },
- {18, 16, 14, 12, 10, 8, 7 },
- {17, 15, 13, 11, 9, 7, 6 },
- {16, 14, 12, 10, 8, 6, 5 },
- {15, 13, 11, 9, 7, 5, 4 },
- {14, 12, 10, 8, 6, 4, 3 },
- {13, 11, 9, 7, 5, 3, 2 },
- {12, 10, 8, 6, 4, 2, 1 },
- {11, 9, 7, 5, 3, 1, 0 },
- {10, 8, 6, 4, 2, 0, -1 } };
-
- /* Fighter combat table */
- int FighterTable[21][11] = {
- {26, 25, 23, 21, 20, 20, 20, 18, 16, 14 },
- {25, 24, 22, 20, 20, 20, 19, 17, 15, 13 },
- {24, 23, 21, 20, 20, 20, 18, 16, 14, 12 },
- {23, 22, 20, 20, 20, 19, 17, 15, 13, 11 },
- {22, 21, 20, 20, 20, 18, 16, 14, 12, 10 },
- {21, 20, 20, 20, 19, 17, 15, 13, 11, 9 },
- {20, 20, 20, 20, 18, 16, 14, 12, 10, 8 },
- {20, 20, 20, 19, 17, 15, 13, 11, 9, 7 },
- {20, 20, 20, 18, 16, 14, 12, 10, 8, 6 },
- {20, 20, 19, 17, 15, 13, 11, 9, 7, 5 },
- {20, 20, 18, 16, 14, 12, 10, 8, 6, 4 },
- {20, 19, 17, 15, 13, 11, 9, 7, 5, 3 },
- {19, 18, 16, 14, 12, 10, 8, 6, 4, 2 },
- {18, 17, 15, 13, 11, 9, 7, 5, 3, 1 },
- {17, 16, 14, 12, 10, 8, 6, 4, 2, 0 },
- {16, 15, 13, 11, 9, 7, 5, 3, 1, -1 },
- {15, 14, 12, 10, 8, 6, 4, 2, 0, -2 },
- {14, 13, 11, 9, 7, 5, 3, 2, -1, -3 },
- {13, 12, 10, 8, 6, 4, 2, 1, -2, -4 },
- {12, 11, 9, 7, 5, 3, 1, 0, -3, -5 },
- {11, 10, 8, 6, 4, 2, 0, -1, -4, -6 } };
-
- /* Magic user combat table */
- int MagicTable[21][6] = {
- {26, 24, 21, 20, 20 },
- {25, 23, 20, 20, 20 },
- {24, 22, 20, 20, 19 },
- {23, 21, 20, 20, 18 },
- {22, 20, 20, 19, 17 },
- {21, 20, 20, 18, 16 },
- {20, 20, 20, 17, 15 },
- {20, 20, 19, 16, 14 },
- {20, 20, 18, 15, 13 },
- {20, 20, 17, 14, 12 },
- {20, 19, 16, 13, 11 },
- {20, 18, 15, 12, 10 },
- {19, 17, 14, 11, 9 },
- {18, 16, 13, 10, 8 },
- {17, 15, 12, 9, 7 },
- {16, 14, 11, 8, 6 },
- {15, 13, 10, 7, 5 },
- {14, 12, 9, 6, 4 },
- {13, 11, 8, 5, 3 },
- {12, 10, 7, 4, 2 },
- {11, 9, 6, 3, 1 } };
-
- /* Thief combat table */
- int ThiefTable[21][7] = {
- {26, 24, 21, 20, 20, 20 },
- {25, 23, 20, 20, 20, 19 },
- {24, 22, 20, 20, 20, 18 },
- {23, 21, 20, 20, 19, 17 },
- {22, 20, 20, 20, 18, 16 },
- {21, 20, 20, 19, 17, 15 },
- {20, 20, 20, 18, 16, 14 },
- {20, 20, 19, 17, 15, 13 },
- {20, 20, 18, 16, 14, 12 },
- {20, 20, 17, 15, 13, 11 },
- {20, 19, 16, 14, 12, 10 },
- {20, 18, 15, 13, 11, 9 },
- {19, 17, 14, 12, 10, 8 },
- {18, 16, 13, 11, 9, 7 },
- {17, 15, 12, 10, 8, 6 },
- {16, 14, 11, 9, 7, 5 },
- {15, 13, 10, 8, 6, 4 },
- {14, 12, 9, 7, 5, 3 },
- {13, 11, 8, 6, 4, 2 },
- {12, 10, 7, 5, 3, 1 },
- {11, 9, 6, 4, 2, 0 } };
-
- /* Monster combat table */
- int MonsterTable[21][13] = {
- {26, 25, 24, 23, 21, 20, 20, 20, 20, 19, 18, 17 },
- {25, 24, 23, 22, 20, 20, 20, 20, 19, 18, 17, 16 },
- {24, 23, 22, 21, 20, 20, 20, 20, 18, 17, 16, 15 },
- {23, 22, 21, 20, 20, 20, 20, 19, 17, 16, 15, 14 },
- {22, 21, 20, 20, 20, 20, 19, 18, 16, 15, 14, 13 },
- {21, 20, 20, 20, 20, 20, 18, 17, 15, 14, 13, 12 },
- {20, 20, 20, 20, 20, 19, 17, 16, 14, 13, 12, 11 },
- {20, 20, 20, 20, 19, 18, 16, 15, 13, 12, 11, 10 },
- {20, 20, 20, 20, 18, 17, 15, 14, 12, 11, 10, 9 },
- {20, 20, 20, 19, 17, 16, 14, 13, 11, 10, 9, 8 },
- {20, 20, 19, 18, 16, 15, 13, 12, 10, 9, 8, 7 },
- {20, 19, 18, 17, 15, 14, 12, 11, 9, 8, 7, 6 },
- {19, 18, 17, 16, 14, 12, 11, 10, 8, 7, 6, 5 },
- {18, 17, 16, 15, 13, 11, 10, 9, 7, 6, 5, 4 },
- {17, 16, 15, 14, 12, 10, 9, 8, 6, 5, 4, 3 },
- {16, 15, 14, 13, 11, 9, 8, 7, 5, 4, 3, 2 },
- {15, 14, 13, 12, 10, 8, 7, 6, 4, 3, 2, 1 },
- {14, 13, 12, 11, 9, 7, 6, 5, 3, 2, 1, 0 },
- {13, 12, 11, 10, 8, 6, 5, 4, 2, 1, 0, -1 },
- {12, 11, 10, 9, 7, 5, 4, 3, 1, 0, -1, -2 },
- {11, 10, 9, 8, 6, 5, 3, 2, 0, -1, -2, -3 } };
-
- /* Undead turning table */
- int TurnTable[13][10] = {
- {10, 7, 4, 0, 0,-1,-1,-2,-2,-2}, /* 0 => automatic turn */
- {13,10, 7, 0, 0,-1,-1,-2,-2,-2}, /*-1 => automatic death*/
- {16,13,10, 4, 0, 0,-1,-1,-1,-2}, /*-2 => auto death 7-12*/
- {19,16,13, 7, 4, 0, 0,-1,-1,-2},
- {20,19,16,10, 7, 4, 0, 0,-1,-1},
- {21,20,19,13,10, 7, 4, 0, 0,-1},
- {21,21,20,16,13,10, 7, 4, 0,-1},
- {21,21,21,20,16,13,10, 7, 4, 0},
- {21,21,21,21,20,16,13,10, 7, 0},
- {21,21,21,21,21,20,16,13,10, 4},
- {21,21,21,21,21,21,20,16,13, 7},
- {21,21,21,21,21,21,21,19,16,10},
- {21,21,21,21,21,21,21,20,19,13} };
-
- extern long IntuitionBase;
- extern long GfxBase;
- long MathBase;
- long LayersBase;
-
- /* Do saving throw */
- SaveRoll(num)
- int num;
- {
- int roll,needed,len;
- char buff[80];
-
- roll = random(20);
- needed = characters[Attacker].Saves[num];
- if (roll >= needed)
- len = sprintf(buff,"%15s needs %2d, rolls %2d, saved! ",
- characters[Attacker].Name,needed,roll);
- else
- len = sprintf(buff,"%15s needs %2d, rolls %2d, failed! ",
- characters[Attacker].Name,needed,roll);
- Move(wG->RPort,9,195);
- SetAPen(wG->RPort,1); /* Contrasting color for visibility*/
- Text(wG->RPort,buff,len);
- SetAPen(wG->RPort,3); /* Reset color */
- return(0);
- }
-
- /* Do undead turning */
- TurnRoll(row)
- int row;
- {
- int roll,needed,len,level,col=0;
- char buff[80];
-
- level = characters[Attacker].Level;
- if (level < 9)
- col = level - 1;
- else if (level < 14)
- col = 8;
- else if (level > 13)
- col = 9;
- roll = random(20);
- needed = TurnTable[row][col];
- if (needed == 21)
- len = sprintf(buff,"%15s needs %2d, rolls %2d, failed! ",
- characters[Attacker].Name,needed,roll);
- else if (needed == -1)
- len = sprintf(buff,"%15s kills %2d! ",
- characters[Attacker].Name,random(12));
- else if (needed == -2)
- len = sprintf(buff,"%15s kills %2d! ",
- characters[Attacker].Name,random(6)+6);
- else if (roll < needed)
- len = sprintf(buff,"%15s needs %2d, rolls %2d, failed! ",
- characters[Attacker].Name,needed,roll);
- else
- if (row < 12)
- len = sprintf(buff,"%15s needs %2d, rolls %2d, turned %2d ",
- characters[Attacker].Name,needed,roll,random(12));
- else
- len = sprintf(buff,"%15s needs %2d, rolls %2d, turned %2d ",
- characters[Attacker].Name,needed,roll,random(2));
-
- Move(wG->RPort,9,195);
- SetAPen(wG->RPort,1); /* Contrasting color for visibility*/
- Text(wG->RPort,buff,len);
- SetAPen(wG->RPort,3); /* Reset color */
- return(0);
- }
-
- /* Handle a pop-up menu event */
- void HandleMenu(num)
- USHORT num;
- {
- switch (ITEMNUM(num)) {
- case 0 : TurnRoll(SUBNUM(num));
- break;
- case 2 : SaveRoll(SUBNUM(num));
- break;
- }
- }
-
- /* Determine fighter to-hit number */
- fighter(level,ac)
- int level; /* Level of fighter */
- int ac; /* AC of defender */
- {
- int row,col;
-
- if (level <= 0) /* This mess determines proper row and column */
- col = 0; /* | */
- else /* | */
- col = (level + 1)/2; /* | (Advances by twos) */
- if (col > 9) /* | (up to column nine) */
- col = 9; /* | */
- row = 10 + ac; /* | (Ac 10 -> -10) */
- if (row < 0) /* | Handle AC's off table */
- row = 0; /* | */
- if (row > 19) /* | */
- row = 19; /* |_________________________________________*/
- return(FighterTable[row][col]);
- }
-
- /* Determine cleric to-hit number */
- cleric(level,ac)
- int level; /* Level of attacker */
- int ac; /* AC of defender */
- {
- int row,col;
-
- col = (level + 2)/3 - 1;
- if (col < 0)
- col = 0;
- if (col > 6)
- col = 6;
- row = 10 + ac;
- if (row < 0)
- row = 0;
- if (row > 19)
- row = 19;
- return(ClericTable[row][col]);
- }
-
- /* Determine thief to-hit number */
- thief(level,ac)
- int level; /* Level of thief */
- int ac; /* AC of defender */
- {
- int row,col;
-
- col = (level + 3)/4 -1;
- if (col < 0)
- col = 0;
- if (col > 5)
- col = 5;
- row = 10 + ac;
- if (row < 0)
- row = 0;
- if (row > 19)
- row = 19;
- return(ThiefTable[row][col]);
- }
-
- /* Determine magic user to-hit number */
- magic(level,ac)
- int level; /* Level of attacker */
- int ac; /* AC of defender */
- {
- int row,col;
-
- col = (level + 4)/5 - 1;
- if (col < 0)
- col = 0;
- if (col > 4)
- col = 4;
- row = 10 + ac;
- if (row < 0)
- row = 0;
- if (row > 19)
- row = 19;
- return(MagicTable[row][col]);
- }
-
- /* Determine monster to-hit number */
- monster(level,ac)
- int level; /* Level of monster */
- int ac; /* AC of defender */
- {
- int row,col;
-
- col = level - 1;
- if (col < 0)
- col = 0;
- if (col > 11)
- col = 11;
- row = 10 + ac;
- if (row < 0)
- row = 0;
- if (row > 19)
- row = 19;
- return(MonsterTable[row][col]);
- }
-
- /* User selected reverse gadget, so switch attacker and defender
- and call repeat */
- Reverse(gad)
- struct Gadget *gad;
- {
- int temp;
- int Repeat();
-
- temp = Attacker;
- Attacker = Defender;
- Defender = temp;
- Repeat(NULL);
- return(0);
- }
-
- /* User selected repeat gadget or selected defender, so handle combat */
- Repeat(gad)
- struct Gadget *gad;
- {
- int len,ToHit,Roll,NumDice,TypeDie,DamPlus,Damage,i;
- char buf[80]; /* to hold result string */
-
- switch(characters[Attacker].Job) { /* get proper to-hit number */
- case(FIGHTER) : ToHit = fighter(characters[Attacker].Level,characters[Defender].AC);
- break;
- case(CLERIC) : ToHit = cleric(characters[Attacker].Level,characters[Defender].AC);
- break;
- case(MAGICUSER) : ToHit = magic(characters[Attacker].Level,characters[Defender].AC);
- break;
- case(THIEF) : ToHit = thief(characters[Attacker].Level,characters[Defender].AC);
- break;
- case(MONSTER) : ToHit = monster(characters[Attacker].Level,characters[Defender].AC);
- break;
- }
-
- if (characters[Defender].Size == SMALL) { /* Adjust vars for small defender */
- ToHit += characters[Attacker].SmHitPlus;
- NumDice = characters[Attacker].SmNumDie;
- TypeDie = characters[Attacker].SmTypeDie;
- DamPlus = characters[Attacker].SmDamPlus;
- }
- else { /* Adjust vars for large defender */
- ToHit += characters[Attacker].LgHitPlus;
- NumDice = characters[Attacker].LgNumDie;
- TypeDie = characters[Attacker].LgTypeDie;
- DamPlus = characters[Attacker].LgDamPlus;
- }
-
- Roll = random(20); /* Roll dem bones! */
- Damage = 0;
- if (Roll >= ToHit) { /* Contact! */
- for (i=0;i<NumDice;i++)
- Damage += random(TypeDie);
- Damage += DamPlus;
- }
-
- len = sprintf(buf,"%15s vs. %15s needs %2d, rolls %2d, for %3d ",
- characters[Attacker].Name,characters[Defender].Name,ToHit,Roll,Damage);
- Move(wG->RPort,9,195);
- SetAPen(wG->RPort,1); /* Contrasting color for visibility*/
- Text(wG->RPort,buf,len);
- SetAPen(wG->RPort,3); /* Reset color */
- return(0);
- }
-
- /* Display character names on main window */
- PrintChars()
- {
- int len,row,col,i;
- char buf[20];
-
- i = 0;
- for (row=0; row < 15; row++) {
- for (col = 0; col < 4; col++) {
- len = sprintf(buf,"%15s",characters[i++].Name);
- Move(wG->RPort,3+160*col,10*row+18);
- Text(wG->RPort,buf,len);
- }
- }
- return(0);
- }
- void PrintOne(i,fp,bp)
- int i;
- UBYTE fp,bp;
- {
- int row,col,len;
- char buf[20];
-
- row = i/4;
- col = i%4;
- len = sprintf(buf,"%15s",characters[i].Name);
- SetAPen(wG->RPort,fp);
- SetBPen(wG->RPort,bp);
- Move(wG->RPort,3+160*col,10*row+18);
- Text(wG->RPort,buf,len);
- SetAPen(wG->RPort,3);
- SetBPen(wG->RPort,0);
- }
- USHORT quit_flag = FALSE;
-
- /* This is for the event handler */
- void quit(object)
- APTR object;
- {
- quit_flag = TRUE;
- return(0);
- }
-
-
- struct Window *OpenWindow();
- struct Screen *OpenScreen();
-
- /* User selected attacker with Left Mouse button, determine which */
- SetAttacker(x,y)
- int x,y;
- {
- int row,col,charnum;
-
- PrintOne(Attacker,3,0);
- row = (y-12)/10;
- col = (x/160);
- charnum = row*4+col;
- charnum = MAX(charnum,0); /* Make sure that */
- charnum = MIN(charnum,MAXCHARS-1); /* we are in range*/
- Attacker = charnum;
- PrintOne(Attacker,1,3);
- return(0);
- }
-
- /* User selected defender with Right Mouse button, determine which */
- SetDefender(x,y)
- int x,y;
- {
- int row,col,charnum;
-
- row = (y-12)/10;
- col = (x/160);
- charnum = row*4+col;
- charnum = MAX(charnum,0); /* Make sure that */
- charnum = MIN(charnum,MAXCHARS-1); /* we are in range */
- Defender = charnum;
- return(0);
- }
-
- /* The main program was adapted from PW's example program and contains
- some unused leftovers from that code. Sorry. */
- main()
- {
- UWORD code;
- ULONG class;
- APTR object;
- int x,y; /* for mouse button message */
-
- struct Gadget *gad;
- extern struct Window *MyWindow; /* Roller window */
- struct Window *win; /* Main combat window */
- struct RastPort *rpG;
- struct IntuiMessage *message; /* the message the IDCMP sends us */
- USHORT num;
- extern int Total;
- struct StringInfo *sinfo;
- long last;
-
- IntuitionBase = OpenLibrary("intuition.library", 0);
- if (IntuitionBase == NULL)
- {
- printf("intuition is not here. where are we?\n");
- goto cleanup1;
- }
- LayersBase = OpenLibrary("layers.library",0);
- GfxBase = OpenLibrary("graphics.library", 0);
- MathBase = OpenLibrary("mathffp.library",0);
-
- /* Must set up own port to handle input from multiple windows*/
- MyPort = (struct MsgPort *) CreatePort("CombatPort",0);
- wG = OpenWindow(&NewWindowStructure1); /* open the window */
- if ( wG == NULL )
- {
- printf ("open window failed\n");
- goto cleanup1;
- }
- wG->UserPort = MyPort; /* Attach to port*/
-
- /* To facilitate user port, no IDCMP were specified in NewWindow*/
- /* so add the ones we want now. */
- ModifyIDCMP(wG,MOUSEBUTTONS|GADGETDOWN|GADGETUP|CLOSEWINDOW);
-
- rpG = wG->RPort; /* get a rastport pointer for the window */
-
- InitChars(); /* Initialize character array*/
-
- PrintChars(); /* Display character names in main window */
-
- PrintOne(Attacker,1,0); /*Highlight Attacker*/
- #ifdef IntuiTextList1
- PrintIText(rpG,&IntuiTextList1,0,0); /* Print the text if there is
- any */
- #endif
-
- #ifdef BorderList1
- DrawBorder(rpG,&BorderList1,0,0); /* Draw the borders if there are
- any */
- #endif
-
- #ifdef ImageList1
- DrawImage(rpG,&ImageList1,0,0); /* Draw the images if there are any */
- #endif
-
- do {
- WaitPort(wG->UserPort);
- while( (message = (struct IntuiMessage *) GetMsg(wG->UserPort)) != NULL)
- {
- code = message->Code; /* MENUNUM */
- object = message->IAddress; /* Gadget */
- class = message->Class;
- x = message->MouseX;
- y = message->MouseY;
- win = message->IDCMPWindow;
- ReplyMsg(message); /* All good stuff is recorded, make Intuition :) */
-
- /* User did something, no figure out what */
- if (win == wG) { /* Main window event!*/
- if ( class == CLOSEWINDOW ) (quit_flag = TRUE);
- if (( class == GADGETDOWN ) ||
- (class == GADGETUP)) {
- if (object == (APTR) &ExtraGad) {
- num = PopUpMenu(wG,&Menu1);
- HandleMenu(num);
- }
- else
- HandleEvent(object);
- }
- if ( class == MOUSEBUTTONS ){
- if (code == SELECTUP)
- SetAttacker(x,y); /* Left button means attacker */
- if (code == MENUUP) {
- SetDefender(x,y); /* Right button means defender */
- Repeat(); /* Resolve combat */
- }
- }
- }
- else { /* Must be roller window!*/
- switch(class) {
- case CLOSEWINDOW: cleanup();
- break;
- case GADGETDOWN:
- case GADGETUP: gad = (struct Gadget *) object;
- switch((int)gad->GadgetID) {
- /* Gadget ID's : */ case 25:
- /* 25: UserNum */ sinfo = (struct StringInfo *)gad->SpecialInfo;
- /* 50: Again */ last = sinfo->LongInt;
- /* 75: ClearTotal*/ display(last);
- break;
- case 50: display(last);
- break;
- case 75: Total = 0;
- DisplayTotal();
- break;
- default: display((int)gad->GadgetID); /* Roll 'em */
- break;
- }
- break;
- default: cleanup();
- break;
- }
- }
- }
- } while (quit_flag == FALSE);
-
- cleanup3:
-
- cleanup2:
- wG->UserPort = NULL;
- CloseWindow(wG);
- cleanup();
- DeletePort(MyPort);
- cleanup1:
- if (MathBase != NULL) CloseLibrary(MathBase);
- if (GfxBase != NULL) CloseLibrary(GfxBase);
- if (LayersBase != NULL) CloseLibrary(LayersBase);
- if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
- return(0);
-
- }
-