Stuff for define_extra.h

For a change, something that's actually useful for a header you have:

Code:
#define PRODATA_IT_WP_SOUND       (100)


 #define WEAP_SND_ATTACK   "WA" 
 #define WEAP_SND_EMPTY    "WO"
 #define WEAP_SND_RELOAD   "WR"
 #define WEAP_SND_IMPACT_FLESH  "F"
 #define WEAP_SND_IMPACT_METAL  "M"
 #define WEAP_SND_IMPACT_MISS  "S"
 #define WEAP_SND_IMPACT_DUD  "W"
 #define WEAP_SND_IMPACT_GENERIC  "X"
 #define play_weapon_sound(pid, effect, type, alt)   play_sfx(effect + sprintf("%c", get_proto_data(pid, PRODATA_IT_WP_SOUND)) + type + "XXX" + alt)
 #define play_weapon_sound_impact(pid, type, target, alt)   play_sfx("WH" + sprintf("%c", get_proto_data(pid, PRODATA_IT_WP_SOUND)) + type + target + "XX" + alt)

E.g.:

Code:
    play_weapon_sound(PID_MINIGUN, WEAP_SND_ATTACK, 1, 1);

plays the first version of the minigun primary attacking sound. The minigun has only primary fire, and two variations, so putting 2 in the third argument, or 3 in the last will result in no sound being played. There's probably no way to find out whether or not a certain sound file exists to avoid such errors, right @phobos2077?

edit: crap, missed the fact that impact sounds are contextual, updated.

edit2: well, seems I overlooked sfx_build_weapon_name, which probably does the exact same fucking thing. Well, that was some wasted effort right there...

edit3: hmm, going through that command it does strike me as my approach being a bit more versatile, but I'm not sure (e.g. there doesn't seem to be a way to use alt fire/impact sound, and you're restricted to an equiped weapon for some reason)
 
Last edited:
some random stuff. First some things that help you get info about walls:

Code:
               #define WALL_TYPE_EAST_WEST      134217728
               #define WALL_TYPE_NORTH_CORNER      268435456
               #define WALL_TYPE_SOUTH_CORNER      536870912
               #define WALL_TYPE_EAST_CORNER      1073741824
               #define WALL_TYPE_WEST_CORNER      -2147483648
               #define wall_type_east_west(x)     ((get_proto_data(obj_pid(x), 24) bwand 134217728) != 0) 
               #define wall_type_north_corner(x)     ((get_proto_data(obj_pid(x), 24) bwand 268435456) != 0) 
               #define wall_type_south_corner(x)     ((get_proto_data(obj_pid(x), 24) bwand 536870912) != 0)   
               #define wall_type_east_corner(x)     ((get_proto_data(obj_pid(x), 24) bwand 1073741824) != 0)  
               #define wall_type_west_corner(x)     ((get_proto_data(obj_pid(x), 24) bwand -2147483648) != 0)
               #define NOT_WALL_TYPE_NORTH_SOUTH     (WALL_TYPE_EAST_WEST bwor WALL_TYPE_NORTH_CORNER bwor WALL_TYPE_SOUTH_CORNER bwor WALL_TYPE_EAST_CORNER bwor WALL_TYPE_WEST_CORNER)
               #define wall_type_north_south(x)       ((get_proto_data(obj_pid(x), 24) bwand (NOT_WALL_TYPE_NORTH_SOUTH)) == 0)
               #define wall_light_through(x)          ((get_proto_data(obj_pid(x), 20) bwand 536870912) != 0)
               #define wall_shoot_through(x)          ((get_proto_data(obj_pid(x), 20) bwand 2147483648) != 0)

Finally a macro to use art_exists for weapon animations easily:

Code:
#define PRODATA_IT_WP_ANIM         (36)
 #define weapon_art_exists(weapon_pid, critter)    art_exists((obj_art_fid(critter) bwand 0xffff0fff) bwor (get_proto_data(weapon_pid, PRODATA_IT_WP_ANIM) * 0x1000))
 
some random stuff. First some things that help you get info about walls:

Code:
               #define WALL_TYPE_EAST_WEST      134217728
               #define WALL_TYPE_NORTH_CORNER      268435456
               #define WALL_TYPE_SOUTH_CORNER      536870912
               #define WALL_TYPE_EAST_CORNER      1073741824
               #define WALL_TYPE_WEST_CORNER      -214748364

You should use hexadecimal constants for stuff like that, so it won't look like some magic numbers.
 
A procedure that is useful if you need the actual rotation from one tile to another. rotation_to_tile is built with animations in mind, which due to the "flatness" of the hexes in FO means that horizontal directions are "privileged" and absorb more tiles under their wings. This is extremely annoying if you want to, say, draw a line across the hex geometry properly.

Code:
procedure real_rotation_to_tile(variable begin_tile, variable dest_tile) begin
  	variable temp_dist:=tile_distance(begin_tile, dest_tile);
  	variable temp_rot:=rotation_to_tile(begin_tile, dest_tile);
  	if temp_rot == 4 then begin         //the horizontal rotations are "greedy" and are treated as having more hexes under them than they should
  	   if tile_distance(tile_num_in_direction(begin_tile, temp_rot, temp_dist), dest_tile) > tile_distance(tile_num_in_direction(begin_tile, 5, temp_dist), dest_tile) then
  	      temp_rot:=5;
  	   else if tile_distance(tile_num_in_direction(begin_tile, temp_rot, temp_dist), dest_tile) > tile_distance(tile_num_in_direction(begin_tile, 3, temp_dist), dest_tile) then
  	      temp_rot:=3;
  	end else if temp_rot == 1 then begin
  	   if tile_distance(tile_num_in_direction(begin_tile, temp_rot, temp_dist), dest_tile) > tile_distance(tile_num_in_direction(begin_tile, 0, temp_dist), dest_tile) then
  	      temp_rot:=0;
  	   else if tile_distance(tile_num_in_direction(begin_tile, temp_rot, temp_dist), dest_tile) > tile_distance(tile_num_in_direction(begin_tile, 2, temp_dist), dest_tile) then
  	      temp_rot:=2;
  	end
  	return temp_rot;
end
 
@phobos2077 chided me earlier for using "magic numbers" instead of hexadecimals when dealing with flags, but I can't figure out for the life of me how to manipulate something like 0x0004000 or whatever to do my bidding.

If there's others who feel the same, the following might be useful (at least, I think it works nicely):

Code:
    #define set_flag_on(flags, flag)   (flags BWOR (2^(flag-1)))
    #define set_flag_off(flags, flag)   (flags - (flags BWAND (2^(flag-1))))
    #define is_flag_on(flags, flag)   ((flags BWAND (2^(flag-1))) != 0)

This way, you can still make yourself a flag, but don't have to deal with weird numbers you can't wrap your head around. Flag 5 isn't 16 or 0x00000010, but simply 5:

Code:
    tmp_flags:=0;
    tmp_flags:=set_flag_on(tmp_flags, 3);
    tmp_flags:=set_flag_on(tmp_flags, 14);
    tmp_flags:=set_flag_on(tmp_flags, 15);
    display_msg("check flag " + is_flag_on(tmp_flags, 14));   //returns 1
    tmp_flags:=set_flag_off(tmp_flags, 14);
    display_msg("check flag2 " + is_flag_on(tmp_flags, 14));   //returns 0

Phobos will of course correct me if I'm doing something stupid here ;).
 
Last edited by a moderator:
Well in original scripts they use flags in form "bit_1", "bit_2" etc (simple constants, see vanilla define.h). The resulting code just works faster because there is less instructions generated, and you still manipulate bits by their ordinal number.
 
Well in original scripts they use flags in form "bit_1", "bit_2" etc (simple constants, see vanilla define.h). The resulting code just works faster because there is less instructions generated, and you still manipulate bits by their ordinal number.

I know that that's faster, but I think there's plenty of cases where you want to use flags in loops...

edit: the reason I was bothering with this is that I have a UI with 24 buttons, each of which set a flag on or off, which makes having a button name be, e.g., "button_num_8388608" a bit weird, but it's of course more straightforward to do (2^(button_num-1)) to get the flag number than to have than to do it the way I originally did.

edit2:

so this would be more straightforward when dealing with loops through flags:

Code:
    #define set_flag_on(flags, flag)   (flags BWOR flag)
    #define set_flag_off(flags, flag)   (flags - (flags BWAND flag))
    #define is_flag_on(flags, flag)   ((flags BWAND flag) != 0)
    
    #define hex_num(value)      (2^(value-1))

and then as you're looping with a counter through the flags, you do hex_num(counter) to get the flag num.

edit3:

and because it's useful (at least I think it is?) to move back to decimals from hexes:

Code:
    #define dec_num(value)      floor((log(value)/log(2)) + 1)

i.e.:

Code:
    display_msg("decimal " + dec_num(bit_14));    //returns 14


edit14456: I think what the last one is useful for is if you want to connect flags with items in a list, say ["flag 1 str", "flag 2 str", "flag 3 str"].
 
Last edited:
small correction to the last one, on the small chance that someone will ever use it :p

Code:
round((log(value)/log(2)) + 1)

because for some very weird reason, some of the floats which show up as 14.00000 or 15.00000 in debug floor to 14 and 14. I have no idea why this is and there doesn't seem to be anything overtly wrong with floor(), given that testing for those values is no problem (maybe the float for 15.0000 is actually 14.99999n but gets displayed as 15.00000?), but eh, just use round to be sure ;).
 
Here's something for the more eccentric modders out there:

Know how there's only one unused stat for critters? Well, what if you wanted to add a few more; you would have to make room right? Well, not necessarily.

STAT_unused accepts an integer of any size, meaning you can stack multiple values in it if you would desire to. Now, the only way the game normally lets you do that is through regular flags, which can let you store 32 boolean 1 or 0 values in one integer. Of course, if you want to make stats for critters, you usually want more of a range than 0-1. So I thought I'd put something together that lets you store either nine 0-9 stats (i.e. you can add 9 additional SPECIAL type attributes if you simply add 1 to them), four 0-99 stats, or two 0-999 stats:

Code:
#define get_flag_ten(flags, flag)  ((flags/(10^(flag-1))) % 10)
#define get_flag_hundred(flags, flag)  ((flags/(100^(flag-1))) % 100)
#define get_flag_thousand(flags, flag)  ((flags/(1000^(flag-1))) % 1000)


#define set_flag_ten(flags, flag, value)  (flags - ((get_flag_ten(flags, flag))*(10^(flag-1))) + (value*(10^(flag-1))))
#define set_flag_hundred(flags, flag, value)  (flags - ((get_flag_hundred(flags, flag))*(100^(flag-1))) + (value*(100^(flag-1))))
#define set_flag_thousand(flags, flag, value)  (flags - ((get_flag_thousand(flags, flag))*(1000^(flag-1))) + (value*(1000^(flag-1))))
[/code]

So, the way you use it is:

Code:
    flags:=15830;       //i.e. for tens: flag 1 = 0, flag 2 = 3, flag 3 = 8, flag 4 = 5, flag 5 = 1, flag 6-9 = 0
    display_msg("flags = " + flags + ", flag 3 = " + get_flag_ten(flags, 3));    //returns 8
    flags:=set_flag_ten(flags, 3, 2);                                            //sets flags to 15230
    display_msg("flags = " + flags + ", flag 3 = " + get_flag_ten(flags, 3));    //returns 2
    //for hundreds: flag 1 = 30, flag 2 = 52, flag 3 = 1, flag 4 = 0
    display_msg("flags = " + flags + ", flag 3 = " + get_flag_hundred(flags, 3));    //returns 1
    flags:=set_flag_hundred(flags, 3, 45);                                           //sets flags to 455230
    display_msg("flags = " + flags + ", flag 3 = " + get_flag_hundred(flags, 3));    //returns 45

Of course you don't get anything like the huge processing advantage from using bitwise operations instead of an array filled with 0-1 values, but I'm guessing it's at least a bit faster still than using an array for this (maybe @phobos2077 knows, or can say if I'm doing something really stupid). Anyway, even if it were slower, it's not like you can store an array inside the critter stats anyway.
 
Last edited by a moderator:
Back
Top