Modding Q&A [For Quick Questions and Answers]

Users who are viewing this thread

Status
Not open for further replies.
@Jarv, at the moment it is only occuring 1 per hour, in that it checks if the player is within range 1 time every hour, you I presume want it to fire every frame so should set this to 0,
 
@Jarvisimo you are missing a try_end for the try_for_parties

(1,
  [
(try_for_parties, ":parties"),
        (party_is_active, ":parties"),
        (assign, ":main",  "p_main_party"),
        (party_get_position, pos1, ":main"),
        (party_get_position, pos2, ":parties"),
        (get_distance_between_positions, ":distance_to_region_node", pos1, pos2),
        (lt,":distance_to_region_node", 300),
        (try_begin),
            (eq, ":parties", "p_town_6"),
              (display_message, "@You are now entering Anorien.", 0x0000FF),
        (else_try),
            (eq, ":parties", "p_town_8"),
              (display_message, "@You are now entering Belfalas.", 0x0000FF),
        (try_end),
(try_end),
    ]),
 
Thanks Lumos!



Sigh
Aaaand I'm back. Alright, so it worked. The trigger fired and "You are entering Anorien." printed about 50 times down the screen until I left the vicinity.
I thought: I need a way of stopping messages from being printed whenever I am in a region after I enter it for the first time.
So I made the variable $inregion, which would record with a boolean whether the party was currently in a region or not. So I did this as you can see. When the party goes inside a region the message is displayed then $inregion stores that the party is in the region.

Then in the second block of code below, I added a greater than thingie to do the opposite: When a party leaves a region, display a message then set $inregion to 0 (not in a region).

I went in game, went into the region and hooray! "You are entering Anorien." displayed once. Brilliant! Then I went to leave the region and nothing happened again.  :sad: However I know that the variable $inregion is assigning correctly - if I tried to enter the region again nothing happened, so it's obviously a problem with the bottom block (under the gt function).

What did I do this time? (code below)

Code:
(0,
   [
        (try_for_parties, ":parties"),
        (party_is_active, ":parties"),
        (assign, ":main",  "p_main_party"),
        (party_get_position, pos1, ":main"),
        (party_get_position, pos2, ":parties"),
        (get_distance_between_positions, ":distance_to_region_node", pos1, pos2),
		
        (lt,":distance_to_region_node", 300),
        (try_begin),
        (eq, ":parties", "p_town_6"),
	(eq, "$inregion",0),
             (display_message, "@You are now entering Anorien.", 0x0000FF),
	     (assign, "$inregion",1),
        (else_try),
        (eq, ":parties", "p_town_8"),
	(eq, "$inregion",0),
             (display_message, "@You are now entering Belfalas.", 0x0000FF),
	     (assign, "$inregion",1),
        (try_end),
		
	(gt,":distance_to_region_node", 300),
	(try_begin),
        (eq, ":parties", "p_town_6"),
	(eq, "$inregion",1),
             (display_message, "@You are now leaving Anorien.", 0x0000FF),
	     (assign, "$inregion",0),
        (else_try),
        (eq, ":parties", "p_town_8"),
	(eq, "$inregion",1),
             (display_message, "@You are now leaving Belfalas.", 0x0000FF),
	     (assign, "$inregion",0),
        (try_end),
		
	(try_end),
    ]),
 
Stop for a minute and reconsider why you're using a try_for_parties loop every single frame for just checking two parties (trust me, it's not premature optimization :razz:). Although you can't really tell where the player party is going, you can sort of estimate it with distance checks. And because it's sort of discrete you can't immediately tell if it's coming or going (so you need to set an appropriate polling interval). Do something like the following:
Code:
#set your fixed point multiplier
(party_get_position, pos1, "p_main_party"),
(try_for_range, ":center_no"),
  (party_get_position, pos2, ":center_no"),
  (get_distance_between_positions, ":distance_to_region_node", pos1, pos2),
  (lt, ":distance_to_region_node", 300), #also check for boundary (region around 300 units)
  (party_get_slot, ":old_distance", ":center_no", slot_center_whatever),
  (assign, reg1, -1),
  (try_begin), #going in
    (gt, ":old_distance", ":distance_to_region_node"),
    (assign, reg1, 1),
  (else_try), 
    (lt, ":old_distance", ":distance_to_region_node"),
    (assign, reg1, 0),
  (try_end),
  (try_begin), #display message
    (neq, reg1, -1),
    (party_set_slot, ":center_no", slot_center_whatever, ":distance_to_region_node"),
    (str_store_party_name_link, s1, ":center_no"),
    (display_message, "@You are now {reg1?entering:leaving} {s1}.", 0x0000FF),
  (try_end),
(else_try), #party outside domain
  (party_set_slot, ":center_no", slot_center_whatever, 9999),
(try_end),
 
You need to place the second condition in an else_try, because as it is now, it's being checked after checking for the first one, and given that the one excludes the other, it won't be run, ever.
Well, I see your post. Great.

However, your code isn't as good as it could be, and while I shouldn't stick my nose into others' business, here's a bit of recommendations as to how to improve it:
- Indentation. Your indentation is nearly perfect as it is, but "nearly" is not enough. Consider having try_ blocks one tab out, just so you can always see where your logic branches out. Also, remember to put a space after every comma (except at the end of the line), because... uh... because this improves readability! (And absolutely not because I'm a grammar nazi.)
- try_for_parties checks every single party on the map. Static parties, moving parties, parties spawned from templates, everything. That's why it hampers performance quite a bit when compared to a short try_for_range, and that's especially true when you've got a large map with a lot of **** on it. Therefore, replacing the try_for_parties with a try_for_range, ":party", towns_begin, towns_end, would be much faster. However, it's pointless to check against all towns when you always know what the region nodes will be (and when there's going to be handful of region nodes), so you can avoid that altogether and manually check them, like this:
Code:
  (0, [
	(try_begin),
		(eq, "$inregion", 0), # The main party is not in a region
		(party_get_position, pos1, "p_main_party"),
		(try_begin),
			(party_get_position, pos2, "p_town_6"),
			(get_distance_between_positions, ":dist", pos1, pos2),
			(lt, ":dist", 300),
			(display_message, "@You are now entering Anorien.", 0x0000FF),
			(assign, "$inregion", 1),
		(else_try),
			(party_get_position, pos2, "p_town_8"),
			(get_distance_between_positions, ":dist", pos1, pos2),
			(lt, ":dist", 300),
			(display_message, "@You are now entering Belfalas.", 0x0000FF),
			(assign, "$inregion", 1),
		(try_end),
	(else_try),
		(eq, "$inregion", 1), # Just so we're safe from rogue inregion values
		(party_get_position, pos1, "p_main_party"),
		(try_begin),
			(party_get_position, pos2, "p_town_6"),
			(get_distance_between_positions, ":dist", pos1, pos2),
			(ge, ":dist", 300),
			(display_message, "@You are now leaving Anorien.", 0x0000FF),
			(assign, "$inregion", 0),
		(else_try),
			(party_get_position, pos2, "p_town_8"),
			(get_distance_between_positions, ":dist", pos1, pos2),
			(ge, ":dist", 300),
			(display_message, "@You are now leaving Belfalas.", 0x0000FF),
			(assign, "$inregion", 0),
		(try_end),
	(try_end),
   ]),
Yes, there is code redundancy, but it omits all checks which slow everything down. (I am by the way obsessed by stuff like that due to one time where I accidentally spawned a party each from all of my centers (at least about 2500 in total), all at the same time... the game could not bear it. From that day on, I can't stop but redo every sub-optimal piece of code I find.)
There is, of course, a better way, especially if you want your region nodes to change. You can set a slot on all such nodes, then use the try_for_range with towns, check against that slot, then display a message based on the distance and the "$inregion" whether or not you're entering or leaving the region. Retrieving the name would be problematic though, given that (I presume) the region's name would be different to the node's name. Of course, you could use the slot value to determine which region it is, based on a list of strings (in module_strings), which would allow you to change the region nodes for whatever reason.
However, for only a few centers which will never change ownership of their regions, checking by hand is the fastest, though not the most elegant.

EDIT: Ninja'd by Somebody, though not really.
Also, Somebody, your (try_for_range, ":center_no"), seems to be missing its bounds. Is that on purpose, and what are the default bounds if it is, and you use it like that?
 
jacobhinds said:
openbrf is a file editor you can download, just google it. then find the piece of armour you want to change in the resource folder of whatever module you're using (use ctrl-f in openbrf because there are a lot of .brf files in the resource folder) and apply feminized frame to that item.

um thanks  :!:
 
Wow, thank you guys. I'll go with Lumos's solution as it looks less scary so I can edit it and twist it to my malicious purposes more easily. Cheers!

Lumos said:
Your indentation is nearly perfect as it is
Oh Lumos, you are quite the flirt. I'm blushing.
 
Lav said:
It happens because (try_for_parties) does not accept a range, it iterates through all parties. Including Sargoth itself. And since it's calculated strength definitely matches the (ge) criteria...
Any operation you know of that will accept a range? It seems horribly inefficient to iterate through every party and then to an is_between. :???:
 
I tryied and re-tried but i'm unable to make this work on multiplayer.
Resume
I want to make a native compatible mod. When a player hit a scene prop he sees a message and enters in a mode. So, i edited the native anvil scene prop :
Code:
("smithy_anvil", 0,"smithy_anvil","bo_smithy_anvil", 
  [
	(ti_on_init_scene_prop,
      [
        (store_trigger_param_1, ":instance_no"),
        ]),
     (ti_on_scene_prop_hit,
      [
        (store_trigger_param_1, ":instance_no"),
        (try_begin),
		  (this_or_next|multiplayer_is_server),
		  (neg|game_in_multiplayer_mode),
		  (prop_instance_get_variation_id, ":var_id", ":instance_no"),
		  (eq, ":var_id", 1),
                  (set_fixed_point_multiplier, 1),
                  (position_get_x, ":attacker_agent_id", pos2),
                  (get_player_agent_no, ":player_agent"),
		  (agent_get_player_id, ":player_id",":player_agent"),
		  (agent_is_human, ":player_agent"),
                  (eq, ":player_agent", ":attacker_agent_id"),
		  (multiplayer_send_int_to_player, ":player_id", multiplayer_event_show_bk_mode, ":player_agent"),
        (try_end),
    ]),
  ]),
I wrote this looking to dummy_a_undestructable

I added a new event to header_common (multiplayer_event_show_bk_mode) and a new agent slot to module_constants (slot_agent_in_bk_mode)

Then i added a new client event:
Code:
(else_try),
          (eq, ":event_type", multiplayer_event_show_bk_mode),
          (store_script_param, ":value_player_no", 3),
          (try_begin),
            (agent_is_active, ":value_player_no"),
            (neq,":value_player_no",0),
            (try_begin),
              (neg|agent_slot_eq, ":value_player_no", slot_agent_in_bk_mode, ":value_player_no"),
	      (agent_set_slot, ":value_player_no", slot_agent_in_bk_mode, ":value_player_no"),
              (display_message, "@Berserker mode activated!", 0xFF001eff),
            (else_try),
              (agent_slot_eq, ":value_player_no", slot_agent_in_bk_mode, ":value_player_no"),
	      (agent_set_slot, ":value_player_no", slot_agent_in_bk_mode, -1),
              (display_message, "@Berserker mode cancelled!", 0xFF001eff),
            (try_end),

On hosted server this works. But on dedicated it always give me an error of INVALID AGENT ID: . Can someone help me ? I spent hours on this.  :smile: :cry:
 
@K.A

dummy_a_undestructable scene prop is for single player/client side only (the server controls nothing about it, even if you delete it's code, the clients will still see that damage message when they hit the dummy).

Then in your code you used "(get_player_agent_no, ":player_agent"),", wich is a singleplayer operation. In mp, if you are the hoster(ingame hoster) it will return your agent id, else (if it is dedicated) it will return 0, wich can lead to invalid things (depends where you use it).
Also you don't need to make a new event (because this will not be native compatible anymore) to display a string in clients; there is already one: multiplayer_event_show_server_message, wich is sending a string (multiplayer_send_string_to_player, ":player_no", multiplayer_event_show_server_message, "@String that player will see on it's screen" / "str_id" / s1 / s2 / s3 (string ids) (these are the possible strings format that you can send)).

Then your code it not entirely good.
The trigger ti_on_init_scene_prop does nothing in your case, so you can remove it.
Your ti_on_scene_prop_hit should look like this:

(ti_on_scene_prop_hit,
      [
(store_trigger_param_1, ":instance_no"),
(set_fixed_point_multiplier, 1),
(position_get_x, ":attacker_agent_id", pos2),
(try_begin),
    (this_or_next|multiplayer_is_server),
    (neg|game_in_multiplayer_mode),
    (prop_instance_get_variation_id, ":var_id", ":instance_no"),
    (eq, ":var_id", 1),
    (neg|agent_is_non_player, ":attacker_agent_id"), #makes sure that the agent that hit the anvil is controlled by a player (it can be a bot too); it also removes the necessity of putting player_is_active below, since we know that this operation will only be false if the agent is controlled by a player, and if we negate it (neg|) will result that it will be true if the agent is controlled by a player
      (agent_get_player_id, ":player_id", ":attacker_agent_id"),
      (player_is_active, ":player_id"),    #we already know that the agent is controlled by a player, but we put this check because most modders forgot about it normally (you can delete this line, the result will be the same)
      (str_clear, s1),
                  ###do your verifications below, agent get slot, compare the things, give superpowers to the agent id and make a proper output message stored in s1


      (multiplayer_send_string_to_player, ":player_id", multiplayer_event_show_server_message, s1),
(try_end),
    ]),
 
K.A. said:
Thanks, i undestand now. Last thing, i noticed that agent id changes when dies. Is it the same for player id ?
Player ID should stay the same unless they rejoin the server. If you really want the berserk status to be persistent even if a player leaves track it by the player's unique id.
The Dark Robin said:
Any operation you know of that will accept a range? It seems horribly inefficient to iterate through every party and then to an is_between. :???:
Use the ubiquitous
Code:
try_for_range
.
 
try_for_range on parties is meaningless (except with static parties defined in module_parties, but that's not your case) and using party templates as range doesn't do what you want it to do.
If you want to iterate through all bandit parties on the map, your only option is using try_for_parties with an is_between check.
 
cmpxchg8b said:
If you want to iterate through all bandit parties on the map, your only option is using try_for_parties with an is_between check.
Minor nitpick: try_for_parties followed by party_get_template_id with an is_between check. :smile:
 
Status
Not open for further replies.
Back
Top Bottom