|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 39442 (0x9a12) Types: TextFile Names: »combat.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Conquer/combat.c«
/*conquer : Copyright (c) 1988 by Ed Barlow. * I spent a long time writing this code & I hope that you respect this. * I give permission to alter the code, but not to copy or redistribute * it without my explicit permission. If you alter the code, * please document changes and send me a copy, so all can have it. * This code, to the best of my knowledge works well, but it is my first * 'C' program and should be treated as such. I disclaim any * responsibility for the codes actions (use at your own risk). I guess * I am saying "Happy gaming", and am trying not to get sued in the process. * Ed */ #include <math.h> #include "header.h" #include "data.h" #define MGKNUM 32 /* number of units possible in battle */ #define ATKR 2 #define DFND 1 #define NTRL 0 #define WIMP 3 extern FILE *fpmsg; extern FILE *fnews; extern short country; short retreatside; /* ATKR, DFND, or none (0) */ short retreatx; /* retreat x square */ short retreaty; /* retreat y square */ int unit[MGKNUM]; /*armynum*/ int owner[MGKNUM]; /*owner*/ int side[MGKNUM]; /*see definitions->1=units 2=unit*/ long troops[MGKNUM]; /*starting troops in army */ int xspot,yspot; /*location of battles*/ int anation; /*nation attacking in this fight*/ int dnation; /*one nation defending in this fight*/ /************************************************************************/ /* COMBAT() run all combat on the map */ /* for each sector, determine if armies in with attack mode */ /************************************************************************/ void combat() { register int i,j; char **fought; /* TRUE if already fought in sctr */ int temp,ctry; short armynum,nvynum; int valid; int count=0; fought = (char **) m2alloc(MAPX,MAPY,sizeof(char)); printf("Run Combat Routines\n"); fprintf(fnews,"4\tBATTLE SUMMARY STATISTICS\n"); /*for each nation, if in attack mode run a check*/ /* no sectors have been fought in yet */ for(i=0;i<MAPX;i++) for(j=0;j<MAPY;j++) fought[i][j]=FALSE; for(ctry=NTOTAL-1;ctry>0;ctry--) if(isactive(ntn[ctry].active)) { /*army combat*/ for(j=0;j<MAXARM;j++) if((ntn[ctry].arm[j].sold>0) &&(ntn[ctry].arm[j].stat>=ATTACK) &&(ntn[ctry].arm[j].stat<=SORTIE ||ntn[ctry].arm[j].stat>=NUMSTATUS) &&(fought[ntn[ctry].arm[j].xloc][ntn[ctry].arm[j].yloc]==0)){ /* someone can initiate combat in xspot,yspot */ xspot=ntn[ctry].arm[j].xloc; yspot=ntn[ctry].arm[j].yloc; fought[xspot][yspot]=TRUE; /*initialize matrix*/ for(temp=0;temp<MGKNUM;temp++){ unit[temp]=(-1); owner[temp]=(-1); side[temp]=NTRL; troops[temp]=0; } /*check all armies in sector and add to matrix*/ count=0; valid=FALSE; /*is valid,set matrix*/ for(country=0;country<NTOTAL;country++) if(isactive(ntn[country].active)) for(armynum=0;armynum<MAXARM;armynum++) if((ASOLD>0) &&(ASTAT!=SCOUT) &&(AXLOC==xspot) &&(AYLOC==yspot) &&(count<MGKNUM)) { if((country!=ctry) &&(ntn[ctry].dstatus[country]>HOSTILE)) { valid=TRUE; if( sct[xspot][yspot].owner==ctry ) { dnation=ctry; anation=country; } else if(( rand()%2==0 ) ||( sct[xspot][yspot].owner==country )){ anation=ctry; dnation=country; } else { dnation=ctry; anation=country; } } unit[count]=armynum; owner[count]=country; count++; } if(valid==TRUE) fight(); } /*navy combat*/ for(j=0;j<MAXNAVY;j++) if((ntn[ctry].nvy[j].warships!=0) &&(fought[ntn[ctry].nvy[j].xloc][ntn[ctry].nvy[j].yloc]==0) &&(sct[ntn[ctry].nvy[j].xloc][ntn[ctry].nvy[j].yloc].altitude==WATER)){ xspot=ntn[ctry].nvy[j].xloc; yspot=ntn[ctry].nvy[j].yloc; fought[xspot][yspot]=1; /*initialize matrix*/ for(temp=0;temp<MGKNUM;temp++){ unit[temp]=(-1); owner[temp]=(-1); side[temp]=NTRL; troops[temp]=0; } /*check all fleets in 2 sector range and add to matrix*/ count=0; valid=FALSE; /*is valid,set matrix*/ for(country=0;country<NTOTAL;country++) if(isactive(ntn[country].active)) for(nvynum=0;nvynum<MAXNAVY;nvynum++) if((NWSHP+NMSHP+NGSHP!=0) &&(abs(NXLOC-xspot)<=2) &&(abs(NYLOC-yspot)<=2) &&(sct[NXLOC][NYLOC].altitude==WATER) &&(count<MGKNUM)) { fought[NXLOC][NYLOC]=1; if((country!=ctry) &&(ntn[ctry].dstatus[country]>HOSTILE)){ valid=TRUE; anation=ctry; dnation=country; } unit[count]=nvynum; owner[count]=country; count++; } if(valid==TRUE) navalcbt(); } } free(fought); printf("\nall army and navy attacks completed\n"); } /* macro for owner, accounts for runaway indicator */ #define UOWNER(x) ((owner[(x)]<(-1))?(-owner[(x)]-1):(owner[(x)])) /************************************************************************/ /* FIGHT() - fight an individual battle given the three */ /* matricies global to this module */ /************************************************************************/ void fight() { int roll,strength,fortdam=FALSE; int odds; /* odds (asold/dsold) times 100 */ int done; int i,j,k; long asold=0,dsold=0; /*a's and d's total soldiers*/ long astr=0,dstr=0; /*a's and d's relative strength*/ long Aloss,Dloss; /*a's and d's total losses*/ int PAloss,PDloss; /*percent a and d loss*/ long loss; int abonus=0,dbonus=0; /* bonus aggregate */ long vampire=0; /* # non vamps deaded */ short nvamps=0; /* number of vampire armies */ /* determine who is attacker & who is on defenders side?*/ for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ if(owner[j]==anation) side[j]=ATKR; else if(owner[j]==dnation) side[j]=DFND; else if(ntn[anation].dstatus[owner[j]]==JIHAD) side[j]=DFND; else if(ntn[owner[j]].dstatus[anation]==JIHAD) side[j]=DFND; else if(ntn[anation].dstatus[owner[j]]==WAR) side[j]=DFND; else if(ntn[owner[j]].dstatus[anation]==WAR) side[j]=DFND; else if((ntn[owner[j]].dstatus[anation]==TREATY)&&(ntn[owner[j]].dstatus[dnation]>HOSTILE)) side[j]=ATKR; else if((ntn[owner[j]].dstatus[anation]==ALLIED)&&(ntn[owner[j]].dstatus[dnation]>HOSTILE)) side[j]=ATKR; } /*calculate number of troops and assign statuses */ asold=0; dsold=0; for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) { /* record troops for all units in sector */ troops[i]=ntn[owner[i]].arm[unit[i]].sold; if(((ntn[owner[i]].arm[unit[i]].unittyp == A_MERCENARY) ||(ntn[owner[i]].arm[unit[i]].unittyp == A_ORC) ||(ntn[owner[i]].arm[unit[i]].unittyp == A_GOBLIN)) &&( ntn[owner[i]].arm[unit[i]].stat < NUMSTATUS ) &&( rand()%100<15 )) { if( ispc(ntn[owner[i]].active)) { mailopen( owner[i] ); fprintf(fm,"Message to %s from Conquer\n",ntn[owner[i]].name); fprintf(fm,"\n Your %s Army %d Refuses to Fight\n", unittype[ntn[owner[i]].arm[unit[i]].unittyp], unit[i]); mailclose(); } retreatside = side[i]; fdxyretreat(); if((retreatx==xspot)&&(retreaty==yspot)){ /* move to capitol & kill 30% */ ntn[owner[i]].arm[unit[i]].xloc=ntn[owner[i]].capx; ntn[owner[i]].arm[unit[i]].yloc=ntn[owner[i]].capy; ntn[owner[i]].arm[unit[i]].sold*=7; ntn[owner[i]].arm[unit[i]].sold/=10; } else { /* retreat normally and kill 20% */ ntn[owner[i]].arm[unit[i]].sold*=8; ntn[owner[i]].arm[unit[i]].sold/=10; retreat( i ); } owner[i]=(-1-owner[i]); continue; } else if(side[i]==ATKR){ if((ntn[owner[i]].arm[unit[i]].stat!=RULE) &&( ntn[owner[i]].arm[unit[i]].stat!=TRADED) &&( ntn[owner[i]].arm[unit[i]].stat!=SCOUT)) { asold += ntn[owner[i]].arm[unit[i]].sold; } else { side[i]=NTRL; } /* sortie 20% bonus in odds */ if(ntn[owner[i]].arm[unit[i]].stat==SORTIE) asold += ntn[owner[i]].arm[unit[i]].sold/5; } else if(side[i]==DFND){ if(ntn[owner[i]].arm[unit[i]].stat!=RULE) { dsold += ntn[owner[i]].arm[unit[i]].sold; } } if((magic(owner[i],VAMPIRE)==TRUE) && (ntn[owner[i]].arm[unit[i]].unittyp==A_ZOMBIE)) nvamps++; } if(asold<=0) { printf("\nCombat aborted due to lack of attackers.\n"); return; } if( asold > dsold*100) odds=10000; else if( dsold > asold*100 ) odds=1; else odds = (asold*100)/dsold; /* mercenaries/orcs/goblins might run away */ for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) { if(((( odds > 200 )&&(side[i]==DFND)) ||(( odds < 100 )&&(side[i]==ATKR))) &&((ntn[owner[i]].arm[unit[i]].unittyp == A_MERCENARY) ||(ntn[owner[i]].arm[unit[i]].unittyp == A_ORC) ||(ntn[owner[i]].arm[unit[i]].unittyp == A_GOBLIN)) &&(ntn[owner[i]].arm[unit[i]].stat < NUMSTATUS) &&( rand()%100<30 )) { if( ispc(ntn[owner[i]].active)) { mailopen( owner[i] ); fprintf(fm,"Message to %s from Conquer\n",ntn[owner[i]].name); fprintf(fm," Your %s Army %d Runs Away\n", unittype[ntn[owner[i]].arm[unit[i]].unittyp], unit[i]); mailclose(); } retreatside = side[i]; if( side[i] == ATKR ) asold-= troops[i]; if( side[i] == DFND ) dsold-= troops[i]; fdxyretreat(); if((retreatx==xspot)&&(retreaty==yspot)){ /* move to capitol & kill 75% */ ntn[owner[i]].arm[unit[i]].xloc=ntn[owner[i]].capx; ntn[owner[i]].arm[unit[i]].yloc=ntn[owner[i]].capy; ntn[owner[i]].arm[unit[i]].sold/=4; } else { /* retreat normally and kill 50% */ ntn[owner[i]].arm[unit[i]].sold/=2; retreat( i ); } owner[i]=(-1-owner[i]); continue; } } retreatside=0; if( asold<=0 ) { printf("Exit from battle due to lack of attackers\n"); return; } /* CALCULATE AVERAGE COMBAT BONUS */ abonus=0; dbonus=0; for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) { if(side[i]==ATKR) abonus += cbonus(i)*troops[i]; else if(side[i]==DFND && ntn[owner[i]].arm[unit[i]].stat!=RULE) dbonus += cbonus(i)*troops[i]; } /*archer bonus if not in fort vs knights/cavalry*/ j=0; k=0; for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) if(ISCITY(sct[xspot][yspot].designation)){ if((ntn[owner[i]].arm[unit[i]].unittyp == A_CAVALRY) ||(ntn[owner[i]].arm[unit[i]].unittyp == A_KNIGHT)) if(side[i]==ATKR) j+=troops[i]; else if(side[i]==DFND) k+=troops[i]; } for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) { if(j>0) abonus += (15 * j * troops[i]) / asold; if(k>0 && dsold>0) dbonus += (15 * k * troops[i]) / dsold; } abonus/=asold; if (dsold>0) dbonus/=dsold; /*CALCULATED BONUSES TO WHOLE COMBAT*/ for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)) { if(fort_val(&sct[xspot][yspot]) != 0){ /*Catapults add +1%/20 men defending castle (max +10%)*/ if((ntn[owner[i]].arm[unit[i]].unittyp == A_CATAPULT) &&(side[i]==DFND)) dbonus += max((troops[i]/20),10); /*Catapults add +1%/40 men attacking castle (max +10%)*/ else if((ntn[owner[i]].arm[unit[i]].unittyp == A_CATAPULT) &&(side[i]==ATKR)) { strength = max((troops[i]/40),10); abonus += strength; /* possible damage 20% chance */ if(rand()%100<2*strength) { fortdam=TRUE; sct[xspot][yspot].fortress--; if(sct[xspot][yspot].fortress == 0) sct[xspot][yspot].designation = DRUIN; } } /*Siege_engines add +1%/20 men when attacking fortress*/ else if((ntn[owner[i]].arm[unit[i]].unittyp == A_SIEGE) &&(side[i]==ATKR)) { strength = max((troops[i]/20),30); abonus += strength; /* possible damage 15% chance */ if(rand()%100<strength/2) { fortdam=TRUE; sct[xspot][yspot].fortress--; if(sct[xspot][yspot].fortress == 0) sct[xspot][yspot].designation = DRUIN; } } } else { /*Catapults add +1%/40 men normal combat (max +10%)*/ if(ntn[owner[i]].arm[unit[i]].unittyp == A_CATAPULT) abonus+=max((troops[i]/40),10); } } /*RUN COMBAT */ /*FIRST GIVE RANDOM ROLL FROM 0 to 100 */ /*WITH A PROBABILITY BELL CURVE */ /* high roll favors attacker [ 5 d21 - 5 ] */ roll = 0; for(i=0;i<5;i++) { roll += rand()%21+1; } roll -= 5; /*find relative strength of troops*/ astr = asold * (100 + abonus); dstr = dsold * (100 + dbonus); /*Recalculate odds based on quality of troops*/ if( astr > dstr*100) odds=10000; else if( dstr > astr*100 ) odds=1; else odds = (astr*100)/dstr; /* calculate loss for an even battle */ PDloss = MAXLOSS * roll / 100; PAloss = MAXLOSS * (100 - roll) / 100; /* adjust for odds */ if( odds == 1 ) { PDloss=0; PAloss=200; } else if( odds == 10000 ) { PAloss=0; PDloss=200; } else if(odds > 100) { PDloss += (odds / 12 - 8); /* 8.33% for higher odds */ PAloss -= (odds / 16 - 6); /* 6.25% for lower odds */ if(PAloss<(100-roll)/20) PAloss=(100-roll)/20; /* can't get too small */ } else { PAloss += ( 800 / odds - 8); /* 8% for higher odds */ PDloss -= ( 600 / odds - 6); /* 6% for lower odds */ if(PDloss<roll/20) PDloss = roll/20; /* can't get too small */ } if( fort_val(&sct[xspot][yspot]) > 0 ){ PDloss *= 120; PAloss *= 120; PDloss /= 100; PAloss /= 100; } retreatside = 0; if((PDloss > 2* PAloss) &&(odds>150) &&(((PDloss>=50)&&(rand()%4==0)) ||(rand()%8))) retreatside=DFND; if((PAloss > 2* PDloss) &&(odds<150) &&(((PAloss>=50)&&(rand()%2==0)) ||(rand()%6))) retreatside=ATKR; if(retreatside!=0) { fdxyretreat(); /* no legal retreat route */ if((retreatside!=0) && (retreatx== xspot) && (retreaty== yspot)){ if(retreatside==ATKR) PAloss+=15; else if(retreatside==DFND) PDloss+=15; #ifdef DEBUG printf("side %d (%d %d) can't retreat...+15%% loss\n",retreatside,retreatx,retreaty); #endif DEBUG retreatside = 0; } #ifdef DEBUG else printf("retreat side %d to %d %d\n",retreatside,retreatx,retreaty); #endif DEBUG } if(PAloss>100) PAloss = 100; if(PDloss>100) PDloss = 100; Aloss = Dloss = 0; for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)){ if(side[i]==ATKR){ if( ntn[owner[i]].arm[unit[i]].unittyp >= MINLEADER) { if((rand()%100) < PAloss){ /* kill it */ for(j=0;j<MAXARM;j++) if(ntn[owner[i]].arm[j].stat==unit[i]+NUMSTATUS) ntn[owner[i]].arm[j].stat=ATTACK; Aloss += troops[i]; ntn[owner[i]].arm[unit[i]].sold=0; } } else { loss=(troops[i]*PAloss)/100; /*archers/catapults on sortie take 1/4 damage*/ if((ntn[owner[i]].arm[unit[i]].stat==SORTIE) &&(fort_val(&sct[xspot][yspot]) > 0) &&(sct[xspot][yspot].owner==country) &&((ntn[owner[i]].arm[unit[i]].unittyp==A_ARCHER) ||(ntn[owner[i]].arm[unit[i]].unittyp==A_CATAPULT))) loss /= 4; /*army can't have less than 25 men in it*/ if(troops[i]-loss<25) loss=troops[i]; if( loss>troops[i] ) { printf("I AM VERY CONFUSED - PLEASE HELP... combat.c\n"); } Aloss+=loss; ntn[owner[i]].arm[unit[i]].sold-=loss; if((ntn[owner[i]].arm[unit[i]].unittyp==A_MILITIA)&&(retreatside==ATKR)) { sct[ntn[owner[i]].arm[unit[i]].xloc][ntn[owner[i]].arm[unit[i]].yloc].people += ntn[owner[i]].arm[unit[i]].sold; ntn[owner[i]].arm[unit[i]].sold=0; } } } else if(side[i]==DFND){ if( ntn[owner[i]].arm[unit[i]].unittyp >= MINLEADER) { if((ntn[owner[i]].arm[unit[i]].stat!=RULE ||PDloss>=80)&&((rand()%100) < PDloss)){ /* kill it */ for(j=0;j<MAXARM;j++) if(ntn[owner[i]].arm[j].stat==unit[i]+NUMSTATUS) ntn[owner[i]].arm[j].stat=ATTACK; Dloss +=troops[i]; ntn[owner[i]].arm[unit[i]].sold=0; } } else { loss=(troops[i]*PDloss)/100; /*destroy army if < 25 men*/ if(troops[i]-loss<25) loss=troops[i]; Dloss+=loss; ntn[owner[i]].arm[unit[i]].sold-=loss; if((ntn[owner[i]].arm[unit[i]].unittyp==A_MILITIA)&&(retreatside==DFND)) { sct[ntn[owner[i]].arm[unit[i]].xloc][ntn[owner[i]].arm[unit[i]].yloc].people += ntn[owner[i]].arm[unit[i]].sold; ntn[owner[i]].arm[unit[i]].sold=0; } } } /* non-vampire troops are sucked in by vampires */ if((nvamps>0)&&(magic(owner[i],VAMPIRE)==FALSE) &&(ntn[owner[i]].arm[unit[i]].unittyp!=A_ZOMBIE) &&(ntn[owner[i]].arm[unit[i]].unittyp<MINLEADER)) vampire+= loss / 3; } /* use k variable to hold length */ #ifdef HIDELOC if( isntn( ntn[sct[xspot][yspot].owner].active )) { fprintf(fnews,"4.\tBattle occurs in %s", ntn[sct[xspot][yspot].owner].name); k = 27+strlen(ntn[sct[xspot][yspot].owner].name); } else { fprintf(fnews,"4.\tBattle on unowned land"); k = 30; } #else fprintf(fnews,"4.\tBattle in %d,%d",xspot,yspot); k = 25; #endif for(j=0;j<MGKNUM;j++) if(UOWNER(j)>(-1)){ done=FALSE; for(i=0;i<j;i++) if(UOWNER(j)==UOWNER(i)) done=TRUE; if(done==FALSE) { loss=NTRL; for(i=j;(loss==NTRL||loss==WIMP) && i<MGKNUM;i++) if(UOWNER(i)==UOWNER(j)) { if(owner[i]<(-1)) loss=WIMP; else loss=side[i]; } if(loss!=NTRL) { k += 11 + strlen(ntn[UOWNER(j)].name); if(loss==WIMP) k++; if(k>79) { k = 30; fprintf(fnews,",\n4.\t "); } else fprintf(fnews,", "); if(loss==ATKR) fprintf(fnews,"attacker %s",ntn[UOWNER(j)].name); else if(loss==DFND) fprintf(fnews,"defender %s",ntn[UOWNER(j)].name); else if(loss==WIMP) fprintf(fnews,"retreater %s",ntn[UOWNER(j)].name); } } } fprintf(fnews,"\n"); if(nvamps>0){ for(i=0;i<MGKNUM;i++) if(owner[i]>(-1)){ if((magic(owner[i],VAMPIRE)==TRUE) &&(ntn[owner[i]].arm[unit[i]].unittyp==A_ZOMBIE) &&(ntn[owner[i]].arm[unit[i]].sold > 0)) ntn[owner[i]].arm[unit[i]].sold+=vampire/nvamps; } } /*who is in the battle; but don't send to scared armies */ for(j=0;j<MGKNUM;j++) if(owner[j]>(-1)){ done=FALSE; /*first time your nation appears done=FALSE*/ for(i=0;i<j;i++) if(owner[j]==owner[i]) done=TRUE; if((done==FALSE)&&(ispc(ntn[owner[j]].active))) { loss=NTRL; for(i=j;loss==NTRL && i<MGKNUM;i++) loss=side[i]; mailopen( owner[j] ); fprintf(fm,"BATTLE SUMMARY for sector %d, %d\n",xspot,yspot); fprintf(fm,"Battle occured during %s of Year %d\n",PSEASON(TURN),YEAR(TURN)); if(loss==ATKR) fprintf(fm,"You are on the Attacking Side\n"); else if(loss==DFND) fprintf(fm,"You are on the Defending Side\n"); else fprintf(fm,"You are Neutral\n"); /*detail all participants in battle*/ for(k=0;k<MGKNUM;k++) if(owner[k]!=(-1)){ fprintf(fm," %s ",ntn[UOWNER(k)].name); if(owner[k]<(-1)) fprintf(fm,"chickens out: "); else if(side[k]==DFND && ntn[UOWNER(k)].arm[unit[k]].stat!=RULE) fprintf(fm,"defending: "); else if(side[k]==ATKR) fprintf(fm,"attacking: "); else fprintf(fm,"neutral: "); fprintf(fm,"army %d (%s, men %d, bonus=%d, loss=%d)", unit[k], unittype[ntn[UOWNER(k)].arm[unit[k]].unittyp%UTYPE], troops[k], cbonus(k), troops[k]-ntn[UOWNER(k)].arm[unit[k]].sold); if((ntn[UOWNER(k)].arm[unit[k]].unittyp >= MINLEADER) &&( ntn[UOWNER(k)].arm[unit[k]].sold == 0)) fprintf(fm," (killed)\n"); else if((ntn[owner[k]].arm[unit[k]].unittyp == A_MILITIA) &&( ntn[owner[k]].arm[unit[k]].sold == 0)) fprintf(fm," (disbanded)\n"); else fputc('\n',fm); } fprintf(fm,"attacking soldiers=%ld -> percent loss %d%%\n",asold,PAloss); fprintf(fm,"defending soldiers=%ld -> percent loss %d%%\n",dsold,PDloss); fprintf(fm,"ODDS=%d => adjusted to %d to 100; Die Roll is %d\n",odds*(100+dbonus)/(100+abonus),odds,roll); fprintf(fm,"RESULT: Attackers lose %ld men, Defenders lose %ld men\n",Aloss, Dloss); if(fortdam==TRUE) fprintf(fm,"Fortifications damaged during the attack\n"); if(retreatside==ATKR){ if(Aloss<asold) fprintf(fm,"Additionally, All attackers retreat to %d %d\n",retreatx,retreaty); } else if(retreatside==DFND){ if(Dloss<dsold) fprintf(fm,"Additionally, All defenders retreat to %d %d\n",retreatx,retreaty); } mailclose(); } } retreat( -1 ); } /************************************************************************/ /* CBONUS() - return combat bonuses for unit i */ /************************************************************************/ int cbonus(num) { short armynum; int armbonus; armbonus=0; armynum=unit[num]; country=UOWNER(num); /*Racial combat bonus due to terrain (the faster you move the better)*/ armbonus+=5*(9-movecost[xspot][yspot]); /* this line always has */ /* the same result... must fix -- ADB */ if(((magic(country,DESTROYER)==1) ||(magic(country,DERVISH)==1)) &&((sct[xspot][yspot].vegetation==ICE) ||(sct[xspot][yspot].vegetation==DESERT))) armbonus+=30; if(ASTAT>=NUMSTATUS) armbonus+=20; /* army group */ if(side[num]==DFND){ if(sct[xspot][yspot].altitude==MOUNTAIN) armbonus+=20; else if(sct[xspot][yspot].altitude==HILL) armbonus+=10; if(sct[xspot][yspot].vegetation==JUNGLE) armbonus+=20; else if(sct[xspot][yspot].vegetation==FOREST) armbonus+=15; else if(sct[xspot][yspot].vegetation==WOOD) armbonus+=10; if(ATYPE==A_MERCENARY) armbonus += MERCDEF; else armbonus += ntn[UOWNER(num)].dplus; if(ASTAT==MAGDEF) armbonus+=30; else if(ASTAT==SORTIE) armbonus-=30; else if(ASTAT==SIEGED) armbonus-=20; if((sct[xspot][yspot].owner==country) &&(ASTAT==GARRISON||ASTAT==MILITIA||ASTAT==SIEGED)){ if(ATYPE == A_ZOMBIE) /* don't utilize walls well */ armbonus += fort_val(&sct[xspot][yspot])/2; else armbonus += fort_val(&sct[xspot][yspot]); } } else if(side[num]==ATKR) { if( (fort_val(&sct[xspot][yspot]) > 0) &&( magic(country,SAPPER)==TRUE)) armbonus += 10; if(ATYPE == A_MERCENARY) armbonus += MERCATT; else armbonus += ntn[UOWNER(num)].aplus; if(ASTAT==MAGATT) armbonus += 30; if(ASTAT==SORTIE && (fort_val(&sct[xspot][yspot]) > 0) && sct[xspot][yspot].owner==country) { armbonus += 10; if((ATYPE==A_DRAGOON)||(ATYPE==A_LEGION) ||(ATYPE==A_PHALANX)) { /* bonus for organization or riding cavalry */ armbonus += 5; } else if ((ATYPE==A_LT_CAV)||(ATYPE==A_CAVALRY)) { /* bonus for mounted sortie */ armbonus += 10; } else if (avian(ATYPE)||ATYPE==A_ELEPHANT||ATYPE==A_KNIGHT) { /* bonus for mounted or flying sortie */ armbonus += 15; } if ((ATYPE>=MINMONSTER)||(ATYPE<=MAXMONSTER)) { /* bonus for monsters (scare factor) */ armbonus += 5; } } } /*army status is important*/ if(ASTAT==MARCH) armbonus-=40; /*if a fortress*/ if(fort_val(&sct[xspot][yspot]) > 0){ /*Cavalry and Knights get -20%*/ if((ATYPE == A_CAVALRY) ||(ATYPE == A_KNIGHT)) armbonus -= 20; /*Archers gain pluses*/ else if((ATYPE == A_ARCHER)&&(sct[xspot][yspot].owner==country)) armbonus += 15; else if(ATYPE == A_ARCHER) armbonus += 5; } if(side[num]==ATKR) armbonus+= *(unitattack+(ATYPE%UTYPE)); else armbonus+= *(unitdefend+(ATYPE%UTYPE)); /*Phalanx and Legionaires need certain numbers of troops*/ if((ATYPE==A_PHALANX)||(ATYPE==A_LEGION)) { if(ASOLD>1000){ armbonus+=20; } else if(ASOLD>500) armbonus+=10; } return(armbonus); } void fdxyretreat() /* finds retreat location */ { int x,y,nation=(-1); int xsctr= xspot; int ysctr= yspot; retreatx=xsctr; retreaty=ysctr; if((sct[xsctr][ysctr].designation==DTOWN) ||(sct[xsctr][ysctr].designation==DCAPITOL) ||(sct[xsctr][ysctr].designation==DCITY)){ retreatside=0; return; } if(retreatside == ATKR) nation=anation; else nation=dnation; for(x= xsctr-1; x<=xsctr+1; x++) for(y= ysctr-1; y<=ysctr+1; y++) if(ONMAP(x,y)){ if(tofood( &sct[x][y], sct[x][y].owner == country ? country : 0)==0) continue; if(((sct[x][y].owner == nation) ||(ntn[sct[x][y].owner].dstatus[nation] < NEUTRAL)) ||(solds_in_sector( x, y, sct[x][y].owner) == 0)){ retreatx=x; retreaty=y; #ifdef DEBUG printf("armies in %d %d retreat to %d %d\n",xsctr,ysctr,x,y); #endif DEBUG return; } } } void retreat(unitnum) int unitnum; /* if -1 then normal, else retreat only unit ismerc */ { int cnum; if(retreatside == 0) return; for(cnum=0;cnum<MGKNUM;cnum++) if(owner[cnum]>(-1)){ if( unitnum != (-1) ) cnum=unitnum; if((side[cnum]==ATKR)&&(retreatside==ATKR)){ ntn[owner[cnum]].arm[unit[cnum]].xloc = retreatx; ntn[owner[cnum]].arm[unit[cnum]].yloc = retreaty; } else if((side[cnum]==DFND)&&(retreatside==DFND)){ ntn[owner[cnum]].arm[unit[cnum]].xloc = retreatx; ntn[owner[cnum]].arm[unit[cnum]].yloc = retreaty; } if( unitnum != (-1) ) return; } } /*SUBROUTINE TO RUN NAVAL COMBAT ON ALL SHIPS */ /* quick define for easier reading */ #define QWAR 1 #define QGAL 2 #define QMER 3 /* just like fight, this takes array of owner,side,unit and calculates */ /* a random battle based on the strengths of the combatants. */ void navalcbt() { int acrew=0,dcrew=0; /*a's and d's crew and soldier strength*/ int ahold=0,dhold=0; /*a's and d's warship strength*/ int awsunk=0,dwsunk=0; /*a's and d's warship losses for the round*/ int agsunk=0,dgsunk=0; /*a's and d's galley losses for the round*/ int amsunk=0,dmsunk=0; /*a's and d's merchent losses for the round*/ int awcapt=0,dwcapt=0; /*a's and d's warship captures for the round*/ int agcapt=0,dgcapt=0; /*a's and d's galley captures for the round*/ int amcapt=0,dmcapt=0; /*a's and d's merchant captures for the round*/ int akcrew=0,dkcrew=0; /*a's and d's crew losses for the round*/ char wnum[MGKNUM],gnum[MGKNUM],mnum[MGKNUM]; register int done,i,j,k; int roll,odds,savecntry=country; int PAloss, PDloss, Ploss, which, shipsize; int thold, ghold, nvynum, armynum; int dcptpct, acptpct, cptpct; struct s_nation *saventn=curntn; void show_ships(),capture(); printf("In Naval Combat....\n"); /* determine who is attacker & who is on defenders side?*/ for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ if(owner[j]==anation) side[j]=ATKR; else if(ntn[anation].dstatus[owner[j]]==JIHAD) side[j]=DFND; else if(ntn[owner[j]].dstatus[anation]==JIHAD) side[j]=DFND; else if(ntn[anation].dstatus[owner[j]]==WAR) side[j]=DFND; else if(ntn[owner[j]].dstatus[anation]==WAR) side[j]=DFND; else if((ntn[owner[j]].dstatus[anation]==TREATY) &&(ntn[owner[j]].dstatus[dnation]>HOSTILE)) side[j]=ATKR; else if((ntn[owner[j]].dstatus[anation]==ALLIED) &&(ntn[owner[j]].dstatus[dnation]>HOSTILE)) side[j]=ATKR; } /* Loop through all competitors to determine * relative combat strengths: * men/unit strength * crew on ship: * warship crew 1 * galley crew 2 * merchant crew 4 * soldiers onboard: * SAILOR/ARCHER 3/4 * MARINE 1/3 * others 4/3 */ for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ curntn= &ntn[owner[j]]; country= owner[j]; wnum[j]=SHIPS(ntn[country].nvy[unit[j]].warships,N_LIGHT)+ SHIPS(ntn[country].nvy[unit[j]].warships,N_MEDIUM)+ SHIPS(ntn[country].nvy[unit[j]].warships,N_HEAVY); mnum[j]=SHIPS(ntn[country].nvy[unit[j]].merchant,N_LIGHT)+ SHIPS(ntn[country].nvy[unit[j]].merchant,N_MEDIUM)+ SHIPS(ntn[country].nvy[unit[j]].merchant,N_HEAVY); gnum[j]=SHIPS(ntn[country].nvy[unit[j]].galleys,N_LIGHT)+ SHIPS(ntn[country].nvy[unit[j]].galleys,N_MEDIUM)+ SHIPS(ntn[country].nvy[unit[j]].galleys,N_HEAVY); if(side[j]==DFND) { if((k=fltwhold(unit[j]))>0) { dhold += k; if (magic(country,SAILOR)==TRUE) { dcrew += 5*k*curntn->nvy[unit[j]].crew/4; } else dcrew += k*curntn->nvy[unit[j]].crew; } if((k=fltmhold(unit[j]))>0) { if (magic(country,SAILOR)==TRUE) { dcrew += 5*k*curntn->nvy[unit[j]].crew/16; } else dcrew += k*curntn->nvy[unit[j]].crew/4; } if((k=fltghold(unit[j]))>0) { if (magic(country,SAILOR)==TRUE) { dcrew += 5*k*curntn->nvy[unit[j]].crew/8; } else dcrew += k*curntn->nvy[unit[j]].crew/2; if(curntn->nvy[unit[j]].armynum!=MAXARM) { k = curntn->nvy[unit[j]].armynum; switch (curntn->arm[k].unittyp) { case A_ARCHER: case A_SAILOR: dcrew += 3*curntn->arm[k].sold/2; break; case A_MARINES: dcrew += 3*curntn->arm[k].sold; break; default: dcrew += 3*curntn->arm[k].sold/4; break; } } } } else if(side[j]==ATKR) { if((k=fltwhold(unit[j]))>0) { ahold += k; if (magic(country,SAILOR)==TRUE) { acrew += 5*k*curntn->nvy[unit[j]].crew/4; } else acrew += k*curntn->nvy[unit[j]].crew; } if((k=fltmhold(unit[j]))>0) { if (magic(country,SAILOR)==TRUE) { acrew += 5*k*curntn->nvy[unit[j]].crew/16; } else acrew += k*curntn->nvy[unit[j]].crew/4; } if((k=fltghold(unit[j]))>0) { if (magic(country,SAILOR)==TRUE) { acrew += 5*k*curntn->nvy[unit[j]].crew/8; } else acrew += k*curntn->nvy[unit[j]].crew/2; if(curntn->nvy[unit[j]].armynum!=MAXARM) { k = curntn->nvy[unit[j]].armynum; switch (curntn->arm[k].unittyp) { case A_ARCHER: case A_SAILOR: acrew += 3*curntn->arm[k].sold/2; break; case A_MARINES: acrew += 3*curntn->arm[k].sold; break; default: acrew += 3*curntn->arm[k].sold/4; break; } } } } } /*find battle odds*/ if( acrew > dcrew*100 ) odds=10000; else if ( dcrew > acrew*100 ) odds=1; else odds = (acrew*100)/dcrew; /* calculate capture percentages */ /* * This formula produces: * 0% capture for 1:100 odds * 2% capture for 1:10 odds * 15% capture for 1:1 odds * 60% capture for 10:1 odds * 100% capture for >60:1 odds * with linear progression between each. */ if (odds>6000) { dcptpct=0; acptpct=100; } else if (odds>1000) { dcptpct= (6000-odds)/2500; acptpct= (odds-1000)/125+60; } else if (odds>100) { dcptpct= (1000-odds)/69+2; acptpct= (odds-100)/20+15; } else if (odds>10) { dcptpct= (100-odds)/2+15; acptpct= (odds-10)/6.9+2; } else if (odds>6) { dcptpct= (10-odds)*14+60; acptpct= (odds-6)/2; } else { dcptpct= 100; acptpct= 0; } #ifdef DEBUG printf("capture percentage: attack = %d defend = %d\n",acptpct,dcptpct); #endif DEBUG /*figure combat on a one-to-one basis */ /* use a bell curve roll */ roll = 0; for(i=0;i<5;i++) { roll += rand()%21+1; } roll -= 5; PDloss = MAXLOSS * roll / 100; PAloss = MAXLOSS * (100 - roll) / 100; #ifdef DEBUG printf("Pdloss = %d PAloss = %d\n",PDloss,PAloss); #endif DEBUG /* adjust based on the odds */ if( odds == 1 ) { PDloss = 0; PAloss = 100; } else if ( odds == 10000 ) { PAloss = 0; PDloss = 100; } else if ( odds > 100 ) { PDloss += (odds / 10 - 10); /* 10% increase */ PAloss -= (odds / 25 - 4); /* 4% decrease */ if(PAloss<(100-roll)/5) PAloss=(100-roll)/5; } else { PAloss += ( 1000 / odds - 10); /* 10% increase */ PDloss -= ( 400 / odds - 4); /* 4% decrease */ if(PDloss<roll/5) PDloss = roll/5; } if (PAloss>100) PAloss=100; if (PDloss>100) PDloss=100; /* calculate actual losses */ for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ curntn= &ntn[owner[j]]; country= owner[j]; /* determine side */ which=side[j]; /* capturing is by foe so use other percent */ if(which==ATKR) { cptpct=dcptpct; Ploss= PAloss; } else if(which==DFND) { cptpct=acptpct; Ploss= PDloss; } else continue; /* find all weighting info */ nvynum = unit[j]; thold = flthold(nvynum); ghold = fltghold(nvynum); /* go through all ships in the navy */ for(shipsize=N_LIGHT;shipsize<=N_HEAVY;shipsize++) { /* check warships */ for(i=0;i<P_NWAR(shipsize);i++) if (rand()%100<Ploss) { if(rand()%100<cptpct/2) { /* capture a ship */ if(which==ATKR){ if (dhold) { awcapt++; ahold-=(shipsize+1); capture(QWAR,DFND,shipsize,rand()%dhold+1); NSUB_WAR(1); } } else { if (ahold) { dwcapt++; dhold-=(shipsize+1); capture(QWAR,ATKR,shipsize,rand()%ahold+1); NSUB_WAR(1); } } if(which==ATKR) akcrew += P_NCREW; else dkcrew += P_NCREW; } else if (rand()%2==0 || Ploss>90) { /* destroy a ship */ NSUB_WAR(1); k = P_NCREW*(shipsize+1); thold -= (shipsize+1); if(which==ATKR) { awsunk++; ahold-=(shipsize+1); akcrew+=k; } else { dwsunk++; dhold-=(shipsize+1); dkcrew+=k; } } else { /* damage a ship */ k = (shipsize+1)*Ploss*P_NCREW/100; if(which==ATKR) akcrew += k; else dkcrew += k; P_NCREW -= k/thold; } } /* check galleys */ for(i=0;i<P_NGAL(shipsize);i++) if (rand()%100<Ploss) { if(rand()%100<cptpct) { /* capture a ship */ if(which==ATKR){ if (dhold) { agcapt++; ghold-=(shipsize+1); thold-=(shipsize+1); capture(QGAL,DFND,shipsize,rand()%dhold+1); NSUB_GAL(1); } } else if(which==DFND) { if (ahold) { dgcapt++; ghold-=(shipsize+1); thold-=(shipsize+1); capture(QGAL,ATKR,shipsize,rand()%ahold+1); NSUB_GAL(1); } } if(which==ATKR) akcrew += P_NCREW; else dkcrew += P_NCREW; if (P_NARMY!=MAXARM) { armynum = P_NARMY; k = P_ASOLD*(shipsize+1)/(ghold+shipsize+1); if(P_ATYPE<MINLEADER) { if(which==ATKR) akcrew += k; else dkcrew += k; P_ASOLD -= k; } else if(rand()%100<k*100/P_ASOLD){ if(which==ATKR) akcrew += P_ASOLD; else dkcrew += P_ASOLD; P_ASOLD = 0; P_NARMY = MAXARM; } } } else if (rand()%3==0||Ploss>90) { /* ship destroyed */ k = (shipsize+1)*SHIPCREW; if(which==ATKR) akcrew += k; else dkcrew += k; NSUB_GAL(1); ghold-=(shipsize+1); thold-=(shipsize+1); /* kill all soldiers onboard */ if (P_NARMY!=MAXARM) { armynum = P_NARMY; k = P_ASOLD*(shipsize+1)/(ghold+shipsize+1); if(P_ATYPE<MINLEADER) { if(which==ATKR) akcrew += k; else dkcrew += k; P_ASOLD -= k; } else if(rand()%100<k*100/P_ASOLD){ if(which==ATKR) akcrew += P_ASOLD; else dkcrew += P_ASOLD; P_ASOLD = 0; P_NARMY = MAXARM; } } if(which==ATKR) agsunk++; else dgsunk++; } else { /* damage a ship */ k = (shipsize+1)*Ploss*P_NCREW/100; if(which==ATKR) akcrew += k; else dkcrew += k; P_NCREW -= k/thold; /* damage any soldiers onboard */ if (P_NARMY!=MAXARM) { armynum = P_NARMY; k = P_ASOLD*(shipsize+1)*Ploss/(ghold*100); if(P_ATYPE<MINLEADER) { P_ASOLD -= k; if(which==ATKR) akcrew += k; else dkcrew += k; } else if(rand()%100<k*100/P_ASOLD){ if(which==ATKR) akcrew += P_ASOLD; else dkcrew += P_ASOLD; P_ASOLD = 0; P_NARMY = MAXARM; } } } } /* check merchants */ for(i=0;i<P_NMER(shipsize);i++) if (rand()%100<Ploss) { if(rand()%100<cptpct) { /* capture a ship */ if(which==ATKR){ if (dhold) { amcapt++; capture(QMER,DFND,shipsize,rand()%dhold+1); NSUB_MER(1); } } else if(which==DFND) { if (ahold) { dmcapt++; capture(QMER,ATKR,shipsize,rand()%ahold+1); NSUB_MER(1); } } if(which==ATKR) akcrew += P_NCREW; else dkcrew += P_NCREW; } else if (rand()%3==0 || Ploss>90) { /* ship destroyed */ k = (shipsize+1)*P_NCREW; if(which==ATKR) akcrew += k; else dkcrew += k; P_NCREW -= k/thold; k = P_NCREW*thold; NSUB_MER(1); if((thold-=(shipsize+1))!=0) P_NCREW = k / thold; else P_NCREW = 0; /* kill all people onboard */ k = (shipsize+1)*P_NPEOP; if(which==ATKR) akcrew += k; else dkcrew += k; P_NPEOP -= k/(thold+shipsize+1); k = P_NPEOP*(thold+shipsize+1); if (thold>0) P_NPEOP = k / thold; else P_NPEOP=0; if(which==ATKR) amsunk++; else dmsunk++; } else { /* damage a ship */ k = (shipsize+1)*Ploss*P_NCREW/100; if(which==ATKR) akcrew += k; else dkcrew += k; P_NCREW -= k/thold; /* damage any people onboard */ k = (shipsize+1)*Ploss*P_NPEOP/100; if(which==ATKR) akcrew += k; else dkcrew += k; P_NPEOP -= k/thold; } } } } #ifdef HIDELOC fprintf(fnews,"4.\tNaval Battle occurs"); #else fprintf(fnews,"4.\t%d,%d: Naval Battle",xspot,yspot); #endif for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ k=0; for(i=0;i<j;i++) if(owner[j]==owner[i]) k=1; if(k==0) { if(side[i]==DFND) fprintf(fnews,", attacker %s",ntn[owner[j]].name); else if(side[i]==ATKR) fprintf(fnews,", defender %s",ntn[owner[j]].name); } } fprintf(fnews,"\n"); /*mail results; who is in the battle*/ for(j=0;j<MGKNUM;j++) if(owner[j]!=(-1)){ done=FALSE; /*first time your nation appears done=FALSE*/ for(i=0;i<j;i++) if(owner[j]==owner[i]) done=TRUE; if((done==FALSE)&&(ispc(ntn[owner[j]].active))) { mailopen( owner[j] ); fprintf(fm,"NAVAL BATTLE in sector %d %d\n",xspot,yspot); fprintf(fm,"Battle occured during %s of Year %d\n", PSEASON(TURN),YEAR(TURN)); if(side[j]==ATKR) fprintf(fm,"You are on the Attacking Side\n"); else if(side[j]==DFND) fprintf(fm,"You are on the Defending Side\n"); else fprintf(fm,"You are on the Neutral Side\n"); /*detail all participants in battle*/ for(k=0;k<MGKNUM;k++) if(owner[k]!=(-1)){ if(side[k]==DFND) fprintf(fm," %s is defender with navy ",ntn[owner[k]].name); else if(side[k]==ATKR) fprintf(fm," %s is attacker with navy ",ntn[owner[k]].name); else fprintf(fm," %s is neutral with navy ",ntn[owner[k]].name); fprintf(fm,"%d (%d warships %d galleys %d merchants)", unit[k],wnum[k],gnum[k],mnum[k]); putc('\n',fm); } fprintf(fm,"attacker strength (%d men) -> percent loss %d%%\n",acrew,PAloss); fprintf(fm,"defender strength (%d men) -> percent loss %d%%\n",dcrew,PDloss); fprintf(fm,"Odds are %d to 100; RANDOM ROLL is %d\n",odds,roll); fprintf(fm,"RESULT: Attackers lose %d men Defenders lose %d men\n",akcrew,dkcrew); /* display any other results */ show_ships("Attacking","sunk",awsunk,agsunk,amsunk); show_ships("Defending","sunk",dwsunk,dgsunk,dmsunk); show_ships("Attacking","captured",awcapt,agcapt,amcapt); show_ships("Defending","captured",dwcapt,dgcapt,dmcapt); mailclose(); } } curntn= saventn; country= savecntry; printf("Out Naval Combat....\n"); } /* routine to distribute a captured ship */ void capture(type,to,shipsize,holdcount) int type,to,shipsize,holdcount; { int i,nvynum; struct s_nation *saventn=curntn; #ifdef DEBUG printf("capture: hdcnt==%d typ==%d spsz==%d to==%d\n",holdcount, type,shipsize,to); #endif DEBUG for (i=0;holdcount && i<MGKNUM;i++) { if (owner[i]!=(-1) && side[i]==to) { curntn= &ntn[owner[i]]; holdcount -= fltwhold(unit[i]); } if(holdcount<=0) { holdcount=0; i--; } } #ifdef DEBUG printf("capture 2: holdcount==%d i==%d\n",holdcount,i); #endif DEBUG if (i==MGKNUM) { curntn = saventn; return; } nvynum = unit[i]; #ifdef DEBUG printf("Should have succesful capture of %d\n",type); #endif DEBUG switch(type) { case QWAR: (void) NADD_WAR(1); break; case QGAL: (void) NADD_GAL(1); break; case QMER: (void) NADD_MER(1); break; default: fprintf(stderr,"unknown type in function capture"); break; } curntn = saventn; } /* routine to display combat results */ void show_ships(who,what,war,gal,mer) char *who,*what; int war, gal, mer; { if (war+gal+mer>0) { fprintf(fm,"%s ships %s: ",who,what); if (war) fprintf(fm,"%d Warships ",war); if (gal) fprintf(fm,"%d Galleys ",gal); if (mer) fprintf(fm,"%d Merchants",mer); putc('\n',fm); } }