- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- About the Distance Between Sims During Actions
- Site Map >
- Modding and Creation >
- Sims 3 Creation >
- Modding Discussion >
- About the Distance Between Sims During Actions
Posts: 175
Thanks: 175 in 1 Posts
As I said in my previous post, I am developing a mod which can implement a workable swordfight interaction in TS3. However - I've ran into a problem.
The method I chose to try to accomplish this was using a "clone" of the martial arts spar interaction and change the animations to those from TSM. But, during the fight, the two sims are too close together for the animations to work correctly. How could I fix this?
Posts: 1,491
Thanks: 4229 in 39 Posts
Posts: 175
Thanks: 175 in 1 Posts
Posts: 73
Thanks: 789 in 5 Posts
To be fair, I've not yet done the coding - I noticed this problem while testing the animations using cmomoney Animation Player. |
I'm afraid I didn't understand your question, but from what I understand, the sims are very close, right?
The interactions of The Sims 3 have specific distances, that is, they always start at a standard distance and end at a standard distance, which are the same. That is why there is X (which is the yes you are controlling) and Y (which is the other yes, inactive). Testing on AnimationPlayer, you may not have a good idea; therefore, I recommend that you make a standard replacement for some game animation, preferably easy to find, such as the hug.
Make the interaction and then you will have the real distance.
Posts: 1,491
Thanks: 4229 in 39 Posts
To be fair, I've not yet done the coding - I noticed this problem while testing the animations using cmomoney Animation Player. |
ctrl + shift + c then use moveobjects on. After that you can manually move the two Sims to whatever distance you want in buy/build mode. That will give you an idea.
Posts: 175
Thanks: 175 in 1 Posts
I'm afraid I didn't understand your question, but from what I understand, the sims are very close, right? The interactions of The Sims 3 have specific distances, that is, they always start at a standard distance and end at a standard distance, which are the same. That is why there is X (which is the yes you are controlling) and Y (which is the other yes, inactive). Testing on AnimationPlayer, you may not have a good idea; therefore, I recommend that you make a standard replacement for some game animation, preferably easy to find, such as the hug. Make the interaction and then you will have the real distance. |
I've done what you asked. Made an default replacement for the "basic" animation of the Spar interaction, and that was the result:
Posts: 1,491
Thanks: 4229 in 39 Posts
Posts: 175
Thanks: 175 in 1 Posts
Was this happening for the animation player? |
@PuddingFace , the problem is not in the animations, but in the Spar interaction. The two actor sims are too close together during the interaction for the animations to play out in a manner that looks right - And that's to be expected, since in TSM, the sims are 1-2 squares apart, while in during the Spar, they are in the square adjacent to one another.
Posts: 1,491
Thanks: 4229 in 39 Posts
Posts: 175
Thanks: 175 in 1 Posts
The distance can be changed using the Jigs. That's not too big of a problem. But in that picture the animations themselves have turned the Sim from humanoid to a pyramid which is a much bigger problem. |
@Puddingface That's just the Wing acessories I'm using on them. I'm using my two angel sims to test the mod. Any place where I could read about Social Jigs?
Posts: 1,491
Thanks: 4229 in 39 Posts
Posts: 175
Thanks: 175 in 1 Posts
Here's a more clear pĂcture.
Posts: 1,491
Thanks: 4229 in 39 Posts
Posts: 175
Thanks: 175 in 1 Posts
Posts: 1,491
Thanks: 4229 in 39 Posts
BTW can you post your interactions's Run()
Posts: 175
Thanks: 175 in 1 Posts
It is basically the same as the run () function from the Martial Arts spar, since I'm still trying to figure out a bit of coding.
protected override bool Run() { if (!base.SafeToSync()) { return false; } Lot lotCurrent = base.Actor.LotCurrent; ObjectGuid objectId = base.Target.ObjectId; Household household = base.Target.Household; if ((household != null) && (ReferenceEquals(lotCurrent, base.Actor.LotHome) && !household.IsGreetedOnLot(lotCurrent, objectId))) { household.AddGreetedLotToHousehold(lotCurrent, objectId); } base.SocialJig = GlobalFunctions.CreateObjectOutOfWorld("SparJig") as SocialJigTwoPerson; if (!base.BeginSocialInteraction(new SocialInteractionB.Definition(null, Localization.LocalizeString("Gameplay/Actors/Sim/Spar:InteractionName", new object[0]), false), true, false)) { return false; } this.mActorsMartialArtsSkill = base.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); this.mTargetsMartialArtsSkill = base.Target.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); base.StandardEntry(); this.mActorsMartialArtsSkill.ChangeIntoKarateGi(); this.mTargetsMartialArtsSkill.ChangeIntoKarateGi(); base.Actor.LookAtManager.DisableLookAts(); base.Target.LookAtManager.DisableLookAts(); base.EnterStateMachine("spar", "Enter", "x", "y"); base.SetParameter("CanXplaySuperAnimations", this.mActorsMartialArtsSkill.mbCanPlaySuperAnimations); base.SetParameter("CanYplaySuperAnimations", this.mTargetsMartialArtsSkill.mbCanPlaySuperAnimations); this.RegisterAnimationToScriptEventCallbacks(); this.EnableWatchInteraction(); base.AnimateJoinSims("Bow"); MartialArts.StartDisciplinedFunCommodity(this); base.BeginCommodityUpdates(); this.StartSkillGain(); this.mCurrentSparState = MartialArts.SparState.StartRound; bool succeeded = this.DoLoop(~(ExitReason.Replan | ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached), new InteractionInstance.InsideLoopFunction(this.SparLoopDelegate), base.mCurrentStateMachine); this.StopSkillGain(); this.DisposeVisualEffects(); base.AnimateSim("Exit"); this.PostMatchCeremony(); base.FinishLinkedInteraction(true); base.EndCommodityUpdates(succeeded); MartialArts.EndDisciplinedFunCommodity(this); this.DisableWatchInteraction(); base.StandardExit(); base.WaitForSyncComplete(); return succeeded; } protected override bool Run() { if (!base.SafeToSync()) { return false; } Lot lotCurrent = base.Actor.LotCurrent; ObjectGuid objectId = base.Target.ObjectId; Household household = base.Target.Household; if ((household != null) && (ReferenceEquals(lotCurrent, base.Actor.LotHome) && !household.IsGreetedOnLot(lotCurrent, objectId))) { household.AddGreetedLotToHousehold(lotCurrent, objectId); } base.SocialJig = GlobalFunctions.CreateObjectOutOfWorld("SparJig") as SocialJigTwoPerson; if (!base.BeginSocialInteraction(new SocialInteractionB.Definition(null, Localization.LocalizeString("Gameplay/Actors/Sim/Spar:InteractionName", new object[0]), false), true, false)) { return false; } this.mActorsMartialArtsSkill = base.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); this.mTargetsMartialArtsSkill = base.Target.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); base.StandardEntry(); this.mActorsMartialArtsSkill.ChangeIntoKarateGi(); this.mTargetsMartialArtsSkill.ChangeIntoKarateGi(); base.Actor.LookAtManager.DisableLookAts(); base.Target.LookAtManager.DisableLookAts(); base.EnterStateMachine("spar", "Enter", "x", "y"); base.SetParameter("CanXplaySuperAnimations", this.mActorsMartialArtsSkill.mbCanPlaySuperAnimations); base.SetParameter("CanYplaySuperAnimations", this.mTargetsMartialArtsSkill.mbCanPlaySuperAnimations); this.RegisterAnimationToScriptEventCallbacks(); this.EnableWatchInteraction(); base.AnimateJoinSims("Bow"); MartialArts.StartDisciplinedFunCommodity(this); base.BeginCommodityUpdates(); this.StartSkillGain(); this.mCurrentSparState = MartialArts.SparState.StartRound; bool succeeded = this.DoLoop(~(ExitReason.Replan | ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached), new InteractionInstance.InsideLoopFunction(this.SparLoopDelegate), base.mCurrentStateMachine); this.StopSkillGain(); this.DisposeVisualEffects(); base.AnimateSim("Exit"); this.PostMatchCeremony(); base.FinishLinkedInteraction(true); base.EndCommodityUpdates(succeeded); MartialArts.EndDisciplinedFunCommodity(this); this.DisableWatchInteraction(); base.StandardExit(); base.WaitForSyncComplete(); return succeeded; }
Posts: 433
Thanks: 782 in 6 Posts
you could try to create the jig via this code
base.SocialJig = CreateJigForTwoPersonSocial(actor, target, 1.25f)
I haven't tested that though
E: try replacing Line 14 with that. if that works but is still to close try 1.68f as the last parameter value instead
Posts: 175
Thanks: 175 in 1 Posts
Posts: 433
Thanks: 782 in 6 Posts
Do you get errors when trying to compile, is the distance still wrong or does something else unexpected happen ?
Posts: 175
Thanks: 175 in 1 Posts
Posts: 433
Thanks: 782 in 6 Posts
btw regarding the protection level you might want to get these references instead of the vanilla ones
https://github.com/Chain-Reaction/N.../Sims3/Compiler
Posts: 175
Thanks: 175 in 1 Posts
using Sims3.Gameplay.Abstract using Sims3.Gameplay.Actors; using Sims3.Gameplay.ActorSystems; using Sims3.Gameplay.Autonomy; using Sims3.Gameplay.CAS; using Sims3.Gameplay.Core; using Sims3.Gameplay.EventSystem; using Sims3.Gameplay.Interactions; using Sims3.Gameplay.Interfaces; using Sims3.Gameplay.Socializing; using Sims3.Gameplay.TuningValues; using Sims3.Gameplay.Tutorial; using Sims3.Gameplay.Utilities; using Sims3.Gameplay.WorldBuilderUtil; using Sims3.SimIFace; using Sims3.SimIFace.CAS; using Sims3.SimIFace.RouteDestinations; using Sims3.UI; using Sims3.UI.Hud; using System; using System.Collections; using System.Collections.Generic; namespace Sims3.Gameplay.Skills { public class MartialArts : Skill { private static string[] kMaleOutfitNames = new string[3] { "OutfitNameMaleTeen", "OutfitNameMaleAdult", "OutfitNameMaleElder" }; private static string[] kFemaleOutfitNames = new string[3] { "OutfitNameFemaleTeen", "OutfitNameFemaleAdult", "OutfitNameFemaleElder" }; private static Dictionary<int, MartialArts.MartialArtsSkillLevel> sMartialArtsSkillData = new Dictionary<int, MartialArts.MartialArtsSkillLevel>(); private static Dictionary<int, int> sBoardTypeToUnlockingSkillLevelMap = new Dictionary<int, int>(); [Tunable] [TunableComment("Fade in and out duration. Positive float. Initial GPE Default: 2f")] private static float kFadeInAndOutTimeForMeditationTeleportation = 2f; [TunableComment("While performaing meditate interaction, Meditative Focus buff is added to the sim (unpaused) after this duration. Units: Sim Minutes. Positive float. Initial GPE Default: 60f")] [Tunable] private static float kMeditationDurationToUnlockMeditativeFocus = 60f; [Tunable] [TunableComment("Once the sim possesses Meditative focus for a base timeout, every x minutes, we increment the buff's timeout. This is x. Units: Sim Minutes. Positive float. Initial GPE Default: 30f")] private static float kMeditationIntervalToIncrementMeditativeFocus = 30f; [Tunable] [TunableComment("For each meditation interval, we bump up the Meditative Focus buff's timeout by this amount. Units: Sim Minutes. Positive float. Initial GPE Default: 60f")] private static float kIncrementInMeditativeFocusTimeout = 60f; [TunableComment("This is the upper cap on the meditative focus timeout. At this point we start levitation. Units: Sim Minutes. Positive float. Initial GPE Default: 240f")] [Tunable] private static float kMaximumMeditativeFocusTimeout = 240f; [Tunable] [TunableComment("Every interval the meditating sim will lose a negative mental moodlet. Units: Sim Minutes. Positive float. Initial GPE Default: 15f")] private static float kFrequencyToRemoveNegativeMentalMoodlets = 15f; [TunableComment("Specific traits slow meditation. Each tunable for meditation timing are multiplied with this tunable. Positive float. Initial GPE Default: 1.5f")] [Tunable] private static float kMultiplierToSlowMeditation = 1.5f; [TunableComment("Specific traits speed up meditation. Each tunable for meditation timing is multiplied with this tunable. Positive float. Range: [0, 1]. Initial GPE Default: 0.75f")] [Tunable] private static float kMultiplierToSpeedUpMeditation = 0.75f; [TunableComment("If the sim has Meditative Focus moodlet, any increase in performance is modified (incremented) by this tunable. Positive float. Initial GPE default: 5f.")] [Tunable] public static float kMeditativeFocusCareerPerformanceModifier = 5f; [Tunable] [TunableComment("If the sim has Meditative Focus moodlet, any increase in skill is modified (incremented) by this tunable. Positive float. Initial GPE default: 0.25f.")] public static float kMeditativeFocusSkillGainModifier = 0.25f; [Tunable] [TunableComment("Each time a master of meditation teleports, this amount is reduced from his Meditative Focus buff. Units: Sim Minutes. Positive float. Initial GPE default: 30f.")] public static float kMeditativeFocusTimeOutReductionForMasterOfMeditationTeleport = 30f; [Tunable] [TunableComment("Minimum energy motive value to be able to spar. Negative float. Initial GPE default: -50f.")] private static float kMinimumEnergyToBeAbleToSpar = -50f; [Tunable] [TunableComment("Maximum number of rounds in a sparring match. Positive integer. Odd number. Initial GPE default: 3.")] private static int kRoundsInSpar = 3; [TunableComment("Given the highest difference in the skill levels of the opponents, this is the time taken for the sim to Win. Positive float. Initial GPE Default: 3f")] [Tunable] private static float kMinimumTimeForSingleSparRound = 3f; [Tunable] [TunableComment("Given the smallest difference in the skill levels of the opponents, i.e. 0, this is the time taken for the sim to Win. Positive float. Constrains: Greater than minimum counterpart. Initial GPE Default: 30f")] private static float kMaximumTimeForSingleSparRound = 30f; [TunableComment("Once the actual time to procede in a round t is computed, we'll find a random number between (t - this tunable) and (t + this tunable). Positive float. Constrains: Smaller than the minimum value to participate in a round. Initial GPE Default: 1.5f")] [Tunable] private static float kSparRoundTimeJitter = 1.5f; [Tunable] [TunableComment("Increase in LTR per spar round. Positive float. Initial GPE Default: 0.75f")] private static float kLtrIncreasePerSparRound = 0.75f; [TunableComment("Target STC at the end for each spar round. String. Valid STC enum value. Initial GPE Default: Friendly")] [Tunable] private static CommodityTypes kStcAtTheEndOfSparRound = CommodityTypes.Friendly; [Tunable] [TunableComment("Target STC value at the end for each spar round. Positive float. Initial GPE Default: 75f")] private static float kStcValueAtTheEndOfSparRound = 75f; [Tunable] [TunableComment("Scaling Martial arts skill level to increase chances of winning a sparring round. Positive float. Initial GPE Default: 3f")] private static float kMartialArtsSkillLevelMultiplier = 3f; [TunableComment("Scaling Athletic skill level to increase chances of winning a sparring round. Positive float. Initial GPE Default: 1.5f")] [Tunable] private static float kAthleticSkillLevelMultipler = 1.5f; [TunableComment("Increment score to win a sparing round by this amount for each designed buff and trait. This value stacks per buff or trait. Positive float. Initial GPE Default: 2.5f")] [Tunable] private static float kIncreasedScoreDueToBuffOrTrait = 2.5f; [TunableComment("For the lowest skill level (i.e. 1), this is the skill gain rate for the sparring opponent. Positive float. Initial GPE Default: 1.5f")] [Tunable] private static float kMinimumMartialArtsSkillGainRateWhileSparring = 1.5f; [TunableComment("For the highest skill level, this is the skill gain rate for the sparring opponent. Positive float. Initial GPE Default: 7f")] [Tunable] private static float kMaximumMartialArtsSkillGainRateWhileSparring = 7f; [TunableComment("Athletic skill gain rate when you spar. Independent of the opponent's skills. Positive float. Initial GPE Default: 3f")] [Tunable] private static float kAthleticSkillGainRateWhileSparring = 3f; [TunableComment("Once the martial artist is a Grand Master, the opponent's skill gain rate is incremented by this tunable. Positive float. Initial GPE Default: 3f")] [Tunable] private static float kGrandMasterSkillGainModifier = 3f; [Tunable] [TunableComment("When you choose to watch sparring sims, this is the maximum radius around sparring sims (in an attempt to route). Positive float. Initial GPE Default: 4f")] private static float kMaximumRadiusToWatchSparringMatch = 4f; [Tunable] [TunableComment("When a sim is watching a spar game, this is the amount of LTR liking needed to be cheering for the sim. Positive float. Initial GPE Default: 40f")] private static float kLtrLikingToBeASparMatchFan = 40f; [TunableComment("When a sim is watching a spar game, if the LTR between the sim and the winner is less than this number, the sim boos. Negative float. Initial GPE Default: -20f")] [Tunable] private static float kLtrLikingToBooASparMatchParticipant = -20f; [Tunable] [TunableComment("In worst case, if a sim is stuck watching spar interaction, we will bail out of the interaction if its lifetime is more than this amount. Positive float. Units: Sim Minutes. Initial GPE Default: 180f")] private static float kWatchSparTimeOut = 180f; [TunableComment("RGB values for Mastery effects 1. Positive floats.")] [Tunable] private static float[] kSparMasteryEffectsRgbAlpha = new float[3] { 1f, 0.1f, 0.1f }; [TunableComment("RGB values for Mastery effects 1. Positive floats.")] [Tunable] private static float[] kSparMasteryEffectsRgbBeta = new float[3] { 0.1f, 1f, 0.1f }; [TunableComment("RGB values for Mastery effects 1. Positive floats.")] [Tunable] private static float[] kSparMasteryEffectsRgbGamma = new float[3] { 0.1f, 0.1f, 1f }; [Tunable] [TunableComment("RGB values for Mastery effects 1. Positive floats.")] private static float[] kSparMasteryEffectsRgbDelta = new float[3] { 0.5f, 0.5f, 0.5f }; [Tunable] [TunableComment("RGB values for Mastery effects 1. Positive floats.")] private static float[] kSparMasteryEffectsRgbEpsilon = new float[3] { 1f, 0.2f, 0.5f }; [Tunable] [TunableComment("Number of matches you need to participate to unlock this lifetime achievement. Positive int. Initial GPE default: 50.")] public static float kSparMatchParticipationToBeSparMaster = 50f; [Tunable] [TunableComment("If the sim is a Spar Master, increment score to win a sparing round by this amount. This value stacks. Positive float. Initial GPE Default: 5f")] private static float kIncreasedScoreForSparMaster = 5f; [Tunable] [TunableComment("Number of Oak or higher level board you need to break to get the Board Breaker Lifetime Opportunity. Positive int. Initial GPE default: 50.")] public static float kNumberOfBoardsBrokenForLifetimeOpportunity = 50f; [Tunable] [TunableComment("Number of hours needed to be a master of meditation. Positive int. Initial GPE default: 100.")] public static int kHoursMeditatedToBeMasterOfMeditation = 100; [Tunable] [TunableComment("Advanced board breaker breaks Space rock. Chance of nothing happening. Score between [0, 100). Positive float. Initial GPE default: 30f.")] public static float kChanceToGiveNoGems = 30f; [Tunable] [TunableComment("Advanced board breaker breaks Space rock. Chance of Low priced gem. Score between (0, 100). Greater than no chance. Positive float. Initial GPE default: 80f.")] public static float kChanceToGiveLowPricedGems = 80f; [Tunable] [TunableComment("Advanced board breaker breaks Space rock. Chance of nothing happening. Score between (0, 100). Positive float. Greater than low priced. Anythgin above this is the chance to get high priced gems. Initial GPE default: 95f.")] public static float kChanceToGiveMediumPricedGems = 95f; [Tunable] [TunableComment("Advanced board breaker breaks Space rock. The sim gets a random number of gems between 1 and this number. Positive int. Initial GPE default: 3.")] public static int kMaximumNumberOfGemsAwarded = 3; [TunableComment("Gems with price below this number are low priced gems. Positive float. Initial GPE default: 50f.")] [Tunable] public static float kGemPriceThresholdBetweenLowAndMedium = 50f; [Tunable] [TunableComment("Gems above this price are high priced gems. Positive float. Initial GPE default: 200f.")] public static float kGemPriceThresholdBetweenMediumAndHigh = 200f; [Tunable] [TunableComment("Number of wins over in a tournament needed to level up in Spar Tournament Ranking. Right now we assume 5 is the highest rank (that is why there are 5 numbers in this array). Implementation wise there are six ranks (0 to 5). Make sure this list has at least 1 number (that'll maintain at least 1 ranks). Positive increasing set of integers. NOTE: If you change the size of this array, talk with Manu (or some GPE).")] private static int[] kTournamentWinsToImproveSparringRank = new int[5] { 3, 5, 9, 15, 20 }; [TunableComment("Ideal Martial arts skill of the opponent at a given Spar Tournament rank. Right now we assume 5 is the highest rank. Make sure this list has one more element than kTournamentWinsToImproveSparringRank. Initial GPE default for the first element is 2. Positive increasing set of integers. NOTE: If you change the size of this array, talk with Manu (or some GPE).")] [Tunable] private static int[] kMartialArtsSkillForOpponentPerTournamentRank = new int[6] { 2, 4, 5, 7, 8, 10 }; [TunableComment("When we are selecting the next spar opponent, anyone with Athletic skill is preferred by providing this score. This will help improve initial randomness in selection i.e. the case when the world is devoid of Martial Artists. Positive int. Initial GPE default: 3.")] [Tunable] public static int kIncreaseInAffinityForOpponentsWithAthleticSkill = 3; [Tunable] [TunableComment("How much a particular sim's Martial Skill be increased (while we are faking the skill level of a newly chosen challenger). Positive integet. Initial GPE Default: 2.")] public static int kMaximumVarienceInSkillLevelForSparTournametOpponent = 2; private bool mbSparMasterLifetimeOpportunityIsNew = true; private bool mbGrandMasterLifetimeOpportunityIsNew = true; private bool mbMasterOfMeditationLifetimeOpportunityIsNew = true; private bool mbAdvancedBoardBreakerLifetimeOpportunityIsNew = true; private const string sLocalizationKey = "Gameplay/Skills/MartialArts"; private const string sLocalizationBoardKey = "Gameplay/Objects/HobbiesSkills/BoardBreaker"; private const string kSparJig = "SparJig"; private const string kSparStateMachine = "spar"; private const string kSkillLevel = "SkillLevel"; private const string kMartialArts = "MartialArts"; private const string kMediateStateMachine = "meditate"; private const string kLevelProgression = "LevelProgression"; private const string kSitOnFloorJig = "SimSittingOnFloorJig"; private const string kCheckOutOutfitJig = "WorkOutJig"; private const string kToughestBoardTypeColumnName = "ToughestBoardType"; private const string kIdealCheckOutMyBeltAnimationName = "a_martialArts_idle_x"; private const string kFallbackCheckOutMyBeltAnimationName = "a_react_newMartialArtsBelt_x"; private const string kMartialArtsUnlocalizedText = "***MartialArtsUnlocalizedText***"; private const string kSparInteractionName = "Gameplay/Actors/Sim/Spar:InteractionName"; private const string kMeditateSoundNameLooping = "meditate_lp"; private const string kSparStringRegularMatchWin = "mararts_match_win"; private const string kSparStringRegularMatchLoss = "mararts_match_lose"; private const string kSparStringTournamentMatchWin = "mararts_tourn_win"; private const string kSparStringTournamentMatchLoss = "mararts_tourn_lose"; private const string kMeditateSoundNameAppearAfterTeleport = "meditate_appear_lp"; public const string kWatchMartialArtistStateMachine = "watch_martial_artist"; private const uint kHashMartialArtsSkill = 1686701310; private const uint kHashSparringMatchWins = 3226911199; private const uint kHashHoursSpentMeditating = 3314205252; private const uint kHashMeditativeFocusReceivedCount = 386563019; private const uint kHashSparringMatchParticipationCount = 2316266698; private const uint kHashSimsTrained = 2893326410; private const uint kHashBoardsBrokenToBeAdvancedBoardBreaker = 3283842579; private const uint kHashStrongestBoardBroken = 1047218399; private const uint kHashTournamentRank = 1407655670; private const uint kHashSparringTournamentMatchWins = 3556810684; private const uint kHashSparringTournamentMatchLosses = 3970790436; private const uint kHashSparMasterLifetimeOpportunityIsNew = 2277903937; private const uint kHashGrandMasterLifetimeOpportunityIsNew = 1627220185; private const uint kHashMasterOfMeditationLifetimeOpportunityIsNew = 2726569446; private const uint kHashAdvancedBoardBreakerLifetimeOpportunityIsNew = 2429055553; private const uint kHashBoardBreakerStackSizeMap = 1137671927; private const uint kHashHasUniformForLevel = 141247492; private bool mbCanSpar; private bool mbCanMeditate; private bool mbCanUseBoardBreaker; private bool mbCanPlaySuperAnimations; private bool mbCanStartMasteryEffects; private bool mbImmuneToBadCatacombEvents; private bool mbCanTrainOtherMartialArtists; private bool mbCanParticipateInTournaments; private bool mbAlreadyNotifedPlayerAbsoluteMeditativeFocus; private int mSparringMatchWins; private float mHoursSpentMeditating; private int mMeditativeFocusReceivedCount; private int mSparringMatchParticipationCount; private Dictionary<ulong, bool> mSimsTrained; private int mBoardsBrokenToBeAdvancedBoardBreaker; private MartialArts.BoardType mStrongestBoardBroken; private int mTournamentRank; private ulong mTournamentChallenger; private int mSparringTournamentMatchWins; private int mSparringTournamentMatchLosses; private Dictionary<int, int> mBoardTypeMapToBoardBreakerStackSize; private bool[] mHasUniformForLevel; [Persistable(false)] private List<ITrackedStat> mTrackedStats; [Persistable(false)] private List<ILifetimeOpportunity> mLifetimeOpportunities; public static string LocalizeString(bool isFemale, string name, params object[] parameters) { return Localization.LocalizeString(isFemale, "Gameplay/Skills/MartialArts:" + name, parameters); } public static string LocalizeBoardString(string name) { return Localization.LocalizeString("Gameplay/Objects/HobbiesSkills/BoardBreaker:" + name); } private static float sSlopeOfLineRepresentingTimeVsDeltaSkillLevel { get { Skill staticSkill = SkillManager.GetStaticSkill(SkillNames.MartialArts); return staticSkill != null ? (MartialArts.kMaximumTimeForSingleSparRound - MartialArts.kMinimumTimeForSingleSparRound) / (float)-staticSkill.MaxSkillLevel : 0.0f; } } private static float sSlopeOfLineRepresentingOpponentSkillLevelVsSkillGainRate { get { Skill staticSkill = SkillManager.GetStaticSkill(SkillNames.MartialArts); return staticSkill != null ? (MartialArts.kMaximumMartialArtsSkillGainRateWhileSparring - MartialArts.kMinimumMartialArtsSkillGainRateWhileSparring) / (float)(staticSkill.MaxSkillLevel - 1) : 0.0f; } } public bool CanSpar { get { return this.mbCanSpar; } } public bool CanUseBoardBreaker { get { return this.mbCanUseBoardBreaker; } } public bool ImmuneToBadCatacombEvents { get { return this.mbImmuneToBadCatacombEvents; } } public bool CanParticipateInTournaments { get { return this.mbCanParticipateInTournaments; } } public bool CanTrainOtherMartialArtists { get { return this.mbCanTrainOtherMartialArtists; } } public bool IsGrandMaster { get { return this.mTournamentRank == MartialArts.kTournamentWinsToImproveSparringRank.Length; } } public bool IsSparMaster { get { return (double)this.mSparringMatchParticipationCount >= (double)MartialArts.kSparMatchParticipationToBeSparMaster; } } public bool IsMasterOfMeditation { get { return (double)this.mHoursSpentMeditating >= (double)MartialArts.kHoursMeditatedToBeMasterOfMeditation; } } public bool IsAdvancedBoardBreaker { get { return (double)this.mBoardsBrokenToBeAdvancedBoardBreaker >= (double)MartialArts.kNumberOfBoardsBrokenForLifetimeOpportunity; } } public SimDescription TournamentChallenger { get { SimDescription tournamentOpponent = SimDescription.Find(this.mTournamentChallenger); if (tournamentOpponent == null || tournamentOpponent.DeathStyle != SimDescription.DeathType.None || (tournamentOpponent.CreatedSim == null || tournamentOpponent.CreatedSim.WorldBuilderDeath != null) || !tournamentOpponent.IsValidDescription) tournamentOpponent = this.FindSparTournamentOpponent(tournamentOpponent); return tournamentOpponent; } } public MartialArts(SkillNames guid) : base(guid) { } public MartialArts() { } public override bool ParseSkillData(XmlDbTable skillData) { if (skillData == null || skillData.Rows == null) return false; foreach (XmlDbRow row in skillData.Rows) { int key = row.GetInt("SkillLevel"); MartialArts.BoardType boardType; row.TryGetEnum<MartialArts.BoardType>("ToughestBoardType", out boardType, MartialArts.BoardType.None); if (!MartialArts.sMartialArtsSkillData.ContainsKey(key)) { string[] maleUniformNames = new string[MartialArts.kMaleOutfitNames.Length]; string[] femaleUniformNames = new string[MartialArts.kFemaleOutfitNames.Length]; int num = Math.Min(MartialArts.kMaleOutfitNames.Length, MartialArts.kFemaleOutfitNames.Length); for (int index = 0; index < num; ++index) { maleUniformNames[index] = row.GetString(MartialArts.kMaleOutfitNames[index]); femaleUniformNames[index] = row.GetString(MartialArts.kFemaleOutfitNames[index]); } if (boardType != MartialArts.BoardType.None) MartialArts.sBoardTypeToUnlockingSkillLevelMap[(int)boardType] = key; string names = row.GetString("LevelProgression"); List<MartialArts.LevelProgression> list = new List<MartialArts.LevelProgression>(); ParserFunctions.TryParseCommaSeparatedList<MartialArts.LevelProgression>(names, out list, MartialArts.LevelProgression.None); MartialArts.MartialArtsSkillLevel martialArtsSkillLevel = new MartialArts.MartialArtsSkillLevel(maleUniformNames, femaleUniformNames, boardType, list); MartialArts.sMartialArtsSkillData[key] = martialArtsSkillLevel; } } return true; } private void GenerateSimOutfit(string uniformName, out SimOutfit uniform) { uniform = (SimOutfit)null; if (string.IsNullOrEmpty(uniformName)) return; ResourceKey outfitKey = ResourceKey.CreateOutfitKey(uniformName, 0U); uniform = new SimOutfit(outfitKey); if (uniform.IsValid) return; uniform = (SimOutfit)null; } public override void SkillLeveledUp() { base.SkillLeveledUp(); int num = (int)this.UnlockLevelSpecificKarateGi(this.SkillLevel, true); this.UnlockLevelSpecificBenefits(this.SkillLevel); Sim createdSim = this.SkillOwner.CreatedSim; if (createdSim == null) return; ActiveTopic.AddToSim(createdSim, "Martial Arts Skill"); } private void UnlockLevelSpecificBenefits(int skillLevel) { MartialArts.MartialArtsSkillLevel martialArtsSkillLevel; if (MartialArts.sMartialArtsSkillData == null || !MartialArts.sMartialArtsSkillData.TryGetValue(skillLevel, out martialArtsSkillLevel)) return; foreach (MartialArts.LevelProgression unlockedBenefit in martialArtsSkillLevel.UnlockedBenefits) { switch (unlockedBenefit) { case MartialArts.LevelProgression.UnlockSpar: this.mbCanSpar = true; continue; case MartialArts.LevelProgression.UnlockBoardBreaker: this.mbCanUseBoardBreaker = true; continue; case MartialArts.LevelProgression.UnlockTournaments: this.mbCanParticipateInTournaments = true; this.FindSparTournamentOpponent((SimDescription)null); continue; case MartialArts.LevelProgression.UnlockMeditate: this.mbCanMeditate = true; continue; case MartialArts.LevelProgression.UnlockCatacombImmunity: this.mbImmuneToBadCatacombEvents = true; continue; case MartialArts.LevelProgression.UnlockTrainOtherSims: this.mbCanTrainOtherMartialArtists = true; continue; case MartialArts.LevelProgression.UnlockMasteryEffects: this.mbCanStartMasteryEffects = true; continue; case MartialArts.LevelProgression.UnlockSuperAnimations: this.mbCanPlaySuperAnimations = true; continue; default: continue; } } } public override Skill Clone(SimDescription owner) { MartialArts martialArts = base.Clone(owner) as MartialArts; martialArts.mSimsTrained = new Dictionary<ulong, bool>(); martialArts.mBoardTypeMapToBoardBreakerStackSize = new Dictionary<int, int>(); martialArts.mHasUniformForLevel = new bool[this.MaxSkillLevel]; return (Skill)martialArts; } public override void OnInstantiated() { Sim createdSim = this.SkillOwner.CreatedSim; if (createdSim == null) return; ActiveTopic.AddToSim(createdSim, "Martial Arts Skill"); } public override void OnSkillAddition(bool suppressTNS) { base.OnSkillAddition(suppressTNS); if (this.SkillOwner.TraitManager.HasElement(TraitNames.Disciplined)) this.SkillOwner.SkillManager.AddToSkillGainModifier(SkillNames.MartialArts, TraitTuning.kDisciplinedTraitsMartialArtsSkillMultiplier - 1f); Tutorialette.TriggerLesson(Lessons.MartialArtsSkill, this.SkillOwner.CreatedSim); } public static MartialArts.BoardType GetMostCompatibleBoard(int skillLevel) { MartialArts.BoardType boardType = MartialArts.BoardType.None; for (int key = skillLevel; key >= 1; --key) { MartialArts.MartialArtsSkillLevel martialArtsSkillLevel; if (MartialArts.sMartialArtsSkillData.TryGetValue(key, out martialArtsSkillLevel)) { MartialArts.BoardType toughestBoardType = martialArtsSkillLevel.ToughestBoardType; if (toughestBoardType != MartialArts.BoardType.None) { boardType = toughestBoardType; break; } } } return boardType; } public static List<MartialArts.BoardType> GetBreakableBoards() { Array values = Enum.GetValues(typeof(MartialArts.BoardType)); List<MartialArts.BoardType> boardTypeList = new List<MartialArts.BoardType>(); for (int index = 0; index < values.Length; ++index) { MartialArts.BoardType boardType = (MartialArts.BoardType)values.GetValue(index); if (boardType != MartialArts.BoardType.None) boardTypeList.Add(boardType); } return boardTypeList; } public static int GetSkillLevelToUnlockBoard(MartialArts.BoardType type) { int num; return type != MartialArts.BoardType.None && MartialArts.sBoardTypeToUnlockingSkillLevelMap.TryGetValue((int)type, out num) ? num : -1; } private static Sim GetWinnerForRound(Sim x, Sim y, MartialArts xSkill, MartialArts ySkill) { float forMartialArtist1 = MartialArts.GetScoreForMartialArtist(x, xSkill); float forMartialArtist2 = MartialArts.GetScoreForMartialArtist(y, ySkill); return (double)RandomUtil.GetFloat(forMartialArtist1 + forMartialArtist2) >= (double)forMartialArtist1 ? y : x; } private static float GetScoreForMartialArtist(Sim actor, MartialArts martialArtsSkill) { if (actor == null || martialArtsSkill == null) return 0.0f; float num = (float)martialArtsSkill.SkillLevel * MartialArts.kMartialArtsSkillLevelMultiplier; int skillLevel = actor.SkillManager.GetSkillLevel(SkillNames.Athletic); if (skillLevel > 0) num += (float)skillLevel * MartialArts.kAthleticSkillLevelMultipler; BuffNames[] buffNamesArray = new BuffNames[3] { BuffNames.MeditativeFocus, BuffNames.OddlyPowerful, BuffNames.Pumped }; foreach (BuffNames guid in buffNamesArray) { if (actor.BuffManager.HasElement(guid)) num += MartialArts.kIncreasedScoreDueToBuffOrTrait; } if (actor.HasTrait(TraitNames.Disciplined)) num += MartialArts.kIncreasedScoreDueToBuffOrTrait; if (martialArtsSkill.IsSparMaster) num += MartialArts.kIncreasedScoreForSparMaster; return num; } private static float[] GetRgbForMasteryEffects(Sim actor) { if (actor == null) return new float[3] { 1f, 1f, 1f }; switch (Math.Abs((int)actor.ObjectId.mValue % 5)) { case 1: return MartialArts.kSparMasteryEffectsRgbBeta; case 2: return MartialArts.kSparMasteryEffectsRgbGamma; case 3: return MartialArts.kSparMasteryEffectsRgbDelta; case 4: return MartialArts.kSparMasteryEffectsRgbEpsilon; default: return MartialArts.kSparMasteryEffectsRgbAlpha; } } public static void StartDisciplinedFunCommodity(InteractionInstance ii) { if (ii.InstanceActor.HasTrait(TraitNames.Disciplined)) ii.AddMotiveDelta(CommodityKind.Fun, TraitTuning.kDisciplinedTraitMartialArtsFun); if (!(ii.Target is Sim target) || !target.HasTrait(TraitNames.Disciplined) || target.CurrentInteraction == null) return; target.CurrentInteraction.AddMotiveDelta(CommodityKind.Fun, TraitTuning.kDisciplinedTraitMartialArtsFun); } public static void EndDisciplinedFunCommodity(InteractionInstance ii) { if (ii.InstanceActor.HasTrait(TraitNames.Disciplined)) ii.RemoveMotiveDelta(CommodityKind.Fun); if (!(ii.Target is Sim target) || !target.HasTrait(TraitNames.Disciplined) || target.CurrentInteraction == null) return; target.CurrentInteraction.RemoveMotiveDelta(CommodityKind.Fun); } private static bool CreatePlaceAndRouteToJig( Sim sim, string jigName, out SocialJigOnePerson jig, bool doRouteFail) { jig = GlobalFunctions.CreateObjectOutOfWorld(jigName) as SocialJigOnePerson; if (jig == null) return false; Vector3 position = sim.Position; Vector3 forwardVector = sim.ForwardVector; jig.RegisterParticipants(sim, (Sim)null); if (!GlobalFunctions.FindGoodLocationNearby((IGameObject)jig, ref position, ref forwardVector)) { jig.Destroy(); jig = (SocialJigOnePerson)null; return false; } jig.SetPosition(position); jig.SetForward(forwardVector); jig.AddToWorld(); jig.SetHiddenFlags(HiddenFlags.Model); Route route = sim.CreateRoute(); route.AddDestination((RouteDestination)new PointDestination() { mPoint = position, mFacingDirection = forwardVector }); route.AddObjectToIgnoreForRoute(jig.ObjectId); route.Plan(); route.DoRouteFail = doRouteFail; if (sim.DoRoute(route)) return true; jig.Destroy(); jig = (SocialJigOnePerson)null; return false; } public static bool IsSimsMotiveSparWorthy(Sim actor) { return actor != null && actor.Motives != null && (!actor.BuffManager.HasElement(BuffNames.Fatigued) && (double)actor.Motives.GetValue(CommodityKind.Energy) > (double)MartialArts.kMinimumEnergyToBeAbleToSpar); } private void EnsureAtLeastOneMartialArtsOutfit() { if (this.mSkillOwner.Outfits[(object)OutfitCategories.MartialArts] is ArrayList outfit && outfit.Count != 0) return; int skillLevel = this.SkillLevel; while (skillLevel > 0 && this.UnlockLevelSpecificKarateGi(skillLevel, false) != MartialArts.UnlockUniformFailureReason.None) --skillLevel; } private MartialArts.UnlockUniformFailureReason UnlockLevelSpecificKarateGi( int level, bool bPushCheckOutMyAwesomeBelt) { if (CharacterImportOnGameLoad.InProgress || level <= 0) return MartialArts.UnlockUniformFailureReason.InvalidRequest; MartialArts.MartialArtsSkillLevel levelData; if (!MartialArts.sMartialArtsSkillData.TryGetValue(level, out levelData)) return MartialArts.UnlockUniformFailureReason.MissingTuningDataForLevel; SimOutfit uniform = this.GetUniform(levelData); if (uniform == null) return MartialArts.UnlockUniformFailureReason.NoUniformForLevel; int index = level - 1; if (this.mHasUniformForLevel[index]) return MartialArts.UnlockUniformFailureReason.SimAlreadyHasUniformForLevel; SimOutfit outfit = new SimOutfit(OutfitUtils.ApplyUniformToOutfit(this.mSkillOwner.GetOutfit(OutfitCategories.Everyday, 0), uniform, this.mSkillOwner, "MartialArts.UnlockLevelSpecificKarateGi")); if (!outfit.IsValid) return MartialArts.UnlockUniformFailureReason.FailedToCreateUniform; this.mHasUniformForLevel[index] = true; this.mSkillOwner.AddOutfit(outfit, OutfitCategories.MartialArts, true); Sim createdSim = this.mSkillOwner.CreatedSim; if (bPushCheckOutMyAwesomeBelt && createdSim != null) { InteractionInstance instance = MartialArts.CheckOutMyAwesomeBelt.Singleton.CreateInstance((IGameObject)createdSim, (IActor)createdSim, new InteractionPriority(InteractionPriorityLevel.UserDirected), false, true); if (instance != null) createdSim.InteractionQueue.AddNext(instance); } return MartialArts.UnlockUniformFailureReason.None; } private SimOutfit GetUniform(MartialArts.MartialArtsSkillLevel levelData) { int uniformIndex = -1; switch (this.SkillOwner.Age) { case CASAgeGenderFlags.Teen: uniformIndex = 0; break; case CASAgeGenderFlags.YoungAdult: case CASAgeGenderFlags.Adult: uniformIndex = 1; break; case CASAgeGenderFlags.Elder: uniformIndex = 2; break; } return this.BuildOrLookupSimOutfitCache(ref levelData, uniformIndex); } private SimOutfit BuildOrLookupSimOutfitCache( ref MartialArts.MartialArtsSkillLevel levelData, int uniformIndex) { if (uniformIndex == -1) return (SimOutfit)null; string[] strArray = this.SkillOwner.IsMale ? levelData.UniformNameMale : levelData.UniformNameFemale; if (strArray == null || strArray.Length < uniformIndex || strArray[uniformIndex] == null) return (SimOutfit)null; SimOutfit uniform = (SimOutfit)null; SimOutfit[] simOutfitArray = this.SkillOwner.IsMale ? levelData.UniformMale : levelData.UniformFemale; if (simOutfitArray != null) { uniform = simOutfitArray[uniformIndex]; if (uniform != null) return uniform; } this.GenerateSimOutfit(strArray[uniformIndex], out uniform); if (this.SkillOwner.IsMale) { if (levelData.UniformMale == null) levelData.UniformMale = new SimOutfit[MartialArts.kMaleOutfitNames.Length]; levelData.UniformMale[uniformIndex] = uniform; } else { if (levelData.UniformFemale == null) levelData.UniformFemale = new SimOutfit[MartialArts.kFemaleOutfitNames.Length]; levelData.UniformFemale[uniformIndex] = uniform; } return uniform; } public void LoadAllUniforms() { for (int skillLevel = this.SkillLevel; skillLevel > 0; --skillLevel) { int num = (int)this.UnlockLevelSpecificKarateGi(skillLevel, false); } } public List<SimOutfit> GetSimUniforms(CASAgeGenderFlags age) { List<SimOutfit> simOutfitList = (List<SimOutfit>)null; for (int skillLevel = this.SkillLevel; skillLevel >= 1; --skillLevel) { MartialArts.MartialArtsSkillLevel levelData; if (MartialArts.sMartialArtsSkillData.TryGetValue(skillLevel, out levelData)) { SimOutfit uniform = this.GetUniform(levelData); if (uniform != null) { if (simOutfitList == null) simOutfitList = new List<SimOutfit>(); simOutfitList.Add(uniform); } } } return simOutfitList; } public void UpdateBoardBreakerPracticeStatistics(MartialArts.BoardType boardType, int stackSize) { if (boardType == MartialArts.BoardType.None) return; int key = (int)boardType; int num; if (this.mBoardTypeMapToBoardBreakerStackSize.TryGetValue(key, out num)) { if (stackSize <= num) return; this.mBoardTypeMapToBoardBreakerStackSize[key] = stackSize; } else this.mBoardTypeMapToBoardBreakerStackSize[key] = stackSize; } public IGameObject UpdateBoardBreakerStatisticsAndProvideRewards( MartialArts.BoardType board, int stackSize) { if (board == MartialArts.BoardType.None) return (IGameObject)null; if (board > this.mStrongestBoardBroken) this.mStrongestBoardBroken = board; if (board >= MartialArts.BoardType.OakBoard) { this.mBoardsBrokenToBeAdvancedBoardBreaker += stackSize; this.TestForNewLifetimeOpp(); } IGameObject gameObject = (IGameObject)null; if (this.IsAdvancedBoardBreaker && board == MartialArts.BoardType.SpaceRockBlock) { int num1 = RandomUtil.GetInt(1, MartialArts.kMaximumNumberOfGemsAwarded); for (int index = 0; index < num1; ++index) { float num2 = RandomUtil.GetFloat(0.0f, 100f); gameObject = (double)num2 > (double)MartialArts.kChanceToGiveNoGems ? ((double)num2 > (double)MartialArts.kChanceToGiveLowPricedGems ? ((double)num2 > (double)MartialArts.kChanceToGiveMediumPricedGems ? RockGemMetalBase.GetGemInPriceRange(MartialArts.kGemPriceThresholdBetweenMediumAndHigh, float.MaxValue, false) : RockGemMetalBase.GetGemInPriceRange(MartialArts.kGemPriceThresholdBetweenLowAndMedium, MartialArts.kGemPriceThresholdBetweenMediumAndHigh, false)) : RockGemMetalBase.GetGemInPriceRange(0.0f, MartialArts.kGemPriceThresholdBetweenLowAndMedium, false)) : (IGameObject)null; } } return gameObject; } public bool TryAddingNewTrainee(ulong simDescriptionId) { if (this.mSimsTrained.ContainsKey(simDescriptionId)) return false; this.mSimsTrained[simDescriptionId] = true; return true; } public void ChangeIntoKarateGi() { this.EnsureAtLeastOneMartialArtsOutfit(); this.mSkillOwner.CreatedSim?.SwitchToOutfitWithSpin(Sim.ClothesChangeReason.GoingToSparOrTrain, OutfitCategories.MartialArts); } public bool TryGetBestStackSizeForPracticingOnBoardBreaker( MartialArts.BoardType boardType, out int stackSize) { stackSize = -1; return boardType != MartialArts.BoardType.None && this.mBoardTypeMapToBoardBreakerStackSize.TryGetValue((int)boardType, out stackSize); } private SimDescription FindSparTournamentOpponent(SimDescription presentChallenger) { if (GameUtils.GetCurrentWorld() != WorldName.China || CharacterImportOnGameLoad.InProgress) return (SimDescription)null; if (this.SkillOwner == null || this.SkillOwner.Household != null && !this.SkillOwner.Household.IsActive) return (SimDescription)null; SimDescription suitableOpponent = TournamentManagement.FindSuitableOpponent(this.mSkillOwner, Household.sHouseholdList, presentChallenger, new TournamentManagement.GetAffinity(this.GetAffinity)); if (suitableOpponent != null) { this.mTournamentChallenger = suitableOpponent.SimDescriptionId; Household household = suitableOpponent.Household; if (!household.IsActive && !household.IsTravelHousehold && suitableOpponent.SkillManager.AddElement(SkillNames.MartialArts) is MartialArts martialArts) { int num = MartialArts.kMartialArtsSkillForOpponentPerTournamentRank[this.mTournamentRank]; if (martialArts.SkillLevel < num) { int targetLevel = MathUtils.Clamp(num + RandomUtil.GetInt(0, MartialArts.kMaximumVarienceInSkillLevelForSparTournametOpponent), MartialArts.kMartialArtsSkillForOpponentPerTournamentRank[1], martialArts.MaxSkillLevel); martialArts.ForceSkillLevelUp(targetLevel); } } } return suitableOpponent; } private int GetAffinity(SimDescription simDescription) { int num1 = 0; if (this.mSkillOwner.Household != simDescription.Household) ++num1; int num2 = MartialArts.kMartialArtsSkillForOpponentPerTournamentRank[this.mTournamentRank]; SkillManager skillManager = simDescription.SkillManager; if (skillManager != null) { MartialArts skill = skillManager.GetSkill<MartialArts>(SkillNames.MartialArts); if (simDescription.Household.IsActive && (skill == null || !skill.CanParticipateInTournaments)) return 0; if (skill != null) { int num3 = Math.Abs(num2 - skill.SkillLevel); num1 += this.MaxSkillLevel - num3; } else num1 += this.MaxSkillLevel - num2; if (skillManager.HasElement(SkillNames.Athletic)) num1 += MartialArts.kIncreaseInAffinityForOpponentsWithAthleticSkill; } return num1; } private void OnSparTournamentMatchWin() { int index = 0; while (index < MartialArts.kTournamentWinsToImproveSparringRank.Length && this.mSparringTournamentMatchWins >= MartialArts.kTournamentWinsToImproveSparringRank[index]) ++index; if (this.mTournamentRank < index) { this.ShowTNSWindow(MartialArts.LocalizeString((this.mSkillOwner.IsFemale ? 1 : 0) != 0, "SparTournamentRankIncreased", (object)this.mSkillOwner, (object)index)); this.mTournamentRank = index; this.TestForNewLifetimeOpp(); } if (this.IsGrandMaster) EventTracker.SendEvent(EventTypeId.kSimIsMartialArtsGrandMaster, (IActor)this.mSkillOwner.CreatedSim); this.FindSparTournamentOpponent(this.TournamentChallenger); } public override List<ITrackedStat> TrackedStats { get { return this.mTrackedStats; } } public override List<ILifetimeOpportunity> LifetimeOpportunities { get { return this.mLifetimeOpportunities; } } public override void CreateSkillJournalInfo() { this.mTrackedStats = new List<ITrackedStat>(); this.mTrackedStats.Add((ITrackedStat)new MartialArts.TournamentRank(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.SparringTournamentWinsAndLosses(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.SparringMatchsWon(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.HoursSpentMeditating(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.MeditativeFocusReceivedCount(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.StrongestBoardBroken(this)); this.mTrackedStats.Add((ITrackedStat)new MartialArts.StudentsTrained(this)); this.mLifetimeOpportunities = new List<ILifetimeOpportunity>(); this.mLifetimeOpportunities.Add((ILifetimeOpportunity)new MartialArts.GrandMaster(this)); this.mLifetimeOpportunities.Add((ILifetimeOpportunity)new MartialArts.MasterOfMeditation(this)); this.mLifetimeOpportunities.Add((ILifetimeOpportunity)new MartialArts.SparMaster(this)); this.mLifetimeOpportunities.Add((ILifetimeOpportunity)new MartialArts.AdvancedBoardBreaker(this)); } public override uint GetSkillHash() { return 1686701310; } public override bool ExportContent(IPropertyStreamWriter writer) { base.ExportContent(writer); writer.WriteInt32(3226911199U, this.mSparringMatchWins); writer.WriteFloat(3314205252U, this.mHoursSpentMeditating); writer.WriteInt32(386563019U, this.mMeditativeFocusReceivedCount); writer.WriteInt32(2316266698U, this.mSparringMatchParticipationCount); writer.WriteInt32(3283842579U, this.mBoardsBrokenToBeAdvancedBoardBreaker); writer.WriteInt32(1047218399U, (int)this.mStrongestBoardBroken); writer.WriteInt32(1407655670U, this.mTournamentRank); writer.WriteInt32(3556810684U, this.mSparringTournamentMatchWins); writer.WriteInt32(3970790436U, this.mSparringTournamentMatchLosses); writer.WriteBool(2277903937U, this.mbSparMasterLifetimeOpportunityIsNew); writer.WriteBool(1627220185U, this.mbGrandMasterLifetimeOpportunityIsNew); writer.WriteBool(2726569446U, this.mbMasterOfMeditationLifetimeOpportunityIsNew); writer.WriteBool(2429055553U, this.mbAdvancedBoardBreakerLifetimeOpportunityIsNew); writer.WriteBool(141247492U, this.mHasUniformForLevel); this.ExportSimsTrained(writer); this.ExportMapFromBoardTypeToStackSize(writer); return true; } private bool ExportSimsTrained(IPropertyStreamWriter writer) { if (this.mSimsTrained == null) return true; MartialArts.MartialArtsPropertyStreamWriter propertyStreamWriter = new MartialArts.MartialArtsPropertyStreamWriter(); writer.AdoptChild(2893326410U, (IPropertyStreamWriter)propertyStreamWriter); bool flag = propertyStreamWriter.Export(this.mSimsTrained); if (flag) writer.CommitChild(); else writer.CancelChild(2893326410U); return flag; } private bool ExportMapFromBoardTypeToStackSize(IPropertyStreamWriter writer) { if (this.mBoardTypeMapToBoardBreakerStackSize == null) return true; MartialArts.MartialArtsPropertyStreamWriter propertyStreamWriter = new MartialArts.MartialArtsPropertyStreamWriter(); writer.AdoptChild(1137671927U, (IPropertyStreamWriter)propertyStreamWriter); bool flag = propertyStreamWriter.Export(this.mBoardTypeMapToBoardBreakerStackSize); if (flag) writer.CommitChild(); else writer.CancelChild(1137671927U); return flag; } public override bool ImportContent(IPropertyStreamReader reader) { base.ImportContent(reader); reader.ReadInt32(3226911199U, out this.mSparringMatchWins, 0); reader.ReadFloat(3314205252U, out this.mHoursSpentMeditating, 0.0f); reader.ReadInt32(386563019U, out this.mMeditativeFocusReceivedCount, 0); reader.ReadInt32(2316266698U, out this.mSparringMatchParticipationCount, 0); reader.ReadInt32(3283842579U, out this.mBoardsBrokenToBeAdvancedBoardBreaker, 0); int num = 0; reader.ReadInt32(1047218399U, out num, int.MaxValue); this.mStrongestBoardBroken = num == int.MaxValue || !Enum.IsDefined(typeof(MartialArts.BoardType), (object)num) ? MartialArts.BoardType.None : (MartialArts.BoardType)num; reader.ReadInt32(1407655670U, out this.mTournamentRank, 0); reader.ReadInt32(3556810684U, out this.mSparringTournamentMatchWins, 0); reader.ReadInt32(3970790436U, out this.mSparringTournamentMatchLosses, 0); reader.ReadBool(2277903937U, out this.mbSparMasterLifetimeOpportunityIsNew, true); reader.ReadBool(1627220185U, out this.mbGrandMasterLifetimeOpportunityIsNew, true); reader.ReadBool(2726569446U, out this.mbMasterOfMeditationLifetimeOpportunityIsNew, true); reader.ReadBool(2429055553U, out this.mbAdvancedBoardBreakerLifetimeOpportunityIsNew, true); reader.ReadBool(141247492U, out this.mHasUniformForLevel); this.ImportSimsTrained(reader); this.ImportMapFromBoardTypeToStackSize(reader); for (int skillLevel = 0; skillLevel <= this.SkillLevel; ++skillLevel) this.UnlockLevelSpecificBenefits(skillLevel); return true; } public override void MergeTravelData(Skill skill) { base.MergeTravelData(skill); MartialArts martialArts = skill as MartialArts; this.mSparringMatchWins = martialArts.mSparringMatchWins; this.mHoursSpentMeditating = martialArts.mHoursSpentMeditating; this.mMeditativeFocusReceivedCount = martialArts.mMeditativeFocusReceivedCount; this.mSparringMatchParticipationCount = martialArts.mSparringMatchParticipationCount; this.mBoardsBrokenToBeAdvancedBoardBreaker = martialArts.mBoardsBrokenToBeAdvancedBoardBreaker; this.mStrongestBoardBroken = martialArts.mStrongestBoardBroken; this.mTournamentRank = martialArts.mTournamentRank; this.mSparringTournamentMatchWins = martialArts.mSparringTournamentMatchWins; this.mSparringTournamentMatchLosses = martialArts.mSparringTournamentMatchLosses; this.mbSparMasterLifetimeOpportunityIsNew = martialArts.mbSparMasterLifetimeOpportunityIsNew; this.mbGrandMasterLifetimeOpportunityIsNew = martialArts.mbGrandMasterLifetimeOpportunityIsNew; this.mbMasterOfMeditationLifetimeOpportunityIsNew = martialArts.mbMasterOfMeditationLifetimeOpportunityIsNew; this.mbAdvancedBoardBreakerLifetimeOpportunityIsNew = martialArts.mbAdvancedBoardBreakerLifetimeOpportunityIsNew; this.mSimsTrained = martialArts.mSimsTrained; this.mBoardTypeMapToBoardBreakerStackSize = martialArts.mBoardTypeMapToBoardBreakerStackSize; this.mHasUniformForLevel = martialArts.mHasUniformForLevel; GameStates.TravelComplete += new GameStates.TravelCallback(this.UnlockBenefitsPostLoad); } private void UnlockBenefitsPostLoad() { GameStates.TravelComplete -= new GameStates.TravelCallback(this.UnlockBenefitsPostLoad); for (int skillLevel = 0; skillLevel <= this.SkillLevel; ++skillLevel) this.UnlockLevelSpecificBenefits(skillLevel); } private bool ImportSimsTrained(IPropertyStreamReader reader) { MartialArts.MartialArtsPropertyStreamReader propertyStreamReader = new MartialArts.MartialArtsPropertyStreamReader(); reader.AdoptChild(2893326410U, (IPropertyStreamReader)propertyStreamReader); return propertyStreamReader.Import(out this.mSimsTrained); } private bool ImportMapFromBoardTypeToStackSize(IPropertyStreamReader reader) { MartialArts.MartialArtsPropertyStreamReader propertyStreamReader = new MartialArts.MartialArtsPropertyStreamReader(); reader.AdoptChild(1137671927U, (IPropertyStreamReader)propertyStreamReader); return propertyStreamReader.Import(out this.mBoardTypeMapToBoardBreakerStackSize); } public enum BoardType { None, FoamBoard, BalsaWoodBoard, OakBoard, ThinStoneBlock, SpaceRockBlock, } private enum LevelProgression { None, UnlockSpar, UnlockBoardBreaker, UnlockTournaments, UnlockMeditate, UnlockCatacombImmunity, UnlockTrainOtherSims, UnlockMasteryEffects, UnlockSuperAnimations, } private enum SparState { None, StartRound, BlockX, BlockY, HitX, HitY, ActorWinsMatch, TargetWinsMatch, ActorCancelledMatch, TargetCancelledMatch, } internal enum SparMatchType { None, Regular, Tournament, } public enum WatchReactions { None, Boo, Clap, Cheer, Laugh, } private enum UnlockUniformFailureReason { None, InvalidRequest, MissingTuningDataForLevel, NoUniformForLevel, SimAlreadyHasUniformForLevel, FailedToCreateUniform, } [Persistable(false)] private class MartialArtsSkillLevel { public string[] UniformNameMale; public string[] UniformNameFemale; public SimOutfit[] UniformMale; public SimOutfit[] UniformFemale; public MartialArts.BoardType ToughestBoardType; public List<MartialArts.LevelProgression> UnlockedBenefits; internal MartialArtsSkillLevel( string[] maleUniformNames, string[] femaleUniformNames, MartialArts.BoardType boardType, List<MartialArts.LevelProgression> unlockedBenefits) { this.UniformMale = (SimOutfit[])null; this.UniformFemale = (SimOutfit[])null; this.UniformNameMale = maleUniformNames; this.UniformNameFemale = femaleUniformNames; this.ToughestBoardType = boardType; this.UnlockedBenefits = unlockedBenefits; } } internal sealed class Meditate : Interaction<Sim, Sim> { private static readonly uint[] kPersistentAnimationToScriptEvents = new uint[7] { 1001U, 1002U, 1003U, 1004U, 1005U, 1006U, 1007U }; public static readonly ISoloInteractionDefinition Singleton = (ISoloInteractionDefinition)new MartialArts.Meditate.Definition(); private int mMeditationInterval = 1; private int mMoodletRemovalInterval = 1; private Vector3 mTeleportationDestination = Vector3.Invalid; private const uint kPostTeleportOneShotAnimationToScriptEvent = 111; private BuffInstance mMeditativeFocus; private SocialJigOnePerson mSitOnFloorJig; private bool mbHasLevitationStarted; private bool mbHasTeleportationStarted; private ObjectSound mSoundHandleMeditation; private ObjectSound mSoundHandlePostTeleport; public bool IsActorLevitating { get { return this.mbHasLevitationStarted; } } public SocialJigOnePerson MeditationJig { get { return this.mSitOnFloorJig; } } public bool EnableTeleportation(Vector3 destination) { if (!(destination != Vector3.Invalid) || !(destination != Vector3.Zero)) return false; this.mTeleportationDestination = destination; return true; } protected override bool Run() { SocialJigOnePerson jig; if (!MartialArts.CreatePlaceAndRouteToJig(this.Actor, "SimSittingOnFloorJig", out jig, true)) return false; this.mSitOnFloorJig = jig; DateAndTime dateAndTime1 = SimClock.CurrentTime(); this.EnterStateMachine("meditate", "Enter", "x"); this.AddOneShotScriptEventHandler(111U, new SacsEventHandler(this.PostTeleportCallback)); for (int index = 0; index < MartialArts.Meditate.kPersistentAnimationToScriptEvents.Length; ++index) this.AddPersistentScriptEventHandler(MartialArts.Meditate.kPersistentAnimationToScriptEvents[index], new SacsEventHandler(this.AudioSpecificEventCallback)); MartialArts.StartDisciplinedFunCommodity((InteractionInstance)this); this.Actor.LookAtManager.DisableLookAts(); this.Actor.BuffManager.PauseBuff(BuffNames.MeditativeFocus); this.BeginCommodityUpdates(); this.AnimateSim(nameof(Meditate)); bool succeeded = this.DoLoop(ExitReason.Default, new InteractionInstance.InsideLoopFunction(this.MeditateDelegate), this.mCurrentStateMachine); this.EndCommodityUpdates(succeeded); MartialArts.EndDisciplinedFunCommodity((InteractionInstance)this); if (this.Actor.BuffManager.HasElement(BuffNames.MeditativeFocus)) this.Actor.BuffManager.UnpauseBuff(BuffNames.MeditativeFocus); this.AnimateSim(this.mbHasTeleportationStarted ? "Teleportation Exit" : "Exit"); DateAndTime dateAndTime2 = SimClock.CurrentTime() - dateAndTime1; MartialArts skill = this.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); skill.mHoursSpentMeditating += dateAndTime2.Hour + dateAndTime2.Minute / 60f; skill.TestForNewLifetimeOpp(); return succeeded; } public override void Cleanup() { base.Cleanup(); this.DisposeSoundHandles(); if (this.Actor != null && this.Actor.LookAtManager != null) this.Actor.LookAtManager.EnableLookAts(); if (this.mSitOnFloorJig == null) return; this.mSitOnFloorJig.Destroy(); this.mSitOnFloorJig = (SocialJigOnePerson)null; } private void MeditateDelegate(StateMachineClient smc, InteractionInstance.LoopData loopData) { if (this.mbHasTeleportationStarted) return; EventTracker.SendEvent((Sims3.Gameplay.EventSystem.Event)new TimePassedEvent(EventTypeId.kMeditated, (IActor)this.Actor, (IGameObject)null, loopData.mDeltaTime)); Lot lotCurrent = this.Actor.LotCurrent; if (lotCurrent != null) { EventTracker.SendEvent((Sims3.Gameplay.EventSystem.Event)new StringEvent(EventTypeId.kSimMeditatedAtLot, (IActor)this.Actor, (IGameObject)lotCurrent, lotCurrent.AddressLocalizationKey)); EventTracker.SendEvent((Sims3.Gameplay.EventSystem.Event)new TimePassedStringEvent(EventTypeId.kSimMeditatedAtLot, (IActor)this.Actor, (IGameObject)lotCurrent, loopData.mDeltaTime, lotCurrent.AddressLocalizationKey)); } float mLifeTime = loopData.mLifeTime; float timeMultipler = this.GetTimeMultipler(); float num1 = MartialArts.kMeditationDurationToUnlockMeditativeFocus * timeMultipler; if ((double)mLifeTime > (double)num1) this.DoMeditate(mLifeTime, timeMultipler); float num2 = (float)this.mMoodletRemovalInterval * MartialArts.kFrequencyToRemoveNegativeMentalMoodlets; if ((double)mLifeTime >= (double)num2) { ++this.mMoodletRemovalInterval; BuffManager buffManager = this.Actor.BuffManager; BuffInstance categoryAndPolarity = buffManager.GetRandomBuffOfGivenCategoryAndPolarity(BuffCategory.Mental, BuffPolarity.Negative); if (categoryAndPolarity != null) buffManager.RemoveElement(categoryAndPolarity.BuffGuid); } this.DoTeleport(); } private void DoMeditate(float lifeTime, float scaling) { if (this.mMeditativeFocus == null) this.mMeditativeFocus = this.Actor.BuffManager.GetElement(BuffNames.MeditativeFocus); if (this.mMeditativeFocus != null) { if ((double)this.mMeditativeFocus.mTimeoutCount >= (double)MartialArts.kMaximumMeditativeFocusTimeout) { this.DoLevitate(); } else { float num1 = MartialArts.kMeditationIntervalToIncrementMeditativeFocus * scaling; float num2 = MartialArts.kMeditationDurationToUnlockMeditativeFocus + (float)this.mMeditationInterval * num1; if ((double)lifeTime < (double)num2) return; ++this.mMeditationInterval; float val2 = this.mMeditativeFocus.mTimeoutCount + MartialArts.kIncrementInMeditativeFocusTimeout; this.mMeditativeFocus.mTimeoutCount = Math.Min(MartialArts.kMaximumMeditativeFocusTimeout, val2); } } else { this.Actor.BuffManager.AddElementPaused(BuffNames.MeditativeFocus, Origin.FromMeditation); ++this.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts).mMeditativeFocusReceivedCount; } } private void DoLevitate() { if (this.mbHasLevitationStarted) return; this.mbHasLevitationStarted = true; this.AnimateSim("Levitate"); MartialArts skill = this.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); if (skill.mbAlreadyNotifedPlayerAbsoluteMeditativeFocus) return; skill.mbAlreadyNotifedPlayerAbsoluteMeditativeFocus = true; this.Actor.ShowTNSIfSelectable(MartialArts.LocalizeString((this.Actor.IsFemale ? 1 : 0) != 0, "FirstTeleportMessage", (object)this.Actor), StyledNotification.NotificationStyle.kGameMessagePositive, ObjectGuid.InvalidObjectGuid, this.Actor.ObjectId); } private void DoTeleport() { if (this.mbHasTeleportationStarted || !this.mbHasLevitationStarted || !(this.mTeleportationDestination != Vector3.Invalid)) return; this.mbHasTeleportationStarted = true; this.AnimateSim("Initiate Teleportation"); this.Actor.FadeOut(true, false, MartialArts.kFadeInAndOutTimeForMeditationTeleportation); this.AnimateSim("Finish Teleportation"); } private void PostTeleportCallback(StateMachineClient sender, IEvent evt) { if (World.TestObjectPlacement(this.mSitOnFloorJig.ObjectId, TestObjectPlacementBooleans.Routable, this.mTeleportationDestination)) { this.mSitOnFloorJig.SetPosition(this.mTeleportationDestination); this.Actor.SetPosition(this.mTeleportationDestination); } this.Actor.FadeIn(false, MartialArts.kFadeInAndOutTimeForMeditationTeleportation); this.Actor.AddExitReason(ExitReason.Finished); this.Actor.BuffManager.RemoveElement(BuffNames.MeditativeFocus); } private void AudioSpecificEventCallback(StateMachineClient sender, IEvent evt) { switch (evt.EventId) { case 1001: if (this.mSoundHandleMeditation != null) break; this.mSoundHandleMeditation = new ObjectSound(this.Actor.ObjectId, "meditate_lp"); this.mSoundHandleMeditation.StartLoop(); break; case 1002: case 1006: this.DisposeMeditationSoundHandle(); break; case 1003: this.mSoundHandleMeditation.Stop(); break; case 1004: if (this.mSoundHandlePostTeleport != null) break; this.mSoundHandlePostTeleport = new ObjectSound(this.Actor.ObjectId, "meditate_appear_lp"); this.mSoundHandlePostTeleport.StartLoop(); break; case 1005: case 1007: this.DisposePostTeleportSoundHandle(); break; } } private float GetTimeMultipler() { float num = 1f; if (this.Actor.HasTrait(TraitNames.AbsentMinded) || this.Actor.HasTrait(TraitNames.Excitable) || this.Actor.HasTrait(TraitNames.Neurotic)) num *= MartialArts.kMultiplierToSlowMeditation; if (this.Actor.HasTrait(TraitNames.Loner)) num *= MartialArts.kMultiplierToSpeedUpMeditation; if (this.Actor.BuffManager.HasElement(BuffNames.Zen)) num *= BuffZen.MultiplierToSpeedUpMeditation; if (this.Actor.BuffManager.HasElement(BuffNames.NeuronicSynergy)) num *= BuffNeuronicSynergy.MultiplierToSpeedUpMeditation; return num; } private void DisposeSoundHandles() { this.DisposeMeditationSoundHandle(); this.DisposePostTeleportSoundHandle(); } private void DisposeMeditationSoundHandle() { if (this.mSoundHandleMeditation == null) return; this.mSoundHandleMeditation.Stop(); this.mSoundHandleMeditation.Dispose(); this.mSoundHandleMeditation = (ObjectSound)null; } private void DisposePostTeleportSoundHandle() { if (this.mSoundHandlePostTeleport == null) return; this.mSoundHandlePostTeleport.Stop(); this.mSoundHandlePostTeleport.Dispose(); this.mSoundHandlePostTeleport = (ObjectSound)null; } private sealed class Definition : SoloSimInteractionDefinition<MartialArts.Meditate> { protected override bool Test( Sim actor, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { if (base.Test(actor, target, isAutonomous, ref greyedOutTooltipCallback)) { MartialArts skill = actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); if (skill != null) return skill.mbCanMeditate; } return false; } } } internal sealed class TeleportDuringMeditation : InteractionGameObjectHit<Sim, Terrain>, IImmediateInteraction { public static readonly InteractionDefinition Singleton = (InteractionDefinition)new MartialArts.TeleportDuringMeditation.Definition(); protected override bool Run() { return (this.Actor.InteractionQueue.RunningInteraction as MartialArts.Meditate).EnableTeleportation(this.Hit.mPoint); } [DoesntRequireTuning] private sealed class Definition : ImmediateInteractionDefinition<Sim, Terrain, MartialArts.TeleportDuringMeditation> { public override InteractionTestResult Test( ref InteractionInstanceParameters parameters, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { InteractionTestResult interactionTestResult = base.Test(ref parameters, ref greyedOutTooltipCallback); if (interactionTestResult != InteractionTestResult.Pass) return interactionTestResult; Sim actor = parameters.Actor as Sim; if (!(actor.InteractionQueue.RunningInteraction is MartialArts.Meditate runningInteraction) || !runningInteraction.IsActorLevitating || Terrain.CanSimTeleport(parameters.Hit, actor) == InteractionTestResult.GenericFail) return InteractionTestResult.Def_TestFailed; Vector3 mPoint = parameters.Hit.mPoint; return World.TestObjectPlacement(runningInteraction.MeditationJig.ObjectId, TestObjectPlacementBooleans.Routable, mPoint) ? InteractionTestResult.Pass : InteractionTestResult.Def_TestFailed; } protected override bool Test( Sim actor, Terrain target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return !isAutonomous && actor.SkillManager.HasElement(SkillNames.MartialArts); } protected override string GetInteractionName( Sim actor, Terrain target, InteractionObjectPair iop) { return MartialArts.LocalizeString(actor.IsFemale, "TeleportWhileMeditating"); } } } internal sealed class TeleportMasterOfMeditation : Terrain.TeleportMeHere { private static ResourceKey meditationIcon = new ResourceKey(3733UL, 832458525U, 0U); public new static readonly InteractionDefinition Singleton = (InteractionDefinition)new MartialArts.TeleportMasterOfMeditation.TeleportMasterOfMeditationDefinition(); public override ThumbnailKey GetIconKey() { return new ThumbnailKey(MartialArts.TeleportMasterOfMeditation.meditationIcon, ThumbnailSize.Large); } protected override void PostTeleport() { base.PostTeleport(); BuffInstance element = this.Actor.BuffManager.GetElement(BuffNames.MeditativeFocus); if (element == null) return; float num = Math.Max(0.0f, element.mTimeoutCount - MartialArts.kMeditativeFocusTimeOutReductionForMasterOfMeditationTeleport); if ((double)num == 0.0) this.Actor.BuffManager.RemoveElement(BuffNames.MeditativeFocus); else element.mTimeoutCount = num; } private sealed class TeleportMasterOfMeditationDefinition : Terrain.TeleportMeHere.BaseDefinition<MartialArts.TeleportMasterOfMeditation> { protected override string GetInteractionName( Sim actor, Terrain target, InteractionObjectPair iop) { return MartialArts.LocalizeString(actor.IsFemale, "MasterOfMeditationTeleport"); } public override InteractionTestResult Test( ref InteractionInstanceParameters parameters, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { InteractionTestResult interactionTestResult = base.Test(ref parameters, ref greyedOutTooltipCallback); if (interactionTestResult != InteractionTestResult.Pass) return interactionTestResult; Sim actor = parameters.Actor as Sim; MartialArts skill = actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); if (skill != null && skill.IsMasterOfMeditation) { BuffInstance element = actor.BuffManager.GetElement(BuffNames.MeditativeFocus); if (element != null && (double)element.mTimeoutCount > (double)MartialArts.kMeditativeFocusTimeOutReductionForMasterOfMeditationTeleport) return Terrain.CanSimTeleport(parameters.Hit, actor); } return InteractionTestResult.Def_TestFailed; } } } internal sealed class Spar : SocialInteraction { public static readonly InteractionDefinition Singleton = (InteractionDefinition)new MartialArts.Spar.Definition(); private bool mbActorWinsRound = true; internal MartialArts.SparMatchType mSparMatchType = MartialArts.SparMatchType.Regular; private List<SimDescription> mSimsWatchingThisMatch = new List<SimDescription>(); private int mCurrentRound; private int mRoundsActorWon; private MartialArts mActorsMartialArtsSkill; private MartialArts mTargetsMartialArtsSkill; private MartialArts.Spar.SparEffectsHelper mActorsSparEffects; private MartialArts.Spar.SparEffectsHelper mTargetsSparEffects; private MartialArts.SparState mCurrentSparState; private float mTimeToPlayWinAnimationForCurrentRound; protected override bool Run() { if (!this.SafeToSync()) return false; Lot lotCurrent = this.Actor.LotCurrent; ObjectGuid objectId = this.Target.ObjectId; Household household = this.Target.Household; if (household != null && lotCurrent == this.Actor.LotHome && !household.IsGreetedOnLot(lotCurrent, objectId)) household.AddGreetedLotToHousehold(lotCurrent, objectId); base.SocialJig = CreateJigForTwoPersonSocial(actor, target, 1.25f); if (!this.BeginSocialInteraction((InteractionDefinition)new SocialInteractionB.Definition((string)null, Localization.LocalizeString("Gameplay/Actors/Sim/Spar:InteractionName"), false), true, false)) return false; this.mActorsMartialArtsSkill = this.Actor.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); this.mTargetsMartialArtsSkill = this.Target.SkillManager.GetSkill<MartialArts>(SkillNames.MartialArts); this.StandardEntry(); this.mActorsMartialArtsSkill.ChangeIntoKarateGi(); this.mTargetsMartialArtsSkill.ChangeIntoKarateGi(); this.Actor.LookAtManager.DisableLookAts(); this.Target.LookAtManager.DisableLookAts(); this.EnterStateMachine("spar", "Enter", "x", "y"); this.SetParameter("CanXplaySuperAnimations", this.mActorsMartialArtsSkill.mbCanPlaySuperAnimations); this.SetParameter("CanYplaySuperAnimations", this.mTargetsMartialArtsSkill.mbCanPlaySuperAnimations); this.RegisterAnimationToScriptEventCallbacks(); this.EnableWatchInteraction(); this.AnimateJoinSims("Bow"); MartialArts.StartDisciplinedFunCommodity((InteractionInstance)this); this.BeginCommodityUpdates(); this.StartSkillGain(); this.mCurrentSparState = MartialArts.SparState.StartRound; bool succeeded = this.DoLoop(ExitReason.Default, new InteractionInstance.InsideLoopFunction(this.SparLoopDelegate), this.mCurrentStateMachine); this.StopSkillGain(); this.DisposeVisualEffects(); this.AnimateSim("Exit"); this.PostMatchCeremony(); this.FinishLinkedInteraction(true); this.EndCommodityUpdates(succeeded); MartialArts.EndDisciplinedFunCommodity((InteractionInstance)this); this.DisableWatchInteraction(); this.StandardExit(); this.WaitForSyncComplete(); return succeeded; } public override void Cleanup() { base.Cleanup(); this.StopSkillGain(); this.DisableWatchInteraction(); this.DisposeVisualEffects(); this.EnableLookAts(); } private void SparLoopDelegate(StateMachineClient smc, InteractionInstance.LoopData loopData) { if (this.mCurrentSparState == MartialArts.SparState.StartRound) this.SetupRoundAttributes(loopData); if ((double)loopData.mLifeTime >= (double)this.mTimeToPlayWinAnimationForCurrentRound) this.FinishRound(); else this.ContinueBlocking(); if (this.mCurrentSparState != MartialArts.SparState.ActorWinsMatch && this.mCurrentSparState != MartialArts.SparState.TargetWinsMatch) return; this.Actor.AddExitReason(ExitReason.Finished); } private void SetupRoundAttributes(InteractionInstance.LoopData loopData) { ++this.mCurrentRound; this.AnimateSim("Assume Stance"); float num1 = MartialArts.sSlopeOfLineRepresentingTimeVsDeltaSkillLevel * (float)Math.Abs(this.mActorsMartialArtsSkill.SkillLevel - this.mTargetsMartialArtsSkill.SkillLevel) + MartialArts.kMaximumTimeForSingleSparRound; float num2 = RandomUtil.GetFloat(Math.Max(0.0f, num1 - MartialArts.kSparRoundTimeJitter), num1 + MartialArts.kSparRoundTimeJitter); this.mTimeToPlayWinAnimationForCurrentRound = loopData.mLifeTime + num2; this.mbActorWinsRound = MartialArts.GetWinnerForRound(this.Actor, this.Target, this.mActorsMartialArtsSkill, this.mTargetsMartialArtsSkill) == this.Actor; } private void FinishRound() { if (this.mbActorWinsRound) { this.mCurrentSparState = MartialArts.SparState.HitX; ++this.mRoundsActorWon; this.SwapParticipantsMakeInstanceActorX(); this.AnimateSim("Hit"); this.UpdateWiningSparState(MartialArts.SparState.ActorWinsMatch, this.mRoundsActorWon); } else { this.mCurrentSparState = MartialArts.SparState.HitY; this.SwapParticpantsMakeInstanceActorY(); this.AnimateSim("Hit"); this.UpdateWiningSparState(MartialArts.SparState.TargetWinsMatch, this.mCurrentRound - this.mRoundsActorWon); } Relationship relationship = Relationship.Get(this.Actor, this.Target, true); if (relationship == null) return; relationship.LTR.UpdateLiking(MartialArts.kLtrIncreasePerSparRound); relationship.UpdateSTCFromOutsideConversation(this.Actor, this.Target, MartialArts.kStcAtTheEndOfSparRound, MartialArts.kStcValueAtTheEndOfSparRound); } private void UpdateWiningSparState(MartialArts.SparState winState, int numberOfWins) { if (numberOfWins >= (MartialArts.kRoundsInSpar + 1) / 2) { this.mCurrentSparState = winState; this.DisposeVisualEffects(); } else this.mCurrentSparState = MartialArts.SparState.StartRound; } private void ContinueBlocking() { if (this.mCurrentSparState != MartialArts.SparState.BlockX && this.mCurrentSparState != MartialArts.SparState.BlockY) { this.mCurrentSparState = MartialArts.SparState.BlockX; this.AnimateSim("Block"); } if (!RandomUtil.CoinFlip()) return; switch (this.mCurrentSparState) { case MartialArts.SparState.BlockX: this.mCurrentSparState = MartialArts.SparState.BlockY; this.SwapParticpantsMakeInstanceActorY(); break; case MartialArts.SparState.BlockY: this.mCurrentSparState = MartialArts.SparState.BlockX; this.SwapParticipantsMakeInstanceActorX(); break; } } private void RegisterAnimationToScriptEventCallbacks() { if (this.mActorsMartialArtsSkill.mbCanStartMasteryEffects) { this.mActorsSparEffects = new MartialArts.Spar.SparEffectsHelper(this.Actor); this.AddOneShotScriptEventHandler(201U, new SacsEventHandler(this.mActorsSparEffects.StartJawesomeEffects)); } if (!this.mTargetsMartialArtsSkill.mbCanStartMasteryEffects) return; this.mTargetsSparEffects = new MartialArts.Spar.SparEffectsHelper(this.Target); this.AddOneShotScriptEventHandler(203U, new SacsEventHandler(this.mTargetsSparEffects.StartJawesomeEffects)); } private void DisposeVisualEffects() { if (this.mCurrentStateMachine != null) this.mCurrentStateMachine.RemoveAllEventHandlers(); if (this.mActorsSparEffects != null) this.mActorsSparEffects.DisposeEffects(); if (this.mTargetsSparEffects == null) return; this.mTargetsSparEffects.DisposeEffects(); } private void SwapParticipantsMakeInstanceActorX() { this.SetActor("x", (IHasScriptProxy)this.Actor); this.SetActor("y", (IHasScriptProxy)this.Target); this.SetParameter("CanXplaySuperAnimations", this.mActorsMartialArtsSkill.mbCanPlaySuperAnimations); this.SetParameter("CanYplaySuperAnimations", this.mTargetsMartialArtsSkill.mbCanPlaySuperAnimations); } private void SwapParticpantsMakeInstanceActorY() { this.SetActor("x", (IHasScriptProxy)this.Target); this.SetActor("y", (IHasScriptProxy)this.Actor); this.SetParameter("CanXplaySuperAnimations", this.mTargetsMartialArtsSkill.mbCanPlaySuperAnimations); this.SetParameter("CanYplaySuperAnimations", this.mActorsMartialArtsSkill.mbCanPlaySuperAnimations); } private void StartSkillGain() { this.StartSkillGainForSim(this.Actor.SkillManager, this.mTargetsMartialArtsSkill.SkillLevel, this.mTargetsMartialArtsSkill.IsGrandMaster); this.StartSkillGainForSim(this.Target.SkillManager, this.mActorsMartialArtsSkill.SkillLevel, this.mActorsMartialArtsSkill.IsGrandMaster); } private void StartSkillGainForSim( SkillManager skillManager, int opponentSkillLevel, bool bIsOpponentGrandMaster) { if (skillManager == null) return; float rate = MartialArts.sSlopeOfLineRepresentingOpponentSkillLevelVsSkillGainRate * (float)(opponentSkillLevel - 1) + MartialArts.kMinimumMartialArtsSkillGainRateWhileSparring; if (bIsOpponentGrandMaster) rate += MartialArts.kGrandMasterSkillGainModifier; skillManager.StartSkillGain(SkillNames.MartialArts, rate); skillManager.StartGainWithoutSkillMeter(SkillNames.Athletic, MartialArts.kAthleticSkillGainRateWhileSparring, true); } private void StopSkillGain() { if (this.Actor != null && this.Actor.SkillManager != null) { this.Actor.SkillManager.StopSkillGain(SkillNames.Athletic); this.Actor.SkillManager.StopSkillGain(SkillNames.MartialArts); } if (this.Target == null || this.Target.SkillManager == null) return; this.Target.SkillManager.StopSkillGain(SkillNames.Athletic); this.Target.SkillManager.StopSkillGain(SkillNames.MartialArts); } private void PostMatchCeremony() { int wins = 0; int losses = 0; Sim sim1 = (Sim)null; Sim sim2 = (Sim)null; MartialArts losersMartialArts = (MartialArts)null; MartialArts winnersMartialArts = (MartialArts)null; this.CheckIfSomeoneBailedOutOfTheMatch(); switch (this.mCurrentSparState) { case MartialArts.SparState.ActorWinsMatch: case MartialArts.SparState.TargetCancelledMatch: sim1 = this.Actor; sim2 = this.Target; wins = this.mRoundsActorWon; losses = this.mCurrentRound - this.mRoundsActorWon; winnersMartialArts = this.mActorsMartialArtsSkill; losersMartialArts = this.mTargetsMartialArtsSkill; break; case MartialArts.SparState.TargetWinsMatch: case MartialArts.SparState.ActorCancelledMatch: sim1 = this.Target; sim2 = this.Actor; wins = this.mCurrentRound - this.mRoundsActorWon; losses = this.mRoundsActorWon; winnersMartialArts = this.mTargetsMartialArtsSkill; losersMartialArts = this.mActorsMartialArtsSkill; break; } EventTracker.SendEvent((Sims3.Gameplay.EventSystem.Event)new MartialArts.SparEvent(sim1, sim2, true, this.mSparMatchType == MartialArts.SparMatchType.Tournament)); EventTracker.SendEvent((Sims3.Gameplay.EventSystem.Event)new MartialArts.SparEvent(sim2, sim1, false, this.mSparMatchType == MartialArts.SparMatchType.Tournament)); if (sim1 == null || sim2 == null) return; this.UpdateStatistics(losersMartialArts, winnersMartialArts); this.NotifyMatchResult(sim1, sim2, wins, losses); this.LetAudienceReact(sim1.SimDescription); } private void CheckIfSomeoneBailedOutOfTheMatch() { if (this.Actor.HasExitReason(ExitReason.UserCanceled)) { this.mCurrentSparState = MartialArts.SparState.ActorCancelledMatch; } else { if (!this.Target.HasExitReason(ExitReason.UserCanceled)) return; this.mCurrentSparState = MartialArts.SparState.TargetCancelledMatch; } } private void UpdateStatistics(MartialArts losersMartialArts, MartialArts winnersMartialArts) { ++losersMartialArts.mSparringMatchParticipationCount; ++winnersMartialArts.mSparringMatchParticipationCount; ++winnersMartialArts.mSparringMatchWins; if (this.mSparMatchType == MartialArts.SparMatchType.Tournament) { ++winnersMartialArts.mSparringTournamentMatchWins; ++losersMartialArts.mSparringTournamentMatchLosses; winnersMartialArts.OnSparTournamentMatchWin(); } losersMartialArts.TestForNewLifetimeOpp(); winnersMartialArts.TestForNewLifetimeOpp(); } private void NotifyMatchResult(Sim winner, Sim loser, int wins, int losses) { string titleText = string.Empty; string name = string.Empty; bool isActiveSim1 = loser.IsActiveSim; bool isActiveSim2 = winner.IsActiveSim; bool flag = this.mCurrentSparState == MartialArts.SparState.ActorCancelledMatch || this.mCurrentSparState == MartialArts.SparState.TargetCancelledMatch; Sim sim = (Sim)null; if (winner.IsSelectable) sim = winner; else if (loser.IsSelectable) sim = loser; switch (this.mSparMatchType) { case MartialArts.SparMatchType.Regular: if (flag) titleText = MartialArts.LocalizeString((winner.IsFemale ? 1 : 0) != 0, "RegularSparScore_MatchCancelled", (object)winner, (object)loser, (object)wins, (object)losses); else titleText = MartialArts.LocalizeString((winner.IsFemale ? 1 : 0) != 0, "RegularSparScore", (object)winner, (object)loser, (object)wins, (object)losses); if (isActiveSim2) { name = "mararts_match_win"; break; } if (isActiveSim1) { name = "mararts_match_lose"; break; } break; case MartialArts.SparMatchType.Tournament: EventTracker.SendEvent(EventTypeId.kSimWonSparTournamentMatch, (IActor)winner); if (flag) titleText = MartialArts.LocalizeString((winner.IsFemale ? 1 : 0) != 0, "TournamentSparScore_MatchCancelled", (object)winner, (object)loser, (object)wins, (object)losses); else titleText = MartialArts.LocalizeString((winner.IsFemale ? 1 : 0) != 0, "TournamentSparScore", (object)winner, (object)loser, (object)wins, (object)losses); if (isActiveSim2) { name = "mararts_tourn_win"; break; } if (isActiveSim1) { name = "mararts_tourn_lose"; break; } break; } if (sim == null) return; if (!string.IsNullOrEmpty(name)) { int num = (int)Audio.StartObjectSound(sim.ObjectId, name, false); } StyledNotification.Show(new StyledNotification.Format(titleText, StyledNotification.NotificationStyle.kGameMessagePositive)); } private void LetAudienceReact(SimDescription winner) { foreach (SimDescription simDescription in this.mSimsWatchingThisMatch) { Sim createdSim = simDescription.CreatedSim; if (createdSim != null && createdSim.InteractionQueue.RunningInteraction is MartialArts.WatchSparMatch runningInteraction) runningInteraction.SetWinner(winner); } } private void EnableWatchInteraction() { SimDescription[] sparringSims = new SimDescription[2] { this.Actor.SimDescription, this.Target.SimDescription }; this.Actor.AddInteraction((InteractionDefinition)new MartialArts.WatchSparMatch.WatchSparMatchDefinition(sparringSims)); this.Target.AddInteraction((InteractionDefinition)new MartialArts.WatchSparMatch.WatchSparMatchDefinition(sparringSims)); } private void DisableWatchInteraction() { if (this.Actor != null) this.Actor.RemoveInteractionByType(MartialArts.WatchSparMatch.Singleton); if (this.Target == null) return; this.Target.RemoveInteractionByType(MartialArts.WatchSparMatch.Singleton); } private void EnableLookAts() { if (this.Actor != null && this.Actor.LookAtManager != null) this.Actor.LookAtManager.EnableLookAts(); if (this.Target == null || this.Target.LookAtManager == null) return; this.Target.LookAtManager.EnableLookAts(); } public void SetWatchingSim(SimDescription actor) { if (actor == null || this.mSimsWatchingThisMatch == null || this.mSimsWatchingThisMatch.Contains(actor)) return; this.mSimsWatchingThisMatch.Add(actor); } private sealed class Definition : SocialInteraction.SocialInteractionDefinition<MartialArts.Spar> { protected override bool Test( Sim a, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return true; } } [Persistable] private class SparEffectsHelper { private static Slot[] kArmJoints = new Slot[4] { Sim.FXJoints.LeftUpperArm, Sim.FXJoints.LeftForearm, Sim.FXJoints.RightUpperArm, Sim.FXJoints.RightForearm }; private static Slot[] kLegJoints = new Slot[4] { Sim.FXJoints.LeftThighFront, Sim.FXJoints.LeftCalfFront, Sim.FXJoints.RightThighFront, Sim.FXJoints.RightCalfFront }; private VisualEffect[] mSparEffectsArm = new VisualEffect[4]; private VisualEffect[] mSparEffectsLeg = new VisualEffect[4]; private const string kArm = "ep1MotionArm"; private const string kLeg = "ep1MotionLeg"; private const string kTorso = "ep1MotionTorso"; private Sim mActor; private VisualEffect mSparEffectsTorso; public SparEffectsHelper() { } internal SparEffectsHelper(Sim actor) { this.mActor = actor; } internal void StartJawesomeEffects(StateMachineClient sender, IEvent evt) { float[] forMasteryEffects = MartialArts.GetRgbForMasteryEffects(this.mActor); for (int index = 0; index < MartialArts.Spar.SparEffectsHelper.kArmJoints.Length && index < this.mSparEffectsArm.Length; ++index) { VisualEffect visualEffect = VisualEffect.Create("ep1MotionArm"); visualEffect.ParentTo((IHasScriptProxy)this.mActor, MartialArts.Spar.SparEffectsHelper.kArmJoints[index]); visualEffect.SetEffectColorScale(forMasteryEffects[0], forMasteryEffects[1], forMasteryEffects[2]); visualEffect.Start(); this.mSparEffectsArm[index] = visualEffect; } for (int index = 0; index < MartialArts.Spar.SparEffectsHelper.kLegJoints.Length && index < this.mSparEffectsLeg.Length; ++index) { VisualEffect visualEffect = VisualEffect.Create("ep1MotionLeg"); visualEffect.ParentTo((IHasScriptProxy)this.mActor, MartialArts.Spar.SparEffectsHelper.kLegJoints[index]); visualEffect.SetEffectColorScale(forMasteryEffects[0], forMasteryEffects[1], forMasteryEffects[2]); visualEffect.Start(); this.mSparEffectsLeg[index] = visualEffect; } this.mSparEffectsTorso = VisualEffect.Create("ep1MotionTorso"); this.mSparEffectsTorso.ParentTo((IHasScriptProxy)this.mActor, Sim.FXJoints.Spine1); this.mSparEffectsTorso.SetEffectColorScale(forMasteryEffects[0], forMasteryEffects[1], forMasteryEffects[2]); this.mSparEffectsTorso.Start(); } internal void DisposeEffects() { if (this.mSparEffectsArm != null) { for (int index = 0; index < this.mSparEffectsArm.Length; ++index) { if (this.mSparEffectsArm[index] != null) { this.mSparEffectsArm[index].Stop(VisualEffect.TransitionType.HardTransition); this.mSparEffectsArm[index].Dispose(); this.mSparEffectsArm[index] = (VisualEffect)null; } } this.mSparEffectsArm = (VisualEffect[])null; } if (this.mSparEffectsLeg != null) { for (int index = 0; index < this.mSparEffectsLeg.Length; ++index) { if (this.mSparEffectsLeg[index] != null) { this.mSparEffectsLeg[index].Stop(VisualEffect.TransitionType.HardTransition); this.mSparEffectsLeg[index].Dispose(); this.mSparEffectsLeg[index] = (VisualEffect)null; } } this.mSparEffectsLeg = (VisualEffect[])null; } if (this.mSparEffectsTorso == null) return; this.mSparEffectsTorso.Stop(); this.mSparEffectsTorso.Dispose(); this.mSparEffectsTorso = (VisualEffect)null; } } } internal sealed class WatchSparMatch : Interaction<Sim, Sim> { public static readonly InteractionDefinition Singleton = (InteractionDefinition)new MartialArts.WatchSparMatch.WatchSparMatchDefinition(); private MartialArts.WatchReactions mWatchSparMatchReaction = MartialArts.WatchReactions.Clap; private SimDescription mWinner; private SimDescription mFavouriteSim; internal void SetWinner(SimDescription winner) { if (winner == null) return; this.mWinner = winner; } protected override bool Run() { MartialArts.WatchSparMatch.WatchSparMatchDefinition interactionDefinition = this.InteractionDefinition as MartialArts.WatchSparMatch.WatchSparMatchDefinition; SimDescription mSparringSim1 = interactionDefinition.mSparringSims[0]; SimDescription mSparringSim2 = interactionDefinition.mSparringSims[1]; if (mSparringSim1.CreatedSim == null || mSparringSim2.CreatedSim == null) return false; if (!(mSparringSim1.CreatedSim.InteractionQueue.RunningInteraction is MartialArts.Spar runningInteraction)) runningInteraction = mSparringSim2.CreatedSim.InteractionQueue.RunningInteraction as MartialArts.Spar; if (runningInteraction == null) return false; runningInteraction.SetWatchingSim(this.Actor.SimDescription); Relationship relationship1 = Relationship.Get(this.Actor.SimDescription, mSparringSim1, false); Relationship relationship2 = Relationship.Get(this.Actor.SimDescription, mSparringSim2, false); if (relationship1 != null && relationship2 == null) { if ((double)relationship1.LTR.Liking > (double)MartialArts.kLtrLikingToBeASparMatchFan) this.mFavouriteSim = mSparringSim1; } else if (relationship1 == null && relationship2 != null) { if ((double)relationship2.LTR.Liking > (double)MartialArts.kLtrLikingToBeASparMatchFan) this.mFavouriteSim = mSparringSim2; } else if (relationship1 != null && relationship2 != null) { if (((double)relationship1.LTR.Liking > (double)relationship2.LTR.Liking ? mSparringSim1 : mSparringSim2) == mSparringSim1 && (double)relationship1.LTR.Liking > (double)MartialArts.kLtrLikingToBeASparMatchFan) this.mFavouriteSim = mSparringSim1; else if ((double)relationship2.LTR.Liking > (double)MartialArts.kLtrLikingToBeASparMatchFan) this.mFavouriteSim = mSparringSim2; } if (!this.Actor.RouteToPointRadius(this.Target.Position, MartialArts.kMaximumRadiusToWatchSparringMatch) || this.mWinner != null) return false; this.StandardEntry(); this.EnterStateMachine("watch_martial_artist", "Enter", "x"); this.BeginCommodityUpdates(); this.AnimateSim("Watch"); bool succeeded = this.DoLoop(ExitReason.Default, new InteractionInstance.InsideLoopFunction(this.WatchDelegate), this.mCurrentStateMachine); this.AnimateSim("Exit"); this.EndCommodityUpdates(succeeded); this.StandardExit(); return succeeded; } private void WatchDelegate(StateMachineClient smc, InteractionInstance.LoopData loopData) { if (this.mWinner != null) { if (this.mWinner == this.mFavouriteSim) { this.mWatchSparMatchReaction = MartialArts.WatchReactions.Cheer; } else { Relationship relationship = Relationship.Get(this.Actor.SimDescription, this.mWinner, false); if (relationship != null && relationship.LTR != null && (double)relationship.LTR.Liking <= (double)MartialArts.kLtrLikingToBooASparMatchParticipant || this.mFavouriteSim != null) this.mWatchSparMatchReaction = MartialArts.WatchReactions.Boo; } switch (this.mWatchSparMatchReaction) { case MartialArts.WatchReactions.Boo: this.AnimateSim("Boo"); break; case MartialArts.WatchReactions.Cheer: this.AnimateSim("Cheer"); break; default: this.AnimateSim("Clap"); break; } this.Actor.AddExitReason(ExitReason.Finished); } if ((double)loopData.mLifeTime < (double)MartialArts.kWatchSparTimeOut) return; this.Actor.AddExitReason(ExitReason.Finished); } internal sealed class WatchSparMatchDefinition : InteractionDefinition<Sim, Sim, MartialArts.WatchSparMatch> { internal SimDescription[] mSparringSims; internal WatchSparMatchDefinition() { } internal WatchSparMatchDefinition(SimDescription[] sparringSims) { this.mSparringSims = new SimDescription[sparringSims.Length]; this.mSparringSims = sparringSims.Clone() as SimDescription[]; } protected override bool Test( Sim a, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return this.mSparringSims[0] != a.SimDescription && this.mSparringSims[1] != a.SimDescription; } } } private sealed class CheckOutMyAwesomeBelt : Interaction<Sim, Sim> { public static readonly ISoloInteractionDefinition Singleton = (ISoloInteractionDefinition)new MartialArts.CheckOutMyAwesomeBelt.Definition(); private SocialJigOnePerson mMartialArtsMoveJig; protected override bool Run() { SocialJigOnePerson jig; bool placeAndRouteToJig = MartialArts.CreatePlaceAndRouteToJig(this.Actor, "WorkOutJig", out jig, false); this.mMartialArtsMoveJig = jig; this.Actor.SwitchToOutfitWithSpin(Sim.ClothesChangeReason.GoingToSparOrTrain, OutfitCategories.MartialArts, true); if (placeAndRouteToJig) this.Actor.PlaySoloAnimation("a_martialArts_idle_x", true); else this.Actor.PlaySoloAnimation("a_react_newMartialArtsBelt_x", true); this.Actor.ShowTNSIfSelectable(MartialArts.LocalizeString((this.Actor.IsFemale ? 1 : 0) != 0, "CheckOutMyAwesomeBeltTns", (object)this.Actor), StyledNotification.NotificationStyle.kGameMessagePositive, ObjectGuid.InvalidObjectGuid, this.Actor.ObjectId); return true; } public override void Cleanup() { base.Cleanup(); if (this.mMartialArtsMoveJig == null) return; this.mMartialArtsMoveJig.Destroy(); this.mMartialArtsMoveJig = (SocialJigOnePerson)null; } private sealed class Definition : SoloSimInteractionDefinition<MartialArts.CheckOutMyAwesomeBelt> { protected override bool Test( Sim actor, Sim target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return base.Test(actor, target, isAutonomous, ref greyedOutTooltipCallback) && actor.SkillManager.HasElement(SkillNames.MartialArts) && !actor.SimDescription.IsVisuallyPregnant; } } } private class TournamentRank : ITrackedStat { private MartialArts mSkill; public TournamentRank(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatTournamentRank", (object)this.mSkill.mTournamentRank); } } } private class SparringTournamentWinsAndLosses : ITrackedStat { private MartialArts mSkill; public SparringTournamentWinsAndLosses(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatTournamentWinsAndLosses", (object)this.mSkill.mSparringTournamentMatchWins, (object)this.mSkill.mSparringTournamentMatchLosses); } } } private class SparringMatchsWon : ITrackedStat { private MartialArts mSkill; public SparringMatchsWon(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatTotalSparWins", (object)this.mSkill.mSparringMatchWins); } } } private class HoursSpentMeditating : ITrackedStat { private MartialArts mSkill; public HoursSpentMeditating(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatTotalHoursMeditated", (object)this.mSkill.mHoursSpentMeditating); } } } private class MeditativeFocusReceivedCount : ITrackedStat { private MartialArts mSkill; public MeditativeFocusReceivedCount(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatCountOfMeditativeFocus", (object)this.mSkill.mMeditativeFocusReceivedCount); } } } private class StrongestBoardBroken : ITrackedStat { private MartialArts mSkill; public StrongestBoardBroken(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatStrongestBoardBroken", (object)MartialArts.LocalizeBoardString(this.mSkill.mStrongestBoardBroken.ToString())); } } } private class StudentsTrained : ITrackedStat { private MartialArts mSkill; public StudentsTrained(MartialArts skill) { this.mSkill = skill; } public string Description { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "TrackedStatStudentsTrained", (object)this.mSkill.mSimsTrained.Count); } } } private class GrandMaster : ILifetimeOpportunity { private MartialArts mSkill; public GrandMaster(MartialArts skill) { this.mSkill = skill; } public string Title { get { return MartialArts.LocalizeString(this.mSkill.mSkillOwner.IsFemale, "GrandMasterTitle"); } } public bool Completed { get { return this.mSkill.IsGrandMaster; } } public string RewardDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "GrandMasterDescription", (object)MartialArts.kTournamentWinsToImproveSparringRank.Length); } } public string AchievedDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "GrandMasterAchievementDescription", (object)this.mSkill.mSkillOwner); } } public string Icon { get { return "***MartialArtsUnlocalizedText***"; } } public bool IsNew { get { return this.mSkill.mbGrandMasterLifetimeOpportunityIsNew; } set { this.mSkill.mbGrandMasterLifetimeOpportunityIsNew = value; } } } private class MasterOfMeditation : ILifetimeOpportunity { private MartialArts mSkill; public MasterOfMeditation(MartialArts skill) { this.mSkill = skill; } public string Title { get { return MartialArts.LocalizeString(this.mSkill.mSkillOwner.IsFemale, "MasterOfMeditationTitle"); } } public bool Completed { get { return this.mSkill.IsMasterOfMeditation; } } public string RewardDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "MasterOfMeditationDescription", (object)MartialArts.kHoursMeditatedToBeMasterOfMeditation); } } public string AchievedDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "MasterOfMeditationAchievementDescription", (object)this.mSkill.mSkillOwner); } } public string Icon { get { return "***MartialArtsUnlocalizedText***"; } } public bool IsNew { get { return this.mSkill.mbMasterOfMeditationLifetimeOpportunityIsNew; } set { this.mSkill.mbMasterOfMeditationLifetimeOpportunityIsNew = value; } } } private class SparMaster : ILifetimeOpportunity { private MartialArts mSkill; public SparMaster(MartialArts skill) { this.mSkill = skill; } public string Title { get { return MartialArts.LocalizeString(this.mSkill.mSkillOwner.IsFemale, "SparMasterTitle"); } } public bool Completed { get { return this.mSkill.IsSparMaster; } } public string RewardDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "SparMasterDescription", (object)this.mSkill.mSkillOwner, (object)MartialArts.kSparMatchParticipationToBeSparMaster, (object)this.mSkill.mSparringMatchParticipationCount); } } public string AchievedDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "SparMasterAchievementDescription", (object)this.mSkill.mSkillOwner); } } public string Icon { get { return "***MartialArtsUnlocalizedText***"; } } public bool IsNew { get { return this.mSkill.mbSparMasterLifetimeOpportunityIsNew; } set { this.mSkill.mbSparMasterLifetimeOpportunityIsNew = value; } } } private class AdvancedBoardBreaker : ILifetimeOpportunity { private MartialArts mSkill; public AdvancedBoardBreaker(MartialArts skill) { this.mSkill = skill; } public string Title { get { return MartialArts.LocalizeString(this.mSkill.mSkillOwner.IsFemale, "AdvancedBoardBreakerOpportunityTitle"); } } public bool Completed { get { return this.mSkill.IsAdvancedBoardBreaker; } } public string RewardDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "AdvancedBoardBreakerDescription", (object)MartialArts.kNumberOfBoardsBrokenForLifetimeOpportunity, (object)this.mSkill.mBoardsBrokenToBeAdvancedBoardBreaker); } } public string AchievedDescription { get { return MartialArts.LocalizeString((this.mSkill.mSkillOwner.IsFemale ? 1 : 0) != 0, "AdvancedBoardBreakerAchievementDescription", (object)this.mSkill.mSkillOwner); } } public string Icon { get { return "***MartialArtsUnlocalizedText***"; } } public bool IsNew { get { return this.mSkill.mbAdvancedBoardBreakerLifetimeOpportunityIsNew; } set { this.mSkill.mbAdvancedBoardBreakerLifetimeOpportunityIsNew = value; } } } private class MartialArtsPropertyStreamWriter : PropertyStreamWriter { public bool Export(Dictionary<ulong, bool> simsTrained) { if (simsTrained == null) return true; this.mStream.Write(0); this.mStream.Write(simsTrained.Count); foreach (KeyValuePair<ulong, bool> keyValuePair in simsTrained) { this.mStream.Write(keyValuePair.Key); this.mStream.Write(keyValuePair.Value); } return true; } public bool Export(Dictionary<int, int> boardTypeToStackSizeMap) { if (boardTypeToStackSizeMap == null) return true; this.mStream.Write(0); this.mStream.Write(boardTypeToStackSizeMap.Count); foreach (KeyValuePair<int, int> boardTypeToStackSize in boardTypeToStackSizeMap) { this.mStream.Write(boardTypeToStackSize.Key); this.mStream.Write(boardTypeToStackSize.Value); } return true; } } private class MartialArtsPropertyStreamReader : PropertyStreamReader { public bool Import(out Dictionary<ulong, bool> simsTrained) { simsTrained = (Dictionary<ulong, bool>)null; if (this.mStream == null || this.mStream.ReadInt32() > 0) return false; int num = this.mStream.ReadInt32(); simsTrained = new Dictionary<ulong, bool>(); for (int index1 = 0; index1 < num; ++index1) { ulong index2 = this.mStream.ReadUInt64(); bool flag = this.mStream.ReadBoolean(); simsTrained[index2] = flag; } return true; } public bool Import(out Dictionary<int, int> boardTypeToStackSizeMap) { boardTypeToStackSizeMap = (Dictionary<int, int>)null; if (this.mStream == null || this.mStream.ReadInt32() > 0) return false; int num1 = this.mStream.ReadInt32(); boardTypeToStackSizeMap = new Dictionary<int, int>(); for (int index1 = 0; index1 < num1; ++index1) { int index2 = this.mStream.ReadInt32(); int num2 = this.mStream.ReadInt32(); boardTypeToStackSizeMap[index2] = num2; } return true; } } public class SparEvent : Sims3.Gameplay.EventSystem.Event { private bool mHasWon; private bool mIsRanked; public bool HasWon { get { return this.mHasWon; } } public bool IsRanked { get { return this.mIsRanked; } } private SparEvent() { } public SparEvent(Sim actor, Sim target, bool hasWon, bool isRanked) : base(EventTypeId.kSparred, (IActor)actor, (IGameObject)target) { this.mHasWon = hasWon; this.mIsRanked = isRanked; } } } }
Posts: 433
Thanks: 782 in 6 Posts
Posts: 1,491
Thanks: 4229 in 39 Posts
public class CompelToDrink : Interaction<Sim,Sim> { public static InteractionDefinition Singleton = new Definition(); public ActiveTopic topic = new ActiveTopic(); public static float kDistanceToForceRouteAway = 2f; public static float kCloseEnoughToPlaceJig = 2f; SocialJig drinkJig; public float socialRadiusWith; public override void Cleanup() { if (this.drinkJig != null) { this.drinkJig.Destroy(); this.drinkJig = null; } } public override bool Run() { long currentTicks = SimClock.CurrentTicks; BeDrankFrom entry = null; entry = BeDrankFrom.Singleton.CreateInstance(base.Actor, base.Target, base.GetPriority(), false, false) as BeDrankFrom; entry.LinkedInteractionInstance = this; entry.Drinker = base.Actor; base.Target.InteractionQueue.AddNext(entry); if ((base.Actor.GetDistanceToObjectSquared(base.Target) > (kCloseEnoughToPlaceJig * kCloseEnoughToPlaceJig)) && !base.Actor.RouteToPointRadius(base.Target.Position, kCloseEnoughToPlaceJig)) { return false; } socialRadiusWith = base.Target.GetSocialRadiusWith(base.Actor); this.drinkJig = SocialJigTwoPerson.CreateJigForTwoPersonSocial(base.Actor, base.Target, socialRadiusWith); this.drinkJig.RegisterParticipants(base.Actor, base.Target); this.drinkJig.SetOpacity(0f, 0f); Vector3 position = base.Actor.Position; Vector3 forwardVector = base.Actor.ForwardVector; if (!GlobalFunctions.FindGoodLocationNearby(this.drinkJig, ref position, ref forwardVector)) { return false; } this.drinkJig.SetPosition(position); this.drinkJig.SetForward(forwardVector); this.drinkJig.AddToWorld(); entry.Jig = this.drinkJig as SocialJigTwoPerson; while (!this.drinkJig.RouteComplete && !base.Actor.HasExitReason(~(ExitReason.Replan | ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached))) { if ((SimClock.ConvertFromTicks(SimClock.CurrentTicks - currentTicks, TimeUnit.Minutes) > 15f) && (base.Actor.GetDistanceToObject(this.drinkJig) < kDistanceToForceRouteAway)) { base.Actor.RouteToObjectRadialRange(this.drinkJig, kDistanceToForceRouteAway, kDistanceToForceRouteAway); } Simulator.Sleep(0); } if (!base.Actor.DoRoute(this.drinkJig.RouteToJigA(base.Actor))) { return false; } Sim actor = base.Actor; Sim target = base.Target; actor.UnregisterGroupTalk(); target.UnregisterGroupTalk(); base.StandardEntry(); base.BeginCommodityUpdates(); base.StartSocialContext(); BuffMindControl.BuffInstanceMindControl MindControl = target.BuffManager.GetElement((BuffNames)(0xD3C61BD7B1BAF4A4)) as BuffMindControl.BuffInstanceMindControl; if (target.BuffManager.HasElement((BuffNames)(0xD3C61BD7B1BAF4A4))) { if (MindControl.mMasterSim != actor.SimDescription.SimDescriptionId) { base.AcquireStateMachine("vampirehypnoticgaze"); base.EnterStateMachine("vampirehypnoticgaze", "Enter", "x", "y"); base.SetActor("x", base.Actor); base.SetActor("y", base.Target); base.EnterSim("Join"); base.AnimateJoinSims("a2a_soc_vampire_hypnoticGaze_fail_"); base.FinishLinkedInteraction(true); base.StandardExit(); base.WaitForSyncComplete(); base.EndCommodityUpdates(true); if (actor.IsInActiveHousehold) { StyledNotification.Show(new StyledNotification.Format("It appears " + base.Target.FirstName + " has already been compelled by another Vampire ", StyledNotification.NotificationStyle.kSimTalking)); } return true; } } else { base.AcquireStateMachine("vampirehypnoticgaze"); base.EnterStateMachine("vampirehypnoticgaze", "Enter", "x", "y"); base.SetActor("x", base.Actor); base.SetActor("y", base.Target); base.EnterSim("Join"); base.AnimateJoinSims("a2a_soc_vampire_hypnoticGaze_success_"); base.AcquireStateMachine("DrinkBlood"); base.EnterStateMachine("DrinkBlood", "Enter", "x", "y"); base.SetActor("x", base.Actor); base.SetActor("y", base.Target); base.EnterSim("Join"); base.AnimateJoinSims("Drink"); base.FinishLinkedInteraction(true); base.EndCommodityUpdates(true); base.StandardExit(); base.WaitForSyncComplete(); EventTracker.SendEvent(EventTypeId.kSocialInteraction, actor, target); GetStuff.VampireDrinkSuccess2(base.Actor, base.Target, "CompelToDrink", topic, this); } return true; }
I'm posting more of the code in a minute.
Posts: 1,491
Thanks: 4229 in 39 Posts
public class BeDrankFrom : Interaction<Sim,Sim> { public Sim mDrinker; public SocialJigTwoPerson drinkJig; public static InteractionDefinition Singleton = new Definition(); public override bool Run() { while (this.drinkJig == null) { if (base.Actor.HasExitReason(~(ExitReason.Replan | ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached))) { return false; } Simulator.Sleep(1); } if (!base.Actor.DoRoute(this.drinkJig.RouteToJigB(base.Actor))) { this.mDrinker.AddExitReason(ExitReason.CanceledByScript); return false; } this.drinkJig.RouteComplete = true; base.StandardEntry(); base.BeginCommodityUpdates(); base.DoLoop(~(ExitReason.Replan | ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached)); base.EndCommodityUpdates(true); base.StandardExit(); return true; } public Sim Drinker { set { this.mDrinker = value; } } public SocialJigTwoPerson Jig { set { this.drinkJig = value; } }
Who Posted
|