Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ///////////////////////////////////////////////////////////////////
- // Комбат сперва собирает массив данных. В дальнейшем он по минимуму обращается к криттерам или чему-то еще.
- // Например многочисленный (valid(target)) заменяется tr.Valid, который по умолчанию false.
- // Добавление констант осуществляется в структуры attack. at. и tr. сверху. В самой функции они вызываются с параметрами по дефолту,
- // а потом заполняются. Если позиция структуры заполняется не сразу, а после каких-то вычислений, то в этом месте стоит указатель !!!STRUCK UPDATE!!!
- // 90% переменных функции дефайнится еще до первого просчета на toHit.
- // Струк таргета заполняется !ТОЛЬКО! при наличии валидного таргета.
- // Струк attack. также была значительно расширен в хранимых параметрах.
- // Хранимое в структуре ВСЕГДА должно быть приоритетнее временных значений.
- // Если вызывается итоговый ApplyDamage для нескольких криттеров в массиве, то перед отправкой ОБЯЗАТЕЛЬНО вносить валидного криттера[i] в @attack.Target;
- void CombatAttack( Critter& cr, Critter@ target, ProtoItem& weapon, uint8 weaponMode, ProtoItem@ ammo, uint16 hexX, uint16 hexY, int slot ) // Export
- {
- // ///////////////////////////////////////////////////////////////////
- // --------------------------------------------------------- MODULATED
- // ----------------------------------------------------------- RETURNS
- if( !valid( target ) && hexX == 0 && hexY == 0 ) return;
- if( valid( target ) )
- {
- hexX = target.HexX;
- hexY = target.HexY;
- }
- if (valid(target) && valid(cr))
- {
- if ((target.StatBase[ST_FACTION]==16) && (cr.StatBase[ST_FACTION]==16)) return;
- }
- Map@ map = cr.GetMap();
- if(!valid(map)) return;
- bool DebugCom = (cr.IsPlayer() && cr.StatBase[ST_NPC_ROLE]>0 && (cr.Name=="Admin"|| cr.Name=="admin"));
- //int mapTime = map.GetTime();
- //bool isGlobalTimeMap = (mapTime == -1);
- bool trValid = valid(target);
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- CR PERKS && STATS
- CritterStruct at;
- at = _GetAtStruct(cr);
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- TR PERKS && STATS
- TargetStruct tr;
- if(trValid) tr = _GetTrStruct(target);
- tr.Valid = trValid;
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------------ MAIN DEFINES
- Critter@ realTarget;
- Critter@ normalTarget;
- CombatRes[] results;
- if(trValid) @realTarget = target;
- bool isHit = false;
- bool isCritical = false;
- bool hitRandomly = false;
- bool useNormal = false;
- bool useHex = false;
- uint critfailFlags = 0;
- int acmod = 0;
- uint16 hx = cr.HexX;
- uint16 hy = cr.HexY;
- uint16 tx = ( trValid ) ? target.HexX : hexX;
- uint16 ty = ( trValid ) ? target.HexY : hexY;
- uint8 use = _WeaponModeUse( weaponMode );
- uint8 aim = _WeaponModeAim( weaponMode );
- Item@ realWeapon;
- if( slot != 5 )
- @realWeapon = _CritGetItemHand( cr );
- else
- @realWeapon = _CritGetItemArmorExt( cr );
- bool validWeap = valid( realWeapon );
- bool validAmmo = valid( ammo );
- // cr.Say( SAY_NETMSG, "Ammo-"+validAmmo );
- if( cr.Damage[DAMAGE_RIGHT_ARM] != 0 && cr.Damage[DAMAGE_LEFT_ARM] != 0 )
- {
- cr.SayMsg( SAY_NETMSG, TEXTMSG_COMBAT, 105 );
- return;
- }
- if(validWeap && FLAG(realWeapon.Flags, ITEM_TWO_HANDS))
- {
- if(cr.Damage[DAMAGE_RIGHT_ARM] != 0 || cr.Damage[DAMAGE_LEFT_ARM] != 0 )
- {
- cr.SayMsg( SAY_NETMSG, TEXTMSG_COMBAT, 106 );
- return;
- }
- }
- if(validWeap && realWeapon.IsDeteriorable() && realWeapon.Deterioration >= MAX_DETERIORATION)
- {
- cr.SayMsg( SAY_NETMSG, TEXTMSG_COMBAT, 105 );
- return;
- }
- uint16 weapPid = weapon.ProtoId;
- if(weapPid == PID_FLARE) weapPid = PID_ACTIVE_FLARE;
- int skillNum = _WeaponSkill( weapon, use );
- int wpnMaxDist = _WeaponMaxDist( weapon, use )+GetBonusWp(realWeapon, 8);
- if( skillNum == SK_THROWING && weapPid != 898)
- wpnMaxDist = MIN( wpnMaxDist, 3 * MIN( int(10), ( at.Str ) ) );
- if( weapPid == 7960 ) wpnMaxDist = 100;
- bool isAlwaysAlt = ( Present(weapPid, Pids_AlwaysAlt) );
- if( validWeap )
- if( at.IsEngineer && Present(realWeapon.GetProtoId(), Pids_SupportPositions ) )
- skillNum = SK_REPAIR;
- if( slot == 99 )
- skillNum = _WeaponSkill( GetProtoItem( realWeapon.GetProtoId() ), use );
- int skillVal = cr.Skill[ skillNum ] + cr.Stat[ST_SKILL_MOD];
- int skillreal=0;
- // if (skillVal<151) skillreal=skillVal;
- // if (skillVal>150) skillreal=150+(skillVal-150)/2;
- //if (skillVal>200) skillreal=150+(skillVal-200)/2;
- int baseToHit = skillVal;
- int toHit = 0;
- int distmod1 = 0;
- int distmod2 = 0;
- int acc = 0;
- int accloss = 0;
- int sharpshooter = (at.IsSharpshooter) ? 2 : 0;
- int blockers = 0;
- uint8 weaponSubtype = ( skillNum == SK_SMALL_GUNS || skillNum == SK_BIG_GUNS || skillNum == SK_ENERGY_WEAPONS || Present(weapon.ProtoId, Pids_WS_GUN) ) ? WS_GUN : ( ( skillNum == SK_THROWING ) ? WS_THROWING : ( skillNum == SK_MELEE_WEAPONS ) ? WS_MELEE : WS_UNARMED );
- bool isRanged = ( weaponSubtype == WS_THROWING || weaponSubtype == WS_GUN );
- bool isUnarmed = weapon.Weapon_IsUnarmed;
- bool isHthAttack = ( weaponSubtype == WS_MELEE || weaponSubtype == WS_UNARMED );
- int preBonusDmg = 0;
- int smokePen = (tr.Valid) ? (GetSmokePenalty( map, cr, target, tx, ty )) : 0;
- // if (smokePen>0) smokePen -=cr.StatBase[ST_PERCEPTION];
- int margin = 0;
- uint8 aimOld = aim;
- uint fireDamage = 5;
- int skilllvl = 0;
- int maxBurstD = 0;
- int minBurstD = 0;
- int wpdist = 0;
- int perdamage = 0;
- at.CriticalCh=cr.Stat[ST_CRITICAL_CHANCE] + GetHitAim(aim)+cr.Perk[PE_NCR_PERCEPTION]*4+GetBonusWp(realWeapon,4);
- // ///////////////////////////////////////////////////////////////////
- // ---------------------------------------------------- WEAPON DEFINES
- int weaponPerk = weapon.Weapon_Perk;
- int weaponBonusPerk = 0;
- // int b1=item.Val3; int b2=item.Val4; int b3=item.Val8; int b4=item.Val1;
- bool wpnIsRemoved = _WeaponRemove( weapon, use );
- int dmgType = _WeaponDmgType( weapon, use );
- bool isGrenade = ( weaponSubtype == WS_THROWING && ( dmgType == DAMAGE_PLASMA || dmgType == DAMAGE_EMP || dmgType == DAMAGE_ELECTR || dmgType == DAMAGE_EXPLODE || dmgType == DAMAGE_FIRE ) && weapon.ProtoId != 7960 );
- bool isFlamethrower = ( Present( weapPid, Pids_Flamers ) );
- int weapStr = weapon.Weapon_MinStrength;
- bool weapIsTwoHand = FLAG( weapon.Flags, ITEM_TWO_HANDS );
- uint weapPower = weapon.Cost / 100;
- bool isPlaser = ( validWeap && realWeapon.Val7 == PID_P_LASER );
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------------ AMMO DEFINES
- uint16 ammoPid = (validAmmo) ? ammo.ProtoId : 0;
- uint16 ammoRound = _WeaponRound( weapon, use );
- uint ammoCount = (validWeap) ? realWeapon.AmmoCount : 0;
- //uint ammoWeight = (validAmmo) ? ammo.Weight : 0;
- int AmmoAp = validWeap ? _WeaponApCost(weapon, use):4; AmmoAp -= (cr.Perk[PE_BONUS_RATE_OF_FIRE]!=0?1:0)+(cr.Trait[TRAIT_FAST_SHOT]!=0?1:0);
- if (! isHthAttack && cr.Perk[PE_ADD_ATAC]!=0 && Random(0,100)<(AmmoAp*10)) cr.StatBase[ST_CURRENT_AP]+=2*100;
- bool isRocket = ( Present(ammoPid, Pids_RocketAmmo) || weapPid == PID_SHAITAN || weapPid == 7960 );
- bool isBurst = ( ammoRound > 1 );
- bool isThrowRelayted = ( isGrenade || ammoPid == 651 || ammoPid == 652 || ammoPid == 653 || ammoPid == 7961 );
- bool isPG = (ammoPid == 651 || ammoPid == 652 || ammoPid == 653);
- cr.StatBase[ST_AUCTION]=0;
- if (isPG) cr.StatBase[ST_AUCTION]=ammoPid;
- int bulletPower =0;
- int supressRounds = 0;
- int ammoAC = (validAmmo) ? ammo.Ammo_ACMod : 0;
- if (DebugCom) cr.Say( SAY_NETMSG, "Ammo-"+ammoPid+" ПидРужья-"+weapPid+" slot-"+slot+" Dtyp-"+dmgType);
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------ PREWORK EXCEPTIONS
- if( isBurst ) aim = HIT_LOCATION_UNCALLED;
- uint trPidArmor=0; uint crPidArmor=0;
- Item@ armorcr =_CritGetItemArmor(cr); if(valid(armorcr)) crPidArmor = armorcr.GetProtoId();
- if( tr.Valid )
- {
- Item@ armortr =_CritGetItemArmor(target);
- if(valid(armortr)) trPidArmor = armortr.GetProtoId();
- }
- if( slot == 99 && isPG) dmgType = ammo.Weapon_DmgType_0;
- if( weapPid == 7909 ) isBurst = false;
- if( isPlaser || weaponPerk == WEAPON_PERK_NIGHT_SIGHT ) smokePen = smokePen/2;
- if( at.PidSlot1 == PID_TEPLOVISOR) smokePen = 0;
- if (DebugCom) cr.Say( SAY_NETMSG, "Ammo-"+ammoPid+" round-"+ammoRound+" slot-"+slot+" Dtyp-"+dmgType);
- // ///////////////////////////////////////////////////////////////////
- // --------------------------------------------------- MAIN APPEARANCE
- if( !map.IsTurnBased() && map.IsTurnBasedAvailability() ) map.BeginTurnBased( cr );
- if( at.IsHidden ) cr.ModeBase[ MODE_HIDE ] = 0;
- if( tr.IsHidden ) target.ModeBase[ MODE_HIDE ] = 0;
- cr.SetDir( GetDirection( hx, hy, tx, ty ) );
- int crTimeout = BattleTime( cr);
- if( weapPid == 7960 ) crTimeout=__FullSecond+ (crTimeout - __FullSecond)/2;
- if(cr.Timeout[ TO_BATTLE ] < crTimeout - __FullSecond) cr.TimeoutBase[ TO_BATTLE ] = crTimeout;
- cr.TimeoutBase[ TO_SNEAK ] = SNEAK_TIMEOUT( cr );
- if( tr.Valid )
- {
- int targetTimeout = BattleTime(target);
- if( target.Timeout[ TO_BATTLE ] < targetTimeout - __FullSecond ) target.TimeoutBase[ TO_BATTLE ] = targetTimeout;
- target.TimeoutBase[ TO_SNEAK ] = SNEAK_TIMEOUT( target );
- target.EventAttacked( cr );
- }
- // Add scores
- if( at.IsPlayer )
- {
- if( weaponSubtype == WS_GUN ) cr.AddScore( SCORE_SHOOTER, 1 );
- else if( skillNum == SK_MELEE_WEAPONS || skillNum == SK_THROWING ) cr.AddScore( SCORE_MELEE, 1 );
- else if( skillNum == SK_UNARMED ) cr.AddScore( SCORE_UNARMED, 1 );
- }
- // Npc attack text
- if( !at.IsPlayer ) AI_TrySayCombatText( cr, COMBAT_TEXT_ATTACK );
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------ AMMO MANIPULATIONS
- if( validAmmo )
- {
- if(weaponSubtype == WS_GUN)
- {
- uint ammoDT=ammo.SoundId;
- if (ammoDT<8) dmgType = ammoDT;
- if (ammoPid==PID_NAPALM) weaponBonusPerk == WEAPON_PERK_FLAMEBOY;
- }
- }
- // ///////////////////////////////////////////////////////////////////
- // -------------------------------------------------- ATTACK STRUCTURE
- AttackStruct attack;
- @attack.Attacker = cr;
- @attack.Target = realTarget;
- @attack.RealWeapon = realWeapon;
- @attack.RealMap = map;
- attack.IsNight =(slot==99);
- attack.Hx = hx;
- attack.Hy = hy;
- attack.Aim = aim;
- attack.SkillNum = skillNum;
- attack.SkillVal = skillVal;
- attack.IsBurst = isBurst;
- attack.IsFlamethrower = isFlamethrower;
- attack.IsRocket = isRocket;
- attack.IsGrenade = isGrenade;
- attack.IsHthAttack = isHthAttack;
- attack.IsSingleAttack = (!attack.IsBurst && !attack.IsFlamethrower && !attack.IsRocket && !attack.IsGrenade && !attack.IsHthAttack);
- attack.IsAlwaysAlt = isAlwaysAlt;
- attack.BloodyMess = at.IsBloody;
- attack.CombatMessage = true;
- attack.scoreUnarmed = ( weaponSubtype == WS_UNARMED );
- attack.WeaponPerk = ( isUnarmed && weapon.Weapon_UnarmedArmorPiercing ) ? WEAPON_PERK_PENETRATE : weaponPerk;
- attack.WeaponBonusPerk = weaponBonusPerk;
- attack.WeaponUpgrade = 0;
- attack.WeaponSubtype = weaponSubtype;
- attack.Profficiency = 0;
- attack.DmgMin = ( skillNum == SK_REPAIR && !at.IsEngineer ) ? _WeaponDmgMin( weapon, use ) - _WeaponDmgMin( weapon, use ) / 4 + attack.Profficiency: _WeaponDmgMin( weapon, use ) + attack.Profficiency;
- attack.DmgMax = ( skillNum == SK_REPAIR && !at.IsEngineer ) ? _WeaponDmgMax( weapon, use ) - _WeaponDmgMax( weapon, use ) / 4: _WeaponDmgMax( weapon, use );
- attack.DmgType = dmgType;
- attack.BonusDmg = preBonusDmg;
- attack.PlasmaBurn = 8;
- attack.FireDamage = fireDamage;
- attack.Dist = GetDistantion( hx, hy, tx, ty );
- attack.ACMod = ammoAC;
- at.MasterPerk = (at.IsPlayer) ? cr.Perk[ attack.DmgType + 450 ] : 0;
- cr.StatBase[ST_EMP_RESIST_EXT]=0;
- attack.DmgMin+=GetBonusWp(realWeapon, 0);
- attack.DmgMax+=GetBonusWp(realWeapon, 1);
- if( attack.IsHthAttack )
- {
- if(weaponSubtype == WS_MELEE)
- {
- attack.DmgMax += at.MeleeDmg/2; // !!!STRUCK UPDATE!!!
- attack.DmgMin += at.MeleeDmg/2; // !!!STRUCK UPDATE!!!
- }
- else
- {
- attack.DmgMax += at.MeleeDmg; // !!!STRUCK UPDATE!!!
- attack.DmgMin += at.MeleeDmg; // !!!STRUCK UPDATE!!!
- }
- }
- // if( weaponSubtype == WS_GUN && isBurst) attack.BonusDmg += at.BRD * ((attack.DmgMin+attack.DmgMax)*at.BaseLuck/50+1);
- if(attack.DmgType == DAMAGE_FIRE)
- {
- if( at.IsPyro || ammoPid == PID_NAPALM)
- {
- if(at.IsPyro) attack.BonusDmg +=8 ;
- attack.BonusDmg += 7;
- attack.ExplodeRad += 1; // !!!STRUCK UPDATE!!!
- }
- if( !at.IsKind) attack.FireDamage = attack.BonusDmg + at.MasterPerk*2;
- else attack.FireDamage = attack.BonusDmg;
- }
- attack.DmgMul = 1; // !!!STRUCK UPDATE!!!
- if( valid( ammo ) )
- {
- attack.DRMod = ammo.Ammo_DRMod; // !!!STRUCK UPDATE!!!
- attack.DMMod = ammo.Ammo_DmgMult; // !!!STRUCK UPDATE!!!
- attack.DDMod = ammo.Ammo_DmgDiv; // !!!STRUCK UPDATE!!!
- // cr.Say( SAY_NETMSG, "Дмод-"+attack.DDMod);
- if( attack.DMMod == 0 )
- attack.DMMod = 1; // !!!STRUCK UPDATE!!!
- if( attack.DDMod == 0 )
- attack.DDMod = 1; // !!!STRUCK UPDATE!!!
- }
- // ///////////////////////////////////////////////////////////////////
- // ----------------------------- STRUCK >> DIRECT LINK FROM THIS POINT
- // ///////////////////////////////////////////////////////////////////
- // ----------------------------------------------- AFTERATTACK DEFINES
- if( weapPid == 350 || weapPid == 873)
- attack.WeaponBonusPerk = WEAPON_PERK_NIGHT_SIGHT;
- //if (weapPid==PID_LIGHT_SUPPORT_WEAPON || weapPid==PID_AVENGER_MINIGUN) attack.WeaponBonusPerk=WEAPON_PERK_LONG_RANGE;
- //if( weapPid == PID_SOLAR_SCORCHER) attack.WeaponBonusPerk = WEAPON_PERK_FLAMEBOY;
- int dist = attack.Dist;
- int cover = 0;
- uint attackDir = GetDirection( hx, hy, tx, ty );
- uint16 coverX = tx, coverY = ty;
- uint coverstep = 1;
- if( dist > 1 && !isThrowRelayted && tr.Valid)
- {
- attack.RealMap.MoveHexByDir( coverX, coverY, ( ( attackDir + 3 ) % 6 ), coverstep );
- if( attack.RealMap.IsHexPassed( coverX, coverY ) ) cover = 0;
- if( attack.RealMap.IsHexRaked( coverX, coverY ) && !attack.RealMap.IsHexPassed( coverX, coverY ) )
- {
- cover = 2;
- if( tr.IsSupporter ) cover++;
- if( tr.IsNoKnock ) cover++;
- }
- }
- bool isShotgunMechanics = (validWeap && !isPG && ammoPid != PID_12MM_FIRE && Present(weapPid, Pids_WeaponShotguns) );
- bool isKnockMechanics = (validWeap&& !isPG && ( ammoPid == PID_14MM_EXPL || weapPid == 875) );
- // ///////////////////////////////////////////////////////////////////
- // -------------------------------------------------------- HERE WE GO
- if( aim == HIT_LOCATION_EYES )
- if( (tr.Valid && ( at.Dir + 3 ) % 6 != tr.Dir ) || tr.PidSlot1 == PID_PASGT_HELM ) aim = HIT_LOCATION_HEAD;
- attack.Aim = aim; // !!!STRUCK UPDATE!!!
- bool handlau=(validWeap && weapPid == 898);
- if( !tr.Valid && valid(map) && (smokePen==0))
- {
- if(valid( cr ) && hexX != 0 && hexY != 0 && valid( map.GetItem( hexX, hexY, PID_SMOKE ))) smokePen =60;
- if(hexX != 0 && hexY != 0 && valid( map.GetItem( hexX, hexY, PID_MUSTARD_GAS ))) smokePen =25;
- if( valid( cr ) && valid( map.GetItem( cr.HexX, cr.HexY, PID_SMOKE ))) smokePen +=90;
- if( valid( cr ) && valid( map.GetItem( cr.HexX, cr.HexY, PID_MUSTARD_GAS ))) smokePen +=25;
- if( isPlaser || weaponPerk == WEAPON_PERK_NIGHT_SIGHT ||(attack.IsGrenade && !handlau)) smokePen = smokePen/2;
- if( at.PidSlot1 == PID_TEPLOVISOR) smokePen = 0;
- }
- // РАССЧЕТ TOHIT
- acc = attack.Dist;
- uint KPers=5; uint KDist=3; acmod =(tr.Valid ?tr.AC:25);
- if (attack.WeaponPerk==WEAPON_PERK_LONG_RANGE || attack.WeaponBonusPerk==WEAPON_PERK_LONG_RANGE) KPers=8;
- if (attack.WeaponPerk==WEAPON_PERK_SCOPE_RANGE || attack.WeaponBonusPerk==WEAPON_PERK_SCOPE_RANGE) KDist=2;
- if (attack.WeaponPerk==WEAPON_PERK_NIGHT_SIGHT || attack.WeaponBonusPerk==WEAPON_PERK_NIGHT_SIGHT) KPers=6;
- //if (valid(map.GetItem(hexX, hexY, PID_FOXHOLE))) acmod += 20;
- toHit = skillVal+(at.Perc+sharpshooter-2)*KPers-acc*KDist-acmod;
- if (cr.Perk[PE_MYSTERIOUS_STRANGER]==0) toHit -= attack.IsHthAttack ? ( GetHitAim( aim ) / 2 ) : GetHitAim( aim );
- //if( at.IsPlayer && weaponUpgrade == WEAPON_ACCURATE ) toHit += 20;
- if (weaponPerk==WEAPON_PERK_ACCURATE) toHit+=20;
- if( at.IsOneHand ) toHit += ( ( weapIsTwoHand ) ? -40 : 60 );
- if( at.HandlStr < weapStr )
- {
- if( (at.IsOneHand && weapIsTwoHand) || !at.IsOneHand )
- toHit -= ( weapStr - at.HandlStr ) * 20;
- }
- if( (at.IsOneHand && weapIsTwoHand==false)) attack.ClearDamageBonus += 7;
- if (tr.Valid && tr.IsKnockout) toHit += 30;
- if (tr.Valid && target.GetMultihex() > 0 ) toHit += 10;
- toHit -= 5 * at.SuppRate;
- if( at.eyeDamage ) toHit -= 50;
- if( at.IsNearOfficer ) toHit += 5;
- if( at.IsStable ) toHit += 35;
- toHit += cr.Stat[ST_HIT_MOD];
- if( weapPid == 7960 ) toHit = 95;
- if (!attack.IsFlamethrower && !isHthAttack) toHit -= smokePen;
- if( cr.PerkBase[ PE_IMP1]>0 && cr.PerkBase[ PE_IMP1]!=4) toHit += 3;
- int BaseHit= toHit;
- toHit = CLAMP( toHit, 5, 95-(10*cover) );
- // toHit -= 10 * cover;
- bool trowknife=(validWeap && (weapPid==PID_THROWING_KNIFE || weapPid==PID_THROWING_KNIFE_MK2));
- if (cr.Trait[TRAIT_HEAVY_HANDED]!=0 && (weapIsTwoHand || (weaponSubtype!=WS_MELEE &&!trowknife))) toHit = CLAMP( toHit/2, 5, 50 );
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------ MARGIN
- uint bonusth=GetBonusWp(realWeapon, 7);
- margin =toHit-Random(0,100)+bonusth;
- if (tr.Valid && target.Trait[TRAIT_HEAVY_HANDED]!=0 && trPidArmor==265) bonusth+=10;
- tr.DodgeChance = CLAMP( tr.DodgeChance-(sharpshooter>0?5:0), 0, 50 );
- if (cr.StatBase[ST_NEXT_REPLICATION_ENTIRE]!=0) cr.Say (SAY_NETMSG, "tohit-"+ toHit+"% "+" hit-"+margin);
- //cr.Say (SAY_NETMSG, "hit-"+ margin);
- // ------------------------------------------------------------ DODGES
- if (at.IsSniper && at.WasNotInCombat && attack.IsSingleAttack && attack.SkillVal >= 100) margin = 10;
- if (cr.Trait[TRAIT_KAMIKAZE]!=0 && at.WasNotInCombat) cr.StatBase[ST_CURRENT_AP]+=200;
- if( margin >= 0 && !attack.IsBurst && !attack.IsFlamethrower && !attack.IsRocket && !attack.IsGrenade && tr.Valid)
- {
- // cr.Say( SAY_NETMSG, "Dodge-"+tr.DodgeChance);
- if((Random(0,99)<tr.DodgeChance))
- {
- margin = -100;
- target.SayMsg( SAY_NETMSG, TEXTMSG_COMBAT, STR_COMBAT_YOU_DODGED);
- if (tr.IsFortuneFinder) target.StatBase[ ST_CURRENT_AP ] += 100;
- }
- if (Random(0,100)<tr.BaseLuck && target.Perk[PE_HEAVE_HO]>0 && target.CountItem(PID_BOTTLE_CAPS)>0)
- {
- margin = -10;
- _CritDeleteItem( target, PID_BOTTLE_CAPS, 1 );
- }
- }
- else if( margin >= 0 && tr.Valid)
- {
- if((Random(0,99)<tr.DodgeChance))
- {
- attack.PercentDamage = attack.PercentDamage/2;
- margin = 177;
- target.SayMsg( SAY_NETMSG, TEXTMSG_COMBAT, STR_COMBAT_PARTIALLY_DODGED );
- if (tr.IsFortuneFinder) target.StatBase[ ST_CURRENT_AP ] += 100;
- }
- }
- /* if(attack.IsAlwaysAlt)
- {
- if(Random(0,100) <= toHit)
- margin = 10;
- else
- margin = -10;
- } */
- // ------------------------------------------------------------ MISSES
- if( margin < 0)
- {
- if( tr.Valid && tr.IsAnimFriend && margin!=-100)
- {
- if (Random(0,100)<(tr.BaseAgil + tr.BaseChar+tr.BasePerc)) target.StatBase[ST_CURRENT_AP]=toHit*10;
- else target.StatBase[ ST_CURRENT_AP ] += 100;
- }
- if (cr.Perk[PE_CAUTIOUS_NATURE] != 0) cr.StatBase[ ST_CURRENT_AP ] += 100;
- // ------------------------------------------------------------ CRITICAL FAILURE
- if( !at.IsGod )
- {
- isCritical = _ChanceR( RANDOM(Random(1, 100), 20, 5), 2);
- if( !isCritical ) isCritical = ( _Chance( 2, 1 ) && ( at.IsJinxed || ( _Chance( 2, 1 ) && tr.IsJinxed ) ) );
- if( at.IsStable || cr.Trait[TRAIT_HEAVY_HANDED]!=0) isCritical = false;
- if( isCritical )
- {
- int luckmod = at.Luck;
- if( at.PidSlot2 == PID_TALISMAN ) luckmod += 3;
- if( luckmod > 10 )
- luckmod = 10;
- int roll = Random( 1, 100 ) - 5 * ( luckmod - 5 );
- if( roll <= 20 )
- roll = 0;
- else if( roll <= 50 )
- roll = 1;
- else if( roll <= 75 )
- roll = 2;
- else if( roll <= 95 )
- roll = 3;
- else
- roll = 4;
- critfailFlags = CriticalFailureTable[ 5 * weapon.Weapon_CriticalFailture + roll ];
- if( critfailFlags == 0 )
- isCritical = false;
- hitRandomly = FLAG( critfailFlags, MF_HIT_RANDOMLY );
- }
- }
- }
- // ------------------------------------------------------------ HIT APPLIES
- else
- {
- isHit = true;
- if(at.IsAdrenaline && tr.Valid) cr.StatBase[ST_CURRENT_HP] += (cr.StatBase[ ST_PERCEPTION ]*2);
- if( attack.IsHthAttack && at.IsSlayer ) at.CriticalCh = 100; // !!!STRUCK UPDATE!!!
- if( at.IsStable || cr.Trait[TRAIT_HEAVY_HANDED]!=0) at.CriticalCh = 0; // !!!STRUCK UPDATE!!!
- at.CriticalCh = CLAMP( at.CriticalCh, 0, 100 );
- uint critrnd=Random(0,99); bool Critup=(critrnd<at.CriticalCh?true:false);
- if (tr.Valid) cr.StatBase[ST_EMP_RESIST_EXT]=(Critup?target.Id:0); uint anticrrnd=Random(0,100);
- if (tr.Valid && Critup && (tr.CritResist<anticrrnd) ) isCritical = true;
- if(tr.Valid && tr.IsKnockout && Random(0, 3) > 0) isCritical = false; // Персонаж в отключке. Безвылазное критование в минуса отменяется.
- if(!attack.IsSingleAttack && !attack.IsBurst && !attack.IsHthAttack && !attack.IsFlamethrower) isCritical=false;
- if(!tr.Valid) isCritical = false;
- if (tr.IsFortuneFinder && target.Stat[ST_CURRENT_HP]<target.Stat[ST_MAX_LIFE]/3) isCritical = false;
- // ///////////////////////////////////////////////////////////////////
- // --------------------------------------------- DAMAGE MANIPULATIONS
- // if( !at.IsKind && validWeap && at.MasterPerk > 0 ) attack.PercentDamage += at.MasterPerk;
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- ALL MANIPULATIONS
- if( tr.Valid )
- {
- attack.TargetId = target.Id;
- @attack.Target = target; // !!!STRUCK UPDATE!!!
- }
- // ///////////////////////////////////////////////////////////////////
- // ---------------------------------------------------------- SPECIALS
- if( weapPid == 7960 )
- attack.RealMap.PlaySound( "MORTIER_SHOT.ogg", cr.HexX, cr.HexY, 0 );
- if( attack.WeaponPerk == WEAPON_PERK_FLAMEBOY || attack.WeaponBonusPerk == WEAPON_PERK_FLAMEBOY || ammoPid==PID_NAPALM)
- {
- if((attack.RealMap.IsHexRaked( attack.Tx, attack.Ty )) || ( tr.Valid && _ChanceR(RANDOM(Random(1, 100), 20, 5), int(10 + ( (at.IsPyro) ? 20 : 0)) ) ) )
- {
- SmokeBlast( attack.RealMap, hexX, hexY, PID_FIRE, ( valid( attack.Attacker ) ? attack.Attacker.Id : 0 ), 1 + ( ( at.IsPyro || ammoPid == PID_NAPALM) ? 1 : 0 ) );
- }
- }
- }
- if( hitRandomly && tr.Valid )
- {
- Critter@ randomTarget = ChooseRandomTarget( attack.RealMap, cr, target, wpnMaxDist );
- if( @randomTarget != null )
- {
- tx = randomTarget.HexX;
- ty = randomTarget.HexY;
- attack.Dist = GetDistantion( hx, hy, tx, ty ); // !!!STRUCK UPDATE!!!
- attack.Aim = HIT_LOCATION_UNCALLED; // !!!STRUCK UPDATE!!!
- // ------------------------------------------- Перезаписываем класс TR
- tr = _GetTrStruct(randomTarget); // !!!STRUCK UPDATE!!!
- if(tr.IsHidden) randomTarget.ModeBase[ MODE_HIDE ] = 0;
- NotifyOops( cr, target, attack.Target, results );
- }
- }
- else
- {
- @realTarget = target;
- }
- @attack.Target = realTarget; // !!!STRUCK UPDATE!!!
- tr.Valid = valid(attack.Target); // !!!STRUCK UPDATE!!!
- if(tr.Valid)
- attack.TargetId = realTarget.Id; // !!!STRUCK UPDATE!!!
- // ------------------------------------------ // -- BELOW THIS POINT --
- // ------------------------------------------ // target validation = if(tr.Valid)
- // ------------------------------------------ // target handle = attack.Target
- // ------------------------------------------ // target checks from class tr.[CHECK]
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------ IMPORTANT - CR ANIMATION
- cr.Action( ACTION_USE_WEAPON, slot << 16 | ( ( ( !isHit && isCritical && !hitRandomly ) ? 1 : 0 ) << 8 ) | ( aim << 4 ) | use, realWeapon );
- bool changedTarget = ( hitRandomly && tr.Valid );
- // ------------------------------ IMPORTANT - RETURN : CriticalFailure
- if( !isHit && isCritical && ( !hitRandomly || !tr.Valid ) )
- {
- CriticalFailure( cr, weapon, use, ammo, critfailFlags, results, slot );
- return;
- }
- // ///////////////////////////////////////////////////////////////////
- // ///////////////// -------- TARGET WAS HIT -------- ////////////////
- // ///////////////////////////////////////////////////////////////////
- // ----------------------------------------------- UNARMED AND MELEE ATTACK
- uint ClearDB = 0;
- uint ClearDR = 0;
- uint PercentD = 0;
- uint PercentR = 0;
- bool criticalHit = isHit && isCritical;
- if( attack.IsHthAttack )
- {
- if( isHit )
- {
- if( weapPid == 115 && tr.Valid && !tr.IsNoKnock && Random(0,1)==1)
- _KnockBack_Light( weapPid, Random(4, 8), map, cr, attack.Target );
- ApplyDamage( attack, at, tr, attack.Target, 1, criticalHit, true, results );
- }
- else
- {
- if( changedTarget )
- ApplyDamage( attack, at, tr, attack.Target, 1, false, false, results );
- else
- NotifyMiss( cr, results );
- }
- }
- // ---------------------------------------------- WS_GUN SINGLE ATTACK
- else if( ( weaponSubtype == WS_GUN ) && !attack.IsBurst && !attack.IsRocket && !attack.IsFlamethrower )
- {
- if( isHit || changedTarget )
- {
- // ----------------------------------------------- WS_GUN SINGLE ATTACK AMMO MANIPULATIONS ONHIT ONLY
- // ----------------------------- Гаусс - Особенность - прошивает все цели на линии атаки. С каждой прошитой целью мин и макс атака
- // ----------------------------- уменьшается на 5-9. Если мин или макс. атака опускается ниже 10 - нанесение урона прерывается.
- if( ammoPid == PID_2MM_EC_AMMO || ammoPid == PID_2MM_MAG )
- {
- aimOld = attack.Aim;
- Critter@[] critsLine;
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, wpnMaxDist, FIND_LIFE_AND_KO, critsLine );
- if(critsLine.length() == 0) return;
- AdvEffect( weapon, cr, attack.Target );
- for( int i = 0, j = critsLine.length(); ( i < j ); i++ )
- {
- if(attack.DmgMin < 10 || attack.DmgMax < 10)
- continue;
- if( critsLine[ i ].Id == realTarget.Id )
- continue;
- else
- {
- attack.Aim = HIT_LOCATION_UNCALLED;
- @attack.Target = critsLine[ i ];
- attack.TargetId = critsLine[ i ].Id;
- ClearDB = attack.ClearDamageBonus;
- ClearDR = attack.ClearDamageReduction;
- PercentD = attack.PercentDamage;
- PercentR = attack.PercentReduction;
- ApplyDamage( attack, at, tr, attack.Target, 1, false, false, results );
- attack.ClearDamageBonus = ClearDB;
- attack.ClearDamageReduction = ClearDR;
- attack.PercentDamage = PercentD;
- attack.PercentReduction = PercentR;
- attack.DmgMin -= Random(5,9); // !!!STRUCK UPDATE!!!
- attack.DmgMax -= Random(5,9); // !!!STRUCK UPDATE!!!
- @attack.Target = realTarget;
- attack.TargetId = realTarget.Id;
- attack.Aim = aimOld;
- }
- }
- }
- // ----------------------------- Остальные типы спец.патронов.
- if( isKnockMechanics && tr.Valid && !tr.IsNoKnock)
- _KnockBack_Light( weapPid, Random(6, 10), map, cr, attack.Target );
- if( isShotgunMechanics && tr.Valid && !tr.IsNoKnock)
- _KnockBack_Shotgun( weapPid, ammoPid, attack.Dist, wpnMaxDist, weapStr, at.HandlStr, map, cr, attack.Target );
- if( ( ammoPid == PID_12MM_FIRE || ammoPid == PID_10MM_APFIRE || attack.WeaponPerk == WEAPON_PERK_FLAMEBOY || attack.WeaponBonusPerk == WEAPON_PERK_FLAMEBOY) && tr.Valid )
- AffectFire( attack.Target, (15+attack.Attacker.PerkBase[PE_PYROMANIAC]*20+attack.Attacker.Perk[PE_DA_FIRE]*2), attack.Attacker.Id );
- if( ammoPid == PID_HK_NEEDLER_POISON )
- AffectPos( attack.Target, 16, ( valid( attack.Attacker ) ? attack.Attacker.Id : 0 ) );
- // ----------------------------- SUPPRESSION
- if( ( at.IsSupporter ) && toHit > 75)
- {
- supressRounds = 1;
- if( attack.Dist >= 3 && attack.Dist <= 15)
- {
- if( ammoPid == PID_SHOTGUN_SHELLS || ammoPid == PID_12MM_FIRE || ammoPid == PID_12MM_BULL )
- {
- if( ammoPid == PID_SHOTGUN_SHELLS )
- supressRounds = Random( 13, 20 );
- if( ammoPid == PID_12MM_FIRE )
- supressRounds = Random( 20, 34 );
- if( ammoPid == PID_12MM_BULL )
- supressRounds = Random( 24, 28 );
- SuppressCritter( attack.Target, cr, supressRounds );
- }
- }
- else if( ( attack.WeaponPerk == WEAPON_PERK_LONG_RANGE || attack.WeaponBonusPerk == WEAPON_PERK_LONG_RANGE) && skillNum == SK_SMALL_GUNS && attack.Dist >= 25 )
- {
- supressRounds = Random( attack.Dist/2 - 5, attack.Dist/2 + 10 );
- SuppressCritter( attack.Target, cr, supressRounds );
- }
- }
- /* if(attack.Aim != HIT_LOCATION_UNCALLED && attack.Aim != HIT_LOCATION_TORSO && _ChanceR(RANDOM(Random(1, 100), 20, 5), at.Luck*3) && attack.IsSingleAttack && (attack.WeaponPerk == WEAPON_PERK_SCOPE_RANGE || attack.WeaponBonusPerk == WEAPON_PERK_SCOPE_RANGE) )
- {
- SETFLAG(attack.ForceFlags, HF_BYPASS_ARMOR);
- } */
- ApplyDamage( attack, at, tr, attack.Target, 1, criticalHit, !changedTarget, results );
- AdvEffect( weapon, cr, attack.Target );
- }
- // ----------------------------------------------- WS_GUN SINGLE ATTACK AMMO MANIPULATIONS MISS ONLY
- else
- {
- Critter@[] critsLine;
- attack.Aim = HIT_LOCATION_UNCALLED;
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, wpnMaxDist, FIND_LIFE_AND_KO, critsLine );
- if(critsLine.length() == 0) return;
- int bl = 0;
- bool anyHit = false;
- for( int i = 0, j = critsLine.length(); ( i < j ) && !anyHit; i++ )
- {
- if( critsLine[ i ].Id == realTarget.Id )
- {
- bl++;
- continue;
- } // skip the primary target
- // adjust tohit
- dist = GetDistantion( hx, hy, critsLine[ i ].HexX, critsLine[ i ].HexY );
- toHit = getFirstToHit(baseToHit, bl, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, critsLine[ i ], bulletPower, acmod);
- if( !critsLine[ i ].IsKnockout() )
- bl++;
- toHit /= 3;
- if( Random( 1, 100 ) <= toHit )
- {
- NotifyOops( cr, target, critsLine[ i ], results );
- @normalTarget = critsLine[ i ];
- useNormal = true;
- ApplyDamage( attack, at, tr, normalTarget, 1, criticalHit, !changedTarget, results );
- anyHit = true;
- }
- }
- if( !anyHit )
- NotifyMiss( cr, results );
- }
- }
- // ///////////////////////////////////////////////////////////////////
- // ---------------------------------------------------- FLAMERS ATTACK
- // ///////////////////////////////////////////////////////////////////
- else if( isFlamethrower )
- {
- if( changedTarget )
- {
- dist = GetDistantion( hx, hy, tx, ty );
- acc = dist;
- blockers = attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, dist, FIND_LIFE, null );
- if( !attack.Target.IsKnockout() )
- blockers--;
- toHit = getFirstToHit(baseToHit, blockers, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, attack.Target, bulletPower, acmod);
- }
- // critical hit bonus, toHit can be increased over 100
- if( criticalHit ) toHit += 20;
- // proceed with the flame attack
- Critter@[] critsHit( 0 );
- uint[] critsHitBullets( 0 );
- int len_ = 0;
- if( _ChanceR(RANDOM(Random(1, 100), 20, 5), toHit) && tr.Valid)
- {
- critsHit.resize( 1 );
- @critsHit[ 0 ] = attack.Target;
- critsHitBullets.resize( 1 );
- critsHitBullets[ 0 ] += 1;
- len_++;
- }
- Critter@[] lineCentral;
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, wpnMaxDist, FIND_LIFE_AND_KO, lineCentral );
- int bl;
- if(lineCentral.length() > 0)
- {
- for( int lineCount = 0, lineMax = 1; lineCount < lineMax; lineCount++ )
- {
- // lineCentral
- bl = 0; // zero blockers
- for( int i = 0, j = lineCentral.length(); i < j; i++ )
- {
- // adjust tohit
- if(!valid(lineCentral[ i ])) continue;
- dist = GetDistantion( attack.Hx, attack.Hy, lineCentral[ i ].HexX, lineCentral[ i ].HexY );
- toHit = getFirstToHit(baseToHit, bl, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, lineCentral[ i ], bulletPower, acmod);
- if( !lineCentral[ i ].IsKnockout() )
- bl++;
- if( _ChanceR(RANDOM(Random(1, 100), 20, 5), toHit) )
- {
- int crIndex = FindCritterInArray( critsHit, lineCentral[ i ] );
- if( crIndex == -1 )
- {
- critsHit.resize( len_ + 1 );
- @critsHit[ len_ ] = lineCentral[ i ];
- critsHitBullets.resize( len_ + 1 );
- crIndex = len_;
- len_++;
- }
- critsHitBullets[ crIndex ] += 1;
- }
- }
- // lineCentral end
- }
- }
- uint8 leftDir = GetOffsetDir( hx, hy, tx, ty, 89.0f );
- uint16 sx = hx;
- uint16 sy = hy;
- uint16 ex = tx;
- uint16 ey = ty;
- map.MoveHexByDir( sx, sy, leftDir, 1 );
- map.MoveHexByDir( ex, ey, leftDir, 1 );
- Critter@[] lineLeft;
- attack.RealMap.GetCrittersPath( sx, sy, ex, ey, 0.0f, wpnMaxDist - 1, FIND_LIFE_AND_KO, lineLeft );
- int leftStart = 0;
- int leftLen = lineLeft.length();
- while( ( leftStart < leftLen ) && ( GetDistantion( hx, hy, lineLeft[ leftStart ].HexX, lineLeft[ leftStart ].HexY ) ) < 3 )
- leftStart++;
- if(lineLeft.length() > 0)
- {
- for( int i = leftStart, j = leftLen; i < j; i++ )
- {
- // adjust tohit
- if(!valid(lineLeft[ i ])) continue;
- dist = GetDistantion( hx, hy, lineLeft[ i ].HexX, lineLeft[ i ].HexY );
- bl = attack.RealMap.GetCrittersPath( hx, hy, lineLeft[ i ].HexX, lineLeft[ i ].HexY, 0.0f, dist, FIND_LIFE, null ) - 1;
- toHit = getFirstToHit(baseToHit, bl, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, lineLeft[ i ], bulletPower, acmod);
- if( _ChanceR( RANDOM(Random(1, 100), 20, 5), toHit ) )
- {
- int crIndex = FindCritterInArray( critsHit, lineLeft[ i ] );
- if( crIndex == -1 )
- {
- critsHit.resize( len_ + 1 );
- @critsHit[ len_ ] = lineLeft[ i ];
- critsHitBullets.resize( len_ + 1 );
- crIndex = len_;
- len_++;
- }
- critsHitBullets[ crIndex ] += 1;
- }
- } // left line
- }
- uint8 rightDir = GetOffsetDir( hx, hy, tx, ty, -89.0f );
- sx = hx;
- sy = hy;
- ex = tx;
- ey = ty;
- map.MoveHexByDir( sx, sy, rightDir, 1 );
- map.MoveHexByDir( ex, ey, rightDir, 1 );
- Critter@[] lineRight;
- attack.RealMap.GetCrittersPath( sx, sy, ex, ey, 0.0f, wpnMaxDist - 1, FIND_LIFE_AND_KO, lineRight );
- int rightStart = 0;
- int rightLen = lineRight.length();
- while( ( rightStart < rightLen ) && ( GetDistantion( hx, hy, lineRight[ rightStart ].HexX, lineRight[ rightStart ].HexY ) ) < 3 )
- rightStart++;
- if(lineRight.length() > 0)
- {
- for( int i = rightStart, j = rightLen; i < j; i++ )
- {
- // adjust tohit
- if(!valid(lineRight[ i ])) continue;
- dist = GetDistantion( hx, hy, lineRight[ i ].HexX, lineRight[ i ].HexY );
- bl = attack.RealMap.GetCrittersPath( hx, hy, lineRight[ i ].HexX, lineRight[ i ].HexY, 0.0f, dist, FIND_LIFE, null ) - 1;
- toHit = getFirstToHit(baseToHit, bl, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, lineRight[ i ], bulletPower, acmod);
- if( _ChanceR( RANDOM(Random(1, 100), 20, 5), toHit ) )
- {
- int crIndex = FindCritterInArray( critsHit, lineRight[ i ] );
- if( crIndex == -1 )
- {
- critsHit.resize( len_ + 1 );
- @critsHit[ len_ ] = lineRight[ i ];
- critsHitBullets.resize( len_ + 1 );
- crIndex = len_;
- len_++;
- }
- critsHitBullets[ crIndex ] += 1;
- }
- } // right line
- }
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- FLAME DEAL DAMAGE
- // ///////////////////////////////////////////////////////////////////
- for( int i = 0, j = len_; i < j; i++ )
- {
- if(!valid(critsHit[ i ])) continue;
- @attack.Target = critsHit[ i ];
- attack.TargetId = critsHit[ i ].Id;
- // if (critsHit[i].Id==target.Id && cover>0) attack.PercentDamage= attack.PercentDamage/2;
- ClearDB = attack.ClearDamageBonus;
- ClearDR = attack.ClearDamageReduction;
- PercentD = attack.PercentDamage;
- PercentR = attack.PercentReduction;
- if(attack.IsAlwaysAlt)
- ApplyDamage( attack, critsHit[ i ], 1, false, ( cr.IsPlayer() && !changedTarget ) || ( !at.IsPlayer && critsHit[ i ].Id == attack.TargetId ), results );
- else
- ApplyDamage( attack, at, tr, critsHit[ i ], 1, ( realTarget.Id == critsHit[ i ].Id ) && criticalHit, ( at.IsPlayer && !changedTarget ) || ( cr.IsNpc() && critsHit[ i ].Id == target.Id ), results );
- attack.ClearDamageBonus = ClearDB;
- attack.ClearDamageReduction = ClearDR;
- attack.PercentDamage = PercentD;
- attack.PercentReduction = PercentR;
- if( (ammoPid == PID_NAPALM || attack.WeaponPerk == WEAPON_PERK_FLAMEBOY || attack.WeaponBonusPerk == WEAPON_PERK_FLAMEBOY ) )
- AffectFire( critsHit[ i ], (15+attack.Attacker.PerkBase[PE_PYROMANIAC]*20+attack.Attacker.Perk[PE_DA_FIRE]*2), attack.Attacker.Id );
- }
- if( !changedTarget && !attack.TargetHit )
- NotifyMiss( cr, results );
- }
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- BURST FIRE ATTACK
- // ///////////////////////////////////////////////////////////////////
- else if((weaponSubtype==WS_GUN) && isBurst) //
- {
- int skilMod=skillVal-acmod; skilMod=(skilMod>5?skilMod:5);
- BaseHit = CLAMP( BaseHit, 5, skilMod);
- if (ammoCount<=ammoRound) ammoRound=ammoCount;
- int kburst=0; uint burst_accuracy =0;
- for( int i = 0; i < ammoRound; i++ )
- {
- kburst=BaseHit-4*attack.Dist*i;
- if (kburst>0) burst_accuracy += (Random(0,attack.Dist*i)<kburst?1:0);
- }
- uint const_rounds=ammoRound-burst_accuracy;
- uint[] critsHitBullets;
- Critter@[] critsHit;
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, wpnMaxDist, FIND_LIFE_AND_KO, critsHit );
- critsHitBullets.resize(critsHit.length());
- uint dists=0; uint mas=0; int hitto=0; uint tar=0;
- for( int i = 0; i < critsHit.length(); i++ )
- {
- if (target.Id==critsHit[i].Id)
- {critsHitBullets[i] = burst_accuracy; tar=i;}
- else critsHitBullets[i] = 0;
- dists = GetDistantion( hx, hy, critsHit[i].HexX, critsHit[i].HexY );
- if (attack.Dist>dists && burst_accuracy>0 && target.Id!=critsHit[i].Id)
- {
- mas=burst_accuracy/2;
- critsHitBullets[i] += mas;
- burst_accuracy-=mas;
- if (tar!=0) critsHitBullets[tar] = burst_accuracy;
- }
- //cr.Say( SAY_NETMSG, "Bur-"+critsHit[i].Id+"-"+critsHitBullets[i]);
- }
- if (critsHit.length()>1)
- {
- for( int i = 0; i < const_rounds; i++ )
- {
- mas=Random(0,critsHit.length()-1);
- dists = GetDistantion( hx, hy, critsHit[mas].HexX, critsHit[mas].HexY );
- hitto=BaseHit-(attack.Dist)*5-Random(0,100);
- if (target.Id!=critsHit[mas].Id && hitto>0) critsHitBullets[mas] += 1;
- }
- }
- //cr.Say( SAY_NETMSG, "Bur-"+minBurstD+"-"+maxBurstD+" lok-"+i_lock+" bur-"+burst_accuracy);
- uint hitround=0;
- for( int i = 0, j = critsHit.length(); i < j; i++ )
- {
- if(!valid(critsHit[i])) continue;
- hitround+=critsHitBullets[i];
- if(critsHitBullets[i]==0) continue;
- ClearDB = attack.ClearDamageBonus;
- ClearDR = attack.ClearDamageReduction;
- PercentD = attack.PercentDamage;
- PercentR = attack.PercentReduction;
- ApplyDamage( attack, at, tr, critsHit[i], critsHitBullets[i], ( target.Id == critsHit[i].Id ) && criticalHit, (critsHit[i].Id==target.Id), results);
- AdvEffect( weapon, cr, critsHit[ i ] );
- attack.ClearDamageBonus = ClearDB;
- attack.ClearDamageReduction = ClearDR;
- attack.PercentDamage = PercentD;
- attack.PercentReduction = PercentR;
- if( validAmmo && weaponSubtype == WS_GUN )
- {
- uint Ston=(critsHit[i].PerkBase[PE_STONEWALL]==1?Random(0,2):0);
- //if (critsHit[ i ].PerkBase[ PE_STONEWALL ]==1) Ston=Random(0,2);
- bool noKnock = (critsHit[i].Mode[MODE_NO_KNOCK]!=0 || Ston==1 || !critsHit[i].IsCanWalk());
- if( isShotgunMechanics && !noKnock )
- _KnockBack_Shotgun( weapPid, ammoPid, dist, wpnMaxDist, weapStr, at.HandlStr, map, cr, critsHit[ i ] );
- if( isKnockMechanics && !noKnock )
- _KnockBack_Light( weapPid, Random(3, 7), map, cr, critsHit[ i ] );
- if( ammoPid == PID_12MM_FIRE || ammoPid == PID_10MM_APFIRE || attack.WeaponPerk == WEAPON_PERK_FLAMEBOY || attack.WeaponBonusPerk == WEAPON_PERK_FLAMEBOY )
- AffectFire( critsHit[ i ], (15+attack.Attacker.PerkBase[PE_PYROMANIAC]*20+attack.Attacker.Perk[PE_DA_FIRE]*2), attack.Attacker.Id );
- if( ammo.ProtoId == PID_HK_NEEDLER_POISON )
- AffectPos( critsHit[ i ], 16, ( valid( attack.Attacker ) ? attack.Attacker.Id : 0 ) );
- }
- if( ( at.IsSupporter ) && toHit > 75)
- {
- dist = GetDistantion( hx, hy, critsHit[ i ].HexX, critsHit[ i ].HexY );
- supressRounds = critsHitBullets[ i ];
- if( skillNum == SK_SMALL_GUNS && dist >= 3 && dist < 15)
- {
- if( ammoPid != PID_SHOTGUN_SHELLS && ammoPid != PID_12MM_FIRE && ammoPid != PID_12MM_BULL ) SuppressCritter( critsHit[ i ], cr, supressRounds );
- if( ammoPid == PID_SHOTGUN_SHELLS ) supressRounds = Random( 13, 20 );
- if( ammoPid == PID_12MM_FIRE ) supressRounds = Random( 20, 34 );
- if( ammoPid == PID_12MM_BULL ) supressRounds = Random( 24, 28 );
- SuppressCritter( critsHit[ i ], cr, supressRounds * 2 / 3);
- }
- if( skillNum == SK_SMALL_GUNS && dist >= 15)
- {
- if( ammoPid != PID_SHOTGUN_SHELLS && ammoPid != PID_12MM_FIRE && ammoPid != PID_12MM_BULL )
- SuppressCritter( critsHit[ i ], cr, supressRounds*2 );
- }
- if(skillNum == SK_BIG_GUNS && dist >= 3 && dist < 15) SuppressCritter( critsHit[ i ], cr, supressRounds*2 );
- if(skillNum == SK_BIG_GUNS && dist >= 15) SuppressCritter( critsHit[ i ], cr, supressRounds*3 );
- }
- }
- if( (!changedTarget && !attack.TargetHit) || hitround==0) NotifyMiss( cr, results );
- }
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------- ROCKETS, THROWING
- // ///////////////////////////////////////////////////////////////////
- else if( attack.IsRocket || ( weaponSubtype == WS_THROWING && weapPid != PID_FLARE && weapPid != PID_ACTIVE_FLARE) )
- {
- bool exploding = (attack.IsRocket || attack.IsGrenade);
- if(margin == 700)
- isHit = _ChanceR(RANDOM(Random(1, 100), 20, 5), toHit);
- if( isHit || changedTarget )
- {
- if( exploding )
- {
- CommenceExplosion( attack, map, tx, ty, attack.Target, weapPid, criticalHit, (tr.Valid) ? attack.Target.Id : 0, isRocket, results );
- }
- else
- {
- /*if( at.IsHidden && cr.Skill[SK_SNEAK] >= 100)
- attack.DmgMul *= 2;*/
- /* if( at.IsSilentDeath && ( at.Dir == tr.Dir || ( ( at.Dir + 1 ) % 6 ) == tr.Dir || ( ( at.Dir + 5 ) % 6 ) == tr.Dir ) )
- criticalHit = true; */
- if( attack.IsAlwaysAlt )
- ApplyDamage( attack, attack.Target, 1, criticalHit, !changedTarget, results );
- else
- ApplyDamage( attack, at, tr, attack.Target, 1, criticalHit, !changedTarget, results );
- }
- }
- else
- {
- // ///////////////////////////////////////////////////////////////////
- // ---------------------------------------- ROCKETS, THROWING - MISSES
- // ///////////////////////////////////////////////////////////////////
- attack.Aim = HIT_LOCATION_UNCALLED;
- if( weaponSubtype == WS_THROWING )
- sharpshooter = 0;
- uint16 bx = 0;
- uint16 by = 0;
- uint16 pbx = 0;
- uint16 pby = 0;
- Critter@[] critsLine;
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, wpnMaxDist, FIND_LIFE_AND_KO, critsLine, pbx, pby, bx, by );
- int bl = 0;
- bool anyHit = false;
- for( int i = 0, j = critsLine.length(); ( i < j ) && !anyHit; i++ )
- {
- // binyan - hex attack added target validation
- if( tr.Valid && critsLine[ i ].Id == attack.Target.Id )
- {
- bl++;
- continue;
- } // skip the primary target
- dist = GetDistantion( hx, hy, critsLine[ i ].HexX, critsLine[ i ].HexY );
- toHit = getFirstToHit(baseToHit, bl, dist, acc, distmod2, accloss, at.Perc, sharpshooter, at.eyeDamage, at.IsBloody, at.IsStable, critsLine[ i ], bulletPower, acmod);
- if( !critsLine[ i ].IsKnockout() )
- bl++;
- toHit /= 3; // after clamp
- if( _ChanceR( RANDOM(Random(1, 100), 20, 5), toHit) )
- {
- tx = critsLine[ i ].HexX;
- ty = critsLine[ i ].HexY;
- @normalTarget = critsLine[ i ];
- anyHit = true;
- }
- }
- if( anyHit )
- {
- NotifyOops( cr, target, normalTarget, results );
- useNormal = true;
- if( exploding )
- CommenceExplosion( attack, map, tx, ty, normalTarget, weapPid, false, valid( realTarget ) ? realTarget.Id : 0, isRocket, results );
- else
- ApplyDamage( attack, at, tr, normalTarget, 1, false, false, results );
- }
- else
- {
- useHex = true;
- NotifyMiss( cr, results );
- if( attack.IsGrenade )
- {
- // binyan - hex attack added target validation
- tx = (tr.Valid) ? attack.Target.HexX : ( hexX + Random( -5, +5 ) );
- ty = (tr.Valid) ? attack.Target.HexY : ( hexY + Random( -5, +5 ) );
- int newdist = GetDistantion( hx, hy, tx, ty ) + 1;
- map.MoveHexByDir( tx, ty, Random( 0, 5 ), Random( newdist / 2, newdist ) );
- newdist = GetDistantion( hx, hy, tx, ty );
- attack.RealMap.GetCrittersPath( hx, hy, tx, ty, 0.0f, newdist, FIND_LIFE, null, tx, ty, bx, by );
- }
- else
- {
- if( attack.IsRocket )
- {
- tx = hexX + Random( -5, +5 );
- ty = hexY + Random( -5, +5 );
- }
- else
- {
- tx = pbx;
- ty = pby;
- }
- }
- if( exploding )
- CommenceExplosion( attack, map, tx, ty, null, weapPid, false, (tr.Valid) ? attack.Target.Id : 0, isRocket, results );
- }
- }
- }
- // ///////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------ FINISH
- // ///////////////////////////////////////////////////////////////////
- else
- {
- if(weapPid != PID_FLARE && weapPid != PID_ACTIVE_FLARE)
- cr.Say( SAY_NETMSG, "Combat error: weapon PID=" + weapPid + " not handled, please send bug report." );
- }
- FlushResults( results );
- if( _WeaponEffect( weapon, use ) != 0 )
- {
- if( useHex || not valid( realTarget ) )
- map.RunFlyEffect( _WeaponEffect( weapon, use ), cr, null, hx, hy, tx, ty ); // yeah, the target can be null (see: grenades, rocket launcher)
- else
- map.RunFlyEffect( _WeaponEffect( weapon, use ), cr, ( useNormal ? normalTarget : attack.Target ), hx, hy, tx, ty );
- }
- if( validWeap )
- {
- if(ammoRound > 0 && cr.Mode[ MODE_UNLIMITED_AMMO ] == 0 && slot != 99)
- {
- if( ammoCount <= ammoRound )
- realWeapon.AmmoCount = 0;
- else
- realWeapon.AmmoCount -= ammoRound;
- realWeapon.Update();
- }
- if( realWeapon.IsDeteriorable() )
- {
- int deter = ( MAX_SKILL_VAL - skillVal )/4 + 15;
- if (FLAG(realWeapon.BrokenFlags, BI_SERVICE_EXT)) deter+=25;
- DeteriorateItem( cr, realWeapon, deter);
- }
- if( wpnIsRemoved && cr.Mode[ MODE_UNLIMITED_AMMO ] == 0 )
- {
- bool placeOnHex = ( skillNum == SK_THROWING && !attack.IsGrenade );
- if( realWeapon.IsStackable() )
- {
- Item@ tomap;
- // Place on hex
- if( placeOnHex )
- {
- if(weapPid == PID_FLARE)
- @tomap = map.AddItem( tx, ty, PID_ACTIVE_FLARE, 1 );
- else if (Random(0,100)>5)
- @tomap = map.AddItem( tx, ty, weapPid, 1 );
- }
- if(valid(tomap))
- {
- if(tomap.GetProtoId() == PID_ACTIVE_FLARE)
- {
- if(not FLAG(tomap.Flags, ITEM_LIGHT)) SETFLAG(tomap.Flags,ITEM_LIGHT);
- tomap.LightColor= (COLOR_RGB (200,200,25));
- tomap.Update();
- CreateTimeEvent(__FullSecond+REAL_SECOND(Random(120, 180)), "cte_FlareBurn", tomap.Id, false);
- }
- }
- // Sub 1 item
- if( realWeapon.GetCount() > 1 )
- realWeapon.SetCount( realWeapon.GetCount() - 1 );
- else
- DeleteItem( realWeapon );
- }
- else
- {
- MoveItem( realWeapon, 0, map, tx, ty );
- }
- }
- }
- if( !attack.TargetHit && tr.Valid )
- {
- if( !tr.IsPlayer )
- AI_TrySayCombatText( target, COMBAT_TEXT_MISS );
- target.Action( ACTION_DODGE, 0, null ); // Todo: type front/back
- }
- return;
- }
- 14889
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement