Taking Questions about Mixintos and Overrides

Is it possible now to add custom idle animations with a mixinto?
I don’t want to touch the lua files :worried:

I did not try it yet, but my guess would be yes. If nothing has changed you do not need to edit an existing Lua-file, but you will have to create a new one for your animation…

2 Likes

Has anyone gotten a mixinto to work since Alpha 2 dropped? My overrides are all working but even the simplest mixintos are failing. :confused:

Mixintos work fine for me. Make sure that your mixinto is correct - especially the change of model_variants from an array ([]) to an object ({ } with each key being the model variant’s name) could cause errors.

Jofferson does not catch these errors right now, I believe - but it should at least show an unchanged mixinto, too.

Edit: And Jofferson 1.3.1 does that.

1 Like

Trying to figure out htis new model_variant set up, especially the "eyebrows"
I’ve been trying to figure this out but it seems to not be working. . . Anyone know why this isn’t working?

{
    "type": "entity",
    "mixins": "stonehearth:mixins:base_human",
    "components": {
        "render_info": {
            "animation_table": "stonehearth/data/rigs/humans/skeletons/male.json"
        },
        "model_variants": {
            "default": {
                "models": [
                    "stonehearth/entities/humans/male_1/body.qb"
                ]
            }
        }
    },
    "entity_data": {
        "stonehearth:customization_variants": {
            "root": {
                "variants": [
                    [
                        "topknot"
                    ]
                ]
            },
            "topknot": {
                "variants": [
                    [
                        "topknot_black", "topknot_grey"
                    ]
                ]
            },
            "topknot_black": {
                "models": [
                    "file(head_topknot_1_black.qb)",
                    "file(head_topknot_2_black.qb)"
                ],
                "variants": [
                    [
                        "nothing",
                        "eyebrows"
                    ]
                ]
            },
            "topknot_grey": {
                "models": [
                    "file(head_topknot_1_grey.qb)"
                ],
                "variants": [
                    [
                        "nothing"
                    ]
                ]
            },
            "eyebrows": {
                "models": [
                    "file(beard_black)",
		    "file(goatee_black.qb)"
                ]
            },
            "nothing": {}
        }
    }
}

When the game loads it’ll only load head_topknot_grey for the heads. Tried adding the “eyebrows” variant to that variant as well and it still spawned… :frowning:

If you are using mixinto remember about additive stuff as usual.

As for the customization variants,

if variant.models then
	local variant_name = "default"
	local random_model = variant.models[1]
	local model_variants_component = entity:add_component("model_variants")
	model_variants_component:add_variant(variant_name):add_model(random_model)
end

if variant.variants then
	for _, variant_set in ipairs(variant.variants) do
		local random_option = variant_set[math.random(#variant_set)]
		self:customize_citizen(entity, all_variants, random_option)
	end
end

This should shed (some) light. Basically, eyebrows has to be reachable through some variants from root.

In your case, root, topknot, [ topknot_black, topknot_grey ], [ [ nothing, eyebrows ], [ nothing ] ] eyebrows is only reached if topknot_black is used.

If I am reading this code properly, then there’s the xkcd issue.

But that’s just for the model, not the variant. In theory, there should be some citizen that has head_topknot_1_grey.qb as model. Feel free to post your mod so I can throw a few prints into the SH code to look for it - but right now it looks like the bit is still WIP.

I’m using an override at the moment.

I’ll message you a link to the smod I’m using. It’s still odd that only the topknot_grey is the only one working. I have male_2 set up as well and it seems to add “eyebrows” (technically beards) every so often but it only seems to use one of the hair variants. . . Very odd.

Yeah, I tried a simple mixinto and they don’t work. Probably because the team is changing the formats and establishing the mod api…
What I know, is that finally they work as they should, because my old mods overwrote somehow the models with my own list of models, and now they add, as a mixinto should do (horrible images of several trees overlapped come to my mind x_x).

The problem is that now I can’t do anything. Overriding seems fine, but why a mixinto that only changes the name/description of an entity doesn’t work? Is it because of its true nature (adding?) I’m trying to fix my candyland mods, but if I don’t get the mixintos to work this is going to take time…

Yeah, I am having that problem. Mixintos to change things like in-game name, description, scale, not working.

It seems that mixintos are purely additive, i.e. cannot overwrite existing attributes.

… funnily enough, Jofferson is doing exactly the same. Uh… Okay? That shouldn’t be this way.

As for the Candyland… Jelly could solve some issues that you have - because you can override its landscaper completely. :wink:

Edit: It seems as if properties cannot be overridden but everything else (adding properties to objects and items to arrays) seems to work just fine. Uh. I think it’s rather a scary coincidence that Jofferson, by accident, simulated the game’s “broken” behaviour so well…

Hey Everyone, sorry for the long delay.

@Relyss, re: the juniper/candyfloss trees:

@RepeatPan is totally right:

So your code was probably adding a model var array above the existing array, and lucky, the new one got read first. The actual version of the model variant that is read (if there are unexpectedly multiple) might be nondeterministic, so that might be why it works sometimes, but not others. I see why you want to do it this way, though–you want variants of the same tree, right? We’ll keep this in mind going forward.

@SteveAdamo is also correct, this is the same design issue he encountered when new personality types.

The short version is: thanks for beating on the API so we can be aware of what your use cases are trying to do that we haven’t thought of yet!

@Avairian, re: [quote=“Avairian, post:147, topic:5229”]
Not quite related to mixintos and overrides but I was wondering if you could explain how animations work with objects?
[/quote]

Right now, the region does indeed determine how close a person can stand to an object, but I don’t yet think that it affects the y (height) axis of interaction. If the y height is >=3, people cannot path over the object but if it’s less than 3 they walk right through.

To get sleeping on the bed to work, we tell the worker to go exactly to where the bed is, plus a unit of “1” and then run the same sleep animation he gets on the ground. Here’s our lua:

 --[[
    Follow the path to the bed, then play the sleep-related animations.
 --]]
 function SleepInBedAdjacent:run(ai, entity, args)
    local bed = args.bed
    ai:execute('stonehearth:run_effect', { effect = 'yawn' })
   
   --When sleeping, we have a small chance of dreaming
   radiant.events.trigger(stonehearth.personality,
                     'stonehearth:journal_event', 
                     {entity = entity, description = 'dreams'})

   -- move directly on top of the bed
   self._restore_location = radiant.entities.get_world_grid_location(entity)
   local bed_location = radiant.entities.get_world_grid_location(bed)
   bed_location.y = bed_location.y + 1
   radiant.entities.move_to(entity, bed_location)

   local q = bed:get_component('mob'):get_rotation()
   entity:get_component('mob'):set_rotation(q)

   -- goto sleep  
   radiant.entities.think(entity, '/stonehearth/data/effects/thoughts/sleepy')
   radiant.entities.add_buff(entity, 'stonehearth:buffs:sleeping');

   ai:execute('stonehearth:run_effect', { effect = 'goto_sleep' })
   ai:execute('stonehearth:run_effect_timed', { effect = 'sleep', duration = 1})   
   radiant.entities.set_attribute(entity, 'sleepiness', 0)
end

So you could try making a lua file that specifies a height of less than 1, and seeing what happens.

Let me know if you guys would like more info about adding/editing actions via lua. It’s rather in flux at the moment, but hey! Exciting!

1 Like

Gah, that’s a bug. I’ll look into it now.

Edit: Well, there was a bug with mixins, which when fixed, broke the mixintos. Now both bugs are fixed. Sorry about that, folks! Thanks to @Ponder is fixed on my machine now and should be in our next update, whenever that happens.

2 Likes

absolutely! but i imagine providing use cases/scenarios, or issues we run into with the logic, makes it easier to explain the actions?

although, a generic run through of code snippets, ala “Stephanie’s C0ding C0rner” has a nice ring to it… :smile:

1 Like

Yes, actually. So if anyone has specific questions, let me know! It will help me organize my thoughts, anyway.

1 Like

Out of interest… Was it because mixins overwrote normal properties and by changing that (i.e. defined properties overwrite mixin’d ones) you accidentally turned around the way mixintos work too?

1 Like

Yay! So soon I’ll be able to fix my mods to the latest release :slight_smile:
(Candyland1 is half way… A tiramisu terrain is not that easy to combine with candy-related trees, so I’m making new ones).

Yes, because the oak ones have variants, but the juniper ones don’t. And nevertheless I was able to push three variants of the large juniper tree (in my case, 3 candy floss) to overwrite it (it can be seen in the picture here), just with a mixinto. I guess now I’ll have to override the models first and then add variants. But if I’d like to replace the oak tree, which has variants by default, with just one model/variant, will it be possible?

Adding variants is nice, but when a mod needs to replace the standard assets there should be a way to apply all possibilities. Although I wouldn’t want to add variants to the bushes, as the empty ones could appear mixed (or not? Now to think of it, will they change colors depending on season? That’s another thing to take into account).

And what will be the way to add custom idle animations? To try them in-game I’m replacing the content of one of the idle animations (the idle_sway I think). If that’s still in progress, I’ll try the tutorial of voxel_pirate.

1 Like

Tony and I were just talking about this yesterday–it’s actually rather hard to remove things from arrays, because there’s no clear way to reference the item that you’re taking out. If you do it by index, the index might change if there’s another mixinto that adds stuff. If you do it by adding a unique ID to the array object, then… you might as well have a dictionary. So we’re still thinking about that! In the meantime, perhaps you could just replace all 3 model variants with the one model you like? And we could consider an option that just does that by default.

Voxel Pirate’s tutorial is actually spot on (and I don’t see things changing dramatically to contradict it any time soon). At a high level, the idea behind the action mechanism is that any entity can be loaded down with “actions” which are bits of AI that run when their conditions are met.

Actions are added to entities in their .json file, so if you want to see all the actions available to base_human, you can look at the “actions” section of base_human.json.

AI files can get pretty complicated, but at their simplest, they are made of:

  • a “name” field, which uniquely identifies them within a mod
  • a “does” field, which is like the category of action it belongs to
  • a “run” method which is what happens when this action is called upon by the AI service to run.
  • a “priority” number which determines how important this action is; higher is better

The idle_sway_action.lua demonstrates this pretty clearly:

 local IdleSwayAction = class() --declares this a lua class

IdleSwayAction.name = 'sway'  --here's the name
IdleSwayAction.does = 'stonehearth:idle:bored'  --here's its category
IdleSwayAction.args = { }  --args it takes, in this case none
IdleSwayAction.version = 2  --version of the action service, internal use
IdleSwayAction.priority = 1  --priority, kind of low
IdleSwayAction.preemptable = true  --can this be interrupted? Yes.

--function called when it's time to do the action
function IdleSwayAction:run(ai, entity)  
   --do this effect (which has an animation inside)
   ai:execute('stonehearth:run_effect', { effect = 'idle_sway'}) 
end

return IdleSwayAction  --so that you can reference the class from outside of itself

As @voxel_pirate says, to make a new bored animation, you have to make all the .json files, and make a copy of this .lua file, and then change the ai:execute to call your new bored effect instead of idle_sway

To test, you can see all the actions in progress on an entity by hitting the AI button in the upper left corner of the game, and then clicking on a person.

Because idle_sway “does” stonehearth:idle:bored, it will be entered into a prioritized-lottery whenever the AI service decides that it’s time for the person to do a “bored” animation. Actions with higher priority will get picked out of the lottery first. If a bunch of actions have the same priority then they have equal chances to run.

The AI service “does” the “bored” animation whenever there is nothing more pressing on its queue. More details on this if you need to have actions compete with each other (and not just within bored).

3 Likes

Well, part of the next modding request batch would be a way to mess around with JSON loading. I have a few ideas in mind, basically working around the idea of having “magic items” ("@MAGIC: remove(stonehearth/*.qb)@" or some silly syntax like that). We would have to see how it plays out, but that would be my worries then… Always open for some experiments.

1 Like

Btw, we pushed a build to Steam Latest that has the fix for the mixintos from yesterday. Thanks again to @Relyss and @RepeatPan for pointing it out.

3 Likes

OK, I don’t mind doing that.
R53 fixes the mixintos, but I still have a problem.
First, I override the default models so they don’t appear at all.
Second, I add the rest of the variants with a mixinto.

The result is that the files added with the mixinto will overlap the overridden ones. It’s difficult to notice it when the variants are just a color change, but I managed to conclude that, as the mixinto variants don’t show up in those cases.

For example, using my old mods, which added all models with the mixinto, my gummy bears evolve into little lions:

I guess I’ll try to reduce my number of variants and override only what we have, for the moment.

1 Like