U0 AttackHeader(Unit *tmpu,U8 *st,Unit *target) { I64 i=9+StrLen(st); if (target) { i+=9; if (target->armor) i+=8; else i+=10; } '\n\n'; "$BLACK$%h*c$FG$\n" ,i,'-'; if (tmpu->player) "$PURPLE$Player 2$FG$ "; else "$CYAN$Player 1$FG$ "; "%s" ,st; if (target) { if (target->player) " $PURPLE$Player 2"; else " $CYAN$Player 1"; if (target->armor) " Armored"; else " Unarmored"; '$FG$'; } '\n'; "$BLACK$%h*c$FG$\n" ,i,'-'; } F64 HitDamage(Unit *tmpu,Unit *target,I64 facing=1,F64 range_factor=0) { F64 d,res=200.0*Rand; "\nRoll Out of 200\t\t:%6.2f Damage\n" ,res; if (target->armor) { d=target->armor/100.0*(5-facing)/5.0; if (d>=0) { "Armor Attack\t\t:%6.2f\n",ToF64(tmpu->armored_attack); res*=(tmpu->armored_attack/100.0)/d; } else res=0; "Armor(%z) Defense\t:%6.2f\n" ,facing, "Front\0FrontSide\0RearSide\0Rear\0",100*d; } else { d=1.0-range_factor; if (d>0) { "Unarmored Attack\t:%6.2f\n",ToF64(tmpu->unarmored_attack); "Range Adjust\t\t:%6.2f%%\n" ,100*d; res*=(tmpu->unarmored_attack/100.0)*d; } else res=0; } "Attack/Defense Adjusted\t:%6.2f Damage\n",res; return Round(res); } Bool DamageDo(Unit *target,F64 damage) { if (damage>0) { if (target->armor) "Armor Hit Score %6.2f\t:",damage; else "%3d Life - %3f Damage\t=",target->life,damage; if (damage>=target->life) { "$RED$Killed$FG$\n"; Noise(1000*animation_delay,74,98); Sleep(1000*animation_delay); target->life=0; VisRecalc(VR_FRIENDLY_UNIT_DIED,target); alive_cnt[target->player]--; return TRUE; } else { if (target->armor) { if (damage>0.6*target->life) { target->movement=0; "$RED$Immobilized$FG$\n"; } else "$GREEN$No Penetration$FG$\n"; } else { target->life-=damage; "$RED$%6.2f Life$FG$\n" ,ToF64(target->life); } return FALSE; } } else return FALSE; } U0 IndirectAdd(Unit *tmpu,I64 row,I64 col) { IndirectOrders *tmpi; if (tmpu->life<=0 || tmpu->range<=0) return; tmpu->fired=TRUE; tmpi=CAlloc(sizeof(IndirectOrders)); tmpi->attacker=tmpu; tmpi->row=row; tmpi->col=col; QueIns(tmpi,indirect_head.last); } Bool BulletPlot(U0,I64 x,I64 y,I64) { fire_x=x; fire_y=y; firing=TRUE; Sleep(3*animation_delay); return TRUE; } U0 UnitDirectFire(Unit *tmpu,Unit *target) { I64 r,c,facing, t1=terrain[tmpu->row][tmpu->col],t2=terrain[target->row][target->col]; F64 x1,y1,x2,y2,d,a,range_factor; if (tmpu->life<=0 || target->life<=0 || tmpu->range<=0) return; AttackHeader(tmpu,"DirectFire",target); RowCol2XY(&x1,&y1,tmpu->row,tmpu->col); RowCol2XY(&x2,&y2,target->row,target->col); d=100*Rand; "+%5.2f Roll\n" ,d; d+=tmpu->accuracy; "+%2d.00 Accuracy\n" ,tmpu->accuracy; range_factor=Sqrt(Sqr(x2-x1)+Sqr(y2-y1))/(tmpu->range*2*DSIN); "-%5.2f%% of Range\n" ,100*range_factor; d-=100*range_factor; if (t2==TREES) { "-30.00 Target in Trees Penalty\n"; d-=30; } if (t1==MOUNTAINS && t2!=MOUNTAINS) { "+30.00 High Ground Bonus\n"; d+=30; } "_______\n"; target_unit=target; if (d>=0) { "+%5.2f Hit\n",d; target_hit=TRUE; Noise(500*animation_delay,34,41); Sleep(500*animation_delay); Line(NULL,x1,y1,0,x2,y2,0,&BulletPlot); } else { "-%5.2f Miss\n",-d; target_hit=FALSE; Noise(1000*animation_delay,69,74); Sleep(1000*animation_delay); a=pi*2*Rand; d=(0.5-d/100)*HEX_SIDE; Line(NULL,x1,y1,0,x2+d*Cos(a),y2+d*Sin(a),0,&BulletPlot); } firing=FALSE; tmpu->fired=TRUE; if (target_hit) { r=target->row; c=target->col; if ((facing=HexMoveOne(&r,&c,x1,y1))>=0) facing=FacingChg(facing,target->facing); else facing=0; DamageDo(target,HitDamage(tmpu,target,facing,range_factor)); } while (scrncast.ona) //see Snd() Yield; target_unit=NULL; } Bool HexOccupy(Bool overrun,Unit *tmpu,Unit *target) { I64 t2=terrain[target->row][target->col]; F64 damage; if (tmpu->life<=0 || target->life<=0) return FALSE; if (overrun) AttackHeader(tmpu,"OverRun",target); else AttackHeader(tmpu,"CloseAssault",target); Noise(500*animation_delay,34,41); Sleep(500*animation_delay); tmpu->fired=TRUE; target->fired=TRUE; damage=HitDamage(tmpu,target); if (overrun) { damage*=2.0; "x2 OverRun Bonus\t=%6.2f Damage\n" ,damage; if (t2!=PLAINS) { damage/=2.0; "/2 Terrain Penalty\t=%6.2f Damage\n" ,damage; } } else { damage*=3.0; "x3 CloseAssault Bonus\t=%6.2f Damage\n" ,damage; } if (DamageDo(target,Round(damage))) { "$RED$Success$FG$\n"; while (scrncast.ona) //see Snd() Yield; return TRUE; } else { tmpu->life=0; VisRecalc(VR_FRIENDLY_UNIT_DIED,tmpu); alive_cnt[tmpu->player]--; "$RED$Failure$FG$\n"; while (scrncast.ona) //see Snd() Yield; return FALSE; } } U0 IndirectResolveAll() { I64 i,r,c; F64 x1,y1,x2,y2,d,range_factor; Unit *tmpu,*target; IndirectOrders *tmpi=indirect_head.next,*tmpi1; while (tmpi!=*indirect_head) { tmpi1=tmpi->next; tmpu=tmpi->attacker; AttackHeader(tmpu,"IndirectFire",NULL); RowCol2XY(&x1,&y1,tmpu->row,tmpu->col); RowCol2XY(&x2,&y2,tmpi->row,tmpi->col); d=100*Rand; "+%5.2f Roll\n" ,d; d+=tmpu->accuracy; "+%2d.00 Accuracy\n" ,tmpu->accuracy; range_factor=Sqrt(Sqr(x2-x1)+Sqr(y2-y1))/(tmpu->range*2*DSIN); "-%5.2f%% of Range\n" ,100*range_factor; d-=100*range_factor; '_______\n'; if (d>=0) { "+%5.2f Hit\n",d; Noise(500*animation_delay,34,41); Sleep(500*animation_delay); } else { "-%5.2f Miss\n",-d; Noise(1000*animation_delay,69,74); Sleep(1000*animation_delay); i=RandU16%6; if (tmpi->row&1) tmpi->col+=col_offsets_odd[i]; else tmpi->col+=col_offsets_even[i]; tmpi->row+=row_offsets[i]; RowCol2XY(&x2,&y2,tmpi->row,tmpi->col); } Line(NULL,x1,y1,0,x2,y2,0,&BulletPlot); firing=FALSE; tmpu->fired=TRUE; indirect_row=tmpi->row; indirect_col=tmpi->col; indirect_explosion=TRUE; for (i=0; i<7; i++) { if (tmpi->row&1) c=tmpi->col+col_offsets_odd[i]; else c=tmpi->col+col_offsets_even[i]; r=tmpi->row+row_offsets[i]; if (0<=r<map_rows && 0<=c<map_cols && (target=UnitFind(r,c))) { AttackHeader(tmpu,"IndirectFire",target); DamageDo(target,HitDamage(tmpu,target)); } } Noise(2000*animation_delay,70,74); Sleep(2000*animation_delay); while (scrncast.ona) //see Snd() Yield; indirect_explosion=FALSE; QueRem(tmpi); Free(tmpi); tmpi=tmpi1; } }