/// <summary> /// Calculate any possible critical hit/damage. /// </summary> /// <param name="Damage"></param> /// <param name="rollresult"></param> /// <returns></returns> private static bool RollForCritDamage(ref short Damage, Skills.SkillRollResult rollresult) { bool CriticalHit = false; if (rollresult == Skills.SkillRollResult.CriticalSuccess) { //based on dissasembly a crit is a 50:50 chance after the critical roll is scored //seems to be a 50:50 chance for a crit which gives double damage. //(48+(rng 0-30)) >>5 int crit = (48 + Random.Range(0, 31) >> 5); Damage = (short)(Damage * crit); CriticalHit = true; } return(CriticalHit); }
public override bool Eat() { int FoodValue = GameWorldController.instance.objDat.nutritionStats[item_id - 176].FoodValue; bool DrinkIsAlcoholic = false; int StringNo; //uw1 strings //000~001~237~The water refreshes you. \n //000~001~238~You drink the port. \n //000~001~239~You drink the dark ale. \n //uw2 strings //000~001~252~The water refreshes you. \n //000~001~253~You drink the wine. \n //000~001~254~You drink the dark ale. \n switch (_RES) { case GAME_UW2: switch (item_id) { case 187: //ale StringNo = 254; DrinkIsAlcoholic = true; break; case 189: //wine StringNo = 253; DrinkIsAlcoholic = true; break; default: //water StringNo = 252; break; } break; default: switch (item_id) { case 186: //ale StringNo = 239; DrinkIsAlcoholic = true; break; case 190: //port StringNo = 238; DrinkIsAlcoholic = true; break; default: //water StringNo = 237; break; } break; } UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringNo)); if (DrinkIsAlcoholic) { UWCharacter.Instance.Intoxication -= FoodValue; if (UWCharacter.Instance.Intoxication > 63) { UWCharacter.Instance.Intoxication = 63; } //Do a skill check for drunkeness vs strength. Skills.SkillRollResult result = Skills.SkillRoll(UWCharacter.Instance.PlayerSkills.STR, UWCharacter.Instance.Intoxication); switch (result) { case Skills.SkillRollResult.CriticalFailure: //clear intoxicaion. UWCharacter.Instance.Intoxication = 0; //Pass out drumk //000~001~256~As the alcohol hits you, you stumble and collapse into sleep. \n UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_as_the_alcohol_hits_you_you_stumble_and_collapse_into_sleep_)); //sleep UWCharacter.Instance.Sleep(); //wake up unstable UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_wake_feeling_somewhat_unstable_but_better_)); break; case Skills.SkillRollResult.CriticalSuccess: //heal 2 points of health and you feel better. UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_the_drink_makes_you_feel_a_little_better_for_now_)); UWCharacter.Instance.CurVIT = UWCharacter.Instance.CurVIT + 2; if (UWCharacter.Instance.CurVIT > UWCharacter.Instance.MaxVIT) { UWCharacter.Instance.CurVIT = UWCharacter.Instance.MaxVIT; } break; default: //screen shake CameraShake.instance.ShakeCombat(0.5f); break; } } else {//water Healing effect. (water should be 1 point (-1 in table) FoodValue = Mathf.Abs(FoodValue); UWCharacter.Instance.CurVIT += FoodValue; if (UWCharacter.Instance.CurVIT > UWCharacter.Instance.MaxVIT) { UWCharacter.Instance.CurVIT = UWCharacter.Instance.MaxVIT; } //Clear intoxication as well. UWCharacter.Instance.Intoxication = 0; } if (_RES == GAME_UW2) {//Some food items leave left overs LeftOvers(); } objInt().consumeObject();//destroy and remove from inventory/world. return(true); }
/// <summary> /// NPC hits player /// </summary> /// <param name="playerUW">Player U.</param> /// <param name="npc">Npc.</param> public static void NPC_Hits_PC(UWCharacter playerUW, NPC npc) { int flankingbonus = 0; flankingbonus = CalcFlankingBonus(npc.objInt().heading, playerUW.currentHeading); int attackScore = npc.CurrentAttackScore + (npc.EquipDamage >> 1) + Random.Range(0, 5) + 7 + flankingbonus; //+Maybe Npc Level //Player defence //defence skill + sum of all armour+(skill with current weapon >>1) + unknownbonus(stored in critterdata) int DefenderScore = playerUW.PlayerSkills.GetSkill(Skills.SkillDefense) + playerUW.playerInventory.ArmourProtection; if (playerUW.PlayerCombat.currWeapon != null) { DefenderScore += (playerUW.PlayerSkills.GetSkill(playerUW.PlayerCombat.currWeapon.GetSkill()) >> 1); } else { DefenderScore += (playerUW.PlayerSkills.GetSkill(Skills.SkillUnarmed) >> 1); } Skills.SkillRollResult rollresult = Skills.SkillRoll(attackScore, DefenderScore); if ((_RES == GAME_UW1) && (npc.item_id == 124) && (rollresult == Skills.SkillRollResult.CriticalFailure || rollresult == Skills.SkillRollResult.Failure)) { rollresult = Skills.SkillRollResult.Success;//Slasher of veils will always hit. } short Damage = 0; Damage = (short)(npc.CurrentAttackDamage + (npc.Strength / 5)); Damage = (short)Mathf.Max(Damage, 2); int baseDamage = Damage; bool CriticalHit = RollForCritDamage(ref Damage, rollresult); // damage % 6 no of 1D6s to calculate the actual damage and then add the remainder as a final roll 1-remainder Damage = (short)(DamageRoll((short)(Damage / 6), 6) + DamageRoll(1, (short)(Damage % 6))); //TODO: damage for NPCS is scaled based on a lookup table and a property in their mobile data. This is similar to the player attack charge. (values stored in segment_60 in UW2 exe) //Lookup appears to be based on the value in the object at 0xF ( bits 12 to 15) //For now just scale it randomly Damage = (short)Random.Range(2, Damage + 1); switch (rollresult) { case Skills.SkillRollResult.CriticalSuccess: case Skills.SkillRollResult.Success: { Debug.Log("Base Damage = " + (short)(baseDamage) + " Final Damage = " + Damage); playerUW.ApplyDamage(Damage, npc.gameObject); //TODO: restore equipment damage and poisoning. //Ten more seconds of combat music MusicController.LastAttackCounter = 10.0f; if (ObjectInteraction.PlaySoundEffects) { UWCharacter.Instance.aud.clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_MELEE_HIT_1]; UWCharacter.Instance.aud.Play(); } break; } case Skills.SkillRollResult.Failure: case Skills.SkillRollResult.CriticalFailure: //a miss. break; } //////// int PlayerDefence = 0; //////// if (playerUW.PlayerCombat.currWeapon != null) //////// { //////// PlayerDefence = playerUW.PlayerSkills.GetSkill(Skills.SkillDefense) + (playerUW.PlayerSkills.GetSkill(playerUW.PlayerCombat.currWeapon.GetSkill() + 1) / 2); //////// } //////// else //////// { //////// PlayerDefence = playerUW.PlayerSkills.GetSkill(Skills.SkillDefense) + (playerUW.PlayerSkills.GetSkill(Skills.SkillUnarmed) / 2); //////// } //////// int toHit = Mathf.Max(PlayerDefence - npc.Dexterity, 0); //////// int roll = Random.Range(-1, 31); //////// if ((_RES == GAME_UW1) && (npc.item_id == 124)) //////// { //////// roll = 30;//Slasher will always hit. //////// } //////// int BaseDamage = npc.CurrentAttackDamage;//get the damage of the current attack //////// if (((roll >= toHit) || (roll >= 30)) && (roll > -1)) //////// { //////// int PlayerArmourScore = playerUW.playerInventory.getArmourScore(); //////// int ReducedDamage = Mathf.Max(1, BaseDamage - PlayerArmourScore); //////// //Hit //////// playerUW.ApplyDamage(Random.Range(1, ReducedDamage + 1), npc.gameObject); //////// //reduce damage by protection //////// if (BaseDamage > PlayerArmourScore) //////// { //////// //apply equipment damage to a random piece of armour //////// playerUW.playerInventory.ApplyArmourDamage((short)Random.Range(0, npc.ArmourDamage + 1)); //////// } //////// if (npc.PoisonLevel() > 0) //////// {//roll for poisoning. //////// if (!UWCharacter.Instance.isPoisonResistant()) //////// {//Player has resistence against poisoning //////// int PoisonRoll = Random.Range(1, 30); //////// if (PoisonRoll < npc.PoisonLevel()) //////// { //////// int PoisonToAdd = Random.Range(1, npc.PoisonLevel() + 1); //////// int newPlayPoison = (short)Mathf.Min(playerUW.play_poison + PoisonToAdd, 15); //////// UWCharacter.Instance.play_poison = (short)newPlayPoison; //////// if (UWCharacter.Instance.poison_timer == 0) //////// { //////// UWCharacter.Instance.poison_timer = 30f; //////// } //////// } //////// } //////// } //////// MusicController.LastAttackCounter = 10.0f; //Ten more seconds of combat music //////// if (ObjectInteraction.PlaySoundEffects) //////// { //////// UWCharacter.Instance.aud.clip = MusicController.instance.SoundEffects[MusicController.SOUND_EFFECT_MELEE_HIT_1]; //////// UWCharacter.Instance.aud.Play(); //////// } //////// } }
/// <summary> /// Combat calculations for PC hitting an NPC /// </summary> /// <param name="playerUW">Player Character</param> /// <param name="npc">Npc.</param> /// <param name="hit">Hit.</param> public static void PC_Hits_NPC(UWCharacter playerUW, WeaponMelee currentWeapon, string StrikeName, float StrikeCharge, NPC npc, RaycastHit hit) { int attackScore = 0; int flankingbonus = 0; //need to calcu but depending on relative headings between attacker and defender. int magicbonus = 0; //currently unknown what provides this but is calculated by casting/5 + 0xA when set. short MinCharge; short MaxCharge; if (npc != null) { //recalc position to get the correct heading for the flanking bonus npc.objInt().UpdatePosition(); flankingbonus = CalcFlankingBonus(playerUW.currentHeading, npc.objInt().heading); } if (currentWeapon != null) { attackScore = (playerUW.PlayerSkills.GetSkill(Skills.SkillAttack) >> 1) + playerUW.PlayerSkills.GetSkill(currentWeapon.GetSkill()) + (playerUW.PlayerSkills.DEX / 7) + magicbonus + flankingbonus; if (GameWorldController.instance.difficulty == 0) {//bonus of 7 for easy difficulty attackScore += 7; } attackScore += currentWeapon.AccuracyBonus();//Given by the accuracy enchantments. Note in vanilla UW2 accuracy actually increases damage and not attack score. This is fixed here. MinCharge = currentWeapon.GetMinCharge(); MaxCharge = currentWeapon.GetMaxCharge(); } else { //use the unarmed calculations attackScore = (playerUW.PlayerSkills.GetSkill(Skills.SkillAttack) >> 1) + playerUW.PlayerSkills.GetSkill(Skills.SkillUnarmed) + (playerUW.PlayerSkills.DEX / 7) + magicbonus + flankingbonus; if (GameWorldController.instance.difficulty == 0) {//bonus of 7 for easy difficulty attackScore += 7; } MinCharge = WeaponMelee.GetMeleeMinCharge(); MaxCharge = WeaponMelee.GetMeleeMaxCharge(); } //Get base damage int BaseSwingDamage = GetPlayerBaseDamage(currentWeapon, StrikeName); int basePower = (short)(GameWorldController.instance.objDat.critterStats[63].Strength / 9); //the player is actually a critter so power in this case is their STR. int WeaponBonusDamage = 0; if (currentWeapon != null) { WeaponBonusDamage = currentWeapon.DamageBonus(); } else { //unarmed basePower = (short)(GameWorldController.instance.objDat.critterStats[63].Strength / 6); //the player is actually a critter so power in this case is their STR. basePower += (playerUW.PlayerSkills.GetSkill(Skills.SkillUnarmed) / 5); } //scale base damage by charge. Min damage is always 2. short Damage = (short)(basePower + BaseSwingDamage + WeaponBonusDamage); // damage % 6 no of 1D6s to calculate the actual damage and then add the remainder as a final roll 1-remainder Damage = (short)(DamageRoll((short)(Damage / 6), 6) + DamageRoll(1, (short)(Damage % 6))); //Damage is scaled by the amount of weapon charge built up. Damage = CalcAttackChargeDamage((short)StrikeCharge, MinCharge, MaxCharge, Damage); //And a flat flanking bonus Damage += (short)flankingbonus; //Min damage will be 2. Damage = (short)(Mathf.Max(Damage, 2)); Skills.SkillRollResult rollresult = Skills.SkillRoll(attackScore, npc.Defence()); bool CriticalHit = RollForCritDamage(ref Damage, rollresult); switch (rollresult) { case Skills.SkillRollResult.CriticalSuccess: case Skills.SkillRollResult.Success: { Debug.Log("Base Damage = " + ((short)(basePower + BaseSwingDamage + WeaponBonusDamage)) + " Final Damage = " + Damage); if (CriticalHit) { Impact.SpawnHitImpact(Impact.ImpactBlood(), npc.GetImpactPoint() + Vector3.up * 0.1f, npc.objInt().GetHitFrameStart(), npc.objInt().GetHitFrameEnd()); } npc.ApplyAttack(Damage, playerUW.gameObject); Impact.SpawnHitImpact(Impact.ImpactBlood(), npc.GetImpactPoint(), npc.objInt().GetHitFrameStart(), npc.objInt().GetHitFrameEnd()); if (currentWeapon != null) { ///Performs the onHit action of the melee weapon. currentWeapon.onHit(hit.transform.gameObject); } break; } case Skills.SkillRollResult.Failure: npc.ApplyAttack(0, playerUW.gameObject); npc.npc_aud.PlayCombatMissed(); break; case Skills.SkillRollResult.CriticalFailure: { npc.ApplyAttack(0, playerUW.gameObject); npc.npc_aud.PlayCombatMissed(); //Damage weapon short durability = currentWeapon.getDurability(); if (durability <= 30) { currentWeapon.SelfDamage((short)Mathf.Max(0, Random.Range(0, npc.EquipDamage + 1) - durability)); } break; } } }
public override bool ActivateByObject(ObjectInteraction ObjectUsed) { //Code for handling otherobjects used on this object //Doors can be used by keys, picks and spikes. //ObjectInteraction objIntUsed = ObjectUsed.GetComponent<ObjectInteraction>(); if (ObjectUsed != null) { switch (ObjectUsed.GetItemType()) { case ObjectInteraction.KEY: //Key DoorKey dk = ObjectUsed.GetComponent <DoorKey>(); if (dk != null) { if (state() == true) { //Door is already open UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 6)); return(true); } ObjectInteraction doorlock = getLockObjInt(); if (doorlock == null) { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 3)); return(false); } if ((doorlock.link & 0x3F) == dk.owner) //This is a valid key for the door. { ToggleLock(true); if (locked() == true) { //Locked message UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 4)); } else { //Unlockedmessage UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 5)); } return(true); } else { if (link == 53) { //There is no lock UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 3)); } else { //That is the wrong key. UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 2)); } return(true); } } break; case ObjectInteraction.LOCKPICK: //lockpick { //lock pick skill check is based on the zpos of the "lock" object * 3 vs the players (lockpick skill + 1) //Locks cannot be picked if the zpos is 0xE or greater. In either case the skillcheck is attempted. ObjectInteraction LockObject = getLockObjInt(); if (LockObject != null) { int skillvalue = UWCharacter.Instance.PlayerSkills.PickLock + 1; int targetvalue = LockObject.zpos * 3; Skills.SkillRollResult skillroll = Skills.SkillRoll(skillvalue, targetvalue); if (LockObject.zpos >= 0xE) { //unpickable if (skillroll == Skills.SkillRollResult.CriticalFailure) { BreakLockPick(ObjectUsed); } else { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_your_lockpicking_attempt_failed_)); } } else { switch (skillroll) { case Skills.SkillRollResult.CriticalFailure: { BreakLockPick(ObjectUsed); break; } case Skills.SkillRollResult.Failure: { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_your_lockpicking_attempt_failed_)); break; } case Skills.SkillRollResult.Success: case Skills.SkillRollResult.CriticalSuccess: { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_succeed_in_picking_the_lock_)); UnlockDoor(true); break; } } } } else { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, 3)); //There is no lock on that. } } break; //{ //if (Pickable==true) // { // if (UWCharacter.Instance.PlayerSkills.TrySkill(Skills.SkillPicklock, Skills.DiceRoll(1,25))) // { // UWHUD.instance.MessageScroll.Add (StringController.instance.GetString (1,StringController.str_you_succeed_in_picking_the_lock_)); // UnlockDoor(true); // } // else // { // //Debug.Log ("Picklock failed!"); // UWHUD.instance.MessageScroll.Add (StringController.instance.GetString (1,StringController.str_your_lockpicking_attempt_failed_)); // //objIntUsed.consumeObject(); // } // } //else // { // UWHUD.instance.MessageScroll.Add (StringController.instance.GetString (1,StringController.str_your_lockpicking_attempt_failed_)); // } //break; //} case ObjectInteraction.SPIKE: { if (Spike()) { ObjectUsed.consumeObject(); } break; } default: return(false); } } else { return(false); } return(true); }
/// <summary> /// Event handler for processing the repair question y/n /// </summary> /// <param name="ans">Ans.</param> public void OnSubmitPickup(string ans) { Time.timeScale = 1.0f; UWHUD.instance.InputControl.gameObject.SetActive(false); WindowDetectUW.WaitingForInput = false; UWHUD.instance.MessageScroll.Clear();//=""; if (ans.Substring(0, 1).ToUpper() == "Y") { //do the repair //Play the cutscene. switch (_RES) { case GAME_UW2: //todo break; default: UWHUD.instance.CutScenesSmall.anim.SetAnimation = "cs404.n01"; break; } int RepairDifficulty = repairEstimate(); Skills.SkillRollResult result = Skills.SkillRoll(UWCharacter.Instance.PlayerSkills.Repair, RepairDifficulty); switch (result) { case Skills.SkillRollResult.CriticalFailure: //attempt fails. dice roll of 0-63. If repair skill is lower than result damage item by another roll (0-7)+4; { if (Random.Range(0, 64) >= UWCharacter.Instance.PlayerSkills.Repair) { int damage = Random.Range(0, 7) + 4; quality = (short)(quality - (short)damage); if (quality > 0) { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_damaged_the_) + StringController.instance.GetObjectNounUW(item_id)); } } } break; case Skills.SkillRollResult.Failure: //attempt fails. no change to item. UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_your_attempt_has_no_effect_on_the_) + StringController.instance.GetObjectNounUW(item_id)); break; case Skills.SkillRollResult.Success: //repair up to (repair skill/5+3) int newQuality = (UWCharacter.Instance.PlayerSkills.Repair / 5 + 3); if (quality >= newQuality) { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_your_attempt_has_no_effect_on_the_) + StringController.instance.GetObjectNounUW(item_id)); } else { quality = (short)newQuality; if (quality > 63) { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_have_fully_repaired_the_) + StringController.instance.GetObjectNounUW(item_id)); quality = 63; } else { UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_have_partially_repaired_the_) + StringController.instance.GetObjectNounUW(item_id)); } } break; case Skills.SkillRollResult.CriticalSuccess: //fully repair the item. quality = 63; UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_have_fully_repaired_the_) + StringController.instance.GetObjectNounUW(item_id)); break; } if (quality <= 0) { //destroy the item. UWHUD.instance.MessageScroll.Add(StringController.instance.GetString(1, StringController.str_you_destroyed_the_) + StringController.instance.GetObjectNounUW(item_id)); objInt().consumeObject();//ToDO: Create DEBRIS } else { UpdateQuality(); } } //cancel the repair CurrentObjectInHand = null; }