public bool CanPerkBeUpgraded(Data.Entities.Perk perk, PCPerk pcPerk, PlayerCharacter player) { int rank = pcPerk?.PerkLevel ?? 0; int maxRank = perk.PerkLevels.Count; if (rank + 1 > maxRank) { return(false); } PerkLevel level = FindPerkLevel(perk.PerkLevels, rank + 1); if (level == null) { return(false); } if (player.UnallocatedSP < level.Price) { return(false); } foreach (PerkLevelSkillRequirement req in level.PerkLevelSkillRequirements) { PCSkill pcSkill = _db.PCSkills.Single(x => x.PlayerID == player.PlayerID && x.SkillID == req.SkillID); if (pcSkill.Rank < req.RequiredRank) { return(false); } } return(true); }
public void OnHitCastSpell(NWPlayer oPC) { NWObject oTarget = NWObject.Wrap(_.GetSpellTargetObject()); int activeWeaponSkillID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL"); if (activeWeaponSkillID <= 0) { return; } Data.Entities.Perk entity = _db.Perks.Single(x => x.PerkID == activeWeaponSkillID); IPerk perk = App.ResolveByInterface <IPerk>("Perk." + entity.JavaScriptName); if (perk.CanCastSpell(oPC, oTarget)) { perk.OnImpact(oPC, oTarget); if (oTarget.IsNPC) { ApplyEnmity(oPC, NWCreature.Wrap(oTarget.Object), entity); } } else { oPC.SendMessage(perk.CannotCastSpellMessage(oPC, oTarget) ?? "That ability cannot be used at this time."); } oPC.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID"); oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL"); }
public string OnModuleExamine(string existingDescription, NWPlayer examiner, NWObject examinedObject) { if (!examiner.IsPlayer && !examiner.IsDM) { return(existingDescription); } if (examinedObject.ObjectType != OBJECT_TYPE_ITEM) { return(existingDescription); } int perkID = examinedObject.GetLocalInt("ACTIVATION_PERK_ID"); if (perkID <= 0) { return(existingDescription); } Data.Entities.Perk perk = _db.Perks.Single(x => x.PerkID == perkID); string description = existingDescription; description += _color.Orange("Name: ") + perk.Name + "\n" + _color.Orange("Description: ") + perk.Description + "\n"; switch ((PerkExecutionType)perk.PerkExecutionType.PerkExecutionTypeID) { case PerkExecutionType.CombatAbility: description += _color.Orange("Type: ") + "Combat Ability\n"; break; case PerkExecutionType.Spell: description += _color.Orange("Type: ") + "Spell\n"; break; case PerkExecutionType.ShieldOnHit: description += _color.Orange("Type: ") + "Reactive\n"; break; case PerkExecutionType.QueuedWeaponSkill: description += _color.Orange("Type: ") + "Queued Attack\n"; break; } if (perk.BaseManaCost > 0) { description += _color.Orange("Base Mana Cost: ") + perk.BaseManaCost + "\n"; } if (perk.CooldownCategory.BaseCooldownTime > 0.0f) { description += _color.Orange("Cooldown: ") + perk.CooldownCategory.BaseCooldownTime + "s\n"; } if (perk.BaseCastingTime > 0.0f) { description += _color.Orange("Base Casting Time: ") + perk.BaseCastingTime + "s\n"; } return(description); }
public void OnHitCastSpell(NWPlayer oPC) { NWObject oTarget = NWObject.Wrap(_.GetSpellTargetObject()); int activeWeaponSkillID = oPC.GetLocalInt("ACTIVE_WEAPON_SKILL"); if (activeWeaponSkillID <= 0) { return; } Data.Entities.Perk entity = _db.Perks.Single(x => x.PerkID == activeWeaponSkillID); IPerk perk = App.ResolveByInterface <IPerk>("Perk." + entity.JavaScriptName); perk?.OnImpact(oPC, oTarget); oPC.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID"); oPC.DeleteLocalInt("ACTIVE_WEAPON_SKILL"); }
private void HandleQueueWeaponSkill(NWPlayer pc, Data.Entities.Perk entity, IPerk ability) { string queueUUID = Guid.NewGuid().ToString(); pc.SetLocalInt("ACTIVE_WEAPON_SKILL", entity.PerkID); pc.SetLocalString("ACTIVE_WEAPON_SKILL_UUID", queueUUID); pc.SendMessage("Weapon skill '" + entity.Name + "' queued for next attack."); ApplyCooldown(pc, entity.CooldownCategory, ability); // Player must attack within 30 seconds after queueing or else it wears off. pc.DelayCommand(() => { if (pc.GetLocalString("ACTIVE_WEAPON_SKILL_UUID") == queueUUID) { pc.DeleteLocalInt("ACTIVE_WEAPON_SKILL"); pc.DeleteLocalString("ACTIVE_WEAPON_SKILL_UUID"); pc.SendMessage("Your weapon skill '" + entity.Name + "' is no longer queued."); } }, 30.0f); }
private void ApplyEnmity(NWPlayer pc, NWCreature target, Data.Entities.Perk perk) { switch ((EnmityAdjustmentRuleType)perk.EnmityAdjustmentRuleID) { case EnmityAdjustmentRuleType.AllTaggedTargets: _enmity.AdjustEnmityOnAllTaggedCreatures(pc, perk.Enmity); break; case EnmityAdjustmentRuleType.TargetOnly: if (target.IsValid) { _enmity.AdjustEnmity(target, pc, perk.Enmity); } break; case EnmityAdjustmentRuleType.Custom: IPerk perkAction = App.ResolveByInterface <IPerk>("Perk." + perk.JavaScriptName); perkAction?.OnCustomEnmityRule(pc, perk.Enmity); break; } }
private void BuildPerkDetails() { Model vm = GetDialogCustomData <Model>(); Data.Entities.Perk perk = _perk.GetPerkByID(vm.SelectedPerkID); PCPerk pcPerk = _perk.GetPCPerkByID(GetPC().GlobalID, perk.PerkID); PlayerCharacter player = _player.GetPlayerEntity(GetPC().GlobalID); int rank = pcPerk?.PerkLevel ?? 0; int maxRank = perk.PerkLevels.Count; string currentBonus = "N/A"; string nextBonus = "N/A"; string price = "N/A"; PerkLevel currentPerkLevel = _perk.FindPerkLevel(perk.PerkLevels, rank); PerkLevel nextPerkLevel = _perk.FindPerkLevel(perk.PerkLevels, rank + 1); SetResponseVisible("PerkDetailsPage", 1, _perk.CanPerkBeUpgraded(perk, pcPerk, player)); if (rank > 0) { if (currentPerkLevel != null) { currentBonus = currentPerkLevel.Description; } } if (rank + 1 <= maxRank) { if (nextPerkLevel != null) { nextBonus = nextPerkLevel.Description; price = nextPerkLevel.Price + " SP (Available: " + player.UnallocatedSP + " SP)"; } } string header = _color.Green("Name: ") + perk.Name + "\n" + _color.Green("Category: ") + perk.PerkCategory.Name + "\n" + _color.Green("Rank: ") + rank + " / " + maxRank + "\n" + _color.Green("Price: ") + price + "\n" + (perk.BaseManaCost > 0 ? _color.Green("Mana: ") + perk.BaseManaCost : "") + "\n" + (perk.CooldownCategory != null && perk.CooldownCategory.BaseCooldownTime > 0 ? _color.Green("Cooldown: ") + perk.CooldownCategory.BaseCooldownTime + "s" : "") + "\n" + _color.Green("Description: ") + perk.Description + "\n" + _color.Green("Current Bonus: ") + currentBonus + "\n" + _color.Green("Next Bonus: ") + nextBonus + "\n"; if (nextPerkLevel != null) { List <PerkLevelSkillRequirement> requirements = nextPerkLevel.PerkLevelSkillRequirements.ToList(); if (requirements.Count > 0) { header += "\n" + _color.Green("Next Upgrade Skill Requirements:\n\n"); bool hasRequirement = false; foreach (PerkLevelSkillRequirement req in requirements) { if (req.RequiredRank > 0) { string detailLine = req.Skill.Name + " Rank " + req.RequiredRank; PCSkill skill = _skill.GetPCSkillByID(GetPC().GlobalID, req.SkillID); if (skill.Rank >= req.RequiredRank) { header += _color.Green(detailLine) + "\n"; } else { header += _color.Red(detailLine) + "\n"; } hasRequirement = true; } } if (requirements.Count <= 0 || !hasRequirement) { header += "None\n"; } } } SetPageHeader("PerkDetailsPage", header); }
public void OnModuleItemActivated() { NWPlayer pc = NWPlayer.Wrap(_.GetItemActivator()); NWItem item = NWItem.Wrap(_.GetItemActivated()); NWPlayer target = NWPlayer.Wrap(_.GetItemActivatedTarget()); int perkID = item.GetLocalInt("ACTIVATION_PERK_ID"); if (perkID <= 0) { return; } Data.Entities.Perk perk = _db.Perks.SingleOrDefault(x => x.PerkID == perkID); if (perk == null) { return; } IPerk perkAction = App.ResolveByInterface <IPerk>("Perk." + perk.JavaScriptName); if (perkAction == null) { return; } PlayerCharacter playerEntity = _db.PlayerCharacters.Single(x => x.PlayerID == pc.GlobalID); if (_perk.GetPCPerkLevel(pc, perk.PerkID) <= 0) { pc.SendMessage("You do not meet the prerequisites to use this ability."); return; } if (perkAction.IsHostile() && target.IsPlayer) { if (!_pvpSanctuary.IsPVPAttackAllowed(pc, target)) { return; } } if (pc.Area.Resref != target.Area.Resref || _.LineOfSightObject(pc.Object, target.Object) == 0) { pc.SendMessage("You cannot see your target."); return; } if (!perkAction.CanCastSpell(pc, target)) { pc.SendMessage(perkAction.CannotCastSpellMessage() ?? "That ability cannot be used at this time."); return; } int manaCost = perkAction.ManaCost(pc, perkAction.ManaCost(pc, perk.BaseManaCost)); if (playerEntity.CurrentMana < manaCost) { pc.SendMessage("You do not have enough mana. (Required: " + manaCost + ". You have: " + playerEntity.CurrentMana + ")"); return; } if (pc.IsBusy || pc.CurrentHP <= 0) { pc.SendMessage("You are too busy to activate that ability."); return; } // Check cooldown PCCooldown pcCooldown = _db.PCCooldowns.SingleOrDefault(x => x.PlayerID == pc.GlobalID && x.CooldownCategoryID == perk.CooldownCategoryID); if (pcCooldown == null) { pcCooldown = new PCCooldown { CooldownCategoryID = Convert.ToInt32(perk.CooldownCategoryID), DateUnlocked = DateTime.UtcNow.AddSeconds(-1), PlayerID = pc.GlobalID }; _db.PCCooldowns.Add(pcCooldown); _db.SaveChanges(); } DateTime unlockDateTime = pcCooldown.DateUnlocked; DateTime now = DateTime.UtcNow; if (unlockDateTime > now) { string timeToWait = _time.GetTimeToWaitLongIntervals(now, unlockDateTime, false); pc.SendMessage("That ability can be used again in " + timeToWait + "."); return; } // Spells w/ casting time if (perk.PerkExecutionType.PerkExecutionTypeID == (int)PerkExecutionType.Spell) { CastSpell(pc, target, perk, perkAction, perk.CooldownCategory); } // Combat Abilities w/o casting time else if (perk.PerkExecutionType.PerkExecutionTypeID == (int)PerkExecutionType.CombatAbility) { perkAction.OnImpact(pc, target); if (manaCost > 0) { playerEntity.CurrentMana = playerEntity.CurrentMana - manaCost; _db.SaveChanges(); } ApplyCooldown(pc, perk.CooldownCategory, perkAction); } // Queued Weapon Skills else if (perk.PerkExecutionType.PerkExecutionTypeID == (int)PerkExecutionType.QueuedWeaponSkill) { HandleQueueWeaponSkill(pc, perk, perkAction); } }
private void CastSpell(NWPlayer pc, NWObject target, Data.Entities.Perk entity, IPerk perk, CooldownCategory cooldown) { string spellUUID = Guid.NewGuid().ToString(); int itemBonus = pc.CastingSpeed; float baseCastingTime = perk.CastingTime(pc, (float)entity.BaseCastingTime); float castingTime = baseCastingTime; // Casting Bonus % - Shorten casting time. if (itemBonus < 0) { float castingPercentageBonus = Math.Abs(itemBonus) * 0.01f; castingTime = castingTime - (castingTime * castingPercentageBonus); } // Casting Penalty % - Increase casting time. else if (itemBonus > 0) { float castingPercentageBonus = Math.Abs(itemBonus) * 0.01f; castingTime = castingTime + (castingTime * castingPercentageBonus); } if (castingTime < 0.5f) { castingTime = 0.5f; } // Heavy armor increases casting time by 2x the base casting time if (pc.Chest.CustomItemType == CustomItemType.HeavyArmor) { castingTime = baseCastingTime * 2; } if (_.GetActionMode(pc.Object, ACTION_MODE_STEALTH) == 1) { _.SetActionMode(pc.Object, ACTION_MODE_STEALTH, 0); } _.ClearAllActions(); _biowarePosition.TurnToFaceObject(target, pc); _.ApplyEffectToObject(DURATION_TYPE_TEMPORARY, _.EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD), pc.Object, castingTime + 0.2f); float animationTime = castingTime; pc.AssignCommand(() => _.ActionPlayAnimation(ANIMATION_LOOPING_CONJURE1, 1.0f, animationTime - 0.1f)); pc.IsBusy = true; CheckForSpellInterruption(pc, spellUUID, pc.Position); pc.SetLocalInt(spellUUID, SPELL_STATUS_STARTED); _nwnxPlayer.StartGuiTimingBar(pc, (int)castingTime, ""); pc.DelayCommand(() => { if (pc.GetLocalInt(spellUUID) == SPELL_STATUS_INTERRUPTED || // Moved during casting pc.CurrentHP < 0 || pc.IsDead) // Or is dead/dying { pc.DeleteLocalInt(spellUUID); pc.SendMessage("Your spell has been interrupted."); return; } pc.DeleteLocalInt(spellUUID); if ((PerkExecutionType)entity.ExecutionTypeID == PerkExecutionType.Spell || (PerkExecutionType)entity.ExecutionTypeID == PerkExecutionType.CombatAbility) { perk.OnImpact(pc, target); } else { HandleQueueWeaponSkill(pc, entity, perk); } // Adjust mana only if spell cost > 0 PlayerCharacter pcEntity = _db.PlayerCharacters.Single(x => x.PlayerID == pc.GlobalID); if (perk.ManaCost(pc, entity.BaseManaCost) > 0) { pcEntity.CurrentMana = pcEntity.CurrentMana - perk.ManaCost(pc, entity.BaseManaCost); _db.SaveChanges(); pc.SendMessage(_color.Custom("Mana: " + pcEntity.CurrentMana + " / " + pcEntity.MaxMana, 32, 223, 219)); } if (_random.Random(100) + 1 <= 3) { _food.DecreaseHungerLevel(pc, 1); } // Mark cooldown on category ApplyCooldown(pc, cooldown, perk); pc.IsBusy = false; }, castingTime + 0.5f); }
public void DoPerkUpgrade(NWPlayer oPC, int perkID) { Data.Entities.Perk perk = _db.Perks.Single(x => x.PerkID == perkID); PCPerk pcPerk = _db.PCPerks.SingleOrDefault(x => x.PlayerID == oPC.GlobalID && x.PerkID == perkID); PlayerCharacter player = _db.PlayerCharacters.Single(x => x.PlayerID == oPC.GlobalID); if (CanPerkBeUpgraded(perk, pcPerk, player)) { if (pcPerk == null) { pcPerk = new PCPerk(); DateTime dt = DateTime.UtcNow; pcPerk.AcquiredDate = dt; pcPerk.PerkID = perk.PerkID; pcPerk.PlayerID = oPC.GlobalID; pcPerk.PerkLevel = 0; _db.PCPerks.Add(pcPerk); } PerkLevel nextPerkLevel = FindPerkLevel(perk.PerkLevels, pcPerk.PerkLevel + 1); if (nextPerkLevel == null) { return; } pcPerk.PerkLevel++; player.UnallocatedSP -= nextPerkLevel.Price; _db.SaveChanges(); // If a perk is activatable, create the item on the PC. // Remove any existing cast spell unique power properties and add the correct one based on the DB flag. if (!string.IsNullOrWhiteSpace(perk.ItemResref)) { if (_.GetIsObjectValid(_.GetItemPossessedBy(oPC.Object, perk.ItemResref)) == FALSE) { NWItem spellItem = NWItem.Wrap(_.CreateItemOnObject(perk.ItemResref, oPC.Object)); spellItem.IsCursed = true; spellItem.SetLocalInt("ACTIVATION_PERK_ID", perk.PerkID); foreach (ItemProperty ipCur in spellItem.ItemProperties) { int ipType = _.GetItemPropertyType(ipCur); int ipSubType = _.GetItemPropertySubType(ipCur); if (ipType == ITEM_PROPERTY_CAST_SPELL && (ipSubType == IP_CONST_CASTSPELL_UNIQUE_POWER || ipSubType == IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY || ipSubType == IP_CONST_CASTSPELL_ACTIVATE_ITEM)) { _.RemoveItemProperty(spellItem.Object, ipCur); } } ItemProperty ip; if (perk.IsTargetSelfOnly) { ip = _.ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER_SELF_ONLY, IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE); } else { ip = _.ItemPropertyCastSpell(IP_CONST_CASTSPELL_UNIQUE_POWER, IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE); } _biowareXP2.IPSafeAddItemProperty(spellItem, ip, 0.0f, AddItemPropertyPolicy.ReplaceExisting, false, false); } _.SetName(_.GetItemPossessedBy(oPC.Object, perk.ItemResref), perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")"); } oPC.SendMessage(_color.Green("Perk Purchased: " + perk.Name + " (Lvl. " + pcPerk.PerkLevel + ")")); IPerk perkScript = App.ResolveByInterface <IPerk>("Perk." + perk.JavaScriptName); if (perkScript == null) { return; } perkScript.OnPurchased(oPC, pcPerk.PerkLevel); } else { oPC.FloatingText(_color.Red("You cannot purchase the perk at this time.")); } }