예제 #1
0
        /// <summary>
        /// Supply a game object who's tree table this VMEntity can use.
        /// See: TSO.Files.formats.iff.chunks.TTAB
        /// </summary>
        /// <param name="obj">GameObject instance with a tree table to use.</param>
        public void UseTreeTableOf(GameObject obj) //manually set the tree table for an object. Used for multitile objects, which inherit this from the master.
        {
            if (TreeTable != null)
            {
                return;
            }
            var        GLOBChunks = obj.Resource.List <GLOB>();
            GameGlobal SemiGlobal = null;

            if (GLOBChunks != null && GLOBChunks[0].Name != "")
            {
                SemiGlobal = FSO.Content.Content.Get().WorldObjectGlobals.Get(GLOBChunks[0].Name);
            }

            TreeTable = obj.Resource.Get <TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null)
            {
                TreeTableStrings = obj.Resource.Get <TTAs>(obj.OBJ.TreeTableID);
            }
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable        = SemiGlobal.Resource.Get <TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Resource.Get <TTAs>(obj.OBJ.TreeTableID);
            }
        }
예제 #2
0
        public void UseSemiGlobalTTAB(string sgFile,ushort id)
        {
            GameGlobal obj = FSO.Content.Content.Get().WorldObjectGlobals.Get(sgFile);

            if (obj == null)
            {
                return;
            }

            TreeTable = obj.Resource.Get <TTAB>(id);
            if (TreeTable != null)
            {
                TreeTableStrings = obj.Resource.Get <TTAs>(id);
            }
        }
예제 #3
0
        public void SetActiveResource(IffChunk chunk, GameIffResource res)
        {
            Resource   = res;
            Strings    = res.Get <TTAs>(chunk.ChunkID);
            ActiveTTAB = (TTAB)chunk;

            if (Strings == null)
            {
                //we have a problem... make us some strings!
                Strings                = new TTAs();
                Strings.ChunkLabel     = chunk.ChunkLabel;
                Strings.ChunkID        = chunk.ChunkID;
                Strings.ChunkProcessed = true;
                res.MainIff.AddChunk(Strings);
            }

            UpdateListing();
            UpdateSelection(-1);
        }
예제 #4
0
        public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args)
        {
            //if we already have some action, do nothing.
            if (context.Caller.Thread.Queue.Any(x => x.Mode != VMQueueMode.Idle))
            {
                return(VMPrimitiveExitCode.GOTO_TRUE);
            }

            var ents      = new List <VMEntity>(context.VM.Entities);
            var processed = new HashSet <short>();
            var pos1      = context.Caller.Position;

            List <VMPieMenuInteraction> validActions  = new List <VMPieMenuInteraction>();
            List <VMPieMenuInteraction> betterActions = new List <VMPieMenuInteraction>();

            foreach (var iobj in ents)
            {
                if (iobj.Position == LotTilePos.OUT_OF_WORLD)
                {
                    continue;
                }
                var obj = iobj.MultitileGroup.GetInteractionGroupLeader(iobj);
                if (processed.Contains(obj.ObjectID) || (obj is VMGameObject && ((VMGameObject)obj).Disabled > 0))
                {
                    continue;
                }
                processed.Add(obj.ObjectID);

                var pos2     = obj.Position;
                var distance = (short)Math.Floor(Math.Sqrt(Math.Pow(pos1.x - pos2.x, 2) + Math.Pow(pos1.y - pos2.y, 2)) / 16.0);

                if (obj.TreeTable == null)
                {
                    continue;
                }
                foreach (var entry in obj.TreeTable.Interactions)
                {
                    //motive scores must be above their threshold.
                    //pick maximum motive score as our base score
                    int  baseScore = 0;
                    int  negScore  = 0;
                    bool hasAuto   = false;
                    for (int i = 0; i < entry.MotiveEntries.Length; i++)
                    {
                        var motiveScore = entry.MotiveEntries[i];
                        if (motiveScore.EffectRangeMaximum == 0 && motiveScore.EffectRangeMinimum == 0)
                        {
                            continue;
                        }
                        hasAuto = true;
                        //LINEAR INTERPOLATE MIN SCORE TO MAX, using motive data of caller
                        //MAX is when motive is the lowest.
                        //can be in reverse too!
                        var myMotive = ((VMAvatar)context.Caller).GetMotiveData((VMMotive)i);

                        var rangeScore = motiveScore.EffectRangeMinimum + motiveScore.EffectRangeMaximum - myMotive; //0 at max, EffectRangeMaximum at minimum.
                        if (motiveScore.EffectRangeMaximum > 0)
                        {
                            rangeScore = Math.Max(0, Math.Min(motiveScore.EffectRangeMaximum, rangeScore));                                     //enforce range
                        }
                        else
                        {
                            rangeScore = Math.Max(motiveScore.EffectRangeMaximum, Math.Max(0, rangeScore));  //also for negative
                        }
                        //todo: personality ads add values 0-100 for their given personality. makes things like viewing flamingo much more common.
                        baseScore = Math.Max(baseScore, rangeScore);
                        negScore  = Math.Min(negScore, rangeScore);

                        //int interpScore = (myMotive*motiveScore.EffectRangeMinimum + (100-myMotive)*(motiveScore.EffectRangeMinimum+motiveScore.EffectRangeMaximum)) / 100;
                        //if (interpScore > baseScore) baseScore = interpScore;
                    }
                    baseScore -= negScore;
                    float atten      = (entry.AttenuationCode == 0) ? entry.AttenuationValue : TTAB.AttenuationValues[entry.AttenuationCode];
                    int   attenScore = (int)Math.Max(0, baseScore * (1f - (distance * atten)));
                    if (attenScore != 0)
                    {
                        attenScore += (int)context.VM.Context.NextRandom(31) - 15;
                    }



                    if (hasAuto)
                    {
                        var  id     = entry.TTAIndex;
                        var  caller = context.Caller;
                        var  action = obj.GetAction((int)id, caller, context.VM.Context, false);
                        TTAs ttas   = obj.TreeTableStrings;

                        caller.ObjectData[(int)VMStackObjectVariable.HideInteraction] = 0;
                        if (action != null)
                        {
                            action.Flags &= ~TTABFlags.MustRun;
                        }
                        var actionStrings = caller.Thread.CheckAction(action);

                        var pie = new List <VMPieMenuInteraction>();
                        if (actionStrings != null)
                        {
                            if (actionStrings.Count > 0)
                            {
                                foreach (var actionS in actionStrings)
                                {
                                    actionS.ID     = (byte)id;
                                    actionS.Entry  = entry;
                                    actionS.Global = false;
                                    pie.Add(actionS);
                                }
                            }
                            else
                            {
                                if (ttas != null)
                                {
                                    pie.Add(new VMPieMenuInteraction()
                                    {
                                        Name   = ttas.GetString((int)id),
                                        ID     = (byte)id,
                                        Entry  = entry,
                                        Global = false
                                    });
                                }
                            }
                        }
                        foreach (var item in pie)
                        {
                            item.Score  = attenScore;
                            item.Callee = obj;
                            validActions.Add(item);
                        }
                    }
                    //TODO: Lockout interactions that have been used before for a few sim hours (in ts1 ticks. same # of ticks for tso probably)
                    //TODO: special logic for socials?
                }
            }

            var sorted    = validActions.OrderBy(x => - x.Score).ToList();
            var selection = sorted.FirstOrDefault();

            if (selection == null)
            {
                return(VMPrimitiveExitCode.GOTO_FALSE);
            }
            if (!selection.Entry.AutoFirst)
            {
                selection = sorted[(int)context.VM.Context.NextRandom((ulong)Math.Min(4, sorted.Count))];
            }

            selection.Callee.PushUserInteraction(selection.ID, context.Caller, context.VM.Context, false, new short[] { selection.Param0, 0, 0, 0 });
            return(VMPrimitiveExitCode.GOTO_TRUE);
        }
예제 #5
0
        public VMEntity(GameObject obj)
        {
            this.Object = obj;
            /**
             * For some reason, in the aquarium object (maybe others) the numAttributes is set to 0
             * but it should be 4. There are 4 entries in the label table. Go figure?
             */
            ObjectData = new short[80];

            RTTI = new VMEntityRTTI();
            var numAttributes = obj.OBJ.NumAttributes;

            if (obj.OBJ.UsesInTable == 0) EntryPoints = GenerateFunctionTable(obj.OBJ);
            else
            {
                var OBJfChunks = obj.Resource.List<OBJf>();
                if (OBJfChunks != null) EntryPoints = OBJfChunks[0].functions;
            }

            var GLOBChunks = obj.Resource.List<GLOB>();
            if (GLOBChunks != null)
            {
                SemiGlobal = Content.Get().WorldObjectGlobals.Get(GLOBChunks[0].Name);
            }

            var attributeTable = obj.Resource.Get<STR>(256);
            if (attributeTable != null)
            {
                numAttributes = (ushort)Math.Max(numAttributes, attributeTable.Length);
                RTTI.AttributeLabels = new string[numAttributes];
                for (var i = 0; i < numAttributes; i++)
                {
                    RTTI.AttributeLabels[i] = attributeTable.GetString(i);
                }
            }

            TreeTable = obj.Resource.Get<TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null) TreeTableStrings = obj.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable = SemiGlobal.Resource.Get<TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            }
            //no you cannot get global tree tables don't even ask

            this.Attributes = new short[numAttributes];
            if (obj.OBJ.GUID == 0x98E0F8BD)
            {
                this.Attributes[0] = 2;
            }
        }
예제 #6
0
        //manually set the tree table for an object. Used for multitile objects, which inherit this from the master.
        /// <summary>
        /// Supply a game object who's tree table this VMEntity can use.
        /// See: TSO.Files.formats.iff.chunks.TTAB
        /// </summary>
        /// <param name="obj">GameObject instance with a tree table to use.</param>
        public void UseTreeTableOf(GameObject obj)
        {
            if (TreeTable != null) return;
            var GLOBChunks = obj.Resource.List<GLOB>();
            GameGlobal SemiGlobal = null;

            if (GLOBChunks != null) SemiGlobal = TSO.Content.Content.Get().WorldObjectGlobals.Get(GLOBChunks[0].Name);

            TreeTable = obj.Resource.Get<TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null) TreeTableStrings = obj.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable = SemiGlobal.Resource.Get<TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            }
        }
예제 #7
0
        /// <summary>
        /// Constructs a new VMEntity instance.
        /// </summary>
        /// <param name="obj">A GameObject instance.</param>
        public VMEntity(GameObject obj)
        {
            this.Object = obj;

            /**
             * For some reason, in the aquarium object (maybe others) the numAttributes is set to 0
             * but it should be 4. There are 4 entries in the label table. Go figure?
             */
            ObjectData   = new short[80];
            MeToObject   = new Dictionary <ushort,List <short> >();
            SoundThreads = new List <VMSoundEntry>();

            RTTI = new VMEntityRTTI();
            var numAttributes = obj.OBJ.NumAttributes;

            if (obj.OBJ.UsesFnTable == 0)
            {
                EntryPoints = GenerateFunctionTable(obj.OBJ);
            }
            else
            {
                var OBJfChunk = obj.Resource.Get <OBJf>(obj.OBJ.ChunkID); //objf has same id as objd
                if (OBJfChunk != null)
                {
                    EntryPoints = OBJfChunk.functions;
                }
            }

            if (obj.GUID == 0xa9bb3a76)
            {
                EntryPoints[17] = new OBJfFunctionEntry();
            }

            var test = obj.Resource.List <OBJf>();

            SemiGlobal = obj.Resource.SemiGlobal;

            Slots = obj.Resource.Get <SLOT>(obj.OBJ.SlotID); //containment slots are dealt with in the avatar and object classes respectively.

            var attributeTable = obj.Resource.Get <STR>(256);

            if (attributeTable != null)
            {
                numAttributes        = (ushort)Math.Max(numAttributes,attributeTable.Length);
                RTTI.AttributeLabels = new string[numAttributes];
                for (var i = 0; i < numAttributes; i++)
                {
                    RTTI.AttributeLabels[i] = attributeTable.GetString(i);
                }
            }

            TreeTable = obj.Resource.Get <TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null)
            {
                TreeTableStrings = obj.Resource.Get <TTAs>(obj.OBJ.TreeTableID);
            }
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable        = SemiGlobal.Get <TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Get <TTAs>(obj.OBJ.TreeTableID);
            }
            //no you cannot get global tree tables don't even ask

            this.Attributes = new List <short>(numAttributes);
            SetFlag(VMEntityFlags.ChairFacing,true);
        }
예제 #8
0
        /// <summary>
        /// Constructs a new VMEntity instance.
        /// </summary>
        /// <param name="obj">A GameObject instance.</param>
        public VMEntity(GameObject obj)
        {
            this.Object = obj;
            /**
             * For some reason, in the aquarium object (maybe others) the numAttributes is set to 0
             * but it should be 4. There are 4 entries in the label table. Go figure?
             */
            ObjectData = new short[80];
            MeToObject = new Dictionary<ushort, Dictionary<short, short>>();
            SoundThreads = new List<VMSoundEntry>();

            RTTI = new VMEntityRTTI();
            var numAttributes = obj.OBJ.NumAttributes;

            if (obj.OBJ.UsesFnTable == 0) EntryPoints = GenerateFunctionTable(obj.OBJ);
            else
            {
                var OBJfChunk = obj.Resource.Get<OBJf>(obj.OBJ.ChunkID); //objf has same id as objd
                if (OBJfChunk != null) EntryPoints = OBJfChunk.functions;
            }

            var test = obj.Resource.List<OBJf>();

            var GLOBChunks = obj.Resource.List<GLOB>();
            if (GLOBChunks != null)
            {
                SemiGlobal = TSO.Content.Content.Get().WorldObjectGlobals.Get(GLOBChunks[0].Name);
                Object.Resource.SemiGlobal = SemiGlobal.Resource; //used for tuning constant fetching.
            }

            Slots = obj.Resource.Get<SLOT>(obj.OBJ.SlotID); //containment slots are dealt with in the avatar and object classes respectively.

            var attributeTable = obj.Resource.Get<STR>(256);
            if (attributeTable != null)
            {
                numAttributes = (ushort)Math.Max(numAttributes, attributeTable.Length);
                RTTI.AttributeLabels = new string[numAttributes];
                for (var i = 0; i < numAttributes; i++)
                {
                    RTTI.AttributeLabels[i] = attributeTable.GetString(i);
                }
            }

            TreeTable = obj.Resource.Get<TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null) TreeTableStrings = obj.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable = SemiGlobal.Resource.Get<TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Resource.Get<TTAs>(obj.OBJ.TreeTableID);
            }
            //no you cannot get global tree tables don't even ask

            this.Attributes = new short[numAttributes];
            SetFlag(VMEntityFlags.ChairFacing, true);
        }
예제 #9
0
        public void SetActiveResource(IffChunk chunk, GameIffResource res)
        {
            Resource = res;
            Strings = res.Get<TTAs>(chunk.ChunkID);
            ActiveTTAB = (TTAB)chunk;

            if (Strings == null)
            {
                //we have a problem... make us some strings!
                Strings = new TTAs();
                Strings.ChunkLabel = chunk.ChunkLabel;
                Strings.ChunkID = chunk.ChunkID;
                Strings.ChunkProcessed = true;
                res.MainIff.AddChunk(Strings);
            }

            UpdateListing();
            UpdateSelection(-1);
        }
예제 #10
0
        public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args)
        {
            //if we already have some action, do nothing
            var better = context.Caller.Thread.Queue.FirstOrDefault(x => x.Priority > (context.Caller as VMAvatar).GetPersonData(VMPersonDataVariable.Priority));

            if (better != null)
            {
                context.StackObject = better.Callee;
                return(VMPrimitiveExitCode.GOTO_TRUE);
            }

            var ents      = new List <VMEntity>(context.VM.Context.ObjectQueries.WithAutonomy);
            var processed = new HashSet <short>();
            var caller    = (VMAvatar)context.Caller;
            var pos1      = caller.Position;

            var visitor          = (caller.GetPersonData(VMPersonDataVariable.PersonType) == 1);
            var child            = (caller.IsChild && context.VM.TS1);
            var attenTable       = visitor ? TTAB.VisitorAttenuationValues : TTAB.AttenuationValues;
            var global           = Content.Content.Get().WorldObjectGlobals;
            var interactionCurve = child ? global.InteractionScoreChild : global.InteractionScore;
            var happyCurve       = child ? global.HappyWeightChild : global.HappyWeight;

            var isStray = caller.IsPet && context.VM.TS1 && caller.GetPersonData(VMPersonDataVariable.GreetStatus) == 0 && caller.GetPersonData(VMPersonDataVariable.PersonType) == 1;

            // === HAPPY CALCULATION ===

            var newStyle = false;
            // TODO: new style
            var weights = newStyle ? new float[9] : new float[9] {
                1, 1, 1, 1, 1, 1, 1, 1, 1
            };                                                                                  //TODO: weights from curves for new
            var totalWeight = weights.Sum();

            for (int i = 0; i < 9; i++)
            {
                weights[i] /= totalWeight;
            }
            var minScore = (caller.GetPersonData(VMPersonDataVariable.Posture) > 0) ? 1e-6 : 1e-7;

            var motives    = WeightMotives.Select(x => caller.GetMotiveData(x));
            var happyParts = motives
                             .Zip(interactionCurve, (motive, curve) => curve.GetPoint(motive))
                             .Zip(weights, (motive, weight) => motive * weight)
                             .ToArray();

            float baseHappy = happyParts.Sum();

            List <VMPieMenuInteraction> validActions = new List <VMPieMenuInteraction>();

            foreach (var iobj in ents)
            {
                if (iobj.Position == LotTilePos.OUT_OF_WORLD)
                {
                    continue;
                }
                var obj = iobj.MultitileGroup.GetInteractionGroupLeader(iobj);
                if (processed.Contains(obj.ObjectID) || (obj is VMGameObject && ((VMGameObject)obj).Disabled > 0))
                {
                    continue;
                }
                processed.Add(obj.ObjectID);

                if (isStray)
                {
                    if (obj is VMGameObject)
                    {
                        continue;
                    }
                    //determine if the object is indoors
                    var roomID = context.VM.Context.GetObjectRoom(obj);
                    roomID = (ushort)Math.Max(0, Math.Min(context.VM.Context.RoomInfo.Length - 1, roomID));
                    var room    = context.VM.Context.RoomInfo[roomID];
                    var outside = room.Room.IsOutside;
                    if (!outside)
                    {
                        continue;
                    }
                }
                var pos2     = obj.Position;
                var distance = (float)Math.Sqrt(Math.Pow(pos1.x - pos2.x, 2) + Math.Pow(pos1.y - pos2.y, 2) + Math.Pow((pos1.Level - pos2.Level) * 320, 2.0)) / 16.0f;
                var inUse    = obj.GetFlag(VMEntityFlags.Occupied);

                if (obj.TreeTable == null)
                {
                    continue;
                }
                foreach (var entry in obj.TreeTable.AutoInteractions)
                {
                    var id = entry.TTAIndex;
                    if (inUse && !obj.TreeTable.Interactions.Any(x => x.JoiningIndex == id))
                    {
                        continue;
                    }
                    var advertisements = entry.ActiveMotiveEntries; //TODO: cache this
                    if (advertisements.Length == 0)
                    {
                        continue;                             //no ads on this object.
                    }
                    var  action = obj.GetAction((int)id, caller, context.VM.Context, false);
                    TTAs ttas   = obj.TreeTableStrings;

                    caller.ObjectData[(int)VMStackObjectVariable.HideInteraction] = 0;
                    var actionStrings = caller.Thread.CheckAction(action, true);

                    var pie = new List <VMPieMenuInteraction>();
                    if (actionStrings != null)
                    {
                        if (actionStrings.Count > 0)
                        {
                            foreach (var actionS in actionStrings)
                            {
                                if (actionS.Name == null)
                                {
                                    actionS.Name = ttas?.GetString((int)id) ?? "***MISSING***";
                                }
                                actionS.ID     = (byte)id;
                                actionS.Entry  = entry;
                                actionS.Global = false;
                                pie.Add(actionS);
                            }
                        }
                        else
                        {
                            if (ttas != null)
                            {
                                pie.Add(new VMPieMenuInteraction()
                                {
                                    Name   = ttas.GetString((int)id),
                                    ID     = (byte)id,
                                    Entry  = entry,
                                    Global = false,
                                });
                            }
                        }
                    }
                    var first = pie.FirstOrDefault();
                    if (first != null)
                    {
                        // calculate score for this tree.
                        // start with the base happy value, and modify it for each motive changed.
                        float score = baseHappy;
                        for (int i = 0; i < advertisements.Length; i++)
                        {
                            var   motiveI     = advertisements[i].MotiveIndex;
                            var   motiveScore = entry.MotiveEntries[motiveI];
                            short min         = motiveScore.EffectRangeMinimum;
                            short max         = motiveScore.EffectRangeDelta;
                            short personality = (short)motiveScore.PersonalityModifier;
                            if (first.MotiveAdChanges != null)
                            {
                                first.MotiveAdChanges.TryGetValue((0 << 16) | motiveI, out min);
                                first.MotiveAdChanges.TryGetValue((1 << 16) | motiveI, out max);
                                first.MotiveAdChanges.TryGetValue((2 << 16) | motiveI, out personality);
                            }

                            if (max == 0 && min > 0)
                            {
                                //invalid delta. do from 0..delta instead (fix child-talk preference?)
                                max = min;
                                min = 0;
                            }
                            max += min; //it's a delta, add min to it

                            var myMotive = caller.GetMotiveData((VMMotive)motiveI);
                            if (min != 0 && myMotive > min)
                            {
                                continue;
                            }

                            // subtract the base contribution for this motive from happy
                            var weightInd = MotiveToWeight[motiveI];
                            if (weightInd == -1)
                            {
                                continue;
                            }
                            score -= happyParts[weightInd];

                            float personalityMul = 1;
                            if (personality > 0 && personality < VaryByTypes.Length)
                            {
                                personalityMul  = caller.GetPersonData(VaryByTypes[personality]);
                                personalityMul /= 1000f;
                                if (personality < 13)
                                {
                                    if ((personality & 1) == 0)
                                    {
                                        personalityMul = 1 - personalityMul;
                                    }
                                }
                                else
                                {
                                    personalityMul *= 2;
                                }
                            }

                            // then add the new contribution for this motive.
                            score += interactionCurve[weightInd].GetPoint(myMotive + (max * personalityMul) / 1000f) * weights[weightInd];
                        }

                        // score relative to base
                        score -= baseHappy;
                        // modify score using attenuation
                        float atten = (entry.AttenuationCode == 0 || entry.AttenuationCode >= attenTable.Length) ?
                                      entry.AttenuationValue : attenTable[entry.AttenuationCode];

                        score = score / (1 + atten * distance);

                        if (score > minScore)
                        {
                            foreach (var item in pie)
                            {
                                item.Score  = score;
                                item.Callee = obj;
                                validActions.Add(first);
                            }
                        }
                    }
                    //if (attenScore != 0) attenScore += (int)context.VM.Context.NextRandom(31) - 15;

                    //TODO: Lockout interactions that have been used before for a few sim hours (in ts1 ticks. same # of ticks for tso probably)
                    //TODO: special logic for socials?
                }
            }
            List <VMPieMenuInteraction> sorted = validActions.OrderByDescending(x => x.Score).ToList();

            sorted = TakeTopActions(sorted, 4);
            var selection = sorted.FirstOrDefault();

            if (selection == null)
            {
                return(VMPrimitiveExitCode.GOTO_FALSE);
            }
            if (!selection.Entry.AutoFirst)
            {
                // weighted random selection
                //var slice = sorted.Take(Math.Min(4, sorted.Count)).ToList();
                var totalScore = sorted.Sum(x => x.Score);
                var random     = context.VM.Context.NextRandom(10000);

                float randomTotal = 0;
                for (int i = 0; i < sorted.Count; i++)
                {
                    var action = sorted[i];
                    randomTotal += (sorted[i].Score / totalScore) * 10000;
                    if (random <= randomTotal)
                    {
                        selection = action;
                        break;
                    }
                }
            }

            var qaction = selection.Callee.GetAction(selection.ID, context.Caller, context.VM.Context, false, new short[] { selection.Param0, 0, 0, 0 });

            if (qaction != null)
            {
                qaction.Priority = (short)VMQueuePriority.Autonomous;
                context.Caller.Thread.EnqueueAction(qaction);
                context.StackObject = selection.Callee;
                return(VMPrimitiveExitCode.GOTO_TRUE);
            }
            else
            {
                return(VMPrimitiveExitCode.GOTO_FALSE);
            }
        }
예제 #11
0
파일: VMEntity.cs 프로젝트: Daribon/FreeSO
        public void UseSemiGlobalTTAB(string sgFile, ushort id)
        {
            GameGlobal obj = FSO.Content.Content.Get().WorldObjectGlobals.Get(sgFile);
            if (obj == null) return;

            TreeTable = obj.Resource.Get<TTAB>(id);
            if (TreeTable != null) TreeTableStrings = obj.Resource.Get<TTAs>(id);
        }
예제 #12
0
        public VMEntity(GameObject obj)
        {
            this.Object = obj;

            /**
             * For some reason, in the aquarium object (maybe others) the numAttributes is set to 0
             * but it should be 4. There are 4 entries in the label table. Go figure?
             */
            ObjectData = new short[80];

            RTTI = new VMEntityRTTI();
            var numAttributes = obj.OBJ.NumAttributes;

            if (obj.OBJ.UsesInTable == 0)
            {
                EntryPoints = GenerateFunctionTable(obj.OBJ);
            }
            else
            {
                var OBJfChunks = obj.Resource.List <OBJf>();
                if (OBJfChunks != null)
                {
                    EntryPoints = OBJfChunks[0].functions;
                }
            }

            var GLOBChunks = obj.Resource.List <GLOB>();

            if (GLOBChunks != null)
            {
                SemiGlobal = Content.Get().WorldObjectGlobals.Get(GLOBChunks[0].Name);
            }

            var attributeTable = obj.Resource.Get <STR>(256);

            if (attributeTable != null)
            {
                numAttributes        = (ushort)Math.Max(numAttributes, attributeTable.Length);
                RTTI.AttributeLabels = new string[numAttributes];
                for (var i = 0; i < numAttributes; i++)
                {
                    RTTI.AttributeLabels[i] = attributeTable.GetString(i);
                }
            }

            TreeTable = obj.Resource.Get <TTAB>(obj.OBJ.TreeTableID);
            if (TreeTable != null)
            {
                TreeTableStrings = obj.Resource.Get <TTAs>(obj.OBJ.TreeTableID);
            }
            if (TreeTable == null && SemiGlobal != null)
            {
                TreeTable        = SemiGlobal.Resource.Get <TTAB>(obj.OBJ.TreeTableID); //tree not in local, try semiglobal
                TreeTableStrings = SemiGlobal.Resource.Get <TTAs>(obj.OBJ.TreeTableID);
            }
            //no you cannot get global tree tables don't even ask

            this.Attributes = new short[numAttributes];
            if (obj.OBJ.GUID == 0x98E0F8BD)
            {
                this.Attributes[0] = 2;
            }
        }