Example #1
0
        public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args)
        {
            var operand = (VMGenericTS1CallOperand)args;

            var inventoryInd = 10;

            switch (operand.Call)
            {
            // 0. HOUSE TUTORIAL COMPLETE
            case VMGenericTS1CallMode.SwapMyAndStackObjectsSlots:     //1
                var cont1  = context.Caller.Container;
                var cont2  = context.StackObject.Container;
                var contS1 = context.Caller.ContainerSlot;
                var contS2 = context.StackObject.ContainerSlot;
                if (cont1 != null && cont2 != null)
                {
                    context.Caller.PrePositionChange(context.VM.Context);
                    context.StackObject.PrePositionChange(context.VM.Context);
                    cont1.ClearSlot(contS1);
                    cont2.ClearSlot(contS2);
                    cont1.PlaceInSlot(context.StackObject, contS1, true, context.VM.Context);
                    cont2.PlaceInSlot(context.Caller, contS2, true, context.VM.Context);
                }
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.SetActionIconToStackObject:     //2
                context.Thread.ActiveAction.IconOwner = context.StackObject;
                return(VMPrimitiveExitCode.GOTO_TRUE);

            // 3. PullDownTaxiDialog
            case VMGenericTS1CallMode.AddToFamily:     //4
                if (context.VM.TS1State.CurrentFamily == null || context.VM.TS1State.CurrentFamily.FamilyGUIDs.Length >= 8)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                var fneigh = Content.Content.Get().Neighborhood.GetNeighborByID(context.StackObjectID);
                if (fneigh == null)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                AddToFamily(context.VM.TS1State.CurrentFamily, fneigh, context.VM);
                var runtime = context.VM.TS1State.CurrentFamily.RuntimeSubset.ToList();
                runtime.Add(fneigh.GUID);
                context.VM.TS1State.CurrentFamily.RuntimeSubset = runtime.ToArray();
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.CombineAssetsOfFamilyInTemp0:     //5
                //adds the family in temp 0's assets to our budget. (for move in)
                var family = Content.Content.Get().Neighborhood.GetFamily((ushort)context.Thread.TempRegisters[0]);
                context.VM.TS1State.CurrentFamily.Budget += family.ValueInArch + family.Budget;
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.RemoveFromFamily:     //6
                if (context.VM.TS1State.CurrentFamily == null)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                fneigh = Content.Content.Get().Neighborhood.GetNeighborByID(context.StackObjectID);
                if (fneigh == null)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                fneigh.PersonData[(int)VMPersonDataVariable.TS1FamilyNumber] = 0;
                var runtimef = GetRuntimeNeigh(context.VM, (ushort)context.StackObjectID);
                runtimef?.SetPersonData(VMPersonDataVariable.TS1FamilyNumber, 0);

                var guids = context.VM.TS1State.CurrentFamily.FamilyGUIDs.ToList();
                guids.Remove(fneigh.GUID);
                context.VM.TS1State.CurrentFamily.FamilyGUIDs = guids.ToArray();
                TryDeleteFamily(context.VM.TS1State.CurrentFamily);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            /*
             * MakeNewNeighbor = 7, //this one is "depracated". there's a dedicated primitive for this.
             * FamilyTutorialComplete = 8,
             * ArchitectureTutorialComplete = 9, */

            case VMGenericTS1CallMode.DisableBuildBuy:     //10
                context.VM.Context.Architecture.BuildBuyEnabled = false;
                context.VM.SignalGenericVMEvt(VMEventType.TS1BuildBuyChange, 0);
                break;

            case VMGenericTS1CallMode.EnableBuildBuy:     //11
                context.VM.Context.Architecture.BuildBuyEnabled = true;
                context.VM.SignalGenericVMEvt(VMEventType.TS1BuildBuyChange, 1);
                break;

            /*
             * GetDistanceToCameraInTemp0 = 12,
             * AbortInteractions = 13, //abort all interactions associated with the stack object
             **/
            case VMGenericTS1CallMode.HouseRadioStationEqualsTemp0:     //14
                context.VM.SetGlobalValue(31, context.Thread.TempRegisters[0]);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.MyRoutingFootprintEqualsTemp0:     //15
                //todo: change the avatar's routing footprint (need to find out how exactly this is changed in the normal game)
                break;

            // 16. Change Normal Outfit
            case VMGenericTS1CallMode.ChangeToLotInTemp0:     //17
                //-1 is this family's home lot
                var switchLotId = (uint)context.Thread.TempRegisters[0];
                var vacation    = switchLotId >= 40 && switchLotId < 50;
                var crossData   = Content.Content.Get().Neighborhood.GameState;
                crossData.ActiveFamily    = context.VM.TS1State.CurrentFamily;
                crossData.DowntownSimGUID = context.Caller.Object.OBJ.GUID;
                crossData.LotTransitInfo  = (vacation) ? (short)1 : context.VM.GetGlobalValue(34);
                var people = new List <VMAvatar>();

                people.Add((VMAvatar)context.Caller);
                if (crossData.LotTransitInfo >= 1)
                {
                    foreach (VMAvatar person in context.VM.Context.ObjectQueries.Avatars)
                    {
                        if (person.GetPersonData(VMPersonDataVariable.TS1FamilyNumber) == crossData.ActiveFamily.ChunkID && person != context.Caller)
                        {
                            people.Add(person);
                        }
                    }
                }

                int pi = 0;
                foreach (var person in people)
                {
                    var nid   = person.GetPersonData(VMPersonDataVariable.NeighborId);
                    var dtInv = InitInventory(nid);

                    SaveIData(dtInv, 0, person.GetMotiveData(VMMotive.Bladder));
                    SaveIData(dtInv, 1, person.GetMotiveData(VMMotive.Comfort));
                    SaveIData(dtInv, 2, person.GetMotiveData(VMMotive.Energy));
                    SaveIData(dtInv, 3, person.GetMotiveData(VMMotive.Fun));
                    SaveIData(dtInv, 4, person.GetMotiveData(VMMotive.Hunger));
                    SaveIData(dtInv, 5, person.GetMotiveData(VMMotive.Hygiene));
                    SaveIData(dtInv, 6, person.GetMotiveData(VMMotive.Social));

                    if (crossData.LotTransitInfo > 1)
                    {
                        SaveIData(dtInv, 9, (short)context.VM.TS1State.CurrentFamily.FamilyGUIDs.Length);
                    }

                    if (pi++ == 0)
                    {
                        SaveIData(dtInv, 7, (short)context.VM.Context.Clock.Hours);
                        SaveIData(dtInv, 8, (short)context.VM.Context.Clock.Minutes);
                    }
                }

                //the original game sends avatar motive data along in their inventory under type 2
                //this is called "inventory sim data effects"


                context.VM.SignalLotSwitch(switchLotId);
                return(VMPrimitiveExitCode.GOTO_TRUE_NEXT_TICK);

            case VMGenericTS1CallMode.BuildTheDowntownSimAndPlaceObjIDInTemp0:     //18
                //spawn downtown sim out of world

                var crossDataDT = Content.Content.Get().Neighborhood.GameState;

                var control = context.VM.Context.CreateObjectInstance(crossDataDT.DowntownSimGUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH)?.BaseObject;
                ((VMAvatar)control).AvatarState.Permissions = Model.TSOPlatform.VMTSOAvatarPermissions.Owner;
                context.VM.SetGlobalValue(3, control.ObjectID);
                context.VM.SendCommand(new VMNetChangeControlCmd()
                {
                    TargetID = control.ObjectID
                });
                crossDataDT.ActiveFamily.SelectOneMember(crossDataDT.DowntownSimGUID);
                context.VM.TS1State.ActivateFamily(context.VM, crossDataDT.ActiveFamily);

                context.Thread.TempRegisters[0] = context.VM.GetGlobalValue(3);
                if (VM.UseWorld)
                {
                    context.VM.Context.World.CenterTo((AvatarComponent)(context.VM.GetObjectById(context.VM.GetGlobalValue(3))?.WorldUI));
                }
                break;

            case VMGenericTS1CallMode.SpawnDowntownDateOfPersonInTemp0:     //18
                //spawn our autofollow sim
                var neighbourhood = Content.Content.Get().Neighborhood;
                var ntarget       = (VMAvatar)context.VM.GetObjectById(context.Thread.TempRegisters[0]);
                context.Thread.TempRegisters[0] = -1;
                if (ntarget == null)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);                     //vacation?
                }
                var neighbour = ntarget.GetPersonData(Model.VMPersonDataVariable.NeighborId);
                var inventory = neighbourhood.GetInventoryByNID(neighbour);
                if (inventory != null)
                {
                    var toSpawn = inventory.FirstOrDefault(x => x.Type == 2 && x.GUID == inventoryInd)?.Count;
                    if (toSpawn != null)
                    {
                        var spawntarg  = neighbourhood.GetNeighborByID((short)toSpawn);
                        var autofollow = context.VM.Context.CreateObjectInstance(spawntarg.GUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH)?.BaseObject;
                        context.Thread.TempRegisters[0] = autofollow.ObjectID;
                        inventory.RemoveAll(x => x.Type == 2 && x.GUID == inventoryInd);
                    }
                }
                break;

            case VMGenericTS1CallMode.SpawnTakeBackHomeDataOfPersonInTemp0:
                inventoryInd = 11;
                goto case VMGenericTS1CallMode.SpawnDowntownDateOfPersonInTemp0;

            case VMGenericTS1CallMode.SpawnInventorySimDataEffects:
                //for the caller? stack object?
                //do caller for now
                var eperson = (VMAvatar)context.VM.GetObjectById(context.Thread.TempRegisters[0]);
                var eInv    = InitInventory(eperson.GetPersonData(VMPersonDataVariable.NeighborId));

                if (eInv.Count(x => x.Type == 2) == 0)
                {
                    return(VMPrimitiveExitCode.GOTO_TRUE);
                }

                eperson.SetMotiveData(VMMotive.Bladder, GetIData(eInv, 0));
                eperson.SetMotiveData(VMMotive.Comfort, GetIData(eInv, 1));
                eperson.SetMotiveData(VMMotive.Energy, GetIData(eInv, 2));
                eperson.SetMotiveData(VMMotive.Fun, GetIData(eInv, 3));
                eperson.SetMotiveData(VMMotive.Hunger, GetIData(eInv, 4));
                eperson.SetMotiveData(VMMotive.Hygiene, GetIData(eInv, 5));
                eperson.SetMotiveData(VMMotive.Social, GetIData(eInv, 6));

                //remove the effects since we've used em
                //7 and 8, time, were used to start the lot. they arent really used on return
                //9 is not used by fso

                eInv.RemoveAll(x => x.Type == 2 && x.GUID < 7 && x.GUID >= 0);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.SelectDowntownLot:     //22
                //TODO: this is a pre-unleashed system I believe. likely need to add this if we want to support older TS1 versions (need testers)
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.GetDowntownTimeFromSOInventory:     //23
                //eperson = (VMAvatar)context.StackObject;
                //eInv = InitInventory(eperson.GetPersonData(VMPersonDataVariable.NeighborId));
                //context.Thread.TempRegisters[0] = GetIData(eInv, 7);
                //context.Thread.TempRegisters[1] = GetIData(eInv, 8);
                return(VMPrimitiveExitCode.GOTO_TRUE);    //UNUSED?

            case VMGenericTS1CallMode.HotDateChangeSuitsPermanentlyCall:
                //temp 0: outfit type
                //temp 1: outfit index
                context.Thread.TempRegisters[1] = VMTS1PurchasableOutfitHelper.SetSuit(
                    (VMAvatar)context.Caller,
                    context.Thread.TempRegisters[0],
                    context.Thread.TempRegisters[1]);

                return(VMPrimitiveExitCode.GOTO_TRUE);

            // 25. SaveSimPersistentData (motives, relationships?)
            case VMGenericTS1CallMode.SaveSimPersistentData:
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.BuildVacationFamilyPutFamilyNumInTemp0:     //26
                //in our implementation, vacation lots build the family in the same way as normal lots.
                var crossData2 = Content.Content.Get().Neighborhood.GameState;
                if (crossData2.LotTransitInfo >= 1)
                {
                    crossData2.ActiveFamily.SelectWholeFamily();
                    context.VM.TS1State.ActivateFamily(context.VM, crossData2.ActiveFamily);
                    context.Thread.TempRegisters[0] = context.VM.GetGlobalValue(9);

                    //set to 1 if we spawned a whole family.
                    //seems to be from globals 34 on the lot we exited. Magic town uses 0 for a single sim, and 1 for whole family
                    //(blimp, though 1 is still set for whole family when theres only one person in it!)

                    context.VM.TS1State.VerifyFamily(context.VM);
                    context.VM.SendCommand(new VMNetChangeControlCmd()
                    {
                        TargetID = context.VM.Context.ObjectQueries.GetObjectsByGUID(crossData2.DowntownSimGUID).FirstOrDefault()?.ObjectID ?? 0
                    });
                }
                else
                {
                    var control2 = context.VM.Context.CreateObjectInstance(crossData2.DowntownSimGUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH)?.BaseObject;
                    ((VMAvatar)control2).AvatarState.Permissions = Model.TSOPlatform.VMTSOAvatarPermissions.Owner;
                    context.VM.SetGlobalValue(3, control2.ObjectID);
                    context.VM.SendCommand(new VMNetChangeControlCmd()
                    {
                        TargetID = control2.ObjectID
                    });
                    crossData2.ActiveFamily.SelectOneMember(crossData2.DowntownSimGUID);
                    context.VM.TS1State.ActivateFamily(context.VM, crossData2.ActiveFamily);

                    context.Thread.TempRegisters[0] = context.VM.GetGlobalValue(3);
                }

                context.Thread.TempRegisters[1] = (short)((crossData2.LotTransitInfo >= 1) ? 1 : 0);
                break;

            case VMGenericTS1CallMode.ReturnNumberOfAvaiableVacationLotsInTemp0:     //27
                //TODO: vacation lots are disabled when other people have saved the game there! that's what this primitive checks.
                context.Thread.TempRegisters[0] = 9;
                break;

            case VMGenericTS1CallMode.ReturnZoningTypeOfLotInTemp0:     //28
                var   zones  = Content.Content.Get().Neighborhood.ZoningDictionary;
                short result = 1;
                if (zones.TryGetValue(context.Thread.TempRegisters[0], out result))
                {
                    context.Thread.TempRegisters[0] = result;
                }
                else
                {
                    context.Thread.TempRegisters[0] = (short)((context.Thread.TempRegisters[0] >= 81 && context.Thread.TempRegisters[0] <= 89) ? 2 : 1);
                }
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.SetStackObjectsSuit:
                context.Thread.TempRegisters[1] = VMTS1PurchasableOutfitHelper.SetSuit(
                    (VMAvatar)context.StackObject,
                    context.Thread.TempRegisters[0],
                    context.Thread.TempRegisters[1]);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.GetStackObjectsSuit:
                context.Thread.TempRegisters[1] = VMTS1PurchasableOutfitHelper.GetSuitIndex((VMAvatar)context.StackObject, context.Thread.TempRegisters[0]);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.CountStackObjectSuits:
                var validSuits = VMTS1PurchasableOutfitHelper.GetValidOutfits((VMAvatar)context.StackObject, context.Thread.TempRegisters[0]);
                context.Thread.TempRegisters[0] = (short)validSuits.Length;
                return(VMPrimitiveExitCode.GOTO_TRUE);

            // 32. CreatePurchasedPetsNearOwner
            case VMGenericTS1CallMode.CreatePurchasedPetsNearOwner:
                context.VM.TS1State.CurrentFamily.SelectWholeFamily();
                context.VM.TS1State.VerifyFamily(context.VM);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            case VMGenericTS1CallMode.AddToFamilyInTemp0:
                family = Content.Content.Get().Neighborhood.GetFamily((ushort)context.Thread.TempRegisters[0]);
                if (family == null || family.FamilyGUIDs.Length >= 8)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                fneigh = Content.Content.Get().Neighborhood.GetNeighborByID(context.StackObjectID);
                if (fneigh == null)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }
                AddToFamily(context.VM.TS1State.CurrentFamily, fneigh, context.VM);
                return(VMPrimitiveExitCode.GOTO_TRUE);

            // 34. PromoteFameIfNeeded
            case VMGenericTS1CallMode.TakeTaxiHook:     //35
                //not sure where this one is called, seems to have been added for studiotown
                break;

            // 36. DemoteFameIfNeeded
            // 37. CancelPieMenu
            // 38. GetTokensFromString (MM)
            // 39. ChildToAdult (let's make this at least keep their skin colour, maybe)
            // 40. PetToAdult
            // 41. HeadFlush
            // 42. MakeTemp0SelectedSim,
            case VMGenericTS1CallMode.MakeTemp0SelectedSim:
                //right now assume there's only one ts1 client, and that's us.
                var vm     = context.VM;
                var target = vm.GetObjectById(context.Thread.TempRegisters[0]);
                if (target == null || target is VMGameObject)
                {
                    return(VMPrimitiveExitCode.GOTO_FALSE);
                }

                var caller = vm.GetAvatarByPersist(vm.MyUID);
                if (caller != null)
                {
                    //relinquish previous control
                    vm.Context.ObjectQueries.RemoveAvatarPersist(caller.PersistID);
                    caller.PersistID = 0;
                }

                target.PersistID = vm.MyUID;
                vm.Context.ObjectQueries.RegisterAvatarPersist((VMAvatar)target, target.PersistID);
                vm.SetGlobalValue(3, target.ObjectID);

                return(VMPrimitiveExitCode.GOTO_TRUE);
                // 43. FamilySpellsIntoController
            }
            return(VMPrimitiveExitCode.GOTO_TRUE);
        }
Example #2
0
        public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args)
        {
            //make the character iff, save it, and return their new neighbour id.

            var operand = (VMTS1MakeNewCharacterOperand)args;
            var guid    = SimitoneNeighbourGenerator.GenerateGUID(new uint[0]);

            //get
            var color  = context.Locals[operand.ColorLocal];
            var age    = context.Locals[operand.AgeLocal];
            var gender = context.Locals[operand.GenderLocal];


            SimTemplateCreateInfo info;

            if (operand.AvatarType == 0)
            {
                var simtype = ((gender > 0) ? "f" : "m") + ((age < 18) ? "c" : "m");
                var skin    = ColorNames[color];
                var code    = simtype;

                var heads = Content.Content.Get().BCFGlobal.CollectionsByName["c"].ClothesByAvatarType[simtype];
                if (simtype[1] == 'c')
                {
                    simtype += "chd";
                }
                var bodies = Content.Content.Get().BCFGlobal.CollectionsByName["b"].ClothesByAvatarType[simtype];

                //pick a random head and body.

                var tex      = (TS1AvatarTextureProvider)Content.Content.Get().AvatarTextures;
                var texnames = tex.GetAllNames();

                var headTex      = heads.Select(x => RemoveExt(texnames.FirstOrDefault(y => y.StartsWith(ExtractID(x, skin))))).ToList();
                var bodyTex      = bodies.Select(x => RemoveExt(texnames.FirstOrDefault(y => y.StartsWith(ExtractID(x, skin))))).ToList();
                var handgroupTex = bodies.Select(x => (RemoveExt(texnames.FirstOrDefault(y => y == "huao" + FindHG(x))) ?? "huao" + skin).Substring(4)).ToList();

                for (int i = 0; i < heads.Count; i++)
                {
                    if (headTex[i] == null)
                    {
                        headTex.RemoveAt(i);
                        heads.RemoveAt(i--);
                    }
                }

                for (int i = 0; i < bodies.Count; i++)
                {
                    if (bodyTex[i] == null)
                    {
                        bodyTex.RemoveAt(i);
                        handgroupTex.RemoveAt(i);
                        bodies.RemoveAt(i--);
                    }
                }

                var headInd = (int)context.VM.Context.NextRandom((ulong)heads.Count);
                var bodyInd = (int)context.VM.Context.NextRandom((ulong)bodies.Count);

                var body = bodies[bodyInd];

                var ind      = body.IndexOf("_");
                var bodyType = body.Substring(ind - 3, 3);
                code += bodyType;
                info  = new SimTemplateCreateInfo(code, skin);

                info.BodyStringReplace[1] = body + ",BODY=" + bodyTex[bodyInd];
                info.BodyStringReplace[2] = heads[headInd] + ",HEAD-HEAD=" + headTex[headInd];

                var hand = (simtype[1] == 'c') ? 'u' : simtype[0];
                var hg   = handgroupTex[bodyInd];
                info.BodyStringReplace[17] = "H" + hand + "LO,HAND=" + "huao" + hg;
                info.BodyStringReplace[18] = "H" + hand + "RO,HAND=" + "huao" + hg;
                info.BodyStringReplace[19] = "H" + hand + "LP,HAND=" + "huao" + hg;
                info.BodyStringReplace[20] = "H" + hand + "RP,HAND=" + "huao" + hg;
                info.BodyStringReplace[21] = "H" + hand + "LO,HAND=" + "huao" + hg;
                info.BodyStringReplace[22] = "H" + hand + "RC,HAND=" + "huao" + hg;
            }
            else
            {
                //index
                var index = context.StackObject.GetAttribute(8);

                Tuple <string, string>[] outfits;
                if (operand.AvatarType == 1)
                {
                    //dog
                    info            = new SimTemplateCreateInfo("dog", gender > 0);
                    info.CustomGUID = 0x4A70DF92;
                    outfits         = VMTS1PurchasableOutfitHelper.GetValidOutfits(null, -1);
                }
                else
                {
                    info            = new SimTemplateCreateInfo("kat", gender > 0);
                    info.CustomGUID = 0x7BEA0977;
                    outfits         = VMTS1PurchasableOutfitHelper.GetValidOutfits(null, -2);
                }


                info.BodyStringReplace[1] = outfits[index].Item1;
            }

            info.Name = context.StackObject.Name;
            info.Bio  = "";
            for (int i = 0; i < 5; i++)
            {
                info.PersonalityPoints[i] = 500; //todo: randomize
            }
            var n = SimitoneNeighbourGenerator.CreateNeighbor(guid, info);

            context.StackObjectID = n.NeighbourID;
            return(VMPrimitiveExitCode.GOTO_TRUE);
        }