code for scene prop disappear from scene permanently if destroyed

正在查看此主题的用户

duck83

Veteran
Hello.

I made some questions in Q&A thread, but thought it's too much chaos now in there and will start a new thread.

In my mod I have trees that can be choppable. I want them to become trunks if destroyed. I can handle it pretty easy by moving the tree underground and spawning a trunk in it's place.

The thing is I want those trunks appear whenever I re-enter the scene. So far all scene props (including those trees) are loaded just as I have placed them while editing scene. If I destroy one tree, I will see a trunk spawn in it's place but the tree will appear again after I re-enter the scene.

I have made quite an odd code I think, as I barely can understand it myself.

Please, if any of you have a bit of time, look into it. I'm trying to use slot_scene_prop_chopped, defined in module_constants before "scene_prop_slots_end " in Scene props section. I don't know how it is meant to work, but so far my code doesn't make that slot to keep data about the tree being destroyed. The tree appears again, every time I enter my scene.

Here is the code:
###aspen_C

("tree_aspen_c",sokf_destructible,"chopable_aspen_c","bo_chopable_aspen_c",
  [
    (ti_on_init_scene_prop,
      [
        (store_trigger_param_1, ":instance_no"),
        (store_trigger_param_2, ":chopped"),
      (try_begin),
(scene_prop_set_hit_points, ":instance_no", 199),
####code by Dusk Voyager
      (else_try),
        (scene_prop_slot_eq, ":chopped", slot_scene_prop_chopped, 1),
        (prop_instance_get_position, pos1, ":chopped"),
        (set_spawn_position, pos1),
        (spawn_scene_prop, "spr_trunk_aspen_c"),
      (try_end),
####ends here
       
        ]),

(ti_on_scene_prop_destroy,
    [
      (this_or_next|multiplayer_is_server),#only serverside
      (neg|game_in_multiplayer_mode),

      (store_trigger_param_1, ":instance_id"),
      (store_trigger_param_2, ":being_chopped"),

      (prop_instance_get_position, pos1, ":instance_id"),
      (set_spawn_position, pos1),
      (spawn_scene_prop, "spr_preitem_aspen_c"),
      (spawn_scene_prop, "spr_trunk_aspen_c"),

      (position_set_z, pos1, -10000),
      (prop_instance_set_position, ":instance_id", pos1, 0),
        (play_sound, "snd_dummy_hit"),
        (particle_system_burst, "psys_dummy_smoke", pos1, 3),
        (particle_system_burst, "psys_dummy_straw", pos1, 10),

####another part of code by Dusk Voyager
        (scene_prop_set_slot, ":being_chopped", slot_scene_prop_chopped, 1),
####ends here
    ]),
    (ti_on_scene_prop_hit,
      [

        (play_sound, "snd_dummy_hit"),
        (particle_system_burst, "psys_dummy_straw", pos1, 10),
    ]),
  ]),

I'm not a coder myself and I can't really check if the code is written well, beside the fact to see how it works in game. I have some thought that perhaps my trigger parameters are set somewhat wrong.

I know it's basically a boring thread for more experience moders, but if any of you was to share some thoughts on my code I would be most grateful. I also am not sure if I have defined that slot_scene_prop_chopped well in module_constants. Like I said it's before "scene_prop_slots_end" and after "scene_prop_belfry_platform_moved" and has set a number 6. That number was earlier used by "scene_prop_slots_end" and now it has 7. I don't know if it is also correct.
 
The thing is I want those trunks appear whenever I re-enter the scene.
Short of using some sort of global or some other form of data that is persistent, you cannot do this. 

You're talking about long-term data storage of Scene states; for those sorts of things, you must use a variable for each tree to store its individual state.

The code you're utilizing was designed for Persistent World use, where nobody ever leaves the main Scene.

So... basically... you can do this, but the engine's not set up for it and you're going to find it pretty rough going.  Scene prop slots aren't meant to be long-term storage.  So in a SP environment, if you want people to chop wood... there are other ways to handle this gracefully, like just developing randomized forests where they can chop down the trees (script generated scene props built after the Scene is generated)  or whatnot.
 
I'm placing all my trees by myself. It takes zillions of hours, but the effect is exactly the way I wanted.

I will try to use those variables then. I know that there are two fields for variables visible while editing scene. It's hard for me to start any code without any background on how to do that. I know it's way too much to ask, yet I'll try. Perhaps you could point me to somewhere where I can learn on how to use those variables, or perhaps you could even make some skeleton for the code with the use of those?  :lol:

I'll search forum for some variables thread. Thanks for your current input, it's really quite a lot to me.

EDIT:
I forgot to ask. If I am decided to stay with my manual scene prop placing method would that mean I would need to enter an unique var number to every scene prop currently placed?
 
If you aren't a coder, it's time to learn :smile:

Basically, you can do what you want to do, but it's impractical and would have to be coded.

Let's say you have 100 trees you want persistent data stored for in your whole game.

Each one needs to set a persistent variable when cut down.  Therefore, each one needs to set a unique global.  Since the engine doesn't store scene prop slot states but reloads them when a scene is reloaded, you need 100 different tree scripts, one for each tree, and that means 100 different tree props, taking up space in the prop placement menu, amongst other problems.

Basically, you want to find another way to do this. 

If cutting down trees and persistence is a very important concept for your mod idea and you don't want them to do it very quickly, you could make a Scene that people have to visit when they want to cut down trees, with a set number of trees that will give them resources and a long enough walk-time that they'll have to grind a lot to get a bunch of wood. 

Or just limit how much wood they can have in their inventory by making it a real item that takes up space.  Or something.

Basically, the engine just wasn't set up to record persistent data for scene props.  This is pretty frustrating if that's what you want but it's how things are.
 
I have only one big scene where the whole action is going to take place.

As long as I get you right, you were writing about 100 different trees - you meant 100 different meshes, or scene props placed on the scene, using let's say the same mesh?

I'm asking as I thought so far, that while using a limited number of different meshes I'm meant to stick to those limited number of unique code parts set for each mesh. That is while I use unique scene prop and make code for it I'm meant to place parts referring to the variables inside that code. So if I have 10 scene props using same mesh there would be one code for those 10 and other for those using different mesh. I though it would work like -> a tree got chopped, so I store a variable of it somehow and then spawn a trunk regarding to that specific variable. That wouldn't work, right? I mean I would need to write a unique code for every scene prop placed or just for meshes used?

EDIT:
I'm just asking as I'm trying to understand the options the engine grants me. Besides I'm terrified with the thought of making a code for one tree mesh work the way I want it, not to speak about writing the while randomization placement code. Geee. that thing just kills me whenever I try to think about it.
 
It's not that hard actually.
Instance no of hand placed props is guaranteed to be the same even if you exit and reenter the scene, therefore you can just use scene slots to store state of a tree. When the tree gets chopped do something like this:
插入代码块:
(store_add, ":slot_no", ":chopped", tree_prop_states_begin), #tree_prop_states_begin is a constant that you define, that way slots below that constant remain free for other uses
(store_current_scene, ":scene_no"),
(scene_set_slot, ":scene_no", ":slot_no", 1),
... and right after you finish loading a scene check the scene slots for chopped trees and replace them.
 
It will take some time to me to understand that code of yours cmpxchg8b.

I get that this code is meant to be placed in module_scene_props under ti_on_scene_prop_destroyed?

In which module file should I "try" to add parts concerning the new loading of the scene?


EDIT:
Hey cmpxchg8b! What about you just write those last code lines and tell me where to place them and I'll make some super cool texture for you? :wink:
 
I don't really need any textures, but here you go anyway (untested):
插入代码块:
(ti_after_mission_start, 0, 0, [
	(this_or_next|multiplayer_is_server),
	(neg|game_in_multiplayer_mode),
], [
	(store_current_scene, ":scene_no"),
	(try_for_range, ":slot_no", tree_prop_states_begin, tree_prop_states_end),
		(scene_get_slot, ":is_chopped", ":scene_no", ":slot_no"),
		(eq, ":is_chopped", 1),
		(store_sub, ":instance_no", ":slot_no", tree_prop_states_begin),
		(prop_instance_is_valid, ":instance_no"),
		(prop_instance_get_scene_prop_kind, ":scene_prop_kind", ":instance_no"),
		#use the value above to select which trunk to spawn since you probably have several types
		#move the tree prop somewhere underground and spawn trunk props (same code that gets executed in destruction trigger)
	(try_end),
]),
And yes, the snippet I previously wrote goes in the destroyed trigger (variable names need to be adjusted).
 
So, in the destroyable scene props code itself:

插入代码块:
  ("my_destroyable_tree",sokf_moveable|sokf_destructible|spr_hit_points(1),"tree_a01","bo_tree_a01",
   [
     (ti_on_scene_prop_destroy,
      [
       (store_trigger_param_1, ":instance_no"),
       (val_add, ":instance_no", tree_prop_states_begin),
      (store_current_scene, ":cur_scene"),
       (scene_set_slot, ":cur_scene", ":instance_no", 1),

        #Do animation stuff; you would not do that in the ti_after_mission_start example
        #Spawn the non-destroyable remnant prop

        ]),
     ]),

That is an intriguing solution.  I didn't know scene_slots were available to store that data; that's really useful.  Maybe I'll build a dungeon-crawler, hehe.
 
Guys you're great!

I'm reading those two parts of codes ... and don't truely understand the first one done by cmpxchg8b.

But if I get you right xenoargh, I just leave that cmpxchg8b code as it is, put it in the proper mission_templates part regarding the scene mask (or flag? I still can't get myself to remember it correctly). Then I add to your code the part about spawning that replaceable mesh below your part of code and I'm set?!

I'll try that now. You two guys already helped me a lot. Many thanks for that!

EDIT:
All right, I'm worthless. Just need to know that - that tree_prop_states _begin is meant to be changed in accordance to the names of my own meshes? I have an error while processing files that it's not defined and I'm that "smart" to check there is no constant like that, yet there is scene_prop_state_begin slot in the list. So I need to modify it like aspen_c_states_begin? ... and make same part of code in mission template for every other tree mesh I intend on implementing, right? Are there any other values I need to change? Would I need to add some lines to the module_constants with those names of my tree meshes, like this aspen_c_states_begin and ..state_ends, or are those two lines universal?
 
I don't think you need that first part at all.  You do, however, need to define tree_prop_states_begin and tree_prop_states_end in module_constants.  It'll have to be a pretty big range, too; IDK how many Scene Props are allowed in a Scene, precisely, but it's a very large number.

For the second part; for each tree type in module_scene_props, you need a custom version of:

插入代码块:
("my_destroyable_tree",sokf_moveable|sokf_destructible|spr_hit_points(1),"tree_a01","bo_tree_a01",
   [
     (ti_on_scene_prop_destroy,
      [
       (store_trigger_param_1, ":instance_no"),
       (val_add, ":instance_no", tree_prop_states_begin),
      (store_current_scene, ":cur_scene"),
       (scene_set_slot, ":cur_scene", ":instance_no", 1),

        #Do animation stuff; you would not do that in the ti_after_mission_start example
        #Spawn the non-destroyable remnant prop

        ]),
     ]),

In your module_mission_templates, you'd need:

插入代码块:
destructible_tree_checker = (ti_after_mission_start, 0, 0, [
	(this_or_next|multiplayer_is_server),
	(neg|game_in_multiplayer_mode),
], [
	(store_current_scene, ":scene_no"),
	(try_for_range, ":slot_no", tree_prop_states_begin, tree_prop_states_end),
		(scene_get_slot, ":is_chopped", ":scene_no", ":slot_no"),
		(eq, ":is_chopped", 1),
		(store_sub, ":instance_no", ":slot_no", tree_prop_states_begin),
		(prop_instance_is_valid, ":instance_no"),
		(prop_instance_get_scene_prop_kind, ":scene_prop_kind", ":instance_no"),
		#use the value above to select which trunk to spawn since you probably have several types
		#move the tree prop somewhere underground and spawn trunk props (same code that gets executed in destruction trigger)
	(try_end),
])

And in your Missions you'd need to add destructible_tree_checker in a line with a comma ending it, just like common_battle_mission_start, etc.
 
So I don't write tree_prop_state_begin, but aspen_c_state_begin and define it exactly the way I written now in module_constants below the original values there? And of course I add aspen_c_state_ends also there? What numbers should I add after "="?

And is aspen_c_state_begin and aspen_c_state_ends written correctly at all, or should it be aspen_c_prop_state_begin and _ends?

EDIT:
Just that one more clue on that. I change that tree_prop_state_begin to aspen_c_state_begin or aspen_c_prop_state_begin and define it in module_constants with what range? aspen_c would get a number like 5 and another tree mesh 6, and so on, right?
 
So I don't write tree_prop_state_begin, but aspen_c_state_begin and define it exactly the way I written now in module_constants below the original values there? And of course I add aspen_c_state_ends also there? What numbers should I add after "="?

And is aspen_c_state_begin and aspen_c_state_ends written correctly at all, or should it be aspen_c_prop_state_begin and _ends?
Don't do it that way, just follow directions, it should work.  You will need to write the animation code and prop spawning code for the remaining stump, btw.

For aspen_c, you'd create a new Scene Prop definition in module_scene_props:

插入代码块:
("aspen_c_destroyable",sokf_moveable|sokf_destructible|spr_hit_points(1),"aspen_c","bo_aspen_c",
   [
     (ti_on_scene_prop_destroy,
      [
       (store_trigger_param_1, ":instance_no"),
       (val_add, ":instance_no", tree_prop_states_begin),
      (store_current_scene, ":cur_scene"),
       (scene_set_slot, ":cur_scene", ":instance_no", 1),

        #Do animation stuff; you would not do that in the ti_after_mission_start example
        #Spawn the non-destroyable remnant prop

        ]),
     ]),

 
But how is this new definition going to be connected with previous aspen_c definitions in module_scene_props?

I can see I need to add that code written by you into mission_templates ... just once or for every unique mesh?

Then I add this new aspen_c_destructible definition to aspen_c whole code but how is it going to work? I don't get it. Perhaps it's all too much to me.

What about that tree_prop_states_begin that throws an error it's not defined? How should I define it? Just add it in the module_constants in the scene section? What number should it get if yes?
 
But how is this new definition going to be connected with previous aspen_c definitions in module_scene_props?
You just put this:

插入代码块:
     (ti_on_scene_prop_destroy,
      [
       (store_trigger_param_1, ":instance_no"),
       (val_add, ":instance_no", tree_prop_states_begin),
      (store_current_scene, ":cur_scene"),
       (scene_set_slot, ":cur_scene", ":instance_no", 1),

        #Do animation stuff; you would not do that in the ti_after_mission_start example
        #Spawn the non-destroyable remnant prop

        ]),
...where it belongs.  See the other entries in module_scene_props to see where you need to put this, or better yet, just rewrite whatever entries you currently have for this using the example I gave you, it'll probably be less confusing.

插入代码块:
I can see I need to add that code written by you into mission_templates ... just once or for every unique mesh?
Just once, but you'll have to include a reference to that in every Mission where you want to check for destroyed persistent trees and you'll need to write a check for each instance_get_type and see if the type matches the persistent tree objects.

What about that tree_prop_states_begin that throws an error it's not defined? How should I define it? Just add it in the module_constants in the scene section? What number should it get if yes?
Define it in module_constants, probably something like tree_prop_states_begin = 10000 and tree_prop_states_end = 20000.


Long story short:  this code is basically functional but if you want it to be useful, you're going to have to do a fair amount of work.  This is just the basic sketch of a concept of persistent Scene data.
 
Ok, so I got the sketch. It's just a really good start for sure. Will look into other mods perhaps for some examples of things being done that way. Dunno how am I supposed to write that checker, but perhaps that will come with time, or I will get some a bit more skilled than me coder to that project.

Thanks again. You two guys, and especially you  xenoargh helped me a lot. I surely will write your nicks in my "thanks go to" list.
 
后退
顶部 底部