This page is rather stubbly and could use some expansion.
Do I have enough experience to rescue this article?

every little thing counts

few things i picked up along my journey creating characters and etc.
request by replying to @ruins_of on twitter if you have something you want to know,
or want something to be put here

everyone's individual resources

i will list all the separate resources people have made public... atleast the ones i'm actually aware of
(note: the list is WIP)

change the hurtbox

in animation.gml;

hurtboxID.sprite_index = sprite_get("ar_dash_hurtbox");

changing the value of hurtboxID object's sprite_index variable will change the current hurtbox sprite.
it was not documented anywhere except for few select discord messages. there are literally no way we could have known that??????????
hurtboxID has an image_index variable as well (you can read its contents with debug_draw etc) BUT you cannot change its value????
kinda ridiculous for being such a vital part of character to be honest.
that means if you need to animate the hurtbox manually, you have to create a separate sprite for each frame of its animation
AND manually specify what frames to put the specific sprite???????????
there might be some better ways but that's how i managed to do the doublejump hurtbox for Acid Rainbows

do note that it won't help too much by itself
so here's an example application:
[show/hide]

switch (state){ case PS_IDLE: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_IDLE_AIR: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_FIRST_JUMP: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_WALL_JUMP: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_LAND: hurtboxID.sprite_index = sprite_get("ar_crouch_hurtbox"); break; case PS_PRATLAND: hurtboxID.sprite_index = sprite_get("ar_crouch_hurtbox"); break; case PS_LANDING_LAG: hurtboxID.sprite_index = sprite_get("ar_crouch_hurtbox"); break; case PS_WALK: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_WALK_TURN: hurtboxID.sprite_index = sprite_get("ar_hurtbox"); break; case PS_DOUBLE_JUMP: hurtboxID.sprite_index = sprite_get("ar_doublejump_hurtbox"); break; case PS_DASH: hurtboxID.sprite_index = sprite_get("ar_dash_hurtbox"); break; case PS_DASH_START: hurtboxID.sprite_index = sprite_get("ar_dashstart_hurtbox"); break; case PS_DASH_STOP: hurtboxID.sprite_index = sprite_get("ar_dashstop_hurtbox"); break; case PS_DASH_TURN: hurtboxID.sprite_index = sprite_get("ar_dashturn_hurtbox"); break; case PS_WAVELAND: hurtboxID.sprite_index = asset_get("ex_guy_hurt_box"); break; case PS_PARRY: hurtboxID.sprite_index = asset_get("ex_guy_hurt_box"); break; case PS_PARRY_START: hurtboxID.sprite_index = asset_get("ex_guy_hurt_box"); break; case PS_JUMPSQUAT: hurtboxID.sprite_index = sprite_get("ar_crouch_hurtbox"); break; default: break; }

basic form of it is present in the "empty workshop character template" that's in the official doc btw
please note that AR used a bit more nonsense magic to make the doublejump animation work, i simplified(??) the code a bit for public showcase
yes i'm aware "cases" can carry over to cases below if it hasn't been broken (the cat taught me), but i didn't test it yet so i copypasted it there as-is, as a mess

guadua dspecial and its ground detection

i once made a diagram for guadua dspecial if it helps: [link]
so, guadua's dspecial tells us that we can detect the ground and the platform by testing collision with asset_get ("par_block"); and asset_get("par_jumpthrough");.
yes indeed, as with hurtbox, this was not documented anywhere in the official documentation.
...atleast it was mentioned like this in guadua's code...?

clairen plasma field

if you have experience with character making, do i need any more word to explain what i'm gonna explain here?
this too were only explained in few select discord messages unfortunately -
but i have since then datamined things myself and have confirmed its integrity and usability myself
so i figured i could explain it here for others now as well
because what good are knowledge if one just keeps it to themselves?

position_meeting(x,y, asset_get("plasma_field_obj"))

that's right. all you need to do is to check collision with asset_get("plasma_field_obj").
why this is significant is that despite how important it is, it's not documented anywhere!
the least, i have it documented here now. may it help anyone else that has the same issue.

here's an example application:
[show/hide]

if (position_meeting(x,y, asset_get("plasma_field_obj"))){ state = 4; state_timer = 0; sound_play(asset_get("sfx_absa_cloud_crackle")); sound_play(asset_get("sfx_clairen_hit_med")); spawn_hit_fx( x, y, 124 ); }

here's an advanced application:

var col_s = asset_get ("par_block"); var col_j = asset_get("par_jumpthrough"); while ((ray_tmp_y < ray_max_y) && (!position_meeting(ray_x,y+ray_tmp_y, col_s)) && (!position_meeting(ray_x,y+ray_tmp_y, col_j)) && (!position_meeting(ray_x,y+ray_tmp_y, asset_get("plasma_field_obj")))){ //things }

(this stops the "ray" when it hits various things)

the B and the X

the Red B and the white large X. i'm sure you have all seen it once or twice by now
[B] is called solid_32x32, and is the sprite number 0. when the sprite value is "undefined", it will most likely default there.
you will often see it when you call an attack that isn't defined, or the code is failing somewhere in the attack's file.
X is when it can't find the sprite you tried to define.
for example, let's say you do sprite_get("magic") but you don't have a sprite named magic, then it becomes the X.

init_shader and its relevant undocumented code

as of 2020/03/06, a new update for workshop branch were pushed, and came some new functionality.
you could make a new script file with the name of "init_shader.gml" and it constantly ran while any recoloring were done.
with it, there were a few functions added to further take advantage of this.
however, these functions aren't in the official documentations yet... although, it was once present a while back, when the update wasn't out yet.
from once-present documentation in the official website... the undocumented color functions are:

set_character_color_slot( shade_slot, R, G, B, A ) set_article_color_slot( shade_slot, R, G, B, A ) set_character_color_shading( shade_slot, shading_value ) get_color_profile_slot_r( color_slot, shade_slot ) get_color_profile_slot_g( color_slot, shade_slot ) get_color_profile_slot_b( color_slot, shade_slot )

few things i've noted:
for set_character_color_shading, 1 is the default value and 0 is "shadeless".
however, the page specifically stated that you can put larger value than 1.
and now that the update is online, i've confirmed this. 0.5 gave a softer shade, and 2 gave a strong shade.

in fact. i've retrieved the "example code" for set_character_color_shading when the page was still up, so you can have it:
[show/hide]

//this basically makes the 7th slot an "Early Access/Gameboy" style shadeless color if (get_player_color( player ) == 7) { for (var slot_num = 0; slot_num < 4; slot_num++) { set_character_color_shading( slot_num, 0 ); } }

css_draw

if you're even a little bit experienced with coding, you'll figure out what you can do by looking at muno's CSS+ template example.
but as with init_shader.gml, there also came css_draw.gml.
once-present doc info tells that it is "used to draw on top of the playet box on the character select screen." and it does!
unlike with draw_hud, temp_x and temp_y is not available - however, you can ask for x and y normally instead and you seemingly get the top-left location of the player box.
however, if you wanna be safe with it, you can retrieve temp_x/y manually by using this code mista Muno has provided for us:

var temp_x = 23 + 238 * (player - 1); var temp_y = 325;