diff --git a/engine/openbor.c b/engine/openbor.c index b278d0df8..3e12ae272 100644 --- a/engine/openbor.c +++ b/engine/openbor.c @@ -2450,6 +2450,45 @@ void execute_entity_key_script(entity *ent) return; } cs = ent->scripts->key_script; + + /* + * Caskey, Damon V. + * 2026-08-23 + * + * Temporary diagnostic for tracing the SORX aerial-recovery + * regression. Report the complete native gate state only when + * a falling player holds the recovery chord. + */ + if(ent->playerindex >= 0 + && ent->playerindex < MAX_PLAYERS + && ent->drop + && (player[ent->playerindex].keys & (FLAG_MOVEUP | FLAG_JUMP)) + == (FLAG_MOVEUP | FLAG_JUMP)) + { + printf( + "AERIAL_RECOVERY_GATE player=%" PRId64 + " animation=%" PRIu64 + " fall=%" PRIu64 + " frame=%" PRIu64 + " seal=%" PRId64 + " dead=%d" + " guard=%" PRId64 + " maxguard=%d" + " projectile=%d" + " linked=%d\n", + ent->playerindex, + (uint64_t)ent->animnum, + (uint64_t)ANI_FALL, + ent->animpos, + ent->seal, + (ent->death_state & DEATH_STATE_DEAD) != 0, + ent->guardpoints, + ent->modeldata.guardpoints, + ent->projectile, + ent->link != NULL + ); + } + if(Script_IsInitialized(cs)) { ScriptVariant_Init(&tempvar); @@ -13734,42834 +13773,4386 @@ void lcmHandleCommandType(ArgList *arglist, s_model *newchar, char *filename) newchar->type = TYPE_NPC; newchar->bounce = 1; newchar->move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_MAX_Z | MOVE_CONFIG_SUBJECT_TO_MIN_Z | MOVE_CONFIG_SUBJECT_TO_OBSTACLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL); - newchar->move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - } - else if(stricmp(value, "panel") == 0) // NPC type - { - newchar->type = TYPE_PANEL; - newchar->antigravity = 1.0; //float type - newchar->move_config_flags |= (MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_GRAVITY); - } - else - { - borShutdown(1, "Model '%s' has invalid type: '%s'", filename, value); - } -} - -void lcmHandleCommandSubtype(ArgList *arglist, s_model *newchar, char *filename) -{ - char *value = GET_ARGP(1); - int i; - if(stricmp(value, "biker") == 0) - { - newchar->subtype = SUBTYPE_BIKER; - if(newchar->aimove == AIMOVE1_NONE) - { - newchar->aimove = AIMOVE1_NORMAL; - } - newchar->aimove |= AIMOVE1_BIKER; - if(!newchar->offscreenkill) - { - newchar->offscreenkill = 300; - } - - /* Bikers deault to taking double damage. */ - for(i = 0; i < max_attack_types; i++) - { - newchar->defense[i].factor = 2.f; - } - - newchar->move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_MAX_Z | MOVE_CONFIG_SUBJECT_TO_MIN_Z); - newchar->move_config_flags &= ~(MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_SCREEN | MOVE_CONFIG_SUBJECT_TO_WALL); - } - else if(stricmp(value, "arrow") == 0) // 7-1-2005 Arrow type - { - newchar->subtype = SUBTYPE_ARROW; // 7-1-2005 Arrow type - if(newchar->aimove == AIMOVE1_NONE) - { - newchar->aimove = AIMOVE1_NORMAL; - } - newchar->aimove |= AIMOVE1_ARROW; - if(!newchar->offscreenkill) - { - newchar->offscreenkill = 200; - } - - newchar->move_config_flags |= (MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_MAX_Z | MOVE_CONFIG_SUBJECT_TO_MIN_Z); - newchar->move_config_flags &= ~(MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_SCREEN | MOVE_CONFIG_SUBJECT_TO_WALL); - } - else if(stricmp(value, "notgrab") == 0) - { - newchar->subtype = SUBTYPE_NOTGRAB; - } - // ltb 1-18-05 Item Subtype - else if(stricmp(value, "touch") == 0) - { - newchar->subtype = SUBTYPE_TOUCH; - } - else if(stricmp(value, "weapon") == 0) - { - newchar->subtype = SUBTYPE_WEAPON; - } - else if(stricmp(value, "noskip") == 0) // Text animation cannot be skipped if subtype noskip - { - newchar->subtype = SUBTYPE_NOSKIP; - } - else if(stricmp(value, "flydie") == 0) // Obstacle will fly across the screen when hit if subtype flydie - { - newchar->subtype = SUBTYPE_FLYDIE; - } - else if(stricmp(value, "both") == 0) - { - newchar->subtype = SUBTYPE_BOTH; - } - else if(stricmp(value, "project") == 0) - { - newchar->subtype = SUBTYPE_PROJECTILE; - } - else if(stricmp(value, "follow") == 0) - { - newchar->subtype = SUBTYPE_FOLLOW; - child_follow_getsert_property(&newchar->child_follow); - } - else if(stricmp(value, "chase") == 0) - { - newchar->subtype = SUBTYPE_CHASE; - } - // end new subtype - else - { - borShutdown(1, "Model '%s' has invalid subtype: '%s'", filename, value); - } -} - -void lcmHandleCommandSmartbomb(ArgList *arglist, s_model *newchar, char *filename) -{ - //smartbomb now use a normal attack box - if(!newchar->smartbomb) - { - newchar->smartbomb = attack_allocate_object(); - } - else - { - borShutdown(1, "Model '%s' has multiple smartbomb commands defined.", filename); - } - - newchar->smartbomb->attack_force = atoi(GET_ARGP(1)); // Special force - newchar->smartbomb->attack_type = atoi(GET_ARGP(2)); // Special attack type - newchar->smartbomb->attack_drop = 1; //by default - newchar->smartbomb->dropv.y = default_model_dropv.y; - - if(newchar->smartbomb->attack_type == ATK_BLAST) - { - newchar->smartbomb->blast = 1; - newchar->smartbomb->dropv.x = default_model_dropv.x * 2.083f; - } - else - { - newchar->smartbomb->dropv.x = default_model_dropv.x; - } - - if(newchar->smartbomb->attack_type == ATK_FREEZE) - { - newchar->smartbomb->freeze = 1; - newchar->smartbomb->forcemap = MAP_TYPE_FREEZE; - newchar->smartbomb->attack_drop = 0; - } - else if(newchar->smartbomb->attack_type == ATK_STEAL) - { - newchar->smartbomb->steal = 1; - } - - if(newchar->type == TYPE_ITEM) - { - newchar->dofreeze = 0; // Items don't animate - newchar->smartbomb->freezetime = atoi(GET_ARGP(3)) * global_config.game_speed; - } - else - { - newchar->dofreeze = atoi(GET_ARGP(3)); // Are all animations frozen during special - newchar->smartbomb->freezetime = atoi(GET_ARGP(4)) * global_config.game_speed; - } -} - -/* -* Caskey, Damon V. -* 2019-11-22 -* -* Return type flag from string input. -*/ -e_entity_type get_type_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_entity_type flag; - } item_lookup_table[] = { - {"end_level", TYPE_ENDLEVEL}, - {"enemy", TYPE_ENEMY}, - {"item", TYPE_ITEM}, - {"no_copy", TYPE_NO_COPY}, - {"none", TYPE_NONE}, - {"npc", TYPE_NPC}, - {"obstacle", TYPE_OBSTACLE}, - {"playa", TYPE_PLAYER}, // :) - {"player", TYPE_PLAYER}, - {"projectile", TYPE_PROJECTILE}, - {"shot", TYPE_SHOT}, - {"steamer", TYPE_STEAMER}, - {"text_box", TYPE_TEXTBOX}, - {"trap", TYPE_TRAP}, - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown type (%s). \n", value); - return TYPE_UNKNOWN; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read entity type arguments directly from the source line - and combine their corresponding type flags. -*/ -e_entity_type get_type_from_command_line(const char* command_line) -{ - const char* value; - s_command_argument_reader reader; - e_entity_type result = TYPE_UNDECLARED; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= get_type_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Backport weapon loss conditions values -* to legacy weapon loss for backward -* compatability. -*/ -e_weapon_loss_condition_legacy weapon_loss_condition_interpret_to_legacy(e_weapon_loss_condition weapon_loss_condition_value) -{ - e_weapon_loss_condition_legacy result = WEAPLOSS_TYPE_ANY; - - if ((weapon_loss_condition_value & WEAPON_LOSS_CONDITION_DEFAULT) == WEAPON_LOSS_CONDITION_DEFAULT) - { - result |= WEAPLOSS_TYPE_ANY; - return result; - } - - if (weapon_loss_condition_value & WEAPON_LOSS_CONDITION_DEATH) - { - result |= WEAPLOSS_TYPE_DEATH; - return result; - } - - if (weapon_loss_condition_value & WEAPLOSS_TYPE_KNOCKDOWN) - { - result |= WEAPON_LOSS_CONDITION_FALL; - return result; - } - - if (weapon_loss_condition_value & WEAPLOSS_TYPE_CHANGE) - { - result |= WEAPON_LOSS_CONDITION_STAGE; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Interpret legacy weaploss commands into -* weapon loss bits per orginal documentation. -*/ -e_weapon_loss_condition weapon_loss_condition_interpret_from_legacy_weaploss(e_weapon_loss_condition weapon_loss_condition_value, e_weapon_loss_condition_legacy legacy_value) -{ - switch (legacy_value) - { - case WEAPLOSS_TYPE_ANY: - - weapon_loss_condition_value |= WEAPON_LOSS_CONDITION_DEFAULT; - break; - - case WEAPLOSS_TYPE_KNOCKDOWN: - - weapon_loss_condition_value |= WEAPON_LOSS_CONDITION_FALL; - break; - - case WEAPLOSS_TYPE_DEATH: - - weapon_loss_condition_value |= WEAPON_LOSS_CONDITION_PAIN; - break; - - case WEAPLOSS_TYPE_CHANGE: - - weapon_loss_condition_value |= WEAPON_LOSS_CONDITION_STAGE; - break; - - default: - - weapon_loss_condition_value |= WEAPON_LOSS_CONDITION_DEFAULT; - - break; - } - - return weapon_loss_condition_value; -} - -/* -* Caskey, Damon V. -* 2022-05-02 -* -* Accept string input and return -* matching constant. -*/ -e_weapon_loss_condition get_weapon_loss_from_argument(const char* value) -{ - e_weapon_loss_condition result; - - if (stricmp(value, "none") == 0) - { - result = WEAPON_LOSS_CONDITION_NONE; - } - if (stricmp(value, "damage") == 0) - { - result = WEAPON_LOSS_CONDITION_DAMAGE; - } - else if (stricmp(value, "death") == 0) - { - result = WEAPON_LOSS_CONDITION_DEATH; - } - else if (stricmp(value, "fall") == 0) - { - result = WEAPON_LOSS_CONDITION_FALL; - } - else if (stricmp(value, "grabbed") == 0) - { - result = WEAPON_LOSS_CONDITION_GRABBED; - } - else if (stricmp(value, "grabbing") == 0) - { - result = WEAPON_LOSS_CONDITION_GRABBING; - } - else if (stricmp(value, "land_damage") == 0) - { - result = WEAPON_LOSS_CONDITION_LAND_DAMAGE; - } - else if (stricmp(value, "pain") == 0) - { - result = WEAPON_LOSS_CONDITION_PAIN; - } - else if (stricmp(value, "stage") == 0) - { - result = WEAPON_LOSS_CONDITION_STAGE; - } - else if (stricmp(value, "default") == 0) - { - result = WEAPON_LOSS_CONDITION_DEFAULT; - } - else - { - result = WEAPON_LOSS_CONDITION_DEFAULT; - printf("\n\n Unknown weapon loss config value (%s), using 'default'. \n", value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-05-02 -* -* Populate weapon loss model property -* from text arguments. -*/ -void lcmHandleCommandWeaponLossCondition( - const char* command_line, - s_model* newchar -) -{ - const char* value; - s_command_argument_reader reader; - - newchar->weapon_properties.loss_condition = WEAPON_LOSS_CONDITION_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - newchar->weapon_properties.loss_condition |= get_weapon_loss_from_argument(value); - } - -} - -/* -* Caskey, Damon V. -* 2022-05-24 -* -* Read a text argument for model copy flag -* and output appropriate constant. If input -* is legacy integer, we just pass it on. -*/ -e_model_copy get_model_flag_from_argument( - const char* filename, - const char* command, - const char* value -) -{ - e_model_copy result = MODEL_COPY_FLAG_NONE; - - if (stricmp(value, "none") == 0) - { - result = MODEL_COPY_FLAG_NONE; - } - else if (stricmp(value, "no_basic") == 0) - { - result = MODEL_COPY_FLAG_NO_BASIC; - } - else if (stricmp(value, "no_weapon") == 0) - { - result = MODEL_COPY_FLAG_NO_WEAPON; - } - else if (stricmp(value, "no_script") == 0) - { - result = MODEL_COPY_FLAG_NO_SCRIPT; - } - else - { - /* - * For legacy compatability. Get integer - * value and then change it to current - * constants. - */ - - result = getValidInt(value, filename, command); - result = get_model_flag_from_legacy_int(result); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-01-30 -* -* Accept legacy integer model flag int -* and output current constant. -*/ -e_model_copy get_model_flag_from_legacy_int(int legacy_int) -{ - e_model_copy result = MODEL_COPY_FLAG_NONE; - - switch (legacy_int) - { - case 0: - default: - result = MODEL_COPY_FLAG_NONE; - case 1: - result = (MODEL_COPY_FLAG_NO_BASIC); - break; - case 3: - result = (MODEL_COPY_FLAG_NO_BASIC | MODEL_COPY_FLAG_NO_WEAPON); - break; - case 4: - result = (MODEL_COPY_FLAG_NO_BASIC | MODEL_COPY_FLAG_NO_WEAPON | MODEL_COPY_FLAG_NO_SCRIPT); - break; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-05-24 -* -* Populate model flag property -* from text arguments. -*/ -void lcmHandleCommandModelFlag( - char* filename, - char* command, - const char* command_line, - s_model* newchar -) -{ - const char* value; - s_command_argument_reader reader; - - newchar->model_flag = MODEL_COPY_FLAG_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - newchar->model_flag |= get_model_flag_from_argument(filename, command, value); - } - -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Backport air control values to legacy -* jumpmove for backward compatability. -*/ -e_air_control_legacy_x air_control_interpret_to_legacy_jumpmove_x(e_air_control air_control_value) -{ - e_air_control_legacy_x result = AIR_CONTROL_LEGACY_X_NONE; - - if (air_control_value & AIR_CONTROL_JUMP_TURN) - { - result |= AIR_CONTROL_LEGACY_X_FLIP; - } - - if (air_control_value & AIR_CONTROL_JUMP_X_ADJUST) - { - result |= AIR_CONTROL_LEGACY_X_ADJUST; - } - - if (air_control_value & AIR_CONTROL_JUMP_X_MOVE) - { - result |= AIR_CONTROL_LEGACY_X_MOVE; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Backport air control values to legacy -* jumpmove for backward compatability. -*/ -e_air_control_legacy_z air_control_interpret_to_legacy_jumpmove_z(e_air_control air_control_value) -{ - e_air_control_legacy_z result = AIR_CONTROL_LEGACY_Z_NONE; - - if (air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result |= AIR_CONTROL_LEGACY_Z_MOMENTUM; - } - - if (air_control_value & AIR_CONTROL_JUMP_Z_ADJUST) - { - result |= AIR_CONTROL_LEGACY_Z_ADJUST; - } - - if (air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result |= AIR_CONTROL_LEGACY_Z_MOMENTUM; - } - - if (air_control_value & AIR_CONTROL_JUMP_TURN && air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result = AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Backport air control values to legacy -* jumpmove for backward compatability. -*/ -e_air_control_legacy_x air_control_interpret_to_legacy_walkoffmove_x(e_air_control air_control_value) -{ - e_air_control_legacy_x result = AIR_CONTROL_LEGACY_X_NONE; - - if (air_control_value & AIR_CONTROL_WALKOFF_TURN) - { - result |= AIR_CONTROL_LEGACY_X_FLIP; - } - - if (air_control_value & AIR_CONTROL_WALKOFF_X_ADJUST) - { - result |= AIR_CONTROL_LEGACY_X_ADJUST; - } - - if (air_control_value & AIR_CONTROL_WALKOFF_X_MOVE) - { - result |= AIR_CONTROL_LEGACY_X_MOVE; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Backport air control values to legacy -* jumpmove for backward compatability. -*/ -e_air_control_legacy_z air_control_interpret_to_legacy_walkoffmove_z(e_air_control air_control_value) -{ - e_air_control_legacy_z result = AIR_CONTROL_LEGACY_Z_NONE; - - if (air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result |= AIR_CONTROL_LEGACY_Z_MOMENTUM; - } - - if (air_control_value & AIR_CONTROL_JUMP_Z_ADJUST) - { - result |= AIR_CONTROL_LEGACY_Z_ADJUST; - } - - if (air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result |= AIR_CONTROL_LEGACY_Z_MOMENTUM; - } - - if (air_control_value & AIR_CONTROL_JUMP_TURN && air_control_value & AIR_CONTROL_JUMP_Z_INITIAL) - { - result = AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Interpret legacy Jumpmove commands into -* air control bits per orginal documentaiton. -* -* low byte: 0 default 1 flip in air, 2 move in air, 3 flip and move -*/ -e_air_control air_control_interpret_from_legacy_jumpmove_x(e_air_control air_control_value, e_air_control_legacy_x legacy_value) -{ - switch (legacy_value) - { - case AIR_CONTROL_LEGACY_X_NONE: - - air_control_value &= ~(AIR_CONTROL_JUMP_TURN | AIR_CONTROL_JUMP_X_ADJUST | AIR_CONTROL_JUMP_X_MOVE); - break; - - case AIR_CONTROL_LEGACY_X_FLIP: - - air_control_value |= AIR_CONTROL_JUMP_TURN; - break; - - case AIR_CONTROL_LEGACY_X_ADJUST: - - air_control_value |= AIR_CONTROL_JUMP_X_ADJUST; - break; - - case AIR_CONTROL_LEGACY_X_ADJUST_AND_FLIP: - - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_X_ADJUST; - break; - - case AIR_CONTROL_LEGACY_X_MOVE: - case AIR_CONTROL_LEGACY_X_MOVE_ALT: - - air_control_value |= AIR_CONTROL_JUMP_X_MOVE; - break; - - case AIR_CONTROL_LEGACY_X_MOVE_AND_FLIP: - - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_X_MOVE; - break; - - default: - - /* - * Handle non-existent duplicate options - * listed in the legacy manual. - */ - - if (legacy_value > AIR_CONTROL_LEGACY_X_MOVE_ALT) - { - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_X_MOVE; - } - - break; - } - - return air_control_value; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* See interpret_legacy_jumpmove_x(); -*/ -e_air_control air_control_interpret_from_legacy_jumpmove_z(e_air_control air_control_value, e_air_control_legacy_z legacy_value) -{ - switch (legacy_value) - { - case AIR_CONTROL_LEGACY_Z_NONE: - - air_control_value &= ~(AIR_CONTROL_JUMP_TURN | AIR_CONTROL_JUMP_Z_ADJUST | AIR_CONTROL_JUMP_Z_INITIAL); - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM: - - air_control_value |= AIR_CONTROL_JUMP_Z_INITIAL; - break; - - case AIR_CONTROL_LEGACY_Z_ADJUST: - - air_control_value |= AIR_CONTROL_JUMP_Z_INITIAL; - air_control_value |= AIR_CONTROL_JUMP_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_ADJUST: - - air_control_value |= AIR_CONTROL_JUMP_Z_INITIAL; - air_control_value |= AIR_CONTROL_JUMP_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP: - - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_Z_MOVE; - - break; - - default: - - /* - * Handle non-existent duplicate options - * listed in the legacy manual. - */ - - if (legacy_value > AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP) - { - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_Z_MOVE; - } - - break; - - } - - return air_control_value; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Interpret legacy walkmove commands into -* air control bits per orginal documentaiton. -* -* low byte: 0 default 1 flip in air, 2 move in air, 3 flip and move -*/ -e_air_control air_control_interpret_from_legacy_walkoffmove_x(e_air_control air_control_value, e_air_control_legacy_x legacy_value) -{ - switch (legacy_value) - { - case AIR_CONTROL_LEGACY_X_NONE: - - air_control_value &= ~(AIR_CONTROL_WALKOFF_TURN | AIR_CONTROL_WALKOFF_X_ADJUST); - break; - - case AIR_CONTROL_LEGACY_X_FLIP: - - air_control_value |= AIR_CONTROL_WALKOFF_TURN; - break; - - case AIR_CONTROL_LEGACY_X_ADJUST: - - air_control_value |= AIR_CONTROL_WALKOFF_X_ADJUST; - break; - - case AIR_CONTROL_LEGACY_X_ADJUST_AND_FLIP: - case AIR_CONTROL_LEGACY_X_MOVE_AND_FLIP: - - air_control_value |= AIR_CONTROL_WALKOFF_TURN; - air_control_value |= AIR_CONTROL_WALKOFF_X_ADJUST; - break; - - case AIR_CONTROL_LEGACY_X_MOVE: - case AIR_CONTROL_LEGACY_X_MOVE_ALT: - - air_control_value |= AIR_CONTROL_WALKOFF_X_ADJUST; - break; - - default: - - /* - * Handle non-existent duplicate options - * listed in the legacy manual. - */ - - if (legacy_value > AIR_CONTROL_LEGACY_X_MOVE_ALT) - { - air_control_value |= AIR_CONTROL_WALKOFF_TURN; - air_control_value |= AIR_CONTROL_WALKOFF_X_ADJUST; - } - - break; - } - - return air_control_value; -} - -/* -* Caskey, Damon V. -* 2022-04-26 -* -* Interpret legacy walkmove commands into -* air control bits per orginal documentaiton. -* -* low byte: 0 default 1 flip in air, 2 move in air, 3 flip and move -*/ -e_air_control air_control_interpret_from_legacy_walkoffmove_z(e_air_control air_control_value, e_air_control_legacy_z legacy_value) -{ - switch (legacy_value) - { - case AIR_CONTROL_LEGACY_Z_NONE: - - air_control_value &= ~AIR_CONTROL_WALKOFF_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM: - - air_control_value |= AIR_CONTROL_WALKOFF_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_ADJUST: - - air_control_value |= AIR_CONTROL_WALKOFF_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_ADJUST: - - air_control_value |= AIR_CONTROL_WALKOFF_Z_ADJUST; - break; - - case AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP: - - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_WALKOFF_Z_ADJUST; - - break; - - default: - - /* - * Handle non-existent duplicate options - * listed in the legacy manual. - */ - - if (legacy_value > AIR_CONTROL_LEGACY_Z_MOMENTUM_AND_FLIP) - { - air_control_value |= AIR_CONTROL_JUMP_TURN; - air_control_value |= AIR_CONTROL_JUMP_Z_MOVE; - } - - break; - - } - - return air_control_value; -} - -/* -* Caskey, Damon V. -* 2022-04-28 -* -* Accept string input and return -* matching constant. -*/ -e_air_control find_air_control_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_air_control flag; - } item_lookup_table[] = { - {"none", AIR_CONTROL_NONE}, - {"jump_disable", AIR_CONTROL_JUMP_DISABLE}, - {"jump_turn", AIR_CONTROL_JUMP_TURN}, - {"jump_x_adjust", AIR_CONTROL_JUMP_X_ADJUST}, - {"jump_x_move", AIR_CONTROL_JUMP_X_MOVE}, - {"jump_x_stop", AIR_CONTROL_JUMP_X_STOP}, - {"jump_y_stop", AIR_CONTROL_JUMP_Y_STOP}, - {"jump_z_adjust", AIR_CONTROL_JUMP_Z_ADJUST}, - {"jump_z_initial", AIR_CONTROL_JUMP_Z_INITIAL}, - {"jump_z_move", AIR_CONTROL_JUMP_Z_MOVE}, - {"jump_z_stop", AIR_CONTROL_JUMP_Z_STOP}, - {"walkoff_turn", AIR_CONTROL_WALKOFF_TURN}, - {"walkoff_x_adjust", AIR_CONTROL_WALKOFF_X_ADJUST}, - {"walkoff_x_move", AIR_CONTROL_WALKOFF_X_MOVE}, - {"walkoff_x_stop", AIR_CONTROL_WALKOFF_X_STOP}, - {"walkoff_z_adjust", AIR_CONTROL_WALKOFF_Z_ADJUST}, - {"walkoff_z_move", AIR_CONTROL_WALKOFF_Z_MOVE}, - {"walkoff_z_stop", AIR_CONTROL_WALKOFF_Z_STOP}, - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown air control flag (%s). \n", value); - return AIR_CONTROL_NONE; -} - -/* -* Caskey, Damon V. -* 2022-04-28 -* -* Populate air control model property -* from text arguments. -*/ -void lcmHandleCommandAirControl( - const char* command_line, - s_model* newchar -) -{ - const char* value; - s_command_argument_reader reader; - - newchar->air_control = AIR_CONTROL_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - newchar->air_control |= find_air_control_from_string(value); - } - -} - -/* -* Caskey, Damon V. -* 2019-11-22 -* -* Accept string input and return -* matching constant. -*/ -e_move_config_flags find_move_config_flags_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_move_config_flags flag; - } item_lookup_table[] = { - {"none", MOVE_CONFIG_NONE}, - {"no_adjust_base", MOVE_CONFIG_NO_ADJUST_BASE}, - {"no_flip", MOVE_CONFIG_NO_FLIP}, - {"no_hit_head", MOVE_CONFIG_NO_HIT_HEAD}, - {"no_move", MOVE_CONFIG_NO_MOVE}, - {"projectile_base_die", MOVE_CONFIG_PROJECTILE_BASE_DIE}, - {"projectile_wall_bounce", MOVE_CONFIG_PROJECTILE_WALL_BOUNCE}, - {"subject_to_basemap", MOVE_CONFIG_SUBJECT_TO_BASEMAP}, - {"subject_to_gravity", MOVE_CONFIG_SUBJECT_TO_GRAVITY}, - {"subject_to_hole", MOVE_CONFIG_SUBJECT_TO_HOLE}, - {"subject_to_max_z", MOVE_CONFIG_SUBJECT_TO_MAX_Z}, - {"subject_to_min_z", MOVE_CONFIG_SUBJECT_TO_MIN_Z}, - {"subject_to_obstacle", MOVE_CONFIG_SUBJECT_TO_OBSTACLE}, - {"subject_to_platform", MOVE_CONFIG_SUBJECT_TO_PLATFORM}, - {"subject_to_screen", MOVE_CONFIG_SUBJECT_TO_SCREEN}, - {"subject_to_wall", MOVE_CONFIG_SUBJECT_TO_WALL} - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown move config flag (%s). \n", value); - return MOVE_CONFIG_NONE; -} - -/* -* Caskey, Damon V. -* 2021-08-24 -* -* Read a text argument for ko map type and -* output appropriate constant. If input is -* legacy integer, we just pass it on. -*/ -e_ko_colorset_config komap_type_get_value_from_argument(char* filename, char* command, char* value) -{ - e_ko_colorset_config result = KO_COLORSET_CONFIG_INSTANT; - - if (stricmp(value, "instant") == 0) - { - result = KO_COLORSET_CONFIG_INSTANT; - } - else if (stricmp(value, "finish") == 0) - { - result = KO_COLORSET_CONFIG_COMPLETE; - } - else - { - result = getValidInt(value, filename, command); - } - - return result; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read movement configuration arguments directly from the - source line and combine their corresponding behavior flags. -*/ -e_move_config_flags get_move_config_flags_from_command_line( - const char* command_line -) -{ - const char* value; - s_command_argument_reader reader; - e_move_config_flags result = MOVE_CONFIG_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= find_move_config_flags_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2022-04-28 -* -* Accept string input and return -* matching constant. -*/ -e_cheat_options find_cheat_options_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_cheat_options flag; - } item_lookup_table[] = { - {"none", CHEAT_OPTIONS_NONE}, - {"credits_active", CHEAT_OPTIONS_CREDITS_ACTIVE}, - {"credits_menu", CHEAT_OPTIONS_CREDITS_MENU}, - {"energy_active", CHEAT_OPTIONS_ENERGY_ACTIVE}, - {"energy_menu", CHEAT_OPTIONS_ENERGY_MENU}, - {"health_active", CHEAT_OPTIONS_HEALTH_ACTIVE}, - {"health_menu", CHEAT_OPTIONS_HEALTH_MENU}, - {"implacable_active", CHEAT_OPTIONS_IMPLACABLE_ACTIVE}, - {"implacable_menu", CHEAT_OPTIONS_IMPLACABLE_MENU}, - {"master_menu", CHEAT_OPTIONS_MASTER_MENU}, - {"lives_active", CHEAT_OPTIONS_LIVES_ACTIVE}, - {"lives_menu", CHEAT_OPTIONS_LIVES_MENU}, - {"multihit_active", CHEAT_OPTIONS_MULTIHIT_ACTIVE}, - {"multihit_menu", CHEAT_OPTIONS_MULTIHIT_MENU}, - {"touch_of_death_active", CHEAT_OPTIONS_TOD_ACTIVE}, - {"touch_of_death_menu", CHEAT_OPTIONS_TOD_MENU} - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown cheat option (%s). \n", value); - return CHEAT_OPTIONS_NONE; - -} - -/* -* Caskey, Damon V. -* 2022-04-28 -* -* Populate global config cheats -* property from text arguments. -*/ -void lcmHandleCommandGlobalConfigCheats(const char* command_line) -{ - const char* value; - s_command_argument_reader reader; - - global_config.cheats = CHEAT_OPTIONS_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - global_config.cheats |= find_cheat_options_from_string(value); - } - -} - -/* -* Caskey, Damon V. -* 2022-06-08 -* -* Accept string input and return -* matching constant. -*/ -e_aimove get_aimove_constant_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_aimove flag; - } item_lookup_table[] = { - {"none", AIMOVE1_NONE}, - {"default", AIMOVE_SPECIAL_DEFAULT}, - {"chase", AIMOVE1_CHASE}, - {"chasez", AIMOVE1_CHASEZ}, - {"chasex", AIMOVE1_CHASEX}, - {"avoid", AIMOVE1_AVOID}, - {"avoidz", AIMOVE1_AVOIDZ}, - {"avoidx", AIMOVE1_AVOIDX}, - {"wander", AIMOVE1_WANDER}, - {"biker", AIMOVE1_BIKER}, - {"arrow", AIMOVE1_ARROW}, - {"star", AIMOVE1_STAR}, - {"bomb", AIMOVE1_BOMB}, - {"nomove", AIMOVE1_NOMOVE}, - {"ignoreholes", AIMOVE2_IGNOREHOLES}, - {"notargetidle", AIMOVE2_NOTARGETIDLE} - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown AIMove flag (%s). \n", value); - return AIMOVE1_NONE; - -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read AI movement arguments directly from the source line - and combine them with the supplied default behavior flags. -*/ -e_aimove get_aimove_from_command_line( - const char* command_line, - e_aimove default_value -) -{ - const char* value; - s_command_argument_reader reader; - e_aimove result = default_value; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= get_aimove_constant_from_string(value); - } - - return result; -} - -void lcmHandleCommandAiattack(ArgList *arglist, s_model *newchar, int *aiattackset, char *filename) -{ - char *value = GET_ARGP(1); - if(!*aiattackset) - { - newchar->aiattack = 0; - *aiattackset = 1; - } - - //main A.I. move switches - if(value && value[0]) - { - if(stricmp(value, "normal") == 0) - { - newchar->aiattack |= AIATTACK1_NORMAL; - } - else if(stricmp(value, "always") == 0) - { - newchar->aiattack |= AIATTACK1_ALWAYS; - } - else if(stricmp(value, "noattack") == 0) - { - newchar->aiattack |= AIATTACK1_NOATTACK; - } - else - { - printf("Model '%s' has invalid A.I. attack switch: '%s'\n", filename, value); - } - } - /* - value = GET_ARGP(2); - //sub A.I. move switches - if(value && value[0]) - { - - }*/ -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read weapon model names directly from the source line, - allocate an exact-sized list, and safely replace any list - owned by the model without modifying inherited storage. -*/ -void lcmHandleCommandWeapons( - const char* command_line, - s_model* newchar -) -{ - const char* value; - s_command_argument_reader reader; - s_command_token token; - s_command_token_reader count_reader = { - .cursor = command_line - }; - int* weapon_list; - size_t weapon_count = 0; - size_t weapon_index = 0; - - /* Skip the command name before counting its values. */ - command_token_reader_next(&count_reader, &token); - - while(command_token_reader_next(&count_reader, &token)) { - if(weapon_count == INT_MAX) { - borShutdown( - 1, - "Weapon list exceeds the supported integer count range.\n" - ); - } - - weapon_count++; - } - - if(!weapon_count) { - return; - } - - if(weapon_count > SIZE_MAX / sizeof(*weapon_list)) { - borShutdown(1, E_OUT_OF_MEMORY); - } - - weapon_list = malloc(sizeof(*weapon_list) * weapon_count); - - if(!weapon_list) { - borShutdown(1, E_OUT_OF_MEMORY); - } - - /* - * Weapon list arguments left to right, until we - * reach this model's number of weapons. If none, - * populate with "none" index. Otherwise we find - * a model index to populate with. - */ - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - weapon_list[weapon_index] = stricmp(value, "none") != 0 - ? get_cached_model_index(value) - : MODEL_INDEX_NONE; - - weapon_index++; - } - - if(hasFreetype(newchar, MF_WEAPONS) - && newchar->weapon_properties.weapon_list) { - free(newchar->weapon_properties.weapon_list); - } - - newchar->weapon_properties.weapon_list = weapon_list; - newchar->weapon_properties.weapon_count = (int)weapon_count; - newchar->weapon_properties.weapon_state |= WEAPON_STATE_HAS_LIST; - newchar->freetypes |= MF_WEAPONS; -} - -//fetch string between next @script and @end_script -//return end position of @end_script, count from current position -static size_t fetchInlineScript(char *buf, char **scriptbuf, ptrdiff_t *ppos, size_t *plen) -{ - ptrdiff_t pos = *ppos; - size_t len; - while(!starts_with(buf + pos, "@script")) - { - pos++; - } - pos += strclen("@script"); - len = 0; - while(!starts_with(buf + pos, "@end_script")) - { - len++; - pos++; - } - *scriptbuf = malloc(sizeof(**scriptbuf) * len + 1); - strncpy(*scriptbuf, buf + pos - len, len); - (*scriptbuf)[len] = 0; - pos += strclen("@end_script"); - - *ppos = pos; - *plen = len; - return pos; -} - -size_t lcmHandleCommandScripts(ArgList *arglist, char *buf, Script *script, char *scriptname, char *filename, int compile, int first) -{ - ptrdiff_t pos = 0; - size_t len = 0; - int result = 0; - char *scriptbuf = NULL; - Script_Init(script, scriptname, filename, first); - if(stricmp(GET_ARGP(1), "@script") == 0) - { - fetchInlineScript(buf, &scriptbuf, &pos, &len); - if(scriptbuf) - { - result = Script_AppendText(script, scriptbuf, filename); - free(scriptbuf); - } - } - else - { - result = load_script(script, GET_ARGP(1)); - } - if(result) - { - if(compile) - { - Script_Compile(script); - } - } - else - { - borShutdown(1, "Unable to load %s '%s' in file '%s'.\n", scriptname, GET_ARGP(1), filename); - } - return pos; -} - -ptrdiff_t lcmScriptAvoidComment(char *buf, size_t buf_len, ptrdiff_t pos) -{ - if ( buf && buf[0] ) - { - unsigned char c = '\0'; - ptrdiff_t pre_pos = pos; - - c = buf[pos]; - if (c == '/') - { - ++pos; - if ( pos < buf_len-1 ) - { - c = buf[pos]; - if (c == '/') - { - while( pos < buf_len && c != 0x0D && c != 0x0A ) - { - ++pos; - c = buf[pos]; - } - if (pos < buf_len) ++pos; - pos = lcmScriptAvoidComment(buf,buf_len,pos); - return pos; - } - else if (c == '*') - { - ++pos; - if ( pos >= buf_len ) return pos; - c = buf[pos]; - while( pos+1 < buf_len ) - { - if ( c == '*' ) - { - unsigned char c2 = buf[pos+1]; - - if ( c2 == '/' ) - { - pos += 2; - pos = lcmScriptAvoidComment(buf,buf_len,pos); - return pos; - } - } - ++pos; - c = buf[pos]; - } - } - else - { - return pre_pos; - } - } - } else return pre_pos; - } - - return pos; -} - -ptrdiff_t lcmScriptGetMainPos(char *buf, size_t *buf_len) -{ - if ( buf && buf[0] ) - { - size_t len = *buf_len; - ptrdiff_t pos = 0; - enum {START,PRE0,PRE1,PRE2,PRE3,M0,M1,M2,M3,P0,P1,END} current_state = START; - unsigned char c = '\0'; - int index_res = -1; - - pos = lcmScriptAvoidComment(buf,len,pos); - c = (unsigned char)tolower((int)buf[pos]); - while ( pos < len && current_state != END ) - { - switch(current_state) - { - case START: - { - if ( c == 'v' ) - { - index_res = pos; // store void main() start pos - current_state = PRE0; - } - else if ( c == ' ' || c == '\n' || c == '\r' || c == 0x0D || c == 0x0A || c == '\t' ) current_state = START; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case PRE0: - { - if ( c == 'o' ) current_state = PRE1; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case PRE1: - { - if ( c == 'i' ) current_state = PRE2; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case PRE2: - { - if ( c == 'd' ) current_state = PRE3; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case PRE3: - { - if ( c == 'm' ) current_state = M0; - else if ( c == ' ' || c == '\n' || c == '\r' || c == 0x0D || c == 0x0A || c == '\t' ) current_state = PRE3; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case M0: - { - if ( c == 'a' ) current_state = M1; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case M1: - { - if ( c == 'i' ) current_state = M2; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case M2: - { - if ( c == 'n' ) current_state = M3; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case M3: - { - if ( c == '(' ) current_state = P0; - else if ( c == ' ' || c == '\n' || c == '\r' || c == 0x0D || c == 0x0A || c == '\t' ) current_state = M3; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case P0: - { - if ( c == ')' ) current_state = P1; - else if ( c == ' ' || c == '\n' || c == '\r' || c == 0x0D || c == 0x0A || c == '\t' ) current_state = P0; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case P1: - { - if ( c == '{' ) - { - current_state = END; - if (++pos < len) - { - *buf_len = pos-index_res; - return index_res; - } - else return -1; - } - else if ( c == ' ' || c == '\n' || c == '\r' || c == 0x0D || c == 0x0A || c == '\t' ) current_state = P1; - else if ( c == '\0' ) return -1; - else current_state = START; - break; - } - case END: - default: - break; - } - ++pos; // at the end position after the '{' - if (current_state == END) - { - if (pos < len) - { - *buf_len = pos-index_res; - return index_res; - } - else return -1; - } - pos = lcmScriptAvoidComment(buf,len,pos); - c = (unsigned char)tolower((int)buf[pos]); - } // end while loop - - if (current_state == END) - { - if (pos < len) - { - *buf_len = pos-index_res; - return index_res; - } - else return -1; - } else return -1; - } - - return -1; -} - -// add main (or add vars in main) - used for animationscript file -size_t lcmScriptAddMain(char **buf) -{ - size_t len = 0, len2 = 0, buf_len = 0; - ptrdiff_t pos = 0; - char* newbuf = NULL; - - if ( (*buf) && (*buf)[0] ) - { - buf_len = len = strlen(*buf); - - pos = lcmScriptGetMainPos(*buf,&buf_len); - if ( pos == -1 ) // main() not found! - { - char mtxt[] = "\n\nvoid main()\n{\n int frame = getlocalvar(\"frame\");\n int animhandle = getlocalvar(\"animhandle\");\n\n}\n\n"; - - pos += buf_len; - pos = len; // pos before '\0' (at last char) - len2 = strlen(mtxt); - newbuf = calloc(sizeof(**buf)*len + sizeof(mtxt)*len2 + 1, sizeof(char)); - strncpy(newbuf, *buf, pos); - strcpy(newbuf+pos, mtxt); - newbuf[len+len2] = '\0'; - - free( (*buf) ); - (*buf) = newbuf; - - //printf("written main in buffer\n%s\n",newbuf); - } - else - { - int pos2 = 0; - char mtxt[] = "\n\nvoid main()\n{\n int frame = getlocalvar(\"frame\");\n int animhandle = getlocalvar(\"animhandle\");\n\n"; - - pos2 = pos + buf_len; - len2 = strlen(mtxt); - - newbuf = calloc(sizeof(**buf)*pos + sizeof(mtxt)*len2 + sizeof(**buf)*(len-pos2) + 1, sizeof(char)); - strncpy(newbuf, *buf, pos); - strcpy(newbuf+pos, mtxt); - strncpy(newbuf+pos+len2, *buf+pos2, len-pos2); - newbuf[pos+len2+len-pos2] = '\0'; - - free( (*buf) ); - (*buf) = newbuf; - - //printf("search for main in buffer\n%s pos:%d\n",*buf,pos); - } - - //printf("search for main in buffer\n%s pos:%d\n",*buf,pos); - } - - return len; -} - -// used to join animationscript @script/@cmd width animationscript file main() -size_t lcmScriptJoinMain(char **buf, char *first_buf) -{ - size_t len = 0, len2 = 0, buf_len = 0; - ptrdiff_t pos = 0; - int pcount = 0; - char* newbuf = NULL; - - if ( (*buf) && first_buf && (*buf)[0] && first_buf[0] ) - { - buf_len = len = strlen(*buf); - len2 = strlen(first_buf); - - pos = lcmScriptGetMainPos(*buf,&buf_len); - pos += buf_len; - - pcount = 1; - while(pcount > 0) - { - if( (*buf)[pos] == '{' ) ++pcount; - else if( (*buf)[pos] == '}' ) --pcount; - pos++; - } - --pos; // back to last '}' of main() - - newbuf = calloc(sizeof(**buf)*len + sizeof(*first_buf)*len2 + 1,sizeof(char)); - strncpy(newbuf, *buf, pos); - strcpy(newbuf+pos, first_buf); - strncpy(newbuf+pos+len2, *buf+pos, len-pos); - newbuf[len+len2] = '\0'; - - free( (*buf) ); - (*buf) = newbuf; - - //printf("test joined buffer\n%s\n",*buf); - } - - return len; -} - -size_t lcmScriptCopyBuffer(ArgList *arglist, char *buf, char **script_buffer) -{ - ptrdiff_t pos = 0; - size_t len = 0; - - if(stricmp(GET_ARGP(1), "@script") == 0) - { - fetchInlineScript(buf, script_buffer, &pos, &len); - } - else - { - buffer_pakfile(GET_ARGP(1), script_buffer, &len); - } - - //printf("test buffer\n%s\n",*script_buffer); - return pos; -} - -size_t lcmScriptDeleteMain(char **buf) -{ - size_t len = 0, i = 0; - ptrdiff_t pos = 0; - char *newbuf = NULL; - - if ((*buf) && (*buf)[0]) - { - len = strlen(*buf); - - while(!starts_with((*buf) + pos, "main()")) pos++; - pos += strclen("main()"); - while(!starts_with(*buf + pos, "{")) pos++; - pos += strclen("{"); - while(!starts_with(*buf + pos, "int frame = getlocalvar(\"frame\");")) pos++; - pos += strclen("int frame = getlocalvar(\"frame\");"); - while(!starts_with(*buf + pos, "int animhandle = getlocalvar(\"animhandle\");\n")) pos++; - pos += strclen("int animhandle = getlocalvar(\"animhandle\");\n"); - - for(i = len-1; ; i--) - { - if ( (*buf)[i] == '}' ) - { - len = i; - break; - } else continue; - //if (i <= 0) break; - } - - len = len-pos; - newbuf = malloc(sizeof(newbuf) * (len) + 1); - strncpy(newbuf, *buf+pos, len); - newbuf[len] = '\0'; - - free( (*buf) ); - (*buf) = newbuf; - - //printf("test delete main\n%s\n",newbuf); - } - - return len; -} - -//alloc a new model, and everything thats required, -//set all values to defaults -s_model *init_model(const int cacheindex, const int unload) -{ - //to free: newchar, newchar->offense_factors, newchar->special, newchar->animation - OK - int i; - - s_model* const newchar = calloc(1, sizeof(*newchar)); - if(!newchar) - { - borShutdown(1, (char *)E_OUT_OF_MEMORY); - } - newchar->object_type = OBJECT_TYPE_MODEL; - newchar->test_pointer = model_cache[cacheindex].name; - strcpy(newchar->test_fixed, model_cache[cacheindex].name); - - newchar->name = model_cache[cacheindex].name; // well give it a name for sort method - newchar->index = cacheindex; - newchar->isSubclassed = 0; - newchar->freetypes = MF_ALL; - - newchar->priority = 1; - - newchar->defense = defense_allocate_object(); - newchar->offense = offense_allocate_object(); - - newchar->special = calloc(1, sizeof(s_com)); - - alloc_all_scripts(&newchar->scripts); - - - - newchar->death_config_flags = DEATH_CONFIG_MACRO_DEFAULT; - - newchar->edelay = (s_edelay){ - .cap = { - .max = MAX_INT, - .min = 0 - }, - .range = { - .max = MAX_INT, - .min = 0 - }, - .factor = 1.0f - }; - - newchar->unload = unload; - newchar->jumpspecial = 0; // Kratus (10-2021) Added new property to kill or not the default jumpspecial movement - newchar->jumpspeed = default_model_jumpspeed; - newchar->jumpheight = default_model_jumpheight; // 28-12-2004 Set default jump height to 4, if not specified - newchar->runjumpheight = default_model_jumpheight; // Default jump height if a player is running - newchar->runjumpdist = 1; // Default jump distane if a player is running - newchar->grabdistance = default_model_grabdistance; // 30-12-2004 Default grabdistance is same as originally set - newchar->grabflip = 3; - newchar->throwdamage = 21; //21 // default throw damage - - newchar->icon = (s_icon){ - .def = ICON_NONE, - .die = ICON_NONE, - .get = ICON_NONE, - .mphigh = ICON_NONE, - .mplow = ICON_NONE, - .mpmax = ICON_NONE, - .mpmed = ICON_NONE, - .mpnone = ICON_NONE, - .pain = ICON_NONE, - .weapon = ICON_NONE - }; - - newchar->diesound = SAMPLE_ID_NONE; - newchar->nolife = 0; // default show life = 1 (yes) - newchar->shadow_config_flags = SHADOW_CONFIG_DEFAULT; - newchar->remove_config = REMOVE_CONFIG_HIT; // Flag set to projectiles are removed upon hitting an opponent - newchar->throwdist = default_model_jumpheight * 0.625f; - newchar->aimove = AIMOVE1_NONE; - newchar->aiattack = -1; - newchar->throwframewait = FRAME_NONE; // makes sure throw animations run normally unless throwfram is specified, added by kbandressen 10/20/06 - newchar->path = model_cache[cacheindex].path; // Record path, so script can get it without looping the whole model collection. - newchar->edgerange.x = 0; - newchar->edgerange.z = 0; - - newchar->colorsets = (s_colorset){ - .burn = COLORSET_INDEX_NONE, - .frozen = COLORSET_INDEX_NONE, - .hide_end = COLORSET_INDEX_NONE, - .hide_start = COLORSET_INDEX_NONE, - .ko = COLORSET_INDEX_NONE, - .kotype = KO_COLORSET_CONFIG_INSTANT, - .shock = COLORSET_INDEX_NONE - }; - - // Default Attack1 in chain must be referenced if not used. - for(i = 0; i < MAX_ATCHAIN; i++) - { - newchar->atchain[i] = 1; - } - newchar->chainlength = 1; - - if(magic_type == 1) - { - newchar->mprate = 1; - } - else - { - newchar->mprate = 2; - } - newchar->chargerate = newchar->guardrate = 2; - newchar->risetime.rise = -1; - newchar->sleepwait = 1000; - - newchar->guardpoints = 0; - newchar->jugglepoints = 0; - - newchar->mpswitch = -1; // switch between reduce mp or gain mp for mpstabletype 4 - - newchar->weapon_properties = (s_weapon){ - .loss_condition = WEAPON_LOSS_CONDITION_DEFAULT, - .loss_count = 3, - .loss_index = MODEL_INDEX_NONE - }; - - newchar->lifespan = LIFESPAN_DEFAULT; - newchar->summonkill = 1; - - /* - * Faction data. Faction type properties - * get defaults set downstream depending - * on the model's own type. - */ - - newchar->faction = (s_faction){ - .damage_direct = FACTION_GROUP_DEFAULT, - .damage_indirect = FACTION_GROUP_DEFAULT, - .hostile = FACTION_GROUP_DEFAULT, - .member = FACTION_GROUP_DEFAULT, - .type_damage_direct = TYPE_UNDECLARED, - .type_damage_indirect = TYPE_UNDECLARED, - .type_hostile = TYPE_UNDECLARED, - .object_type = OBJECT_TYPE_FACTION - }; - - newchar->move_config_flags = MOVE_CONFIG_NONE; - newchar->pshotno = MODEL_INDEX_NONE; - newchar->project = MODEL_INDEX_NONE; - - newchar->dust = (s_dust){ - .fall_land = MODEL_INDEX_NONE, - .jump_land = MODEL_INDEX_NONE, - .jump_start = MODEL_INDEX_NONE - }; - - newchar->bomb = MODEL_INDEX_NONE; - newchar->star = MODEL_INDEX_NONE; - newchar->knife = MODEL_INDEX_NONE; - newchar->stealth.hide = 0; - newchar->stealth.detect = 0; - newchar->attackthrottle = 0.0f; - newchar->attackthrottletime = noatk_duration * global_config.game_speed; - - /* - * max_animations originates in data/models.txt. Check - * the per-model table multiplication before allocating. - */ - if(max_animations <= 0 - || (size_t)max_animations - > SIZE_MAX / sizeof(*newchar->animation)) { - borShutdown( - 1, - "Invalid per-model animation table size (%d). " - "Check animation limits in data/models.txt.\n", - max_animations - ); - } - - newchar->animation = calloc( - (size_t)max_animations, - sizeof(*newchar->animation) - ); - if(!newchar->animation) - { - borShutdown(1, (char *)E_OUT_OF_MEMORY); - } - - // default string value, only by reference - newchar->rider = get_cached_model_index("K'"); - newchar->flash.model_hit = newchar->flash.model_block = get_cached_model_index("flash"); - - //Default sight ranges. - newchar->sight = (s_sight){ - .max = {.x = MAX_INT, .y = MAX_INT, .z = MAX_INT }, - .min = {.x = MIN_INT, .y = MIN_INT, .z = MIN_INT } - }; - - return newchar; -} - -void update_model_loadflag(s_model *model, char unload) -{ - model->unload = unload; -} - -s_model *load_cached_model(char *name, char *owner, char unload) -{ - #define LOG_CMD_TITLE "%-20s" - - s_model* newchar = NULL; - s_model* tempmodel = NULL; - - s_anim *newanim = NULL; - - char* filename = NULL; - char* buf = NULL; - char* animscriptbuf = NULL; - char* scriptbuf = NULL; - char* command = NULL; - char* value = NULL; - char* value2 = NULL; - - char fnbuf[MAX_BUFFER_LEN] = { "" }; - char namebuf[MAX_BUFFER_LEN] = { "" }; - char argbuf[MAX_ARG_LEN + 1] = { "" }; - - ArgList arglist; - - int ani_id = ANI_NONE; - int script_id = -1; - int frm_id = -1; - bool at_cmd_mergeable = false; - int i = 0; - int tempInt = 0; - int framecount = 0; - int frameset = 0; - int peek = 0; - int cacheindex = 0; - int curframe = 0; - int errorVal = 0; - int shadow_set = 0; - int idle = 0; - int frameshadow = FRAME_SHADOW_NONE; // FRAME_SHADOW_NONE will use default shadow for this entity, otherwise will use this value. - int temp_frame_sound_index = 0; - int aiattackset = 0; - int maskindex = -1; - int nopalette = 0; - - size_t size = 0; - size_t line = 0; - size_t len = 0; - size_t sbsize = 0; - size_t scriptlen = 0; - - uint64_t delay = 0; - - e_delay_unit delay_mode = DELAY_UNIT_GLOBAL; - - ptrdiff_t pos = 0; - ptrdiff_t index = 0; - - s_addframe_data add_frame_data; - - s_axis_plane_vertical_int offset = { .x = 0, - .y = 0 }; - int shadow_xz[2] = {0, 0}; - int shadow_coords[2] = {0, 0}; - - float platform[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - float platform_con[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - s_move move = { { .x = 0, - .y = 0, - .z = 0}, - .base = -1 //-1 = Disabled, 0+ base set - }; - - s_drawmethod drawmethod; - s_drawmethod dm; - - s_frame_sound_collection* temp_frame_sound = NULL; - - /* - * Caskey, Damon V. - * 2026-06-28 (updated from 2021 node header) - * - * Temporary collision collections. As we parse the - * model file, we will build a temporary collection - * of collision data, then clone it into the model's - * target animation frame, and the discard the temporary - * collection. - * - * Index tells us which collision index to target. Any - * time we are updating a collision box, we pass the index - * to the update functions. The parse for index must - * therefore appear before any other collision parsing - * in order, so it modifies the index before we call the - * collision update functions. - */ - int temp_collision_index = 0; - s_collision_collection* temp_collision_attack = NULL; - s_collision_collection* temp_collision_body = NULL; - s_collision_collection* temp_collision_space = NULL; - - /* - * Temp pointer to make adding several collision - * coordinates in one command a little cleaner. - */ - s_hitbox* temp_collision_coordinates = NULL; - - int temp_child_spawn_index = 0; - s_child_spawn* temp_child_spawn_head = NULL; // Spawning sub entities. - - const char *shutdownmessage = NULL; - - unsigned* mapflag = NULL; // in 24bit mode, we need to know whether a colourmap is a common map or a palette - - char alert_buffer[256] = { 0 }; // So we can concatenate specifics *like range max/min* into alert messages. - - const char pre_text[] = // this is the skeleton of frame function - { - "void main()\n" - "{\n" - " int frame = getlocalvar(\"frame\");\n" - " int animhandle = getlocalvar(\"animhandle\");\n" - "\n}\n" - }; - - const char sur_text[] = // end of function text - { - "\n}\n" - }; - - const char ifid_text[] = // if expression to check animation id - { - " if(animhandle==%" PRId64 ")\n" - " {\n" - " return;\n" - " }\n" - }; - - const char endifid_text[] = // end of if - { - " return;\n" - " }\n" - }; - - const char if_text[] = // this is the if expression of frame function - { - " if(frame==%d)\n" - " {\n" - }; - - const char endif_return_text[] = //return to reduce unecessary checks - { - " return;\n" - }; - - const char endif_text[] = // end of if - { - " }\n" - } ; - - const char comma_text[] = // arguments separator - { - ", " - }; - - const char call_indent_text[] = //begin of function call - { - " " - }; - - const char call_open_text[] = - { - "(" - }; - - const char endcall_text[] = //end of function call - { - ");\n" - }; - - modelCommands cmd; - s_scripts* tempscripts; - -#ifdef DEBUG - printf("load_cached_model: %s, unload: %d\n", name, unload); -#endif - - // Start up the standard log entry. - printf("Loading '%s'", name); - - // Model already loaded but we might want to unload after level is completed. - if((tempmodel = findmodel(name)) != NULL) - { - update_model_loadflag(tempmodel, unload); - cache_model_sprites(tempmodel, 1); - return tempmodel; - } - - cacheindex = get_cached_model_index(name); - if(cacheindex < 0) - { - borShutdown(1, "Fatal: No cache entry for '%s' within '%s'\n\n", name, owner); - } - - model_cache[cacheindex].lifecycle = MODEL_LIFECYCLE_LOADING; - - // Get the text file name of model. - filename = model_cache[cacheindex].path; - printf(" from %s \n", filename); - - if(buffer_pakfile(filename, &buf, &size) != 1) - { - borShutdown(1, "Unable to open file '%s'\n\n", filename); - } - - sbsize = size + 1; - scriptbuf = (char *)malloc(sbsize); - - if(scriptbuf == NULL) - { - borShutdown(1, "Unable to create script buffer for file '%s' (%i bytes)", filename, size * 2); - } - scriptbuf[0] = 0; - - //_peek_model_name(cacheindex); - newchar = init_model(cacheindex, unload); - //newchar->name = name; - - //attention, we increase models_loaded here, this can be dangerous if we access that value later on, - //since recursive calls will change it! - models_loaded++; - addModel(newchar); - - drawmethod = plainmethod; // better than memset it to 0 - - newchar->hitwalltype = -1; // init to -1 - - //char* test = "load knife 0"; - //ParseArgs(&arglist,test,argbuf); - - // Now interpret the contents of buf line by line - while(pos < size) - { - //command = GET_ARG(0); - line++; - if(ParseArgs(&arglist, buf + pos, argbuf)) - { - command = GET_ARG(0); - cmd = getModelCommand(modelcmdlist, command); - - //if (cmd != CMD_MODEL_FRAME) framenum = 0; - - switch(cmd) - { - case CMD_MODEL_SUBCLASS: - //inherit everything from an existing, cached model - tempmodel = findmodel(GET_ARG(1)); - if (!tempmodel) - { - shutdownmessage = "tried to subclass a non-existing/not previously loaded model!"; - goto lCleanup; - } - tempscripts = newchar->scripts; - *newchar = *tempmodel; - newchar->scripts = tempscripts; - copy_all_scripts(tempmodel->scripts, newchar->scripts, 1); - newchar->isSubclassed = 1; - newchar->freetypes = MF_SCRIPTS; - break; - case CMD_MODEL_NAME: - lcmHandleCommandName(&arglist, newchar, cacheindex); - break; - case CMD_MODEL_TYPE: - lcmHandleCommandType(&arglist, newchar, filename); - break; - case CMD_MODEL_SUBTYPE: - lcmHandleCommandSubtype(&arglist, newchar, filename); - break; - case CMD_MODEL_HEALTH: - value = GET_ARG(1); - newchar->health = atoi(value); - break; - case CMD_MODEL_PRIORITY: - value = GET_ARG(1); - newchar->priority = atoi(value); - break; - case CMD_MODEL_SCROLL: - value = GET_ARG(1); - newchar->scroll = atof(value); - break; - case CMD_MODEL_MP: //Left for backward compatability. See mpset. // mp values to put max mp for player by tails - value = GET_ARG(1); - newchar->mp = atoi(value); - break; - case CMD_MODEL_NOLIFE: // Feb 25, 2005 - Flag to display enemy life or not - newchar->nolife = GET_INT_ARG(1); - break; - case CMD_MODEL_MAKEINV: // Mar 12, 2005 - If a value is supplied, corresponds to amount of time the player spawns invincible - newchar->makeinv = GET_FLOAT_ARG(1) * global_config.game_speed; - if(GET_INT_ARG(2)) - { - newchar->makeinv = -newchar->makeinv; - } - break; - case CMD_MODEL_RISEINV: - newchar->riseinv = GET_FLOAT_ARG(1) * global_config.game_speed; - if(GET_INT_ARG(2)) - { - newchar->riseinv = -newchar->riseinv; - } - break; - case CMD_MODEL_LOAD: - value = GET_ARG(1); - tempmodel = findmodel(value); - if(!tempmodel) - { - load_cached_model(value, name, GET_INT_ARG(2)); - } - else - { - update_model_loadflag(tempmodel, GET_INT_ARG(2)); - } - break; - case CMD_MODEL_SCORE: - if(!command_argument_get_int64(GET_ARG(1), &newchar->score)) - { - borShutdown( - 1, - "Invalid signed 64-bit score '%s' in %s, line %zu.\n", - GET_ARG(1), - filename, - line - ); - } - newchar->multiple = GET_INT_ARG(2); // New var multiple for force/scoring - break; - case CMD_MODEL_SMARTBOMB: - lcmHandleCommandSmartbomb(&arglist, newchar, filename); - break; - case CMD_MODEL_BOUNCE: - newchar->bounce = GET_INT_ARG(1); - break; - case CMD_MODEL_NOQUAKE: // Mar 12, 2005 - Flag to determine if entity shakes screen - newchar->quake_config |= GET_INT_ARG(1) ? QUAKE_CONFIG_DISABLE_SCREEN : 0; - newchar->quake_config |= GET_INT_ARG(2) ? QUAKE_CONFIG_DISABLE_SELF : 0; - break; - case CMD_MODEL_BLOCK_CONFIG: - - newchar->block_config_flags = block_get_config_flags_from_command_line(buf + pos); - break; - - case CMD_MODEL_BLOCKBACK: - - /* Legacy value to bitmask. */ - - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->block_config_flags |= BLOCK_CONFIG_BACK; - } - else - { - newchar->block_config_flags &= ~BLOCK_CONFIG_BACK; - } - - break; - - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_CONFIG: - - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_config = direction_get_adjustment_from_argument(filename, command, GET_ARG(1)); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_BASE_MAX: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.base.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_BASE_MIN: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.base.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_X_MAX: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.x.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_X_MIN: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.x.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_Y_MAX: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.y.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_Y_MIN: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.y.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_Z_MAX: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.z.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_DIRECTION_ADJUST_RANGE_Z_MIN: - child_follow_getsert_property(&newchar->child_follow)->direction_adjust_range.z.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_CHILD_FOLLOW_OFFSET_X: - - child_follow_getsert_property(&newchar->child_follow)->follow_offset.x = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_OFFSET_Y: - child_follow_getsert_property(&newchar->child_follow)->follow_offset.y = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_OFFSET_Z: - child_follow_getsert_property(&newchar->child_follow)->follow_offset.z = GET_INT_ARG(1); - break; - - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_BASE_MAX: - child_follow_getsert_property(&newchar->child_follow)->recall_range.base.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_BASE_MIN: - child_follow_getsert_property(&newchar->child_follow)->recall_range.base.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_X_MAX: - child_follow_getsert_property(&newchar->child_follow)->recall_range.x.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_X_MIN: - child_follow_getsert_property(&newchar->child_follow)->recall_range.x.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_Y_MAX: - child_follow_getsert_property(&newchar->child_follow)->recall_range.y.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_Y_MIN: - child_follow_getsert_property(&newchar->child_follow)->recall_range.y.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_Z_MAX: - child_follow_getsert_property(&newchar->child_follow)->recall_range.z.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RECALL_Z_MIN: - child_follow_getsert_property(&newchar->child_follow)->recall_range.z.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_BASE_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.base.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_BASE_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.base.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_X_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.x.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_X_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.x.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_Y_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.y.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_Y_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.y.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_Z_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.z.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_RUN_Z_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_run_range.z.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_CHILD_FOLLOW_RANGE_BASE_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_range.base.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_BASE_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_range.base.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_X_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_range.x.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_X_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_range.x.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_Y_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_range.y.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_Y_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_range.y.min = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_Z_MAX: - child_follow_getsert_property(&newchar->child_follow)->follow_range.z.max = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RANGE_Z_MIN: - child_follow_getsert_property(&newchar->child_follow)->follow_range.z.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_CHILD_FOLLOW_RECALL_OFFSET_X: - - child_follow_getsert_property(&newchar->child_follow)->recall_offset.x = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RECALL_OFFSET_Y: - child_follow_getsert_property(&newchar->child_follow)->recall_offset.y = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_FOLLOW_RECALL_OFFSET_Z: - child_follow_getsert_property(&newchar->child_follow)->recall_offset.z = GET_INT_ARG(1); - break; - - case CMD_MODEL_HITENEMY: // Flag to determine if an enemy projectile will hit enemies - value = GET_ARG(1); - if(atoi(value) == 1) - { - newchar->faction.type_damage_direct = newchar->faction.type_hostile = TYPE_PLAYER | TYPE_ENEMY; - } - else if(atoi(value) == 2) - { - newchar->faction.type_damage_direct = newchar->faction.type_hostile = TYPE_PLAYER; - } - - newchar->ground = GET_INT_ARG(2); // Added to determine if enemies are damaged with mid air projectiles or ground only - break; - - /* Faction set up. */ - case CMD_MODEL_FACTION_GROUP_DAMAGE_DIRECT: - newchar->faction.damage_direct = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_MODEL_FACTION_GROUP_DAMAGE_INDIRECT: - newchar->faction.damage_indirect = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_MODEL_FACTION_GROUP_HOSTILE: - newchar->faction.hostile = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_MODEL_FACTION_GROUP_MEMBER: - newchar->faction.member = faction_get_flags_from_command_line(buf + pos); - break; - - /* Legacy type based faction */ - case CMD_MODEL_FACTION_TYPE_HOSTILE: - case CMD_MODEL_HOSTILE: - newchar->faction.type_hostile = get_type_from_command_line(buf + pos); - break; - - case CMD_MODEL_FACTION_TYPE_DAMAGE_DIRECT: - case CMD_MODEL_CANDAMAGE: - newchar->faction.type_damage_direct = get_type_from_command_line(buf + pos); - break; - - case CMD_MODEL_FACTION_TYPE_DAMAGE_INDIRECT: - case CMD_MODEL_PROJECTILEHIT: - newchar->faction.type_damage_indirect = get_type_from_command_line(buf + pos); - break; - - case CMD_MODEL_AIMOVE: - newchar->aimove = get_aimove_from_command_line(buf + pos, AIMOVE1_NORMAL); - break; - case CMD_MODEL_AIATTACK: - lcmHandleCommandAiattack(&arglist, newchar, &aiattackset, filename); - break; - case CMD_MODEL_MOVE_CONFIG: - newchar->move_config_flags = get_move_config_flags_from_command_line(buf + pos); - break; - case CMD_MODEL_SUBJECT_TO_BASEMAP: - - /* Legacy code allowed -1 or 0 for False. */ - if (GET_INT_ARG(1) > 0) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_BASEMAP; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_BASEMAP; - } - - break; - case CMD_MODEL_SUBJECT_TO_WALL: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_WALL; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_WALL; - } - - break; - case CMD_MODEL_SUBJECT_TO_HOLE: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_HOLE; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_HOLE; - } - - break; - case CMD_MODEL_SUBJECT_TO_PLATFORM: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_PLATFORM; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_PLATFORM; - } - - break; - case CMD_MODEL_SUBJECT_TO_OBSTACLE: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_OBSTACLE; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_OBSTACLE; - } - - break; - case CMD_MODEL_SUBJECT_TO_GRAVITY: - - /* Legacy code allowed -1 or 0 for False. */ - if (GET_INT_ARG(1) > 0) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - - break; - case CMD_MODEL_SUBJECT_TO_SCREEN: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_SCREEN; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_SCREEN; - } - - break; - case CMD_MODEL_SUBJECT_TO_MINZ: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_MIN_Z; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_MIN_Z; - } - - break; - case CMD_MODEL_SUBJECT_TO_MAXZ: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_MAX_Z; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_MAX_Z; - } - - break; - case CMD_MODEL_NO_ADJUST_BASE: - - /* Legacy code allowed -1 or 0 for False. */ - if (GET_INT_ARG(1) > 0) - { - newchar->move_config_flags |= MOVE_CONFIG_NO_ADJUST_BASE; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - } - - break; - case CMD_MODEL_INSTANTITEMDEATH: - newchar->instantitemdeath = GET_INT_ARG(1); - break; - case CMD_MODEL_SECRET: - newchar->secret = GET_INT_ARG(1); - newchar->clearcount = GET_INT_ARG(2); - break; - case CMD_MODEL_MODELFLAG: // Legacy model copy flag. - - - lcmHandleCommandModelFlag(filename, command, buf + pos, newchar); - - break; - // weapons - case CMD_MODEL_WEAPLOSS: - - /* Legacy weapon loss. */ - - newchar->weapon_properties.loss_condition = weapon_loss_condition_interpret_from_legacy_weaploss(WEAPON_LOSS_CONDITION_NONE, GET_INT_ARG(1)); - newchar->weapon_properties.loss_index = GET_INT_ARG(2); - break; - - case CMD_MODEL_WEAPON_LOSS_CONFIG: - - lcmHandleCommandWeaponLossCondition(buf + pos, newchar); - break; - - case CMD_MODEL_WEAPON_LOSS_INDEX: - - /* Weapon list entry we revert to when losing weapon. */ - - newchar->weapon_properties.loss_index = GET_INT_ARG(1); - - break; - - case CMD_MODEL_WEAPNUM: - newchar->weapon_properties.weapon_index = GET_INT_ARG(1); - break; - case CMD_MODEL_PROJECT: // New projectile subtype - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->project = MODEL_INDEX_NONE; - } - else - { - newchar->project = get_cached_model_index(value); - } - break; - case CMD_MODEL_WEAPONS: - lcmHandleCommandWeapons(buf + pos, newchar); - break; - case CMD_MODEL_SHOOTNUM: - newchar->weapon_properties.use_count = GET_INT_ARG(1); - break; - case CMD_MODEL_RELOAD: - newchar->weapon_properties.use_add = GET_INT_ARG(1); - break; - case CMD_MODEL_TYPESHOT: - if (GET_INT_ARG(1)) - { - newchar->weapon_properties.weapon_state |= WEAPON_STATE_LIMITED_USE; - } - - break; - case CMD_MODEL_COUNTER: - newchar->weapon_properties.loss_count = GET_INT_ARG(1); - break; - case CMD_MODEL_ANIMAL: - if (GET_INT_ARG(1)) - { - newchar->weapon_properties.weapon_state |= WEAPON_STATE_ANIMAL; - } - break; - case CMD_MODEL_RIDER: - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->rider = MODEL_INDEX_NONE; - } - else - { - newchar->rider = get_cached_model_index(value); - } - break; - case CMD_MODEL_KNIFE: - case CMD_MODEL_FIREB: - case CMD_MODEL_PLAYSHOT: - case CMD_MODEL_PLAYSHOTW: - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->knife = MODEL_INDEX_NONE; - } - else - { - newchar->knife = get_cached_model_index(value); - } - break; - case CMD_MODEL_PLAYSHOTNO: - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->pshotno = MODEL_INDEX_NONE; - } - else - { - newchar->pshotno = get_cached_model_index(value); - } - break; - case CMD_MODEL_STAR: - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->star = MODEL_INDEX_NONE; - } - else - { - newchar->star = get_cached_model_index(value); - } - break; - case CMD_MODEL_BOMB: - case CMD_MODEL_PLAYBOMB: - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->bomb = MODEL_INDEX_NONE; - } - else - { - newchar->bomb = get_cached_model_index(value); - } - break; - case CMD_MODEL_FLASH: // Now all characters can have their own flash - even projectiles (useful for blood) - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->flash.model_hit = MODEL_INDEX_NONE; - } - else - { - newchar->flash.model_hit = get_cached_model_index(value); - } - break; - case CMD_MODEL_BFLASH: // Flash that is spawned if an attack is blocked - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->flash.model_block = MODEL_INDEX_NONE; - } - else - { - newchar->flash.model_block = get_cached_model_index(value); - } - break; - case CMD_MODEL_DUST: // Spawned when hitting the ground to "kick up dust" - value = GET_ARG(1); - if(stricmp(value, "none") == 0) - { - newchar->dust.fall_land = MODEL_INDEX_NONE; - } - else - { - newchar->dust.fall_land = get_cached_model_index(value); - } - value = GET_ARG(2); - if(stricmp(value, "none") == 0) - { - newchar->dust.jump_land = MODEL_INDEX_NONE; - } - else - { - newchar->dust.jump_land = get_cached_model_index(value); - } - value = GET_ARG(3); - if(stricmp(value, "none") == 0) - { - newchar->dust.jump_start = MODEL_INDEX_NONE; - } - else - { - newchar->dust.jump_start = get_cached_model_index(value); - } - break; - case CMD_MODEL_BRANCH: // for endlevel item's level branch - value = GET_ARG(1); - if(!newchar->branch) - { - newchar->branch = malloc(MAX_NAME_LEN + 1); - newchar->branch[0] = 0; - } - strncpy(newchar->branch, value, MAX_NAME_LEN); - break; - case CMD_MODEL_CANTGRAB: - case CMD_MODEL_NOTGRAB: - tempInt = GET_INT_ARG(1); - if(tempInt == 2) - { - newchar->grab_force = -999999; - } - else - { - newchar->grab_resistance = 1; - } - break; - case CMD_MODEL_ANTIGRAB: // a can grab b: a->grab_resistance - b->grab_force <=0 - newchar->grab_resistance = GET_INT_ARG(1); - break; - case CMD_MODEL_GRABFORCE: - newchar->grab_force = GET_INT_ARG(1); - break; - case CMD_MODEL_GRABBACK: - newchar->grabback = GET_INT_ARG(1); - break; - case CMD_MODEL_OFFSCREENKILL: - newchar->offscreenkill = GET_INT_ARG(1); - break; - case CMD_MODEL_ONAF: - newchar->offscreen_noatk_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_FALLDIE: - case CMD_MODEL_DEATH: - - tempInt = GET_INT_ARG(1); - - newchar->death_config_flags = death_config_get_value_from_falldie(newchar->death_config_flags, tempInt); - - break; - - case CMD_MODEL_DEATH_CONFIG: - - newchar->death_config_flags = death_get_config_flags_from_command_line(buf + pos, 1); - break; - - case CMD_MODEL_SPEED: - value = GET_ARG(1); - newchar->speed.x = atof(value); - newchar->speed.x /= 10; - if(newchar->speed.x < 0.5) - { - newchar->speed.x = 0.5; - } - if(newchar->speed.x > 30) - { - newchar->speed.x = 30; - } - break; - case CMD_MODEL_SPEEDF: - value = GET_ARG(1); - newchar->speed.x = atof(value); - break; - case CMD_MODEL_JUMPSPECIAL: // Kratus (10-2021) Added new jumpspecial property - newchar->jumpspecial = GET_INT_ARG(1); - break; - case CMD_MODEL_JUMPSPEED: - value = GET_ARG(1); - newchar->jumpspeed = atof(value); - newchar->jumpspeed /= 10; - break; - case CMD_MODEL_JUMPSPEEDF: - value = GET_ARG(1); - newchar->jumpspeed = atof(value); - break; - case CMD_MODEL_ANTIGRAVITY: - value = GET_ARG(1); - newchar->antigravity = atof(value); - newchar->antigravity /= 100; - break; - case CMD_MODEL_STEALTH: - newchar->stealth.hide = GET_INT_ARG(1); - newchar->stealth.detect = GET_INT_ARG(2); - break; - case CMD_MODEL_JUGGLEPOINTS: - value = GET_ARG(1); - newchar->jugglepoints = atoi(value); - break; - case CMD_MODEL_RISEATTACKTYPE: - value = GET_ARG(1); - newchar->riseattacktype = atoi(value); - break; - case CMD_MODEL_GUARDPOINTS: - value = GET_ARG(1); - newchar->guardpoints = atoi(value); - break; - case CMD_MODEL_DEFENSE: - - /* - * DEFENSE_PARAMETER_LEGACY triggers muti-parameter read - * from 3.0 builds. See function for details. - */ - - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_LEGACY); - break; - case CMD_MODEL_DEFENSE_BLOCK_DAMAGE_ADJUST: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_DAMAGE_ADJUST); - break; - case CMD_MODEL_DEFENSE_BLOCK_DAMAGE_MAX: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_DAMAGE_MAX); - break; - case CMD_MODEL_DEFENSE_BLOCK_DAMAGE_MIN: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_DAMAGE_MIN); - break; - case CMD_MODEL_DEFENSE_BLOCK_POWER: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_POWER); - break; - case CMD_MODEL_DEFENSE_BLOCK_RATIO: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_RATIO); - break; - case CMD_MODEL_DEFENSE_BLOCK_THRESHOLD: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_THRESHOLD); - break; - case CMD_MODEL_DEFENSE_BLOCK_TYPE: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_BLOCK_TYPE); - break; - case CMD_MODEL_DEFENSE_DAMAGE_ADJUST: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_DAMAGE_ADJUST); - break; - case CMD_MODEL_DEFENSE_DAMAGE_MAX: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_DAMAGE_MAX); - break; - case CMD_MODEL_DEFENSE_DAMAGE_MIN: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_DAMAGE_MIN); - break; - case CMD_MODEL_DEFENSE_DEATH_CONFIG: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_DEATH_CONFIG); - break; - case CMD_MODEL_DEFENSE_FACTOR: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_FACTOR); - break; - case CMD_MODEL_DEFENSE_KNOCKDOWN: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_KNOCKDOWN); - break; - case CMD_MODEL_DEFENSE_PAIN: - defense_setup_from_arg(filename, command, buf + pos, newchar->defense, &arglist, DEFENSE_PARAMETER_PAIN); - break; - case CMD_MODEL_OFFENSE: - offense_setup_from_arg(filename, command, newchar->offense, &arglist, OFFENSE_PARAMETER_LEGACY); - break; - case CMD_MODEL_OFFENSE_DAMAGE_ADJUST: - offense_setup_from_arg(filename, command, newchar->offense, &arglist, OFFENSE_PARAMETER_DAMAGE_ADJUST); - break; - case CMD_MODEL_OFFENSE_DAMAGE_MAX: - offense_setup_from_arg(filename, command, newchar->offense, &arglist, OFFENSE_PARAMETER_DAMAGE_MAX); - break; - case CMD_MODEL_OFFENSE_DAMAGE_MIN: - offense_setup_from_arg(filename, command, newchar->offense, &arglist, OFFENSE_PARAMETER_DAMAGE_MIN); - break; - case CMD_MODEL_OFFENSE_FACTOR: - offense_setup_from_arg(filename, command, newchar->offense, &arglist, OFFENSE_PARAMETER_FACTOR); - break; - - case CMD_MODEL_HEIGHT: - newchar->size.y = GET_INT_ARG(1); - break; - case CMD_MODEL_JUMPHEIGHT: - newchar->jumpheight = GET_FLOAT_ARG(1); - break; - - case CMD_MODEL_AIR_CONTROL: - - lcmHandleCommandAirControl(buf + pos, newchar); - break; - - case CMD_MODEL_JUMPMOVE: - - newchar->air_control = air_control_interpret_from_legacy_jumpmove_x(newchar->air_control, GET_INT_ARG(1)); - newchar->air_control = air_control_interpret_from_legacy_jumpmove_z(newchar->air_control, GET_INT_ARG(2)); - break; - - case CMD_MODEL_WALKOFFMOVE: - - newchar->air_control = air_control_interpret_from_legacy_walkoffmove_x(newchar->air_control, GET_INT_ARG(1)); - newchar->air_control = air_control_interpret_from_legacy_walkoffmove_z(newchar->air_control, GET_INT_ARG(2));; - break; - - case CMD_MODEL_KNOCKDOWNCOUNT: - newchar->knockdowncount = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_GRABDISTANCE: - newchar->grabdistance = GET_FLOAT_ARG(1); // 30-12-2004 and store for character - break; - case CMD_MODEL_GRABFLIP: - newchar->grabflip = GET_INT_ARG(1); - break; - case CMD_MODEL_GRABFINISH: - newchar->grabfinish = GET_INT_ARG(1); - break; - case CMD_MODEL_THROWDAMAGE: - newchar->throwdamage = GET_INT_ARG(1); - break; - case CMD_MODEL_SHADOW: - newchar->shadow = GET_INT_ARG(1); - - tempInt= GET_INT_ARG(2); - - newchar->shadow_config_flags = shadow_get_config_from_legacy_shadowbase(newchar->shadow_config_flags, tempInt); - - break; - case CMD_MODEL_SHADOW_CONFIG: - - newchar->shadow_config_flags = shadow_get_config_flags_from_command_line(buf + pos); - - break; - case CMD_MODEL_GFXSHADOW: - - /* Gfxshadow. */ - tempInt = GET_INT_ARG(1); - newchar->shadow_config_flags = shadow_get_config_from_legacy_gfxshadow(newchar->shadow_config_flags, tempInt); - - /* Shadowbase. */ - tempInt = GET_INT_ARG(2); - newchar->shadow_config_flags = shadow_get_config_from_legacy_shadowbase(newchar->shadow_config_flags, tempInt); - - break; - - case CMD_MODEL_AIRONLY: // Shadows display in air only? - - tempInt = GET_INT_ARG(1); - - newchar->shadow_config_flags = shadow_get_config_from_legacy_aironly(newchar->shadow_config_flags, tempInt); - - break; - case CMD_MODEL_FMAP: // Map that corresponds with the remap when a character is frozen - newchar->colorsets.frozen = GET_INT_ARG(1); - break; - case CMD_MODEL_KOMAP: - newchar->colorsets.ko = GET_INT_ARG(1); //Remap. - newchar->colorsets.kotype = komap_type_get_value_from_argument(filename, command, GET_ARG(2)); - break; - case CMD_MODEL_MAP_BURN_INDEX: - newchar->colorsets.burn = GET_INT_ARG(1); - break; - case CMD_MODEL_MAP_KO_INDEX: - newchar->colorsets.ko = GET_INT_ARG(1); - break; - case CMD_MODEL_MAP_KO_TYPE: - newchar->colorsets.kotype = komap_type_get_value_from_argument(filename, command, GET_ARG(1)); - break; - case CMD_MODEL_MAP_FREEZE_INDEX: - newchar->colorsets.frozen = GET_INT_ARG(1); - break; - case CMD_MODEL_MAP_SHOCK_INDEX: - newchar->colorsets.shock = GET_INT_ARG(1); - break; - case CMD_MODEL_HMAP: // Maps range unavailable to player in select screen. - newchar->colorsets.hide_start = GET_INT_ARG(1); //First unavailable map. - newchar->colorsets.hide_end = GET_INT_ARG(2); //Last unavailable map. - break; - case CMD_MODEL_SETLAYER: - newchar->setlayer = GET_INT_ARG(1); - break; - case CMD_MODEL_TOFLIP: // Flag to determine if flashes images will be flipped or not - newchar->toflip = GET_INT_ARG(1); - break; - case CMD_MODEL_NODIEBLINK: - // Added to determine if dying animation blinks or not - - tempInt = GET_INT_ARG(1); - - newchar->death_config_flags = death_config_get_value_from_nodieblink(newchar->death_config_flags, tempInt); - - break; - case CMD_MODEL_NOATFLASH: // Flag to determine if an opponents attack spawns their flash or not - newchar->noatflash = GET_INT_ARG(1); - break; - case CMD_MODEL_NOMOVE: - - /* - * Legacy no move. Set move constraint flags - * to match the old nomove parameters. - */ - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_NO_MOVE; - newchar->pain_config_flags |= PAIN_CONFIG_FALL_DISABLE; - } - - if (GET_INT_ARG(2)) - { - newchar->move_config_flags |= MOVE_CONFIG_NO_FLIP; - } - - break; - case CMD_MODEL_NODROP: - - tempInt = GET_INT_ARG(1); - - newchar->pain_config_flags &= ~(PAIN_CONFIG_FALL_DISABLE | PAIN_CONFIG_FALL_DISABLE_AIR); - - switch (tempInt) - { - default: - case 0: - break; - case 1: - newchar->pain_config_flags |= PAIN_CONFIG_FALL_DISABLE; - break; - case 2: - newchar->pain_config_flags |= (PAIN_CONFIG_FALL_DISABLE | PAIN_CONFIG_FALL_DISABLE_AIR); - break; - } - - break; - case CMD_MODEL_THOLD: - // Threshold for enemies/players block - newchar->thold = GET_INT_ARG(1); - break; - - case CMD_MODEL_RUN_CONFIG: - newchar->run_config_flags = run_get_config_flags_from_command_line(buf + pos, 1); - break; - case CMD_MODEL_RUNNING: - // The speed at which the player runs - newchar->runspeed = GET_FLOAT_ARG(1); - newchar->runspeed /= 10; - newchar->runjumpheight = GET_FLOAT_ARG(2); // The height at which a player jumps when running - newchar->runjumpdist = GET_FLOAT_ARG(3); // The distance a player jumps when running - - tempInt = GET_INT_ARG(4); - - newchar->run_config_flags |= (RUN_CONFIG_X_LEFT_ENABLED | RUN_CONFIG_X_LEFT_INITIAL | RUN_CONFIG_X_RIGHT_ENABLED | RUN_CONFIG_X_RIGHT_INITIAL); - - if (tempInt) - { - newchar->run_config_flags |= (RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_UP_ENABLED); - } - else - { - newchar->run_config_flags &= ~(RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_UP_ENABLED); - } - - tempInt = GET_INT_ARG(5); - - if (tempInt) - { - newchar->run_config_flags |= RUN_CONFIG_LAND; - } - else - { - newchar->run_config_flags &= ~RUN_CONFIG_LAND; - } - - break; - case CMD_MODEL_RUNNING_CONTINUE: - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->run_config_flags |= RUN_CONFIG_LAND; - } - else - { - newchar->run_config_flags &= ~RUN_CONFIG_LAND; - } - break; - case CMD_MODEL_RUNNING_JUMP_VELOCITY_X: - newchar->runjumpdist = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_RUNNING_JUMP_VELOCITY_Y: - newchar->runjumpheight = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_RUNNING_SPEED: - newchar->runspeed = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_RUNNING_Z_MOVE: - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->run_config_flags |= (RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_UP_ENABLED); - } - else - { - newchar->run_config_flags &= ~(RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_UP_ENABLED); - } - - break; - case CMD_MODEL_BLOCKODDS: - // Odds that an attack will hit an enemy (1 : blockodds) - newchar->blockodds = GET_INT_ARG(1); - break; - case CMD_MODEL_HOLDBLOCK: - - tempInt = GET_INT_ARG(1); - - newchar->block_config_flags &= ~(BLOCK_CONFIG_HOLD_IMPACT | BLOCK_CONFIG_HOLD_INFINITE); - - switch (tempInt) - { - default: - case 0: - /* Do nothing. */ - break; - case 1: - newchar->block_config_flags |= BLOCK_CONFIG_HOLD_IMPACT; - break; - case 2: - newchar->block_config_flags |= (BLOCK_CONFIG_HOLD_IMPACT | BLOCK_CONFIG_HOLD_INFINITE); - break; - } - - break; - case CMD_MODEL_BLOCKPAIN: - newchar->blockpain = GET_INT_ARG(1); - break; - case CMD_MODEL_NOPASSIVEBLOCK: - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->block_config_flags |= BLOCK_CONFIG_ACTIVE; - } - else - { - newchar->block_config_flags &= ~BLOCK_CONFIG_ACTIVE; - } - - break; - case CMD_MODEL_EDELAY: - tempInt = GET_INT_ARG(1); - - if (tempInt == EDELAY_MODE_MULTIPLY) - { - newchar->edelay.factor = GET_FLOAT_ARG(2); - } - else - { - newchar->edelay.modifier = GET_INT_ARG(2); - } - - newchar->edelay.cap.min = GET_INT_ARG(3); - newchar->edelay.cap.max = GET_INT_ARG(4); - newchar->edelay.range.min = GET_INT_ARG(5); - newchar->edelay.range.max = GET_INT_ARG(6); - break; - - case CMD_MODEL_ENHANCED_DELAY_CAP_MAX: - - newchar->edelay.cap.max = GET_INT_ARG(1); - break; - - case CMD_MODEL_ENHANCED_DELAY_CAP_MIN: - - newchar->edelay.cap.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_ENHANCED_DELAY_MODIFIER: - - newchar->edelay.modifier = GET_INT_ARG(1); - break; - - case CMD_MODEL_ENHANCED_DELAY_MULTIPLIER: - - newchar->edelay.factor = GET_FLOAT_ARG(1); - break; - - case CMD_MODEL_ENHANCED_DELAY_RANGE_MAX: - - newchar->edelay.range.max = GET_INT_ARG(1); - break; - - case CMD_MODEL_ENHANCED_DELAY_RANGE_MIN: - - newchar->edelay.range.min = GET_INT_ARG(1); - break; - - case CMD_MODEL_PAIN_BACK: - - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->pain_config_flags |= PAIN_CONFIG_BACK_PAIN; - } - else - { - newchar->pain_config_flags &= ~PAIN_CONFIG_BACK_PAIN; - } - - break; - case CMD_MODEL_PAIN_CONFIG: - - tempInt = GET_INT_ARG(1); - - newchar->pain_config_flags = pain_get_config_flags_from_command_line(buf + pos); - - break; - - case CMD_MODEL_PAINGRAB: - newchar->paingrab = GET_INT_ARG(1); - break; - case CMD_MODEL_THROW: - newchar->throwdist = GET_FLOAT_ARG(1); - newchar->throwheight = GET_FLOAT_ARG(2); - break; - case CMD_MODEL_EDGERANGE: - newchar->edgerange.x = GET_FLOAT_ARG(1); - newchar->edgerange.z = GET_FLOAT_ARG(2); - break; - case CMD_MODEL_ENTITYPUSHING: - newchar->entitypushing = GET_INT_ARG(1); - break; - case CMD_MODEL_PUSHINGFACTOR: - newchar->pushingfactor = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_GRABWALK: - newchar->grabwalkspeed = GET_FLOAT_ARG(1); - newchar->grabwalkspeed /= 10; - if(newchar->grabwalkspeed < 0.5) - { - newchar->grabwalkspeed = 0.5; - } - break; - case CMD_MODEL_GRABTURN: - newchar->grabturn = GET_INT_ARG(1); - break; - case CMD_MODEL_THROWFRAMEWAIT: - newchar->throwframewait = GET_INT_ARG(1); - break; - case CMD_MODEL_DIESOUND: - newchar->diesound = sound_load_sample(GET_ARG(1), packfile, 1, 0); - break; - case CMD_MODEL_ICON: - value = GET_ARG(1); - if(newchar->icon.def > -1) - { - shutdownmessage = "model has multiple icons defined"; - goto lCleanup; - } - newchar->icon.def = loadsprite(value, 0, 0, pixelformat); //use same palette as the owner - newchar->icon.pain = newchar->icon.def; - newchar->icon.die = newchar->icon.def; - newchar->icon.get = newchar->icon.def; - newchar->icon.usemap = GET_INT_ARG(2); //be more friendly to some old mods which don't care about icon remap - break; - case CMD_MODEL_ICONPAIN: - value = GET_ARG(1); - newchar->icon.pain = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONDIE: - value = GET_ARG(1); - newchar->icon.die = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONGET: - value = GET_ARG(1); - newchar->icon.get = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONW: - value = GET_ARG(1); - newchar->icon.weapon = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONMPHALF: - value = GET_ARG(1); - newchar->icon.mpmed = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONMPHIGH: - value = GET_ARG(1); - newchar->icon.mphigh = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONMPLOW: - value = GET_ARG(1); - newchar->icon.mplow = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONMPMAX: - value = GET_ARG(1); - newchar->icon.mpmax = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_ICONMPNONE: - value = GET_ARG(1); - newchar->icon.mpnone = loadsprite(value, 0, 0, pixelformat); - break; - case CMD_MODEL_PARROW: - // Image that is displayed when player 1 spawns invincible - value = GET_ARG(1); - newchar->player_arrow[0].sprite = loadsprite(value, 0, 0, pixelformat); - newchar->player_arrow[0].position.x = GET_INT_ARG(2); - newchar->player_arrow[0].position.y = GET_INT_ARG(3); - break; - case CMD_MODEL_PARROW2: - // Image that is displayed when player 2 spawns invincible - value = GET_ARG(1); - newchar->player_arrow[1].sprite = loadsprite(value, 0, 0, pixelformat); - newchar->player_arrow[1].position.x = GET_INT_ARG(2); - newchar->player_arrow[1].position.y = GET_INT_ARG(3); - break; - case CMD_MODEL_PARROW3: - value = GET_ARG(1); - newchar->player_arrow[2].sprite = loadsprite(value, 0, 0, pixelformat); - newchar->player_arrow[2].position.x = GET_INT_ARG(2); - newchar->player_arrow[2].position.y = GET_INT_ARG(3); - break; - case CMD_MODEL_PARROW4: - value = GET_ARG(1); - newchar->player_arrow[3].sprite = loadsprite(value, 0, 0, pixelformat); - newchar->player_arrow[3].position.x = GET_INT_ARG(2); - newchar->player_arrow[3].position.y = GET_INT_ARG(3); - break; - case CMD_MODEL_ATCHAIN: - newchar->chainlength = 0; - for(i = 0; i < MAX_ATCHAIN; i++) - { - newchar->atchain[i] = GET_INT_ARG(i + 1); - if(newchar->atchain[i] < 0) - { - newchar->atchain[i] = 0; - } - if(newchar->atchain[i] > max_attacks) - { - newchar->atchain[i] = max_attacks; - } - if(newchar->atchain[i]) - { - newchar->chainlength = i + 1; - } - } - break; - case CMD_MODEL_COMBOSTYLE: - newchar->combostyle = GET_INT_ARG(1); - break; - case CMD_MODEL_CREDIT: - newchar->credit = GET_INT_ARG(1); - break; - case CMD_MODEL_NOPAIN: - tempInt = GET_INT_ARG(1); - - if (tempInt) - { - newchar->pain_config_flags |= PAIN_CONFIG_PAIN_DISABLE; - } - else - { - newchar->pain_config_flags &= ~PAIN_CONFIG_PAIN_DISABLE; - } - - break; - case CMD_MODEL_ESCAPEHITS: - // How many times an enemy can be hit before retaliating - newchar->escapehits = GET_INT_ARG(1); - break; - case CMD_MODEL_CHARGERATE: - // How much mp does this character gain while recharging? - newchar->chargerate = GET_INT_ARG(1); - break; - case CMD_MODEL_MPRATE: - newchar->mprate = GET_INT_ARG(1); - break; - case CMD_MODEL_MPSET: - // Mp bar wax/wane. - newchar->mp = GET_INT_ARG(1); //Max MP. - newchar->mpstable = GET_INT_ARG(2); //MP stable setting. - newchar->mpstableval = GET_INT_ARG(3); //MP stable value (% Mp bar will try and maintain). - newchar->mprate = GET_INT_ARG(4); //Rate MP value rises over time. - newchar->mpdroprate = GET_INT_ARG(5); //Rate MP value drops over time. - newchar->chargerate = GET_INT_ARG(6); //MP Chargerate. - break; - case CMD_MODEL_SLEEPWAIT: - newchar->sleepwait = GET_INT_ARG(1); - break; - case CMD_MODEL_GUARDRATE: - newchar->guardrate = GET_INT_ARG(1); - break; - case CMD_MODEL_AGGRESSION: - newchar->aggression = GET_INT_ARG(1); - break; - case CMD_MODEL_ATTACKTHROTTLE: - newchar->attackthrottle = GET_FLOAT_ARG(1); - if(arglist.count >= 2) - { - newchar->attackthrottletime = GET_FLOAT_ARG(2) * global_config.game_speed; - } - break; - case CMD_MODEL_RISETIME: - newchar->risetime.rise = GET_INT_ARG(1); - newchar->risetime.riseattack = GET_INT_ARG(2); - break; - case CMD_MODEL_FACING: - newchar->facing = GET_INT_ARG(1); - break; - case CMD_MODEL_TURNDELAY: - newchar->turndelay = GET_INT_ARG(1); - break; - case CMD_MODEL_LIFESPAN: - newchar->lifespan = GET_FLOAT_ARG(1) * global_config.game_speed; - break; - case CMD_MODEL_SUMMONKILL: - newchar->summonkill = GET_INT_ARG(1); - break; - case CMD_MODEL_LIFEPOSITION: - - /* - * Allocate object if we need it first. - */ - - if (!newchar->hud_popup) - { - newchar->hud_popup = bar_status_allocate_object(); - } - - if ((value = GET_ARG(1))[0]) - { - newchar->hud_popup->graph_position.x = atoi(value); - } - if ((value = GET_ARG(2))[0]) - { - newchar->hud_popup->graph_position.y = atoi(value); - } - - break; - case CMD_MODEL_LIFEBARSTATUS: - - /* - * Allocate object if we need it first. - */ - - if (!newchar->hud_popup) - { - newchar->hud_popup = bar_status_allocate_object(); - } - - _readbarstatus(buf + pos, newchar->hud_popup); - newchar->hud_popup->colourtable = &hpcolourtable; - break; - case CMD_MODEL_ICONPOSITION: - if((value = GET_ARG(1))[0]) - { - newchar->icon.position.x = atoi(value); - } - if((value = GET_ARG(2))[0]) - { - newchar->icon.position.y = atoi(value); - } - break; - case CMD_MODEL_NAMEPOSITION: - - /* - * Allocate object if we need it first. - */ - - if (!newchar->hud_popup) - { - newchar->hud_popup = bar_status_allocate_object(); - } - - if((value = GET_ARG(1))[0]) - { - newchar->hud_popup->name_position.x = atoi(value); - } - if((value = GET_ARG(2))[0]) - { - newchar->hud_popup->name_position.y = atoi(value); - } - break; - - case CMD_MODEL_COM: - { - s_command_token_reader token_reader = { - .cursor = buf + pos - }; - - s_command_token token; - - /* - * Parse into a temporary command first. This prevents - * a malformed line from partially modifying the model. - */ - s_com parsed_special = {0}; - - const char* parse_error; - - int freespecial_number; - - /* - * Consume and verify the command-name token. - */ - if(!command_token_reader_next(&token_reader, &token) || !command_token_equals(&token, "com")) { - shutdownmessage = "Invalid freespecial command name.\n"; - goto lCleanup; - } - - /* - * Parse all sequence tokens through the destination - * freespecial animation. - */ - parse_error = special_command_parse_sequence( - &token_reader, - &parsed_special, - &freespecial_number, - alert_buffer, - sizeof(alert_buffer) - ); - - if(parse_error) { - shutdownmessage = parse_error; - goto lCleanup; - } - - parsed_special.anim = animspecials[freespecial_number - 1]; - - if(!alloc_specials(newchar)) { - shutdownmessage = E_OUT_OF_MEMORY; - goto lCleanup; - } - - newchar->special[newchar->specials_loaded] = parsed_special; - newchar->specials_loaded++; - } - break; - - case CMD_MODEL_REMAP: - { - // This command should not be used under 24bit mode, but for old mods, just give it a default palette - value = GET_ARG(1); - value2 = GET_ARG(2); - __realloc(mapflag, newchar->maps_loaded); - errorVal = load_colourmap(newchar, value, value2); - - if(0 >= errorVal) - { - switch(errorVal) - { - case 0: // uhm wait, we just tested for !errorVal... - value2 = "Failed to create colourmap. Image Used Twice!"; - break; - case -1: //should not happen now - value2 = "Failed to create colourmap. Color maps full error (color maps are unlimited by engine - check memory limits of console)!"; - break; - case -2: - value2 = "Failed to create colourmap. Failed to allocate memory!"; - break; - case -3: - value2 = "Failed to create colourmap. Failed to load file 1"; - break; - case -4: - value2 = "Failed to create colourmap. Failed to load file 2"; - break; - } - printf("Warning: %s\n", value2); - } - else - { - if(pixelformat == PIXEL_x8 && newchar->palette == NULL) - { - newchar->palette = malloc(PAL_BYTES); - if(loadimagepalette(value, packfile, newchar->palette) == 0) - { - shutdownmessage = "Failed to load palette!"; - goto lCleanup; - } - } - mapflag[newchar->maps_loaded - 1] = 1; - } - } - break; - case CMD_MODEL_PALETTE: - - if(newchar->palette == NULL) - { - - // Command title for log. Details will be added below accordingly. - // Forced character length is to line up with Alternatepal logs. - //printf("\t\t\tPalette: \t"); - - // Get argument. - value = GET_ARG(1); - - // If "none" then set nopalette, meaning each - // frame retains its own color table as is. - // Otherwise we will set up the model level - // color table. - if(stricmp(value, "none") == 0) - { - nopalette = 1; - - //printf("%s\n", "'None' option active. All sprites for this model will be loaded with independent color tables."); - } - else - { - // Set up the model level color table. - // We can load either directly from - // an .act file or read the color table - // from an image. - - // Allocate space for the color table. - newchar->palette = malloc(PAL_BYTES); - - if(load_palette(newchar->palette, value) == 0) - { - printf("\n%s%s\n", "Failed to load color table from file: ", value); - shutdownmessage = "Failed to load color table from file."; - goto lCleanup; - } - - //printf("%s%s\n", "Loaded color selection 0: ", value); - } - } - - break; - case CMD_MODEL_ALTERNATEPAL: - - // Command title for log. Details will be added blow accordingly. - //printf("\t"LOG_CMD_TITLE"%s", "Alternatepal", " - "); - - __realloc(mapflag, newchar->maps_loaded); - __realloc(newchar->colourmap, newchar->maps_loaded); - value = GET_ARG(1); - - newchar->colourmap[newchar->maps_loaded] = malloc(PAL_BYTES); - - if(load_palette(newchar->colourmap[newchar->maps_loaded], value) == 0) - { - printf("\n%s%s\n", "Failed to load color table from file: ", value); - shutdownmessage = "Failed to load color table from file."; - goto lCleanup; - } - - newchar->maps_loaded++; - - //printf("Loaded color selection %i: %s", newchar->maps_loaded, value); - - break; - case CMD_MODEL_GLOBALMAP: - - // Command title for log. Details will be added blow accordingly. - //printf("\t"LOG_CMD_TITLE"%s", "Globalmap", " - "); - - // use global palette under 24bit mode, so some entity/panel/bg can still use palette feature, that saves some memory - newchar->globalmap = GET_INT_ARG(1); - - //printf("%i: %s\n", newchar->globalmap, value); - - break; - case CMD_MODEL_ALPHA: - newchar->alpha = GET_INT_ARG(1); - break; - case CMD_MODEL_REMOVE: - value = GET_ARG(1); - - newchar->remove_config = get_remove_config_from_string(value); - - break; - case CMD_MODEL_SCRIPT: - //load the update script - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->update_script, "updateentityscript", filename, 1, 0); - break; - case CMD_MODEL_THINKSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->think_script, "thinkscript", filename, 1, 0); - break; - case CMD_MODEL_TAKEDAMAGESCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->takedamage_script, "takedamagescript", filename, 1, 0); - break; - case CMD_MODEL_ON_BIND_UPDATE_OTHER_TO_SELF_SCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->on_bind_update_other_to_self_script, "on_bind_update_other_to_self_script", filename, 1, 0); - break; - case CMD_MODEL_ON_BIND_UPDATE_SELF_TO_OTHER_SCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->on_bind_update_self_to_other_script, "on_bind_update_self_to_other_script", filename, 1, 0); - break; - case CMD_MODEL_ONFALLSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onfall_script, "onfallscript", filename, 1, 0); - break; - case CMD_MODEL_ONPAINSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onpain_script, "onpainscript", filename, 1, 0); - break; - case CMD_MODEL_INHOLESCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->inhole_script, "inholescript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKSSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblocks_script, "onblocksscript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKWSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblockw_script, "onblockwscript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKPSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblockp_script, "onblockpscript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKOSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblocko_script, "onblockoscript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKZSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblockz_script, "onblockzscript", filename, 1, 0); - break; - case CMD_MODEL_ONBLOCKYSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onblocky_script, "onblockyscript", filename, 1, 0); - break; - case CMD_MODEL_ONMOVEXSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onmovex_script, "onmovexscript", filename, 1, 0); - break; - case CMD_MODEL_ONMOVEZSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onmovez_script, "onmovezscript", filename, 1, 0); - break; - case CMD_MODEL_ONMOVEYSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onmovea_script, "onmoveyscript", filename, 1, 0); - break; - case CMD_MODEL_ONDEATHSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->ondeath_script, "ondeathscript", filename, 1, 0); - break; - case CMD_MODEL_ONENTITYCOLLISIONSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onentitycollision_script, "onentitycollisionscript", filename, 1, 0); - break; - case CMD_MODEL_ONKILLSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onkill_script, "onkillscript", filename, 1, 0); - break; - case CMD_MODEL_MODELLOADSCRIPT: - if(Script_IsInitialized(model_cache[cacheindex].load_script)) - { - Script_Clear(model_cache[cacheindex].load_script, 1); - } - pos += lcmHandleCommandScripts( - &arglist, - buf + pos, - model_cache[cacheindex].load_script, - "modelloadscript", - filename, - 1, - 0 - ); - break; - case CMD_MODEL_MODELUNLOADSCRIPT: - if(Script_IsInitialized(model_cache[cacheindex].unload_script)) - { - Script_Clear(model_cache[cacheindex].unload_script, 1); - } - pos += lcmHandleCommandScripts( - &arglist, - buf + pos, - model_cache[cacheindex].unload_script, - "modelunloadscript", - filename, - 1, - 0 - ); - break; - case CMD_MODEL_DIDBLOCKSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->didblock_script, "didblockscript", filename, 1, 0); - break; - case CMD_MODEL_ONDOATTACKSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->ondoattack_script, "ondoattackscript", filename, 1, 0); - break; - case CMD_MODEL_DIDHITSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->didhit_script, "didhitscript", filename, 1, 0); - break; - case CMD_MODEL_ONSPAWNSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onspawn_script, "onspawnscript", filename, 1, 0); - break; - case CMD_MODEL_ONMODELCOPYSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->onmodelcopy_script, "onmodelcopyscript", filename, 1, 0); - break; - case CMD_MODEL_ONDRAWSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->ondraw_script, "ondrawscript", filename, 1, 0); - break; - case CMD_MODEL_ANIMATIONSCRIPT: - //pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->animation_script, "animationscript", filename, 0, 0); - pos += lcmScriptCopyBuffer(&arglist, buf + pos, &animscriptbuf); - //dont compile, until at end of this function - break; - case CMD_MODEL_KEYSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, newchar->scripts->key_script, "entitykeyscript", filename, 1, 0); - break; - case CMD_MODEL_ANIM: - { - bool freespecial_recognized; - - int freespecial_number; - - s_command_token animation_name_token; - - const char* freespecial_error; - - value = GET_ARG(1); - - /* - * Parse numbered freespecial animations before any - * allocation or animation-table indexing takes place. - */ - animation_name_token.text = value; - animation_name_token.length = strlen(value); - - freespecial_error = command_token_get_freespecial_number( - &animation_name_token, - &freespecial_recognized, - &freespecial_number, - alert_buffer, - sizeof(alert_buffer) - ); - - if(freespecial_error) { - shutdownmessage = freespecial_error; - goto lCleanup; - } - - frameset = 0; - framecount = 0; - // Create new animation - newanim = alloc_anim(); - if(!newanim) - { - shutdownmessage = "Not enough memory for animations!"; - goto lCleanup; - } - newanim->model_index = newchar->index; - // Reset vars - curframe = 0; - at_cmd_mergeable = false; - - /* - * Caskey, Damon V. - * 2021-08-23 - * - * Prepare temporary lists for input. - */ - collision_collection_free(temp_collision_attack); - collision_collection_free(temp_collision_body); - collision_collection_free(temp_collision_space); - temp_collision_attack = NULL; - temp_collision_body = NULL; - temp_collision_space = NULL; - temp_collision_index = 0; - - frame_sound_collection_free(temp_frame_sound); - temp_frame_sound = NULL; - temp_frame_sound_index = 0; - - child_spawn_free_list(temp_child_spawn_head); - temp_child_spawn_head = NULL; - temp_child_spawn_index = 0; - - //printf("\n\n anim: %p", newanim); - //child_spawn_dump_list(temp_child_spawn_head); - - memset(&offset, 0, sizeof(offset)); - memset(shadow_coords, 0, sizeof(shadow_coords)); - memset(shadow_xz, 0, sizeof(shadow_xz)); - memset(platform, 0, sizeof(platform)); - - shadow_set = 0; - drawmethod = plainmethod; - idle = 0; - move.base = -1; - move.axis.x = 0; - move.axis.y = 0; - move.axis.z = 0; - frameshadow = FRAME_SHADOW_NONE; - - /* - * Other than Min X, default ranges are - * based on jump height or grabdistance. - * This is partialy for legacy compatability. - * It works well enough that beginners won't - * know the difference and advanced creators - * will always want to adjust for their specfic - * needs. - */ - - const int range_default_grabdistance = (int)newchar->grabdistance / 3; - const int range_default_jumpheight_max = (int)newchar->jumpheight * 20; - const int range_default_jumpheight_min = (int)newchar->jumpheight * 10; - - newanim->range = (s_range){ - .base = {.max = range_default_jumpheight_max, .min = -range_default_jumpheight_min }, - .x = {.max = range_default_jumpheight_max, .min = (newanim->range.x.min) ? newanim->range.x.min : -10 }, - .y = {.max = range_default_jumpheight_max, .min = -range_default_jumpheight_min }, - .z = {.max = range_default_grabdistance, .min = -range_default_grabdistance } - }; - - - newanim->energy_cost.cost = 0; - newanim->energy_cost.disable = 0; - newanim->energy_cost.mponly = COST_TYPE_MP_THEN_HP; - newanim->charge_time = ANIMATION_CHARGE_TIME_DEFAULT; - newanim->projectile = NULL; - newanim->flipframe = FRAME_NONE; - newanim->attack_one = 0; - newanim->move_config_flags |= MOVE_CONFIG_SUBJECT_TO_GRAVITY; - newanim->followup.animation = 0; // Default disabled - newanim->followup.condition = FOLLOW_CONDITION_NONE; - newanim->sub_entity_unsummon = FRAME_NONE; - newanim->landframe.frame = FRAME_NONE; - newanim->landframe.model_index = FRAME_SET_MODEL_INDEX_DEFAULT; - - newanim->jumpframe = (s_onframe_move){ - .frame = FRAME_NONE, - .model_index = MODEL_INDEX_NONE, - .velocity = default_model_dropv - }; - - newanim->dropframe.frame = FRAME_NONE; - newanim->dropframe.model_index = FRAME_SET_MODEL_INDEX_DEFAULT; - newanim->cancel = ANIMATION_CANCEL_DISABLED; // OX. For cancelling anims into a freespecial. - newanim->hit_count = 0; //OX counts hits on a per anim basis for cancels. - newanim->sub_entity_model_index = MODEL_INDEX_NONE; - newanim->sub_entity_spawn = NULL; - newanim->sub_entity_summon = NULL; - newanim->quakeframe.framestart = 0; - newanim->sync = FRAME_NONE; - - if(freespecial_recognized) { - ani_id = animspecials[freespecial_number - 1]; - - } else { - ani_id = translate_ani_id(value, newchar, newanim); - } - - if(ani_id < 0) - { - shutdownmessage = "Invalid animation name!"; - goto lCleanup; - } - - newchar->animation[ani_id] = newanim; - } - break; - case CMD_MODEL_LOOP: - if(!newanim) - { - shutdownmessage = "Can't set loop: no animation specified!"; - goto lCleanup; - } - newanim->loop.mode = GET_INT_ARG(1); //0 = Off, 1 = on. - newanim->loop.frame.min = GET_INT_ARG(2); //Loop to frame. - newanim->loop.frame.max = GET_INT_ARG(3); //Loop end frame. - break; - case CMD_MODEL_ANIMHEIGHT: - newanim->size.y = GET_INT_ARG(1); - break; - case CMD_MODEL_SYNC: - { - bool freespecial_recognized; - - int freespecial_number; - - s_command_token animation_name_token; - - const char* freespecial_error; - - value = GET_ARG(1); - - animation_name_token.text = value; - animation_name_token.length = strlen(value); - - freespecial_error = command_token_get_freespecial_number( - &animation_name_token, - &freespecial_recognized, - &freespecial_number, - alert_buffer, - sizeof(alert_buffer) - ); - - if(freespecial_error) { - shutdownmessage = freespecial_error; - goto lCleanup; - } - - /* - * "none" intentionally translates to FRAME_NONE and - * continues to disable the default synchronization. - */ - newanim->sync = freespecial_recognized - ? animspecials[freespecial_number - 1] - : translate_ani_id(value, NULL, NULL); - } - break; - case CMD_MODEL_DELAY: - { - const char* delay_error = command_token_get_delay( - GET_ARG(1), - GET_ARG(2), - &delay, - &delay_mode - ); - - if(delay_error) { - shutdownmessage = delay_error; - goto lCleanup; - } - - break; - } - case CMD_MODEL_OFFSET: - offset.x = GET_INT_ARG(1); - offset.y = GET_INT_ARG(2); - break; - case CMD_MODEL_SHADOWCOORDS: - shadow_xz[0] = GET_INT_ARG(1); - shadow_xz[1] = GET_INT_ARG(2); - shadow_set = 1; - break; - case CMD_MODEL_ENERGY_COST: - case CMD_MODEL_MPCOST: - - newanim->energy_cost.cost = GET_INT_ARG(1); - newanim->energy_cost.mponly = GET_INT_ARG(2); - newanim->energy_cost.disable = GET_INT_ARG(3); - - // Caskey, Damon V. - // 2019-11-22 - // - // Convert the idiotic arbitrary numeric value in text into bitwise - // logic with entity types. I was a buffoon when I first coded this - // feature and should have used bitwise logic to begin with. - switch (newanim->energy_cost.disable) - { - case 1: - newanim->energy_cost.disable |= TYPE_ENEMY; - newanim->energy_cost.disable |= TYPE_NPC; - newanim->energy_cost.disable |= TYPE_PLAYER; - break; - case 2: - newanim->energy_cost.disable |= TYPE_ENEMY; - newanim->energy_cost.disable |= TYPE_NPC; - break; - case 3: - newanim->energy_cost.disable |= TYPE_NPC; - newanim->energy_cost.disable |= TYPE_PLAYER; - break; - case 4: - newanim->energy_cost.disable |= TYPE_ENEMY; - newanim->energy_cost.disable |= TYPE_PLAYER; - break; - } - - break; - case CMD_MODEL_MPONLY: - newanim->energy_cost.mponly = GET_INT_ARG(1); - break; - case CMD_MODEL_CHARGETIME: - newanim->charge_time = GET_INT_ARG(1); - break; - - /* 2022-05-27 - * Caskey, Damon V. - * - * Index needs to come before any other child spawn - * read in command so we know which object index - * we want the child spawn commands to affect. - * - * The next in order are presets, so the creator - * can use a preset, then customize individual - * settings downstream. - */ - case CMD_MODEL_CHILD_SPAWN_INDEX: - temp_child_spawn_index = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_PRESET_BOMB: - - /* - * Shortcut for creator to set up a bomb projectile. - */ - - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->config = (CHILD_SPAWN_CONFIG_AUTOKILL_HIT | CHILD_SPAWN_CONFIG_BEHAVIOR_BOMB | CHILD_SPAWN_CONFIG_FACTION_DAMAGE_PARENT | CHILD_SPAWN_CONFIG_FACTION_HOSTILE_PARENT | CHILD_SPAWN_CONFIG_FACTION_INDIRECT_PARENT | CHILD_SPAWN_CONFIG_LAUNCH_TOSS | CHILD_SPAWN_CONFIG_MOVE_CONFIG_PARAMETER | CHILD_SPAWN_CONFIG_RELATIONSHIP_OWNER); - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->aimove = AIMOVE1_BOMB; - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->direction_adjust = DIRECTION_ADJUST_SAME; - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->move_config_flags = (MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL | MOVE_CONFIG_SUBJECT_TO_MAX_Z | MOVE_CONFIG_SUBJECT_TO_MIN_Z); - - break; - - case CMD_MODEL_CHILD_SPAWN_PRESET_SHOT: - - /* - * Shortcut for creator to set up a shot projectile. - */ - - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->config = (CHILD_SPAWN_CONFIG_AUTOKILL_HIT | CHILD_SPAWN_CONFIG_BEHAVIOR_SHOT | CHILD_SPAWN_CONFIG_FACTION_DAMAGE_PARENT | CHILD_SPAWN_CONFIG_FACTION_HOSTILE_PARENT | CHILD_SPAWN_CONFIG_FACTION_INDIRECT_PARENT | CHILD_SPAWN_CONFIG_GRAVITY_OFF | CHILD_SPAWN_CONFIG_LAUNCH_THROW | CHILD_SPAWN_CONFIG_MOVE_CONFIG_PARAMETER | CHILD_SPAWN_CONFIG_RELATIONSHIP_OWNER); - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->aimove = AIMOVE1_ARROW; - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->direction_adjust = DIRECTION_ADJUST_SAME; - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->move_config_flags = (MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL | MOVE_CONFIG_SUBJECT_TO_MAX_Z | MOVE_CONFIG_SUBJECT_TO_MIN_Z); - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->takedamage = arrow_takedamage; - - break; - - case CMD_MODEL_CHILD_SPAWN_AIMOVE: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->aimove = get_aimove_from_command_line(buf + pos, AIMOVE1_NONE); - break; - case CMD_MODEL_CHILD_SPAWN_CANDAMAGE: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->candamage = get_type_from_command_line(buf + pos); - break; - case CMD_MODEL_CHILD_SPAWN_COLOR: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->color = child_spawn_get_color_from_argument(filename, command, GET_ARG(1)); - break; - case CMD_MODEL_CHILD_SPAWN_CONFIG: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->config = child_spawn_get_config_argument(buf + pos, 0); - break; - case CMD_MODEL_CHILD_SPAWN_DIRECTION_ADJUST: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->direction_adjust = direction_get_adjustment_from_argument(filename, command, GET_ARG(1)); - break; - case CMD_MODEL_CHILD_SPAWN_HOSTILE: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->hostile = get_type_from_command_line(buf + pos); - break; - case CMD_MODEL_CHILD_SPAWN_MODEL: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->model_index = get_cached_model_index(GET_ARG(1)); - break; - case CMD_MODEL_CHILD_SPAWN_MOVE_CONSTRAINT: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->move_config_flags = get_move_config_flags_from_command_line(buf + pos); - break; - case CMD_MODEL_CHILD_SPAWN_OFFSET_X: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->position.x = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_OFFSET_Y: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->position.y = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_OFFSET_Z: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->position.z = GET_INT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_PROJECTILEHIT: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->projectilehit = get_type_from_command_line(buf + pos); - break; - case CMD_MODEL_CHILD_SPAWN_TAKEDAMAGE: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->takedamage = takedamage_get_reference_from_argument(GET_ARG(1)); - break; - case CMD_MODEL_CHILD_SPAWN_VELOCITY_X: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->velocity.x = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_VELOCITY_Y: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->velocity.y = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_CHILD_SPAWN_VELOCITY_Z: - child_spawn_upsert_property(&temp_child_spawn_head, temp_child_spawn_index)->velocity.z = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_COLLISIONONE: - newanim->attack_one = GET_INT_ARG(1); - break; - - /* 2020-03-02 - * Caskey, Damon V. - * - * This needs to come before any other collision - * parse command so we know which collision index - * we want the collision commands to affect. - */ - case CMD_MODEL_COLLISION_INDEX: - tempInt = GET_INT_ARG(1); - - if(!collision_validate_slot_index(tempInt)) { - snprintf(alert_buffer, sizeof(alert_buffer), - "Collision index (%d) out of range (0 to %d).", tempInt, MAX_COLLISION_BOXES_PER_FRAME - 1); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - temp_collision_index = tempInt; - break; - case CMD_MODEL_COUNTERATTACK: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->counterattack = GET_INT_ARG(1); - - break; - case CMD_MODEL_THROWFRAME: - case CMD_MODEL_PSHOTFRAME: - case CMD_MODEL_PSHOTFRAMEW: - case CMD_MODEL_PSHOTFRAMENO: - - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->throwframe = GET_FRAME_ARG(1); - - if (GET_INT_ARG(2)) - { - newanim->projectile->position.y = GET_INT_ARG(2); - } - break; - - - case CMD_MODEL_SHOOTFRAME: - - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->shootframe = GET_FRAME_ARG(1); - - if (GET_INT_ARG(2)) - { - newanim->projectile->position.y = GET_INT_ARG(2); - } - break; - - case CMD_MODEL_TOSSFRAME: - case CMD_MODEL_PBOMBFRAME: - - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->tossframe = GET_FRAME_ARG(1); - - if (GET_INT_ARG(2)) - { - newanim->projectile->position.y = GET_INT_ARG(2); - } - - // For legacy compatability. See bomb_spawn() for details. - newanim->projectile->velocity.y = MODEL_SPEED_NONE; - break; - case CMD_MODEL_CUSTKNIFE: - case CMD_MODEL_CUSTPSHOT: - case CMD_MODEL_CUSTPSHOTW: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->knife = get_cached_model_index(GET_ARG(1)); - break; - case CMD_MODEL_CUSTPSHOTNO: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->flash = get_cached_model_index(GET_ARG(1)); - break; - case CMD_MODEL_CUSTBOMB: - case CMD_MODEL_CUSTPBOMB: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->bomb = get_cached_model_index(GET_ARG(1)); - - break; - case CMD_MODEL_CUSTSTAR: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->star = get_cached_model_index(GET_ARG(1)); - break; - case CMD_MODEL_PROJECTILE_COLOR_SET_ADJUST: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - tempInt = COLORSET_ADJUST_NONE; - } - else if (stricmp(value, "parent_index") == 0) - { - tempInt = COLORSET_ADJUST_PARENT_INDEX; - } - else if (stricmp(value, "parent_table") == 0) - { - tempInt = COLORSET_ADJUST_PARENT_TABLE; - } - else - { - tempInt = GET_INT_ARG(1); - } - - newanim->projectile->color_set_adjust = tempInt; - break; - case CMD_MODEL_PROJECTILE_DIRECTION_ADJUST: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - tempInt = direction_get_adjustment_from_argument(filename, command, GET_ARG(1)); - - newanim->projectile->direction_adjust = tempInt; - break; - case CMD_MODEL_PROJECTILE_OFFENSE: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - value = GET_ARG(1); - - if (stricmp(value, "parent") == 0) - { - tempInt = PROJECTILE_OFFENSE_PARENT; - } - else if (stricmp(value, "self") == 0) - { - tempInt = PROJECTILE_OFFENSE_SELF; - } - - newanim->projectile->offense = tempInt; - break; - case CMD_MODEL_PROJECTILE_POSITION_X: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->position.x = GET_INT_ARG(1); - break; - case CMD_MODEL_PROJECTILE_POSITION_Y: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->position.y = GET_INT_ARG(1); - break; - case CMD_MODEL_PROJECTILE_POSITION_Z: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->position.z = GET_INT_ARG(1); - break; - case CMD_MODEL_PROJECTILE_VELOCITY_X: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->velocity.x = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_PROJECTILE_VELOCITY_Y: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->velocity.y = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_PROJECTILE_VELOCITY_Z: - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->velocity.z = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_STAR_VELOCITY: - - // If we don't have a projectile allcated, do it now. - if (!newanim->projectile) - { - newanim->projectile = allocate_projectile(); - } - - newanim->projectile->star_velocity[0] = GET_FLOAT_ARG(1); - newanim->projectile->star_velocity[1] = GET_FLOAT_ARG(2); - newanim->projectile->star_velocity[2] = GET_FLOAT_ARG(3); - break; - - // Legacy dive attacks. Turn off animation level subject_to_gravity - // and then use jumpframe to fly down at an angle. - case CMD_MODEL_DIVE: - newanim->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - - newanim->jumpframe = (s_onframe_move){ - .frame = 0, - .model_index = MODEL_INDEX_NONE, - .velocity = {.x = GET_FLOAT_ARG(1), .y = -GET_FLOAT_ARG(2), .z = 0 } - }; - break; - - case CMD_MODEL_DIVE1: - newanim->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - - newanim->jumpframe = (s_onframe_move){ - .frame = 0, - .model_index = MODEL_INDEX_NONE, - .velocity = {.x = GET_FLOAT_ARG(1), .y = 0, .z = 0 } - }; - break; - case CMD_MODEL_DIVE2: - newanim->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - - newanim->jumpframe = (s_onframe_move){ - .frame = 0, - .model_index = MODEL_INDEX_NONE, - .velocity = {.x = 0, .y = -GET_FLOAT_ARG(2), .z = 0 } - }; - break; - case CMD_MODEL_JUMPFRAME: - { - memset(&newanim->jumpframe.velocity, 0, sizeof(s_axis_principal_float)); - - newanim->jumpframe.frame = GET_FRAME_ARG(1); - newanim->jumpframe.velocity.y = GET_FLOAT_ARG(2); - - value = GET_ARG(3); - if(value[0]) - { - newanim->jumpframe.velocity.x = GET_FLOAT_ARG(3); - newanim->jumpframe.velocity.z = GET_FLOAT_ARG(4); - } - else // k, only for backward compatibility :(((((((((((((((( - { - if(newanim->jumpframe.velocity.y <= 0) - { - if(newchar->type == TYPE_PLAYER) - { - newanim->jumpframe.velocity.y = newchar->jumpheight / 2; - newanim->jumpframe.velocity.z = 0; - newanim->jumpframe.velocity.x = 2; - } - else - { - newanim->jumpframe.velocity.y = newchar->jumpheight; - newanim->jumpframe.velocity.z = newanim->jumpframe.velocity.x = 0; - } - } - else - { - if(newchar->type != TYPE_ENEMY && newchar->type != TYPE_NPC) - { - newanim->jumpframe.velocity.z = newanim->jumpframe.velocity.x = 0; - } - else - { - newanim->jumpframe.velocity.z = 0; - newanim->jumpframe.velocity.x = (float)1.3; - } - } - } - - value = GET_ARG(5); - if(value[0]) - { - newanim->jumpframe.model_index = get_cached_model_index(value); - } - else - { - newanim->jumpframe.model_index = MODEL_INDEX_NONE; - } - } - break; - case CMD_MODEL_BOUNCEFACTOR: - newanim->bounce_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_LANDFRAME: - // Landing frame. - newanim->landframe.frame = GET_FRAME_ARG(1); - - // Entity to spawn when land frame triggers. - value = GET_ARG(2); - if(value[0]) - { - newanim->landframe.model_index = get_cached_model_index(value); - } - - break; - case CMD_MODEL_DROPFRAME: - - newanim->dropframe.frame = GET_FRAME_ARG(1); - - // Entity to spawn when drop frame triggers. - value = GET_ARG(2); - if (value[0]) - { - newanim->dropframe.model_index = get_cached_model_index(value); - } - - break; - case CMD_MODEL_CANCEL: - { - s_command_token_reader token_reader = { - .cursor = buf + pos - }; - - s_command_token token; - - /* - * Parse into a temporary command first. This prevents - * a malformed line from partially modifying the model. - */ - s_com parsed_special = {0}; - - const char* parse_error; - - int64_t frame_min; - int64_t frame_max; - int64_t required_hits; - int freespecial_number; - - /* - * Cancel belongs to the currently active animation. - */ - if(!newanim || ani_id < 0) { - shutdownmessage = - "Cannot add cancel command: animation not specified.\n"; - - goto lCleanup; - } - - /* - * Consume and verify the command-name token. - */ - if(!command_token_reader_next(&token_reader, &token) || !command_token_equals(&token, "cancel")) { - shutdownmessage = "Invalid cancel command name.\n"; - goto lCleanup; - } - - /* - * Fixed cancel parameters precede the input sequence. - */ - if(!command_token_reader_next_int64(&token_reader, &frame_min)) { - shutdownmessage = - "Cancel command requires an integer start frame.\n"; - - goto lCleanup; - } - - if(!command_token_reader_next_int64(&token_reader, &frame_max)) { - shutdownmessage = - "Cancel command requires an integer end frame.\n"; - - goto lCleanup; - } - - if(!command_token_reader_next_int64(&token_reader, &required_hits)) { - shutdownmessage = - "Cancel command requires an integer hit count. " - "0 means no hit requirement.\n"; - - goto lCleanup; - } - - if(required_hits < 0) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Cancel command hit count (%" PRId64 ") cannot be negative.\n", - required_hits - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - /* - * Parse the variable-length input sequence. The - * freespecial token terminates the sequence. - */ - parse_error = special_command_parse_sequence( - &token_reader, - &parsed_special, - &freespecial_number, - alert_buffer, - sizeof(alert_buffer) - ); - - if(parse_error) { - shutdownmessage = parse_error; - goto lCleanup; - } - - /* - * Complete cancel-specific command properties. - */ - parsed_special.anim = animspecials[freespecial_number - 1]; - - parsed_special.frame.min = frame_min; - parsed_special.frame.max = frame_max; - parsed_special.cancel = ani_id; - parsed_special.hits = (uint64_t)required_hits; - - /* - * Commit only after the complete command has parsed - * and validated successfully. - */ - if(!alloc_specials(newchar)) { - shutdownmessage = E_OUT_OF_MEMORY; - goto lCleanup; - } - - newchar->special[newchar->specials_loaded] = parsed_special; - newanim->cancel = ANIMATION_CANCEL_ENABLED; - - newchar->specials_loaded++; - } - break; - - case CMD_MODEL_SOUND_INDEX: - tempInt = GET_INT_ARG(1); - - if (!frame_sound_validate_slot_index(tempInt)) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound index (%d) out of range (0 to %d).", - tempInt, - MAX_FRAME_SOUNDS_PER_FRAME - 1 - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - temp_frame_sound_index = tempInt; - break; - case CMD_MODEL_SOUND_CHANNEL_OFFSET: - { - s_command_token offset_token; - s_frame_sound_action* action; - uint64_t channel_offset; - int channel; - - if (!frame_sound_parse_channel(GET_ARG(1), &channel)) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound channel '%s' invalid. Expected an integer from 0 to %u.", - GET_ARG(1), - SOUND_CHANNEL_COUNT_MAX - 1U - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - offset_token.text = GET_ARG(2); - offset_token.length = strlen(offset_token.text); - - if (!command_token_get_uint64( - &offset_token, - &channel_offset - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound channel offset '%s'. Expected an unsigned PCM frame.", - offset_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - action = frame_sound_action_append( - &temp_frame_sound, - FRAME_SOUND_CHANNEL_ACTION_OFFSET - ); - action->channel = channel; - action->offset = channel_offset; - break; - } - case CMD_MODEL_SOUND_CHANNEL_PAUSE: - case CMD_MODEL_SOUND_CHANNEL_RESUME: - case CMD_MODEL_SOUND_CHANNEL_STOP: - { - s_frame_sound_action* action; - e_frame_sound_action action_type; - int channel; - - if (!frame_sound_parse_channel(GET_ARG(1), &channel)) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound channel '%s' invalid. Expected an integer from 0 to %u.", - GET_ARG(1), - SOUND_CHANNEL_COUNT_MAX - 1U - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - action_type = cmd == CMD_MODEL_SOUND_CHANNEL_PAUSE - ? FRAME_SOUND_CHANNEL_ACTION_PAUSE - : cmd == CMD_MODEL_SOUND_CHANNEL_RESUME - ? FRAME_SOUND_CHANNEL_ACTION_RESUME - : FRAME_SOUND_CHANNEL_ACTION_STOP; - - action = frame_sound_action_append( - &temp_frame_sound, - action_type - ); - action->channel = channel; - break; - } - case CMD_MODEL_SOUND_CHANNEL_PRIORITY: - { - s_command_token priority_token; - uint64_t priority; - - priority_token.text = GET_ARG(1); - priority_token.length = strlen(priority_token.text); - - if (!command_token_get_uint64( - &priority_token, - &priority - ) || priority > UINT_MAX) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound channel priority '%s'. Expected an unsigned integer from 0 to %u.", - priority_token.text, - UINT_MAX - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->priority = (unsigned int)priority; - break; - } - case CMD_MODEL_SOUND_CHANNEL_SET: - { - int channel; - - value = GET_ARG(1); - - if (stricmp(value, "auto") == 0) { - channel = -1; - } else if (!frame_sound_parse_channel(value, &channel)) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound channel '%s' invalid. Expected 'auto' or an integer from 0 to %u.", - value, - SOUND_CHANNEL_COUNT_MAX - 1U - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->channel = channel; - break; - } - case CMD_MODEL_SOUND_CHANCE: - tempInt = GET_INT_ARG(1); - - if (tempInt < 0 || tempInt > 100) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound chance (%d) out of range (0 to 100).", - tempInt - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->chance = (unsigned)tempInt; - break; - case CMD_MODEL_SOUND_DELAY: - { - s_command_token delay_token; - uint64_t sound_delay; - - delay_token.text = GET_ARG(1); - delay_token.length = strlen(delay_token.text); - - if (!command_token_get_uint64(&delay_token, &sound_delay)) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound delay '%s'. Expected an unsigned logical tick count.", - delay_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->delay = sound_delay; - break; - } - case CMD_MODEL_SOUND_GROUP: - { - const char* invalid_group; - sound_group_mask_t sound_group; - - if (!sound_group_get_flags_from_arglist( - &arglist, - &sound_group, - &invalid_group - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound group '%s' invalid. Expected none, all, all0, all1, a-z, or a1-z1.", - invalid_group - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->group = sound_group; - break; - } - case CMD_MODEL_SOUND_GROUP_OFFSET: - { - s_command_token offset_token; - s_frame_sound_action* action; - const char* invalid_group; - sound_group_mask_t sound_group; - uint64_t group_offset; - size_t offset_argument; - - if (arglist.count < 3) { - shutdownmessage = - "Sound group offset requires one or more groups followed by an unsigned PCM frame."; - goto lCleanup; - } - - offset_argument = arglist.count - 1U; - offset_token.text = GET_ARG(offset_argument); - offset_token.length = strlen(offset_token.text); - - if (!command_token_get_uint64( - &offset_token, - &group_offset - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound group offset '%s'. Expected an unsigned PCM frame.", - offset_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - if (!sound_group_get_flags_from_arglist_range( - &arglist, - 1, - offset_argument, - &sound_group, - &invalid_group - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound group '%s' invalid. Expected none, all, all0, all1, a-z, or a1-z1.", - invalid_group - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - action = frame_sound_action_append( - &temp_frame_sound, - FRAME_SOUND_GROUP_ACTION_OFFSET - ); - action->group = sound_group; - action->offset = group_offset; - break; - } - case CMD_MODEL_SOUND_GROUP_PAUSE: - case CMD_MODEL_SOUND_GROUP_RESUME: - case CMD_MODEL_SOUND_GROUP_STOP: - { - s_frame_sound_action* action; - e_frame_sound_action action_type; - const char* invalid_group; - sound_group_mask_t sound_group; - - if (!sound_group_get_flags_from_arglist( - &arglist, - &sound_group, - &invalid_group - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound group '%s' invalid. Expected none, all, all0, all1, a-z, or a1-z1.", - invalid_group - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - action_type = cmd == CMD_MODEL_SOUND_GROUP_PAUSE - ? FRAME_SOUND_GROUP_ACTION_PAUSE - : cmd == CMD_MODEL_SOUND_GROUP_RESUME - ? FRAME_SOUND_GROUP_ACTION_RESUME - : FRAME_SOUND_GROUP_ACTION_STOP; - - action = frame_sound_action_append( - &temp_frame_sound, - action_type - ); - action->group = sound_group; - break; - } - case CMD_MODEL_SOUND_LOADING: - { - bool stream; - - value = GET_ARG(1); - - if (stricmp(value, "cache") == 0) { - stream = false; - } else if (stricmp(value, "stream") == 0) { - stream = true; - } else { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound loading mode '%s' invalid. Expected 'cache' or 'stream'.", - value - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->stream = stream; - break; - } - case CMD_MODEL_SOUND_LOOP: - { - s_command_token loop_token; - uint64_t loop; - - loop_token.text = GET_ARG(1); - loop_token.length = strlen(loop_token.text); - - if (!command_token_get_uint64(&loop_token, &loop) - || loop > 1U) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound loop '%s'. Expected 0 or 1.", - loop_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->loop = loop != 0; - break; - } - case CMD_MODEL_SOUND_LOOP_OFFSET: - { - s_command_token loop_offset_token; - uint64_t loop_offset; - - loop_offset_token.text = GET_ARG(1); - loop_offset_token.length = strlen(loop_offset_token.text); - - if (!command_token_get_uint64( - &loop_offset_token, - &loop_offset - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound loop offset '%s'. Expected an unsigned PCM frame.", - loop_offset_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - )->loop_offset = loop_offset; - break; - } - case CMD_MODEL_SOUND_RANDOM: - { - const int random_min = GET_INT_ARG(1); - const int random_max = GET_INT_ARG(2); - - if (!frame_sound_validate_slot_index(random_min) - || !frame_sound_validate_slot_index(random_max) - || random_min > random_max) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Sound random range (%d to %d) invalid. Expected an ascending range from 0 to %d.", - random_min, - random_max, - MAX_FRAME_SOUNDS_PER_FRAME - 1 - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - if (!temp_frame_sound) { - temp_frame_sound = frame_sound_collection_allocate(); - } - - temp_frame_sound->random_status = - frame_sound_get_slot_range_mask(random_min, random_max); - break; - } - case CMD_MODEL_SOUND_START_OFFSET: - { - s_command_token start_offset_token; - s_frame_sound* frame_sound; - uint64_t start_offset; - - start_offset_token.text = GET_ARG(1); - start_offset_token.length = strlen(start_offset_token.text); - - if (stricmp(start_offset_token.text, "auto") == 0) { - frame_sound = frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - ); - frame_sound->start_offset = 0; - frame_sound->start_offset_supplied = false; - break; - } - - if (!command_token_get_uint64( - &start_offset_token, - &start_offset - )) { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Invalid sound start offset '%s'. Expected 'auto' or an unsigned PCM frame.", - start_offset_token.text - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - frame_sound = frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - ); - frame_sound->start_offset = start_offset; - frame_sound->start_offset_supplied = true; - break; - } - case CMD_MODEL_SOUND: - { - s_frame_sound* frame_sound = frame_sound_upsert_index( - &temp_frame_sound, - temp_frame_sound_index - ); - - value = GET_ARG(1); - if (stricmp(value, "none") == 0) { - frame_sound_set_source(frame_sound, NULL); - } else { - frame_sound_set_source(frame_sound, value); - } - - temp_frame_sound->active_status |= - frame_sound_get_slot_mask(temp_frame_sound_index); - break; - } - case CMD_MODEL_HITFX: - - value = GET_ARG(1); - - if(stricmp(value, "none") == 0) - { - tempInt = SAMPLE_ID_NONE; - } - else - { - tempInt = sound_load_sample(value, packfile, 1, 0); - } - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->hitsound = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_HITFLASH: - - /* First find out which flash model index (if any). */ - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - tempInt = MODEL_INDEX_NONE; - } - else - { - tempInt = get_cached_model_index(value); - } - - /* Apply model index to frame attack box or smartbomb? */ - - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->flash.model_hit = tempInt; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_hit = tempInt; - } - - break; - - case CMD_MODEL_BLOCKFLASH: - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_block = MODEL_INDEX_NONE; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_block = get_cached_model_index(value); - } - - break; - - case CMD_MODEL_BLOCKFX: - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blocksound = SAMPLE_ID_NONE; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blocksound = sound_load_sample(value, packfile, 1, 0); - } - - break; - - case CMD_MODEL_FASTATTACK: - - if(GET_INT_ARG(1)) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->next_hit_time = global_config.game_speed / 20; - } - - break; - - case CMD_MODEL_IGNOREATTACKID: - - if(GET_INT_ARG(1)) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->ignore_attack_id = 1; - } - - break; - - case CMD_MODEL_BBOX: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - - value = GET_ARG(1); - if (stricmp(value, "none") == 0) { - - *temp_collision_coordinates = (s_hitbox){ 0 }; - break; - } - - temp_collision_coordinates->x = GET_INT_ARG(1); - temp_collision_coordinates->y = GET_INT_ARG(2); - temp_collision_coordinates->width = GET_INT_ARG(3); - temp_collision_coordinates->height = GET_INT_ARG(4); - - /* - * 2023-01-13: If only the first Z depth provided, - * use it for both directions. We verify a numeric - * instead of checking for empty because the creator - * might intentionally apply a 0 value to foreground - * depth and a simple empty check would override it. - */ - - tempInt = GET_INT_ARG(5); - - temp_collision_coordinates->z_background = tempInt; - - value = GET_ARG(6); - - if (isNumeric(value)) { - tempInt = GET_INT_ARG(6); - } - - temp_collision_coordinates->z_foreground = tempInt; - - break; - case CMD_MODEL_BBOX_COORDINATES: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - - temp_collision_coordinates->x = GET_INT_ARG(1); - temp_collision_coordinates->y = GET_INT_ARG(2); - temp_collision_coordinates->width = GET_INT_ARG(3); - temp_collision_coordinates->height = GET_INT_ARG(4); - temp_collision_coordinates->z_background = GET_INT_ARG(5); - temp_collision_coordinates->z_foreground = GET_INT_ARG(6); - - break; - case CMD_MODEL_BBOX_INDEX: - // Does nothing. Do not modify. - break; - case CMD_MODEL_BBOX_EFFECT_HIT_FLASH_LAYER_ADJUST: - collision_body_upsert_property(&temp_collision_body, temp_collision_index)->flash.layer_adjust = GET_INT_ARG(1); - break; - case CMD_MODEL_BBOX_EFFECT_HIT_FLASH_LAYER_SOURCE: - collision_body_upsert_property(&temp_collision_body, temp_collision_index)->flash.layer_source = GET_INT_ARG(1); - break; - case CMD_MODEL_BBOX_EFFECT_HIT_FLASH_Z_SOURCE: - collision_body_upsert_property(&temp_collision_body, temp_collision_index)->flash.z_source = GET_INT_ARG(1); - break; - case CMD_MODEL_BBOX_POSITION_X: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->x = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOX_POSITION_Y: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->y = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOX_SIZE_X: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->width = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOX_SIZE_Y: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->height = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOX_SIZE_Z_1: - case CMD_MODEL_BBOX_SIZE_Z_BACKGROUND: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->z_background = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOX_SIZE_Z_2: - case CMD_MODEL_BBOX_SIZE_Z_FOREGROUND: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->z_foreground = GET_INT_ARG(1); - - break; - case CMD_MODEL_BBOXZ: - - collision_body_upsert_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates = collision_body_upsert_coordinates_property(&temp_collision_body, temp_collision_index); - temp_collision_coordinates->z_background = GET_INT_ARG(1); - temp_collision_coordinates->z_foreground = GET_INT_ARG(2); - - break; - case CMD_MODEL_PLATFORM: - newchar->hasPlatforms = 1; - for(i = 0; i < arglist.count && arglist.args[i] && arglist.args[i][0]; i++); - if(i < 8) - { - for(i = 0; i < 6; i++) - { - platform[i + 2] = GET_FLOAT_ARG(i + 1); - } - platform[PLATFORM_X] = PLATFORM_DEFAULT_X; - } - else for(i = 0; i < 8; i++) - { - platform[i] = GET_FLOAT_ARG(i + 1); - } - break; - case CMD_MODEL_DRAWMETHOD: - value = GET_ARG(1); - if(isNumeric(value)) - { - // special effects - drawmethod.scalex = GET_INT_ARG(1); - drawmethod.scaley = GET_INT_ARG(2); - drawmethod.config = GET_INT_ARG(3) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_X) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_X); - drawmethod.config = GET_INT_ARG(4) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_Y) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_Y); - drawmethod.shiftx = GET_INT_ARG(5); - drawmethod.alpha = GET_INT_ARG(6); - drawmethod.remap = GET_INT_ARG(7); - drawmethod.fillcolor = parsecolor(GET_ARG(8)); - drawmethod.rotate = GET_INT_ARG(9); - drawmethod.config = GET_INT_ARG(10) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_ROTATE) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_ROTATE); - } - else if (0 == stricmp(value, "scale")) - { - drawmethod.scalex = GET_FLOAT_ARG(2) * 256; - drawmethod.scaley = arglist.count > 3 ? GET_FLOAT_ARG(3) * 256 : drawmethod.scalex; - } - else if (0 == stricmp(value, "scalex")) - { - drawmethod.scalex = GET_FLOAT_ARG(2) * 256; - } - else if (0 == stricmp(value, "scaley")) - { - drawmethod.scaley = GET_FLOAT_ARG(2) * 256; - } - else if (0 == stricmp(value, "xrepeat")) - { - drawmethod.xrepeat = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "yrepeat")) - { - drawmethod.yrepeat = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "xspan")) - { - drawmethod.xspan = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "yspan")) - { - drawmethod.yspan = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "flipx")) - { - drawmethod.config = GET_INT_ARG(2) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_X) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_X); - } - else if (0 == stricmp(value, "flipy")) - { - drawmethod.config = GET_INT_ARG(2) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_Y) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_Y); - } - else if (0 == stricmp(value, "shiftx")) - { - drawmethod.shiftx = GET_FLOAT_ARG(2) * 256; - } - else if (0 == stricmp(value, "rotate")) - { - drawmethod.rotate = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "fliprotate")) - { - drawmethod.config = GET_INT_ARG(2) ? (drawmethod.config | DRAWMETHOD_CONFIG_FLIP_ROTATE) : (drawmethod.config & ~DRAWMETHOD_CONFIG_FLIP_ROTATE); - } - else if (0 == stricmp(value, "fillcolor")) - { - drawmethod.fillcolor = parsecolor(GET_ARG(2)); - } - else if (0 == stricmp(value, "remap")) - { - drawmethod.remap = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "channel")) - { - drawmethod.channelr = GET_FLOAT_ARG(2) * 255; - drawmethod.channelg = arglist.count > 3 ? GET_FLOAT_ARG(3) * 255 : drawmethod.channelr; - drawmethod.channelb = arglist.count > 4 ? GET_FLOAT_ARG(4) * 255 : drawmethod.channelr; - } - else if (0 == stricmp(value, "channelr")) - { - drawmethod.channelr = GET_FLOAT_ARG(2) * 255; - } - else if (0 == stricmp(value, "channelg")) - { - drawmethod.channelg = GET_FLOAT_ARG(2) * 255; - } - else if (0 == stricmp(value, "channelb")) - { - drawmethod.channelb = GET_FLOAT_ARG(2) * 255; - } - else if (0 == stricmp(value, "tintmode")) - { - drawmethod.tintmode = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "tintcolor")) - { - drawmethod.tintcolor = parsecolor(GET_ARG(2)); - } - else if (0 == stricmp(value, "alpha")) - { - drawmethod.alpha = GET_INT_ARG(2); - } - else if (0 == stricmp(value, "clip")) - { - drawmethod.clipx = GET_INT_ARG(2); - drawmethod.clipy = GET_INT_ARG(3); - drawmethod.clipw = GET_INT_ARG(4); - drawmethod.cliph = GET_INT_ARG(5); - } - if(drawmethod.scalex < 0) - { - drawmethod.scalex = -drawmethod.scalex; - drawmethod.config ^= DRAWMETHOD_CONFIG_FLIP_X; - } - if(drawmethod.scaley < 0) - { - drawmethod.scaley = -drawmethod.scaley; - drawmethod.config ^= DRAWMETHOD_CONFIG_FLIP_Y; - } - if(drawmethod.rotate) - { - drawmethod.rotate = ((int)drawmethod.rotate % 360 + 360) % 360; - } - if(!blendfx_is_set) - { - if(drawmethod.alpha > 0 && drawmethod.alpha <= MAX_BLENDINGS) - { - blendfx[drawmethod.alpha - 1] = 1; - } - } - drawmethod.config |= DRAWMETHOD_CONFIG_ENABLED; - break; - case CMD_MODEL_NODRAWMETHOD: - //disable special effects - drawmethod.config &= ~DRAWMETHOD_CONFIG_ENABLED; - break; - - // 2016-10-11 - // Caskey, Damon - // Broken down attack commands. - case CMD_MODEL_COLLISION_BLOCK_COST: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->guardcost = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_BLOCK_PENETRATE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_block = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_COORDINATES: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - - temp_collision_coordinates->x = GET_INT_ARG(1); - temp_collision_coordinates->y = GET_INT_ARG(2); - temp_collision_coordinates->width = GET_INT_ARG(3); - temp_collision_coordinates->height = GET_INT_ARG(4); - temp_collision_coordinates->z_background = GET_INT_ARG(5); - temp_collision_coordinates->z_foreground = GET_INT_ARG(6); - - break; - - case CMD_MODEL_COLLISION_COUNTER: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->counterattack = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_FORCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_force = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_LAND_FORCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->damage_on_landing.attack_force = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_LAND_MODE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blast = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_LETHAL_DISABLE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_kill = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_STEAL: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->steal = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_TYPE: - - value = GET_ARG(1); - - tempInt = get_attack_type_from_string(value, filename); - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_FORCE: - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->force = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_INDEX: - - tempInt = GET_INT_ARG(1); - - if(tempInt < 0 || tempInt >= MAX_RECURSIVE_EFFECTS) { - - snprintf(alert_buffer, sizeof(alert_buffer), "Recursive index (%d) out of range (0 - %d).", - tempInt, MAX_RECURSIVE_EFFECTS - 1); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->index = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_MODE: - - /* - * Caskey, Damon V. - * 2021-08-24 - * - * For legacy support of mode, we have to handle - * integer values differently because like a bonehead, - * I didn't originally set them up with bitwise - * logic in mind. - */ - - value = GET_ARG(1); - - if (isNumeric(value)) - { - /* - * Numeric is legacy. Interpret the number as - * a list of modes. - */ - - tempInt = GET_INT_ARG(1); - - tempInt = recursive_effect_get_mode_setup_from_legacy_argument(tempInt); - } - else - { - /* - * Toggle bits based on items provided in argument list. - */ - - tempInt = recursive_effect_get_mode_setup_from_command_line(buf + pos); - } - - - /* Send resulting bitwise integer to mode value. */ - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->mode = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_TAG: - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->meta_tag = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_TYPE: - - value = GET_ARG(1); - - tempInt = get_attack_type_from_string(value, filename); - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->type = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_TIME_RATE: - - tempInt = GET_INT_ARG(1); - - if (tempInt < 0) { - snprintf(alert_buffer, sizeof(alert_buffer), - "Recursive rate (%d) cannot be negative.", tempInt); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->rate = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_DAMAGE_RECURSIVE_TIME_EXPIRE: - - tempInt = GET_INT_ARG(1); - - if (tempInt < 0) { - snprintf(alert_buffer, sizeof(alert_buffer), - "Recursive time expire (%d) cannot be negative.", tempInt); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - collision_attack_upsert_recursive_property(&temp_collision_attack, temp_collision_index)->time = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_REACTION_FALL_FORCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_FALL_VELOCITY_X: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.x = GET_FLOAT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_FALL_VELOCITY_Y: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.y = GET_FLOAT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_FALL_VELOCITY_Z: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.z = GET_FLOAT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_REPOSITION_DIRECTION: - - tempInt = direction_get_adjustment_from_argument(filename, command, GET_ARG(1)); - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->force_direction = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_EFFECT_BLOCK_FLASH: - - value = GET_ARG(1); - - if(stricmp(value, "none") == 0 || value == 0) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_block = MODEL_INDEX_NONE; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_block = get_cached_model_index(value); - } - - break; - - case CMD_MODEL_COLLISION_EFFECT_BLOCK_SOUND: - - value = GET_ARG(1); - - if(stricmp(value, "none") == 0) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blocksound = SAMPLE_ID_NONE; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blocksound = sound_load_sample(value, packfile, 1, 0); - } - - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_FLASH: - - value = GET_ARG(1); - - if(stricmp(value, "none") == 0 || value == 0) - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_hit = MODEL_INDEX_NONE; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.model_hit = get_cached_model_index(value); - } - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_FLASH_DISABLE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_flash = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_FLASH_LAYER_ADJUST: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.layer_adjust = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_FLASH_LAYER_SOURCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.layer_source = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_FLASH_Z_SOURCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->flash.z_source = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_EFFECT_HIT_SOUND: - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - tempInt = SAMPLE_ID_NONE; - } - else - { - tempInt = sound_load_sample(value, packfile, 1, 0); - } - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->hitsound = tempInt; - - tempInt = 0; - - break; - - case CMD_MODEL_COLLISION_GROUND: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->otg = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_MAP_INDEX: - - /* - * Translate text value into a pre-defined forcemap constant. - * When applying a pre-defined forcemap, we'll look at the model - * and try to find its appropriate index. For example, if the - * pre-defined BURN is used, forcemap will apply the model's - * designated burn. This allows use of effect maps without the - * need to match all model palettes up (i.e. all having their - * second palette a burn palette). - * - * If the creator provides a numeric value, pass it straight - * through. - */ - - value = GET_ARG(1); - if (stricmp(value, "none") == 0) - { - tempInt = MAP_TYPE_NONE; - } - else if (stricmp(value, "burn") == 0) - { - tempInt = MAP_TYPE_BURN; - } - else if (stricmp(value, "freeze") == 0) - { - tempInt = MAP_TYPE_FREEZE; - } - else if (stricmp(value, "ko") == 0) - { - tempInt = MAP_TYPE_SHOCK; - } - else if (stricmp(value, "shock") == 0) - { - tempInt = MAP_TYPE_SHOCK; - } - else - { - tempInt = GET_INT_ARG(1); - } - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->forcemap = tempInt; - - break; - - case CMD_MODEL_COLLISION_MAP_TIME: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->maptime = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_POSITION_X: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->x = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_POSITION_Y: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->y = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_FREEZE_MODE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freeze = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_FREEZE_TIME: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freezetime = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_INVINCIBLE_TIME: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->next_hit_time = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_REPOSITION_DISTANCE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->grab_distance = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_REPOSITION_MODE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->grab = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_PAIN_SKIP: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_pain = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_REACTION_PAUSE_TIME: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->pause_add = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SEAL_COST: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->seal = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SEAL_TIME: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->sealtime = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SIZE_X: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->width = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SIZE_Y: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->height = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SIZE_Z_1: - case CMD_MODEL_COLLISION_SIZE_Z_BACKGROUND: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->z_background = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_SIZE_Z_2: - case CMD_MODEL_COLLISION_SIZE_Z_FOREGROUND: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->z_foreground = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_STAYDOWN_RISE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->staydown.rise = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_STAYDOWN_RISEATTACK: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->staydown.riseattack = GET_INT_ARG(1); - - break; - - case CMD_MODEL_COLLISION_TAG: - - // To do - Add tag system. - - break; - - case CMD_MODEL_COLLISION: - case CMD_MODEL_COLLISION1: - case CMD_MODEL_COLLISION2: - case CMD_MODEL_COLLISION3: - case CMD_MODEL_COLLISION4: - case CMD_MODEL_COLLISION5: - case CMD_MODEL_COLLISION6: - case CMD_MODEL_COLLISION7: - case CMD_MODEL_COLLISION8: - case CMD_MODEL_COLLISION9: - case CMD_MODEL_COLLISION10: - case CMD_MODEL_SHOCK: - case CMD_MODEL_BURN: - case CMD_MODEL_STEAL: - case CMD_MODEL_FREEZE: - case CMD_MODEL_ITEMBOX: - case CMD_MODEL_LOSE: - case CMD_MODEL_COLLISION_ETC: - - // 2020-03-08, - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - - /* - * "none" deactivates attack on this and subsequent frames. - * The attack loading system interprets 0 for all coordinates - * as no attack and will not load to memory. - */ - value = GET_ARG(1); - if (stricmp(value, "none") == 0) { - - *temp_collision_coordinates = (s_hitbox){0}; - - break; - } - - temp_collision_coordinates->x = GET_INT_ARG(1); - temp_collision_coordinates->y = GET_INT_ARG(2); - temp_collision_coordinates->width = GET_INT_ARG(3); - temp_collision_coordinates->height = GET_INT_ARG(4); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_force = GET_INT_ARG(5); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = GET_INT_ARG(6); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_block = GET_INT_ARG(7); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_flash = GET_INT_ARG(8); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->pause_add = GET_INT_ARG(9); - - // -- Not a typo - legacy Z sets identical value to back/fore depth. - temp_collision_coordinates->z_background = GET_INT_ARG(10); - temp_collision_coordinates->z_foreground = GET_INT_ARG(10); - - switch(cmd) - { - case CMD_MODEL_COLLISION: - case CMD_MODEL_COLLISION1: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL; - - break; - - case CMD_MODEL_COLLISION2: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL2; - - break; - - case CMD_MODEL_COLLISION3: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL3; - - break; - - case CMD_MODEL_COLLISION4: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL4; - - break; - - case CMD_MODEL_COLLISION5: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL5; - - break; - - case CMD_MODEL_COLLISION6: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL6; - - break; - - case CMD_MODEL_COLLISION7: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL7; - - break; - - case CMD_MODEL_COLLISION8: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL8; - - break; - - case CMD_MODEL_COLLISION9: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL9; - - break; - - case CMD_MODEL_COLLISION10: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_NORMAL10; - - break; - - case CMD_MODEL_SHOCK: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_SHOCK; - - break; - - case CMD_MODEL_BURN: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_BURN; - - break; - - case CMD_MODEL_STEAL: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->steal = 1; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_STEAL; - - break; - - case CMD_MODEL_FREEZE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_FREEZE; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freeze = 1; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freezetime = GET_FLOAT_ARG(6) * global_config.game_speed; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->forcemap = MAP_TYPE_FREEZE; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = 0; - - break; - - case CMD_MODEL_ITEMBOX: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_ITEM; - - break; - - case CMD_MODEL_LOSE: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_LOSE; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = 0; - - break; - - default: - - //value = GET_ARG(1); - - tempInt = get_attack_type_from_string(command, filename); - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = tempInt; - - break; - } - break; - - - - case CMD_MODEL_HITWALLTYPE: - value = GET_ARG(1); - newchar->hitwalltype = atoi(value); - break; - case CMD_MODEL_COLLISIONZ: - case CMD_MODEL_HITZ: - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->z_background = GET_INT_ARG(1); - temp_collision_coordinates->z_foreground = GET_INT_ARG(2); - - break; - - case CMD_MODEL_BLAST: - - // 2020-03-08, - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates = collision_attack_upsert_coordinates_property(&temp_collision_attack, temp_collision_index); - temp_collision_coordinates->x = GET_INT_ARG(1); - temp_collision_coordinates->y = GET_INT_ARG(2); - temp_collision_coordinates->width = GET_INT_ARG(3); - temp_collision_coordinates->height = GET_INT_ARG(4); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_force = GET_INT_ARG(5); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_block = GET_INT_ARG(6); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_flash = GET_INT_ARG(7); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->pause_add = GET_INT_ARG(8); - - // -- Not a typo - legacy Z sets identical value to back/fore depth. - temp_collision_coordinates->z_background = GET_INT_ARG(9); - temp_collision_coordinates->z_foreground = GET_INT_ARG(9); - - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = 1; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_type = ATK_BLAST; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blast = 1; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.x = default_model_dropv.x * 2.083f; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.y = default_model_dropv.y; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.z = default_model_dropv.z; - - break; - - case CMD_MODEL_DROPV: - - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->dropv.y = GET_FLOAT_ARG(1); - newchar->smartbomb->dropv.x = GET_FLOAT_ARG(2); - newchar->smartbomb->dropv.z = GET_FLOAT_ARG(3); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.y = GET_FLOAT_ARG(1); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.x = GET_FLOAT_ARG(2); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->dropv.z = GET_FLOAT_ARG(3); - } - - break; - - case CMD_MODEL_OTG: - // Over The Ground hit. - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->otg = GET_INT_ARG(1); - - break; - - case CMD_MODEL_JUGGLECOST: - - // if cost >= opponents jugglepoints , we can juggle - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->jugglecost = GET_INT_ARG(1); - - break; - - case CMD_MODEL_GUARDCOST: - - // if cost >= opponents guardpoints , opponent will play guardcrush anim - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->guardcost = GET_INT_ARG(1); - - break; - - case CMD_MODEL_STUN: - - //Like Freeze, but no auto remap. - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->freeze = 1; - newchar->smartbomb->freezetime = GET_FLOAT_ARG(1) * global_config.game_speed; - newchar->smartbomb->attack_drop = 0; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freeze = 1; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->freezetime = GET_FLOAT_ARG(1) * global_config.game_speed; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->attack_drop = 0; - } - - break; - - case CMD_MODEL_GRABIN: - - // fake grab distanse efffect, not link - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->grab = GET_INT_ARG(1); - newchar->smartbomb->grab_distance = GET_FLOAT_ARG(2); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->grab = GET_INT_ARG(1); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->grab_distance = GET_FLOAT_ARG(2); - } - - break; - - case CMD_MODEL_NOREFLECT: - - // only cost target's hp, don't knock down or cause pain, unless the target is killed - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->no_pain = GET_INT_ARG(1); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_pain = GET_INT_ARG(1); - } - - break; - - case CMD_MODEL_NOKILL: - - // don't kill the target, leave 1 hp - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->no_kill = GET_INT_ARG(1); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->no_kill = GET_INT_ARG(1); - } - - break; - - case CMD_MODEL_FORCEDIRECTION: - - tempInt = direction_get_adjustment_from_argument(filename, command, GET_ARG(1)); - - // the attack direction - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->force_direction = tempInt; - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->force_direction = tempInt; - } - - tempInt = 0; - - break; - - case CMD_MODEL_DAMAGEONLANDING: - - // fake throw damage on landing - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->damage_on_landing.attack_force = GET_INT_ARG(1); - newchar->smartbomb->blast = GET_INT_ARG(2); - newchar->smartbomb->damage_on_landing.attack_type = translate_attack_type(GET_ARG(3), filename); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->damage_on_landing.attack_force = GET_INT_ARG(1); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->blast = GET_INT_ARG(2); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->damage_on_landing.attack_type = translate_attack_type(GET_ARG(3), filename); - } - - break; - - case CMD_MODEL_SEAL: - - // Disable special moves for specified time. - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->sealtime = GET_INT_ARG(1) * (global_config.game_speed / 100); - newchar->smartbomb->seal = GET_INT_ARG(2); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->sealtime = GET_INT_ARG(1) * (global_config.game_speed / 100); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->seal = GET_INT_ARG(2); - } - - break; - - case CMD_MODEL_STAYDOWN: - - // Disable special moves for specified time. - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->staydown.rise = GET_INT_ARG(1); - newchar->smartbomb->staydown.riseattack = GET_INT_ARG(2); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->staydown.rise = GET_INT_ARG(1); - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->staydown.riseattack = GET_INT_ARG(2); - } - - break; - - case CMD_MODEL_FORCEMAP: - - /* - * Translate text value into a pre-defined forcemap constant. - * When applying a pre-defined forcemap, we'll look at the model - * and try to find its appropriate index. For example, if the - * pre-defined BURN is used, forcemap will apply the model's - * designated burn. This allows use of effect maps without the - * need to match all model palettes up (i.e. all having their - * second palette a burn palette). - * - * If the creator provides a numeric value, pass it straight - * through. - */ - - value = GET_ARG(1); - - if (stricmp(value, "none") == 0) - { - tempInt = MAP_TYPE_NONE; - } - else if (stricmp(value, "burn") == 0) - { - tempInt = MAP_TYPE_BURN; - } - else if (stricmp(value, "freeze") == 0) - { - tempInt = MAP_TYPE_FREEZE; - } - else if (stricmp(value, "ko") == 0) - { - tempInt = MAP_TYPE_SHOCK; - } - else if (stricmp(value, "shock") == 0) - { - tempInt = MAP_TYPE_SHOCK; - } - else - { - tempInt = GET_INT_ARG(1); - } - - // force color map change for specified time - if (!newanim && newchar->smartbomb) - { - newchar->smartbomb->forcemap = tempInt; - newchar->smartbomb->maptime = GET_FLOAT_ARG(2) * (global_config.game_speed / 100); - } - else - { - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->forcemap = tempInt; - collision_attack_upsert_property(&temp_collision_attack, temp_collision_index)->maptime = GET_FLOAT_ARG(2) * (global_config.game_speed / 100); - } - - break; - - case CMD_MODEL_IDLE: - idle = GET_INT_ARG(1); - break; - case CMD_MODEL_SETA: - move.base = GET_INT_ARG(1); - break; - case CMD_MODEL_MOVE: - move.axis.x = GET_INT_ARG(1); - break; - case CMD_MODEL_MOVEA: - move.axis.y = GET_INT_ARG(1); - break; - case CMD_MODEL_MOVEZ: - move.axis.z = GET_INT_ARG(1); - break; - case CMD_MODEL_FSHADOW: - - value = GET_ARG(1); - if (stricmp(value, "none") == 0) { - tempInt = FRAME_SHADOW_NONE; - - } else { - tempInt = GET_INT_ARG(1); - } - frameshadow = tempInt; - break; - case CMD_MODEL_RANGE: - if(!newanim) { - shutdownmessage = "Cannot set range: no animation!"; - goto lCleanup; - } - newanim->range.x.min = GET_INT_ARG(1); - newanim->range.x.max = GET_INT_ARG(2); - if(newanim->range.x.min == newanim->range.x.max) { - newanim->range.x.min--; - } - break; - case CMD_MODEL_RANGEZ: - if(!newanim) { - shutdownmessage = "Cannot set rangez: no animation!"; - goto lCleanup; - } - newanim->range.z.min = GET_INT_ARG(1); - newanim->range.z.max = GET_INT_ARG(2); - break; - case CMD_MODEL_RANGEA: - if(!newanim) { - shutdownmessage = "Cannot set rangea: no animation!"; - goto lCleanup; - } - newanim->range.y.min = GET_INT_ARG(1); - newanim->range.y.max = GET_INT_ARG(2); - break; - case CMD_MODEL_RANGEB: - if(!newanim) { - shutdownmessage = "Cannot set rangeb: no animation!"; - goto lCleanup; - } - newanim->range.base.min = GET_INT_ARG(1); - newanim->range.base.max = GET_INT_ARG(2); - break; - case CMD_MODEL_PATHFINDSTEP: - newchar->pathfindstep = GET_FLOAT_ARG(1); - break; - case CMD_MODEL_FRAME: - { - s_command_token frame_token; - s_command_token_reader frame_reader; - - // Command title for log. Details will be added blow accordingly. - //printf("\t\t\tFrame: "); - - if(!newanim) { - shutdownmessage = "Cannot add frame: animation not specified!"; - goto lCleanup; - } - - peek = 0; - if(frameset && framecount >= 0) { - framecount = -framecount; - } - - while(!frameset) { - frame_reader.cursor = buf + pos + peek; - - if(command_token_reader_next( - &frame_reader, - &frame_token - )) { - if(command_token_equals(&frame_token, "frame")) { - framecount++; - } - - if(command_token_equals(&frame_token, "anim")) { - frameset = 1; - } - } - - if(pos + peek >= size) { - frameset = 1; - } - - // Go to next line - while(buf[pos + peek] && buf[pos + peek] != '\n' && buf[pos + peek] != '\r') { - ++peek; - } - - while(buf[pos + peek] == '\n' || buf[pos + peek] == '\r') { - ++peek; - } - } - value = GET_ARG(1); - - // Log info. - //printf("%d", ++framenum); - //printf("\tSprite Path: %s\n", value); - - index = stricmp(value, "none") == 0 ? -1 : loadsprite(value, offset.x, offset.y, nopalette ? PIXEL_x8 : PIXEL_8); //don't use palette for the sprite since it will one palette from the entity's remap list in 24bit mode - - if(index >= 0) { - - // If the model does not have a designated palette - // yet and the creator did not specify palette none - // or global palette, then we will use this frame's - // sprite to load a color table. Effectively the first - // frame of a model becomes its palette base. - if(pixelformat == PIXEL_x8 && !nopalette) { - - // No master color table assigned yet? - if(newchar->palette == NULL) { - //printf("\t\t\tAuto Palette - 'Palette' not defined. Attempting to load color table from this frame: "); - - // Allocate memory for color table. - newchar->palette = malloc(PAL_BYTES); - // - if(loadimagepalette(value, packfile, newchar->palette) == 0) { - //printf("\t\t\t%s%s\n", "Failed to load color table from image: ", value); - goto lCleanup; - } - } - - //printf("\t\t\t%s\n", "Success. Loaded color selection 0 from frame."); - - // Assign the color table to sprite. - if(!nopalette) { - sprite_map[index].node->sprite->palette = newchar->palette; - sprite_map[index].node->sprite->pixelformat = pixelformat; - } - } - - if(maskindex >= 0) { - sprite_map[index].node->sprite->mask = sprite_map[maskindex].node->sprite; - maskindex = -1; - } - } - - if(platform[PLATFORM_X] == PLATFORM_DEFAULT_X) { // old style - platform_con[PLATFORM_X] = 0; - platform_con[PLATFORM_Z] = 3; - platform_con[PLATFORM_UPPERLEFT] = platform[PLATFORM_UPPERLEFT] - offset.x; - platform_con[PLATFORM_LOWERLEFT] = platform[PLATFORM_LOWERLEFT] - offset.x; - platform_con[PLATFORM_UPPERRIGHT] = platform[PLATFORM_UPPERRIGHT] - offset.x; - platform_con[PLATFORM_LOWERRIGHT] = platform[PLATFORM_LOWERRIGHT] - offset.x; - platform_con[PLATFORM_DEPTH] = platform[PLATFORM_DEPTH] + 3; - - } else { // wall style - platform_con[PLATFORM_X] = platform[PLATFORM_X] - offset.x; - platform_con[PLATFORM_Z] = platform[PLATFORM_Z] - offset.y; - platform_con[PLATFORM_UPPERLEFT] = platform[PLATFORM_UPPERLEFT]; - platform_con[PLATFORM_LOWERLEFT] = platform[PLATFORM_LOWERLEFT]; - platform_con[PLATFORM_UPPERRIGHT] = platform[PLATFORM_UPPERRIGHT]; - platform_con[PLATFORM_LOWERRIGHT] = platform[PLATFORM_LOWERRIGHT]; - platform_con[PLATFORM_DEPTH] = platform[PLATFORM_DEPTH]; - } - platform_con[PLATFORM_HEIGHT] = platform[PLATFORM_HEIGHT]; - - if(shadow_set) { - shadow_coords[0] = shadow_xz[0] - offset.x; - shadow_coords[1] = shadow_xz[1] - offset.y; - - } else { - shadow_coords[0] = shadow_coords[1] = 0; - } - - if(drawmethod.config & DRAWMETHOD_CONFIG_ENABLED) { - dm = drawmethod; - if(dm.clipw) { - dm.clipx -= offset.x; - dm.clipy -= offset.y; - } - - } else { - dm.config &= ~DRAWMETHOD_CONFIG_ENABLED; - } - - frame_sound_load_collection(temp_frame_sound, packfile); - - add_frame_data.animation = newanim; - add_frame_data.spriteindex = index; - add_frame_data.framecount = framecount; - add_frame_data.delay = delay; - add_frame_data.delay_mode = delay_mode; - add_frame_data.idle = idle; - add_frame_data.move = &move; - add_frame_data.platform = platform_con; - add_frame_data.frameshadow = frameshadow; - add_frame_data.shadow_coords = shadow_coords; - add_frame_data.sound = temp_frame_sound; - add_frame_data.drawmethod = &dm; - add_frame_data.offset = &offset; - - add_frame_data.model = newchar; - - /* - * Delete nodes from frame object lists - * that don't have valid data (i.e. no - * coordinates defined at all or the - * coordinates X/Y/H/W are all 0). - * - * 2023-01-09 - Disabled. Clone functions now - * verify coordinates before copying temp - * to frame. This is to preserve legacy behavior - * of keeping the read in values frame to frame - * even after a collision box is closed. - */ - //collision_attack_remove_undefined_coordinates(&temp_collision_attack); - //collision_body_remove_undefined_coordinates(&temp_collision_body); - - /* - * Multiple per frame object heads may have - * changed, so this needs to be right before - * addframe function. - */ - add_frame_data.collision_attack = temp_collision_attack; - add_frame_data.collision_body = temp_collision_body; - add_frame_data.collision_space = temp_collision_space; - add_frame_data.child_spawn = temp_child_spawn_head; - - /* - * Send data to frame function so it - * can build a new animation frame. - */ - curframe = addframe(&add_frame_data); - - /* - * Clear any data tha we don't want - * retained for the next frame. Also - * reset temp indexes. - */ - - temp_collision_index = 0; - - frame_sound_collection_free(temp_frame_sound); - temp_frame_sound = NULL; - temp_frame_sound_index = 0; - - child_spawn_free_list(temp_child_spawn_head); - temp_child_spawn_head = NULL; - temp_child_spawn_index = 0; - - frm_id = -1; - at_cmd_mergeable = false; - } - break; - case CMD_MODEL_ALPHAMASK: - if(!newanim) - { - shutdownmessage = "Cannot add alpha mask: animation not specified!"; - goto lCleanup; - } - if(maskindex >= 0) - { - shutdownmessage = "Cannot add alpha mask: a mask has already been specified for this frame!"; - goto lCleanup; - } - value = GET_ARG(1); - //printf("frame count: %d\n",framecount); - //printf("Load sprite '%s'...\n", value); - index = loadsprite(value, offset.x, offset.y, PIXEL_8); //don't use palette for the mask - maskindex = index; - break; - case CMD_MODEL_FLIPFRAME: - newanim->flipframe = GET_FRAME_ARG(1); - break; - case CMD_MODEL_FOLLOWANIM: - newanim->followup.animation = GET_INT_ARG(1); - if(newanim->followup.animation > max_follows) - { - newanim->followup.animation = max_follows; - } - break; - case CMD_MODEL_FOLLOWCOND: - - // 2019-11-24 - // Caskey, Damon V. - // - // Follow up condition is now handled by bitwise logic. - // We need to set up our bit flags based on the old int - // arg for backward compatability. - - // Get legacy style condition arg. - tempInt = GET_INT_ARG(1); - - // Make sure condition is reset. - newanim->followup.condition = FOLLOW_CONDITION_NONE; - - switch (tempInt) - { - default: - case FOLLOW_CONDITION_CMD_READ_ALWAYS: - newanim->followup.condition |= FOLLOW_CONDITION_ANY; - break; - case FOLLOW_CONDITION_CMD_READ_HOSTILE: - newanim->followup.condition |= FOLLOW_CONDITION_HOSTILE_TARGET_TRUE; - break; - case FOLLOW_CONDITION_CMD_READ_HOSTILE_NOKILL_NOBLOCK: - newanim->followup.condition |= FOLLOW_CONDITION_HOSTILE_TARGET_TRUE; - newanim->followup.condition |= FOLLOW_CONDITION_BLOCK_FALSE; - newanim->followup.condition |= FOLLOW_CONDITION_LETHAL_FALSE; - break; - case FOLLOW_CONDITION_CMD_READ_HOSTILE_NOKILL_NOBLOCK_NOGRAB: - newanim->followup.condition |= FOLLOW_CONDITION_HOSTILE_TARGET_TRUE; - newanim->followup.condition |= FOLLOW_CONDITION_BLOCK_FALSE; - newanim->followup.condition |= FOLLOW_CONDITION_GRAB_TRUE; - newanim->followup.condition |= FOLLOW_CONDITION_LETHAL_FALSE; - break; - case FOLLOW_CONDITION_CMD_READ_HOSTILE_NOKILL_BLOCK: - newanim->followup.condition |= FOLLOW_CONDITION_HOSTILE_TARGET_TRUE; - newanim->followup.condition |= FOLLOW_CONDITION_BLOCK_TRUE; - newanim->followup.condition |= FOLLOW_CONDITION_LETHAL_FALSE; - break; - } - - case CMD_MODEL_COUNTERRANGE: - newanim->counter_action.frame.min = GET_FRAME_ARG(1); - newanim->counter_action.frame.max = GET_FRAME_ARG(2); - - // 2019-12-04 - // Caskey, Damon V. - // - // Counter action condition is now handled by bitwise logic. - // We need to set up our bit flags based on the old int - // arg for backward compatability. - - // Get legacy style condition arg. - tempInt = GET_INT_ARG(3); - - // Make sure condition is reset. - newanim->counter_action.condition = COUNTER_ACTION_CONDITION_NONE; - - switch (tempInt) - { - default: - case COUNTER_ACTION_CONDITION_CMD_READ_ALWAYS: - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_DAMAGE_LETHAL_FALSE; - break; - case COUNTER_ACTION_CONDITION_CMD_READ_HOSTILE: - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_DAMAGE_LETHAL_FALSE; - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_HOSTILE_TARGET_TRUE; - break; - case COUNTER_ACTION_CONDITION_CMD_READ_HOSTILE_FRONT_NOFREEZE: - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_BACK_TRUE; - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_BLOCK_TRUE; - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_DAMAGE_LETHAL_FALSE; - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_FREEZE_FALSE; - newanim->counter_action.condition |= COUNTER_ACTION_CONDITION_HOSTILE_TARGET_TRUE; - break; - case COUNTER_ACTION_CONDITION_CMD_READ_ALWAYS_RAGE: - newanim->counter_action.condition ^= FOLLOW_CONDITION_ANY; - break; - } - - newanim->counter_action.damaged = GET_INT_ARG(4); - break; - case CMD_MODEL_WEAPONFRAME: - if(!newanim->weaponframe) - { - newanim->weaponframe = malloc(sizeof(*newanim->weaponframe) * 3); - } - newanim->weaponframe[0] = GET_FRAME_ARG(1); - newanim->weaponframe[1] = GET_INT_ARG(2); - newanim->weaponframe[2] = GET_INT_ARG(3); - break; - case CMD_MODEL_QUAKEFRAME: - newanim->quakeframe.framestart = GET_FRAME_ARG(1); - newanim->quakeframe.repeat = GET_INT_ARG(2); - newanim->quakeframe.v = GET_INT_ARG(3); - newanim->quakeframe.cnt = 0; - break; - case CMD_MODEL_SUBENTITY: - case CMD_MODEL_CUSTENTITY: - value = GET_ARG(1); - if(value[0]) - { - newanim->sub_entity_model_index = get_cached_model_index(value); - } - break; - case CMD_MODEL_SPAWNFRAME: - - newanim->sub_entity_spawn = allocate_sub_entity(); - - newanim->sub_entity_spawn->frame = GET_FRAME_ARG(1); - newanim->sub_entity_spawn->position.x = GET_FLOAT_ARG(2); - newanim->sub_entity_spawn->position.z = GET_FLOAT_ARG(3); - newanim->sub_entity_spawn->position.y = GET_FLOAT_ARG(4); - newanim->sub_entity_spawn->placement = GET_INT_ARG(5); - break; - - case CMD_MODEL_SUMMONFRAME: - - newanim->sub_entity_summon = allocate_sub_entity(); - - newanim->sub_entity_summon->frame = GET_FRAME_ARG(1); - newanim->sub_entity_summon->position.x = GET_FLOAT_ARG(2); - newanim->sub_entity_summon->position.z = GET_FLOAT_ARG(3); - newanim->sub_entity_summon->position.y = GET_FLOAT_ARG(4); - newanim->sub_entity_summon->placement = GET_INT_ARG(5); - break; - - - case CMD_MODEL_UNSUMMONFRAME: - newanim->sub_entity_unsummon = GET_FRAME_ARG(1); - break; - case CMD_MODEL_NOHITHEAD: - - if (GET_INT_ARG(1)) - { - newchar->move_config_flags |= MOVE_CONFIG_NO_HIT_HEAD; - } - else - { - newchar->move_config_flags &= ~MOVE_CONFIG_NO_HIT_HEAD; - } - - break; - case CMD_MODEL_AT_SCRIPT: - at_cmd_mergeable = false; - - if(!scriptbuf[0]) // if empty, paste the main function text here - { - buffer_append(&scriptbuf, pre_text, 0xffffff, &sbsize, &scriptlen); - } - scriptbuf[scriptlen - strclen(sur_text)] = 0; // cut last chars - scriptlen = strlen(scriptbuf); - if(ani_id >= 0) - { - if(script_id != ani_id) // if expression 1 - { - sprintf(namebuf, ifid_text, newanim->index); - buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen); - script_id = ani_id; - } - scriptbuf[scriptlen - strclen(endifid_text)] = 0; // cut last chars - scriptlen = strlen(scriptbuf); - } - while(!starts_with(buf + pos, "@script")) - { - pos++; - } - pos += strclen("@script"); - len = 0; - while(!starts_with(buf + pos, "@end_script")) - { - len++; - pos++; - } - buffer_append(&scriptbuf, buf + pos - len, len, &sbsize, &scriptlen); - pos += strclen("@end_script"); - - if(ani_id >= 0) - { - buffer_append(&scriptbuf, endifid_text, 0xffffff, &sbsize, &scriptlen);// put back last chars - } - buffer_append(&scriptbuf, sur_text, 0xffffff, &sbsize, &scriptlen);// put back last chars - break; - case CMD_MODEL_AT_CMD: - { - s_command_token command_token; - s_command_token_reader command_token_reader; - bool command_emitted = false; - bool first_command_argument; - - //translate @cmd into script function call - if(ani_id < 0) - { - shutdownmessage = "command '@cmd' must follow an animation!"; - goto lCleanup; - } - if(!scriptbuf[0]) // if empty, paste the main function text here - { - buffer_append(&scriptbuf, pre_text, 0xffffff, &sbsize, &scriptlen); - } - scriptbuf[scriptlen - strclen(sur_text)] = 0; // cut last chars - scriptlen = strlen(scriptbuf); - if(script_id != ani_id) // if expression 1 - { - at_cmd_mergeable = false; - sprintf(namebuf, ifid_text, newanim->index); - buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen); - script_id = ani_id; - } - scriptbuf[scriptlen - strclen(endifid_text)] = 0; // cut last chars - scriptlen = strlen(scriptbuf); - command_token_reader = (s_command_token_reader){ - .cursor = buf + pos - }; - - /* Skip @cmd, then read the function name. */ - if(command_token_reader_next(&command_token_reader, &command_token) - && command_token_reader_next(&command_token_reader, &command_token)) - { - /* - //no_cmd_compatible will try to optimize if(frame==n) - //which means merging extra if statements within the same frame - //some old mod will have problem if this is enabled, however. - // - // @cmd f - // @cmd f - // frame - // - // When no_cmd_compatible is 1 - // - // if(frame==n) { - // f(); - // f(); - // return; - // } - // - // When no_cmd_compatible is 0 - // - // if(frame==n) { - // f(); - // } - // if(frame==n) { - // f(); - // } - */ - /* - - Caskey, Damon V. - - 2026-08-12 - - - - Merge same-frame @cmd calls only when the - previous generated section is an eligible - @cmd block with the exact expected suffix. - Otherwise, open a new frame condition without - removing any existing script text. - */ - const size_t frame_close_length = strclen(endif_text); - const size_t frame_return_length = strclen(endif_return_text); - - bool merge_previous_command = - no_cmd_compatible - && at_cmd_mergeable - && frm_id == curframe; - - if(merge_previous_command) - { - merge_previous_command = buffer_remove_suffix_pair( - scriptbuf, - &scriptlen, - endif_return_text, - frame_return_length, - endif_text, - frame_close_length - ); - } - - if(!merge_previous_command) - { - sprintf(namebuf, if_text, curframe);//only execute in current frame - buffer_append(&scriptbuf, namebuf, 0xffffff, &sbsize, &scriptlen); - frm_id = curframe; - } - buffer_append(&scriptbuf, call_indent_text, 0xffffff, &sbsize, &scriptlen); - buffer_append( - &scriptbuf, - command_token.text, - command_token.length, - &sbsize, - &scriptlen - ); - buffer_append(&scriptbuf, call_open_text, 0xffffff, &sbsize, &scriptlen); - - first_command_argument = true; - while(command_token_reader_next( - &command_token_reader, - &command_token - )) - { - if(!first_command_argument) - { - buffer_append(&scriptbuf, comma_text, 0xffffff, &sbsize, &scriptlen); - } - buffer_append( - &scriptbuf, - command_token.text, - command_token.length, - &sbsize, - &scriptlen - ); - first_command_argument = false; - } - - command_emitted = true; - } - - if(command_token_reader.unterminated_quote) - { - snprintf( - alert_buffer, - sizeof(alert_buffer), - "Command '@cmd' has an unterminated %c quote.\n", - command_token_reader.unterminated_quote - ); - - shutdownmessage = alert_buffer; - goto lCleanup; - } - - buffer_append(&scriptbuf, endcall_text, 0xffffff, &sbsize, &scriptlen); - if(no_cmd_compatible) - { - buffer_append(&scriptbuf, endif_return_text, 0xffffff, &sbsize, &scriptlen); //return - } - buffer_append(&scriptbuf, endif_text, 0xffffff, &sbsize, &scriptlen);//end of if - buffer_append(&scriptbuf, endifid_text, 0xffffff, &sbsize, &scriptlen); // put back last chars - buffer_append(&scriptbuf, sur_text, 0xffffff, &sbsize, &scriptlen); // put back last chars - at_cmd_mergeable = no_cmd_compatible && command_emitted; - break; - } - default: - if(command && command[0]) - { - if(!handle_txt_include(command, &arglist, &filename, fnbuf, &buf, &pos, &size)) - { - printf("Command '%s' not understood in file '%s'!\n", command, filename); - } - } - } - - } - // Go to next line - pos += getNewLineStart(buf + pos); - } - - - tempInt = 1; - - if(scriptbuf && animscriptbuf && scriptbuf[0] && animscriptbuf[0]) - { - writeToScriptLog("\n#### animationscript function main #####\n# "); - writeToScriptLog(filename); - writeToScriptLog("\n########################################\n"); - writeToScriptLog(scriptbuf); - - lcmScriptDeleteMain(&scriptbuf); - lcmScriptAddMain(&animscriptbuf); - lcmScriptJoinMain(&animscriptbuf,scriptbuf); - - if(!Script_IsInitialized(newchar->scripts->animation_script)) - { - Script_Init(newchar->scripts->animation_script, newchar->name, filename, 0); - } - tempInt = Script_AppendText(newchar->scripts->animation_script, animscriptbuf, filename); - } - else if(animscriptbuf && animscriptbuf[0]) - { - lcmScriptAddMain(&animscriptbuf); - - if(!Script_IsInitialized(newchar->scripts->animation_script)) - { - Script_Init(newchar->scripts->animation_script, newchar->name, filename, 0); - } - tempInt = Script_AppendText(newchar->scripts->animation_script, animscriptbuf, filename); - } - else if(scriptbuf && scriptbuf[0]) - { - //printf("\n%s\n", scriptbuf); - if(!Script_IsInitialized(newchar->scripts->animation_script)) - { - Script_Init(newchar->scripts->animation_script, newchar->name, filename, 0); - } - tempInt = Script_AppendText(newchar->scripts->animation_script, scriptbuf, filename); - //Interpreter_OutputPCode(newchar->scripts->animation_script.pinterpreter, "code"); - writeToScriptLog("\n#### animationscript function main #####\n# "); - writeToScriptLog(filename); - writeToScriptLog("\n########################################\n"); - writeToScriptLog(scriptbuf); - } - - if(!newchar->isSubclassed) - { - Script_Compile(newchar->scripts->animation_script); - } - - if(!tempInt)// parse script failed - { - shutdownmessage = "Error parsing function main of animation script in file '%s'!"; - goto lCleanup; - } - - // We need a little more work to initialize the new A.I. types if they are not loaded from file - if(newchar->aiattack == -1) - { - newchar->aiattack = 0; - } - if(newchar->aimove == AIMOVE1_NONE) - { - newchar->aimove = AIMOVE1_NORMAL; - } - //if(!newchar->offscreenkill) newchar->offscreenkill = 1000; - - //temporary patch for conflicting moves - if(newchar->animation[ANI_FREESPECIAL] && !is_set(newchar, ANI_FREESPECIAL)) - { - if(!alloc_specials(newchar)) - { - shutdownmessage = E_OUT_OF_MEMORY; - goto lCleanup; - } - - newchar->special[newchar->specials_loaded].input[0].press = FLAG_FORWARD; - newchar->special[newchar->specials_loaded].input[1].press = FLAG_FORWARD; - newchar->special[newchar->specials_loaded].input[2].press = FLAG_ATTACK; - newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL; - newchar->special[newchar->specials_loaded].steps = 3; - newchar->specials_loaded++; - } - if(newchar->animation[ANI_FREESPECIAL2] && !is_set(newchar, ANI_FREESPECIAL2)) - { - if(!alloc_specials(newchar)) - { - shutdownmessage = E_OUT_OF_MEMORY; - goto lCleanup; - } - - newchar->special[newchar->specials_loaded].input[0].press = FLAG_MOVEDOWN; - newchar->special[newchar->specials_loaded].input[1].press = FLAG_MOVEDOWN; - newchar->special[newchar->specials_loaded].input[2].press = FLAG_ATTACK; - newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL2; - newchar->special[newchar->specials_loaded].steps = 3; - newchar->specials_loaded++; - } - if(newchar->animation[ANI_FREESPECIAL3] && !is_set(newchar, ANI_FREESPECIAL3)) - { - if(!alloc_specials(newchar)) - { - shutdownmessage = E_OUT_OF_MEMORY; - goto lCleanup; - } - - newchar->special[newchar->specials_loaded].input[0].press = FLAG_MOVEUP; - newchar->special[newchar->specials_loaded].input[1].press = FLAG_MOVEUP; - newchar->special[newchar->specials_loaded].input[2].press = FLAG_ATTACK; - newchar->special[newchar->specials_loaded].anim = ANI_FREESPECIAL3; - newchar->special[newchar->specials_loaded].steps = 3; - newchar->specials_loaded++; - } - - if(newchar->risetime.rise == -1) - { - if(newchar->type == TYPE_PLAYER) - { - if(newchar->animation[ANI_RISEATTACK]) - { - newchar->risetime.rise = global_config.game_speed / 2; - } - else - { - newchar->risetime.rise = global_config.game_speed; - } - } - else if(newchar->type == TYPE_ENEMY || newchar->type == TYPE_NPC) - { - newchar->risetime.rise = 0; - } - } - - if(newchar->faction.type_hostile == TYPE_UNDECLARED) // not been initialized, so initialize it - { - switch (newchar->type) - { - default: - //Do nothing. - break; - case TYPE_ENEMY: - newchar->faction.type_hostile = TYPE_PLAYER; - break; - case TYPE_PLAYER: // dont really needed, since you don't need A.I. control for players - newchar->faction.type_hostile = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE; - break; - case TYPE_TRAP: - newchar->faction.type_hostile = TYPE_ENEMY | TYPE_PLAYER; - case TYPE_OBSTACLE: - newchar->faction.type_hostile = TYPE_UNDECLARED; - break; - case TYPE_PROJECTILE: - // We want a clean slate so the projectile - // spawn functions will copy owner settings - // by default. - newchar->faction.type_hostile = TYPE_UNDECLARED; - break; - case TYPE_SHOT: // only target enemies - newchar->faction.type_hostile = TYPE_ENEMY ; - break; - case TYPE_NPC: // default npc behivior - newchar->faction.type_hostile = TYPE_ENEMY ; - break; - } - } - - if(newchar->faction.type_damage_direct == TYPE_UNDECLARED) // not been initialized, so initialize it - { - switch (newchar->type) - { - default: - //Do nothing. - break; - case TYPE_ENEMY: - newchar->faction.type_damage_direct = TYPE_PLAYER | TYPE_SHOT; - if(newchar->subtype == SUBTYPE_ARROW) - { - newchar->faction.type_damage_direct |= TYPE_OBSTACLE; - } - break; - case TYPE_PLAYER: - newchar->faction.type_damage_direct = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE; - break; - case TYPE_TRAP: - newchar->faction.type_damage_direct = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - case TYPE_OBSTACLE: - newchar->faction.type_damage_direct = TYPE_PLAYER | TYPE_ENEMY | TYPE_OBSTACLE; - break; - case TYPE_PROJECTILE: - // We want a clean slate so the projectile - // spawn functions will copy owner settings - // by default. - newchar->faction.type_damage_direct = TYPE_UNDECLARED; - break; - case TYPE_SHOT: - newchar->faction.type_damage_direct = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - break; - case TYPE_NPC: - newchar->faction.type_damage_direct = TYPE_ENEMY | TYPE_OBSTACLE; - break; - case TYPE_ITEM: - newchar->faction.type_damage_direct = TYPE_PLAYER; - break; - } - } - - if(newchar->faction.type_damage_indirect == TYPE_UNDECLARED) // not been initialized, so initialize it - { - switch (newchar->type) - { - default: - //Do nothing. - break; - case TYPE_ENEMY: - newchar->faction.type_damage_indirect = TYPE_ENEMY | TYPE_OBSTACLE; - break; - case TYPE_PLAYER: - newchar->faction.type_damage_indirect = TYPE_PLAYER | TYPE_OBSTACLE; - break; - case TYPE_TRAP: // hmm, don't really needed - newchar->faction.type_damage_indirect = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - case TYPE_OBSTACLE: // hmm, don't really needed - newchar->faction.type_damage_indirect = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - break; - case TYPE_PROJECTILE: - // We want a clean slate so the projectile - // spawn functions will copy owner settings - // by default. - newchar->faction.type_damage_indirect = TYPE_UNDECLARED; - break; - case TYPE_SHOT: // hmm, don't really needed - newchar->faction.type_damage_indirect = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - break; - case TYPE_NPC: - newchar->faction.type_damage_indirect = TYPE_ENEMY | TYPE_PLAYER | TYPE_OBSTACLE; - break; - } - } - - if(newchar->jumpspeed < 0) - { - newchar->jumpspeed = MAX(newchar->speed.x, 1); - } - - if(blendfx_is_set == 0) - { - if(newchar->alpha) - { - blendfx[newchar->alpha - 1] = 1; - } - if(newchar->shadow_config_flags & SHADOW_CONFIG_GRAPHIC_ALL || newchar->shadow) - { - blendfx[BLEND_MULTIPLY] = 1; - } - } - - // we need to convert 8bit colourmap into 32bit palette - if(pixelformat == PIXEL_x8) - { - convert_map_to_palette(newchar, mapflag); - } - -lCleanup: - - if(buf != NULL) - { - free(buf); - buf = NULL; - } - if(scriptbuf) - { - free(scriptbuf); - scriptbuf = NULL; - } - if(animscriptbuf) - { - free(animscriptbuf); - animscriptbuf = NULL; - } - if(mapflag) - { - free(mapflag); - mapflag = NULL; - } - - /* - * Free parser scratch collision collections. - * - * These collections are temporary carry-forward state - * used while reading model commands. Real animation - * frames receive cloned collections when frames are - * added, so the parser scratch collections should not - * survive model loading. - */ - collision_collection_free(temp_collision_attack); - temp_collision_attack = NULL; - - collision_collection_free(temp_collision_body); - temp_collision_body = NULL; - - collision_collection_free(temp_collision_space); - temp_collision_space = NULL; - - frame_sound_collection_free(temp_frame_sound); - temp_frame_sound = NULL; - - child_spawn_free_list(temp_child_spawn_head); - temp_child_spawn_head = NULL; - - if(!shutdownmessage) - { - model_cache[cacheindex].lifecycle = MODEL_LIFECYCLE_LOAD_EVENT; - execute_model_load_scripts(newchar); - model_cache[cacheindex].lifecycle = MODEL_LIFECYCLE_LOADED; - printf(" ...done!\n"); - return newchar; - } - - borShutdown(1, "Fatal Error in load_cached_model, file: %s, line %d, message: %s\n", filename, line, shutdownmessage); - return NULL; - - #undef LOG_CMD_TITLE -} - - - -int is_set(s_model *model, int m) // New function to determine if a freespecial has been set -{ - int i; - - for(i = 0; i < model->specials_loaded; i++) - { - if(model->special[i].anim == m) - { - return 1; - } - } - - return 0; -} - -int load_script_setting() -{ - char *filename = "data/script.txt"; - char *buf, *command; - ptrdiff_t pos = 0; - size_t size = 0; - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - - if(buffer_pakfile(filename, &buf, &size) != 1) - { - return 0; - } - - while(pos < size) - { - if(ParseArgs(&arglist, buf + pos, argbuf)) - { - command = GET_ARG(0); - if(command && command[0]) - { - if(stricmp(command, "maxscriptvars") == 0) // each script can have a variable list that can be accessed by index - { - max_script_vars = GET_INT_ARG(1) ; - if(max_script_vars < 0) - { - max_script_vars = 0; - } - } - else if(stricmp(command, "maxentityvars") == 0) // each entity can have a variable list that can be accessed by index - { - max_entity_vars = GET_INT_ARG(1) ; - if(max_entity_vars < 0) - { - max_entity_vars = 0; - } - } - else if(stricmp(command, "maxindexedvars") == 0) // a global variable list that can be accessed by index - { - max_indexed_vars = GET_INT_ARG(1); - if(max_indexed_vars < 0) - { - max_indexed_vars = 0; - } - } - else if(stricmp(command, "keyscriptrate") == 0) // Rate that keyscripts fire when holding a key. - { - keyscriptrate = GET_INT_ARG(1); - } - else if(stricmp(command, "alwaysupdate") == 0) //execute update script whenever update() is called - { - alwaysupdate = GET_INT_ARG(1); - } - else if(stricmp(command, "nonestedscript") == 0) // don't call a script if it is being executed - { - no_nested_script = GET_INT_ARG(1); - } - else if(stricmp(command, "nocmdcompatible") == 0) // don't call a script if it is being executed - { - no_cmd_compatible = GET_INT_ARG(1); - } - } - } - // Go to next line - pos += getNewLineStart(buf + pos); - } - - if(buf != NULL) - { - free(buf); - buf = NULL; - } - return 1; -} - -/* -* Convert one models.txt limit to an int without signed -* overflow or partial numeric conversion. -*/ -static bool model_constant_get_unsigned_int(const char* text, int* result) -{ - s_command_token token; - uint64_t parsed_value; - - assert(text); - assert(result); - - token.text = text; - token.length = strlen(text); - - if(!command_token_get_uint64(&token, &parsed_value) - || parsed_value > (uint64_t)INT_MAX) { - return false; - } - - *result = (int)parsed_value; - - return true; -} - -/* -* Allocate a models.txt-driven table only after checking -* its multiplication. Allocation failure is fatal because -* model loading cannot safely continue with a missing table. -*/ -static void* model_constant_array_allocate( - const size_t element_count, - const size_t element_size, - const char* table_name, - const char* filename -) { - void* result; - - assert(table_name); - assert(filename); - - if(element_count == 0 - || element_size == 0 - || element_count > SIZE_MAX / element_size) { - borShutdown( - 1, - "Invalid allocation size for %s while loading %s.\n", - table_name, - filename - ); - - return NULL; - } - - result = malloc(element_count * element_size); - - if(!result) { - borShutdown( - 1, - "Unable to allocate %zu entries for %s while loading %s.\n", - element_count, - table_name, - filename - ); - - return NULL; - } - - return result; -} - -void load_model_constants() -{ - char filename[MAX_BUFFER_LEN] = "data/models.txt"; - int i; - int64_t calculated_max_animations; - char *buf; - size_t size; - ptrdiff_t pos; - char *command; - int line = 0; - int maxanim = MAX_ANIS; // temporary counter - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - modelstxtCommands cmd; - - // reload default values - max_idles = MAX_IDLES; - max_walks = MAX_WALKS; - max_ups = MAX_UPS; - max_downs = MAX_DOWNS; - max_backwalks = MAX_BACKWALKS; - max_attack_types = MAX_ATKS; - max_freespecials = MAX_SPECIALS; - max_follows = MAX_FOLLOWS; - max_attacks = MAX_ATTACKS; - max_animations = MAX_ANIS; - - max_collisons = MAX_COLLISIONS; - - // free old values - if(animspecials) - { - free(animspecials); - animspecials = NULL; - } - if(animattacks) - { - free(animattacks); - animattacks = NULL; - } - if(animfollows) - { - free(animfollows); - animfollows = NULL; - } - if(animpains) - { - free(animpains); - animpains = NULL; - } - if(animbackpains) - { - free(animbackpains); - animbackpains = NULL; - } - if(animfalls) - { - free(animfalls); - animfalls = NULL; - } - if(animbackfalls) - { - free(animbackfalls); - animbackfalls = NULL; - } - if(animrises) - { - free(animrises); - animrises = NULL; - } - if(animbackrises) - { - free(animbackrises); - animbackrises = NULL; - } - if(animriseattacks) - { - free(animriseattacks); - animriseattacks = NULL; - } - if(animbackriseattacks) - { - free(animbackriseattacks); - animbackriseattacks = NULL; - } - if(animblkpains) - { - free(animblkpains); - animblkpains = NULL; - } - if(animbackblkpains) - { - free(animbackblkpains); - animbackblkpains = NULL; - } - if(animdies) - { - free(animdies); - animdies = NULL; - } - if(animbackdies) - { - free(animbackdies); - animbackdies = NULL; - } - if(animwalks) - { - free(animwalks); - animwalks = NULL; - } - if(animbackwalks) - { - free(animbackwalks); - animbackwalks = NULL; - } - if(animidles) - { - free(animidles); - animidles = NULL; - } - if(animups) - { - free(animups); - animups = NULL; - } - if(animdowns) - { - free(animdowns); - animdowns = NULL; - } - if(ai_attack_choices) - { - free(ai_attack_choices); - ai_attack_choices = NULL; - ai_attack_choice_capacity = 0; - } - - // Read file - if(buffer_pakfile(filename, &buf, &size) != 1) - { - borShutdown(1, "Error loading model list from %s", filename); - } - - pos = 0; - while(pos < size) // peek global settings - { - line++; - if(ParseArgs(&arglist, buf + pos, argbuf)) - { - command = GET_ARG(0); - cmd = (modelstxtCommands)getModelCommand(modelstxtcmdlist, command); - switch(cmd) - { - case CMD_MODELSTXT_MAX_COLLISIONS: - // max collision_attack boxes. - max_collisons = GET_INT_ARG(1); - if(max_collisons < MAX_COLLISIONS) - { - max_collisons = MAX_COLLISIONS; - } - break; - case CMD_MODELSTXT_MAXIDLES: - // max idle stances - max_idles = GET_INT_ARG(1); - if(max_idles < MAX_IDLES) - { - max_idles = MAX_IDLES; - } - break; - case CMD_MODELSTXT_MAXWALKS: - max_walks = GET_INT_ARG(1); - if(max_walks < MAX_WALKS) - { - max_walks = MAX_WALKS; - } - break; - case CMD_MODELSTXT_MAXBACKWALKS: - // max backward walks - max_backwalks = GET_INT_ARG(1); - if(max_backwalks < MAX_BACKWALKS) - { - max_backwalks = MAX_BACKWALKS; - } - break; - case CMD_MODELSTXT_MAXUPS: - // max up walks - max_ups = GET_INT_ARG(1); - if(max_ups < MAX_UPS) - { - max_ups = MAX_UPS; - } - break; - case CMD_MODELSTXT_MAXDOWNS: - // max down walks - max_downs = GET_INT_ARG(1); - if(max_downs < MAX_DOWNS) - { - max_downs = MAX_DOWNS; - } - break; - case CMD_MODELSTXT_MAXATTACKTYPES: - // max attacktype/pain/fall/die - max_attack_types = GET_INT_ARG(1) + STA_ATKS; - if(max_attack_types < MAX_ATKS) - { - max_attack_types = MAX_ATKS; - } - break; - case CMD_MODELSTXT_MAXFOLLOWS: - // max follow-ups - max_follows = GET_INT_ARG(1); - if(max_follows < MAX_FOLLOWS) - { - max_follows = MAX_FOLLOWS; - } - break; - case CMD_MODELSTXT_MAXFREESPECIALS: - // max freespecials - if(!model_constant_get_unsigned_int( - GET_ARG(1), - &max_freespecials - )) { - borShutdown( - 1, - "Invalid maxfreespecials value '%s' in %s, line %d. " - "Expected an unsigned integer no greater than %d.\n", - GET_ARG(1), - filename, - line, - INT_MAX - ); - } - - if(max_freespecials < MAX_SPECIALS) - { - max_freespecials = MAX_SPECIALS; - } - break; - case CMD_MODELSTXT_MAXATTACKS: - max_attacks = GET_INT_ARG(1); - if(max_attacks < MAX_ATTACKS) - { - max_attacks = MAX_ATTACKS; - } - break; - default: - if(cmd >= CMD_MODELSTXT_THE_END) - { - printf("command %s not understood in %s, line %d\n", command, filename, line); - } - break; - } - } - - // Go to next line - pos += getNewLineStart(buf + pos); - } - - /* - * Calculate in a wider type before assigning the int - * animation identifiers used throughout the engine. - */ - calculated_max_animations = - (int64_t)MAX_ANIS - + ((int64_t)max_attack_types - MAX_ATKS) * INT64_C(12) - + ((int64_t)max_follows - MAX_FOLLOWS) - + ((int64_t)max_freespecials - MAX_SPECIALS) - + ((int64_t)max_attacks - MAX_ATTACKS) - + ((int64_t)max_idles - MAX_IDLES) - + ((int64_t)max_walks - MAX_WALKS) - + ((int64_t)max_ups - MAX_UPS) - + ((int64_t)max_downs - MAX_DOWNS) - + ((int64_t)max_backwalks - MAX_BACKWALKS); - - if(calculated_max_animations < MAX_ANIS - || calculated_max_animations > INT_MAX) { - borShutdown( - 1, - "Configured model animation limits require %" PRId64 - " animation identifiers, but the supported maximum is %d " - "while loading %s.\n", - calculated_max_animations, - INT_MAX, - filename - ); - } - - max_animations = (int)calculated_max_animations; - - // alloc indexed animation ids - animdowns = model_constant_array_allocate((size_t)max_downs, sizeof(*animdowns), "down animation identifiers", filename); - animups = model_constant_array_allocate((size_t)max_ups, sizeof(*animups), "up animation identifiers", filename); - animbackwalks = model_constant_array_allocate((size_t)max_backwalks, sizeof(*animbackwalks), "backwalk animation identifiers", filename); - animwalks = model_constant_array_allocate((size_t)max_walks, sizeof(*animwalks), "walk animation identifiers", filename); - animidles = model_constant_array_allocate((size_t)max_idles, sizeof(*animidles), "idle animation identifiers", filename); - animpains = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animpains), "pain animation identifiers", filename); - animbackpains = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackpains), "back-pain animation identifiers", filename); - animdies = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animdies), "death animation identifiers", filename); - animbackdies = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackdies), "back-death animation identifiers", filename); - animfalls = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animfalls), "fall animation identifiers", filename); - animbackfalls = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackfalls), "back-fall animation identifiers", filename); - animrises = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animrises), "rise animation identifiers", filename); - animbackrises = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackrises), "back-rise animation identifiers", filename); - animriseattacks = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animriseattacks), "rise-attack animation identifiers", filename); - animbackriseattacks = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackriseattacks), "back-rise-attack animation identifiers", filename); - animblkpains = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animblkpains), "block-pain animation identifiers", filename); - animbackblkpains = model_constant_array_allocate((size_t)max_attack_types, sizeof(*animbackblkpains), "back-block-pain animation identifiers", filename); - animattacks = model_constant_array_allocate((size_t)max_attacks, sizeof(*animattacks), "attack animation identifiers", filename); - animfollows = model_constant_array_allocate((size_t)max_follows, sizeof(*animfollows), "follow animation identifiers", filename); - animspecials = model_constant_array_allocate((size_t)max_freespecials, sizeof(*animspecials), "freespecial animation identifiers", filename); - ai_attack_choice_capacity = (size_t)max_animations; - ai_attack_choices = model_constant_array_allocate(ai_attack_choice_capacity, sizeof(*ai_attack_choices), "AI attack-choice table", filename); - - // copy default values and new animation ids - memcpy(animdowns, downs, sizeof(*animdowns)*MAX_DOWNS); - for(i = MAX_DOWNS; i < max_downs; i++) - { - animdowns[i] = maxanim++; - } - memcpy(animups, ups, sizeof(*animups)*MAX_UPS); - for(i = MAX_UPS; i < max_ups; i++) - { - animups[i] = maxanim++; - } - memcpy(animbackwalks, backwalks, sizeof(*animbackwalks)*MAX_BACKWALKS); - for(i = MAX_BACKWALKS; i < max_backwalks; i++) - { - animbackwalks[i] = maxanim++; - } - memcpy(animwalks, walks, sizeof(*animwalks)*MAX_WALKS); - for(i = MAX_WALKS; i < max_walks; i++) - { - animwalks[i] = maxanim++; - } - memcpy(animidles, idles, sizeof(*animidles)*MAX_IDLES); - for(i = MAX_IDLES; i < max_idles; i++) - { - animidles[i] = maxanim++; - } - memcpy(animspecials, freespecials, sizeof(*animspecials)*MAX_SPECIALS); - for(i = MAX_SPECIALS; i < max_freespecials; i++) - { - animspecials[i] = maxanim++; - } - memcpy(animattacks, normal_attacks, sizeof(*animattacks)*MAX_ATTACKS); - for(i = MAX_ATTACKS; i < max_attacks; i++) - { - animattacks[i] = maxanim++; - } - memcpy(animfollows, follows, sizeof(*animfollows)*MAX_FOLLOWS); - for(i = MAX_FOLLOWS; i < max_follows; i++) - { - animfollows[i] = maxanim++; - } - memcpy(animpains, pains, sizeof(*animpains)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - //printf("\nInitializing animpains[%d]: setting to new anim ID %d", i, maxanim); - animpains[i] = maxanim++; - } - memcpy(animbackpains, backpains, sizeof(*animbackpains)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackpains[i] = maxanim++; - } - memcpy(animfalls, falls, sizeof(*animfalls)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animfalls[i] = maxanim++; - } - memcpy(animbackfalls, backfalls, sizeof(*animbackfalls)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackfalls[i] = maxanim++; - } - memcpy(animrises, rises, sizeof(*animrises)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animrises[i] = maxanim++; - } - memcpy(animbackrises, backrises, sizeof(*animbackrises)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackrises[i] = maxanim++; - } - memcpy(animriseattacks, riseattacks, sizeof(*animriseattacks)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animriseattacks[i] = maxanim++; - } - memcpy(animbackriseattacks, backriseattacks, sizeof(*animbackriseattacks)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackriseattacks[i] = maxanim++; - } - memcpy(animblkpains, blkpains, sizeof(*animblkpains)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animblkpains[i] = maxanim++; - } - memcpy(animbackblkpains, backblkpains, sizeof(*animbackblkpains)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackblkpains[i] = maxanim++; - } - memcpy(animdies, deaths, sizeof(*animdies)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animdies[i] = maxanim++; - } - memcpy(animbackdies, backdeaths, sizeof(*animbackdies)*MAX_ATKS); - for(i = MAX_ATKS; i < max_attack_types; i++) - { - animbackdies[i] = maxanim++; - } - - if(buf) - { - free(buf); - } -} - -// Load / cache all models -int load_models() -{ - char filename[MAX_BUFFER_LEN] = "data/models.txt"; - int i; - char *buf; - size_t size; - ptrdiff_t pos; - char *command; - int line = 0; - - char tmpBuff[MAX_BUFFER_LEN] = {""}; - - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - modelstxtCommands cmd; - int modelLoadCount = 0; - - char* value = NULL; - int tempInt = 0; - - const char* delay_mode_error; - - free_modelcache(); - - /* - * Reset load-only configuration before reading models.txt - * so a reload cannot retain a setting that was removed. - */ - global_config.delay_unit = DELAY_UNIT_CENTISECOND; - - if(isLoadingScreenTypeBg(loadingbg[0].set)) - { - // New alternative background path. - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "loading"); - load_background(tmpBuff); - } - else - { - load_background("data/bgs/loading"); - } - standard_palette(1); - } - if(isLoadingScreenTypeBar(loadingbg[0].set)) - { - lifebar_colors(); - init_colourtable(); - } - - update_loading(&loadingbg[0], -1, 1); // initialize the update screen - - if(custModels != NULL) - { - strcpy(filename, "data/"); - strcat(filename, custModels); - } - - // Read file - if(buffer_pakfile(filename, &buf, &size) != 1) - { - borShutdown(1, "Error loading model list from %s", filename); - } - - pos = 0; - while(pos < size) // peek global settings - { - line++; - if(ParseArgs(&arglist, buf + pos, argbuf)) - { - command = GET_ARG(0); - cmd = (modelstxtCommands)getModelCommand(modelstxtcmdlist, command); - switch(cmd) - { - case CMD_MODELSTXT_COMBODELAY: - combodelay = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_MUSIC: - music(GET_ARG(1), 1, atol(GET_ARG(2))); - break; - case CMD_MODELSTXT_LOAD: - // Add path to cache list - modelLoadCount++; - cache_model(GET_ARG(1), GET_ARG(2), 1); - break; - case CMD_MODELSTXT_COLOURSELECT: - // 6-2-2005 if string for colourselect found - colourselect = GET_INT_ARG(1); // 6-2-2005 - break; - case CMD_MODELSTXT_SPDIRECTION: - // Select Player Direction for select player screen - spdirection[0] = direction_get_direction_from_argument(filename, command, GET_ARG(1)); - spdirection[1] = direction_get_direction_from_argument(filename, command, GET_ARG(2)); - spdirection[2] = direction_get_direction_from_argument(filename, command, GET_ARG(3)); - spdirection[3] = direction_get_direction_from_argument(filename, command, GET_ARG(4)); - break; - case CMD_MODELSTXT_AUTOLAND: - // New flag to determine if a player auto lands when thrown by another player (2 completely disables the ability to land) - autoland = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_NOLOST: - // this is use for dont lost your weapon if you grab a enemy flag it to 1 to no drop by tails - nolost = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_AJSPECIAL: - - value = GET_ARG(1); - - if (stricmp(value, "special") == 0) - { - tempInt = AJSPECIAL_KEY_SPECIAL; - } - else if (stricmp(value, "double") == 0) - { - tempInt = AJSPECIAL_KEY_DOUBLE; - } - else if (stricmp(value, "attack2") == 0) - { - tempInt = AJSPECIAL_KEY_ATTACK2; - } - else if (stricmp(value, "attack3") == 0) - { - tempInt = AJSPECIAL_KEY_ATTACK3; - } - else if (stricmp(value, "attack4") == 0) - { - tempInt = AJSPECIAL_KEY_ATTACK4; - } - else - { - tempInt = GET_INT_ARG(1); - } - - global_config.ajspecial = tempInt; - - break; - case CMD_MODELSTXT_NOCOST: - // Nocost set in models.txt - nocost = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_NOCHEATS: - - /* Disable access to cheats menu. */ - - if (GET_INT_ARG(1)) - { - global_config.cheats &= ~CHEAT_OPTIONS_MASTER_MENU; - } - - break; - - case CMD_MODELSTXT_NODEBUG: - //disable debug option in menu - nodebugoptions = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_NODROPEN: - nodropen = 1; - break; - case CMD_MODELSTXT_NODROPSPAWN: - nodropspawn = 1; - break; - case CMD_MODELSTXT_KNOW: - // Just add path to cache list - cache_model(GET_ARG(1), GET_ARG(2), 0); - break; - case CMD_MODELSTXT_NOAIRCANCEL: - noaircancel = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_NOMAXRUSHRESET: - nomaxrushreset[4] = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_MPBLOCK: - // Take from MP first? - global_config.block_type = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_BLOCKRATIO: - global_config.block_ratio = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_NOCHIPDEATH: - nochipdeath = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_LIFESCORE: - lifescore = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_CREDSCORE: - // Number of points needed to earn a 1-up - credscore = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_DELAY_UNIT: - delay_mode_error = delay_unit_from_text( - GET_ARG(1), - false, - &global_config.delay_unit - ); - - if(delay_mode_error) { - borShutdown( - 1, - "%s Invalid value '%s' in %s, line %d.\n", - delay_mode_error, - GET_ARG(1), - filename, - line - ); - } - break; - case CMD_MODELSTXT_VERSUSDAMAGE: - // Number of points needed to earn a credit - versusdamage = GET_INT_ARG(1); - if(versusdamage == 0 || versusdamage == 1) - { - savedata.mode = versusdamage ^ 1; - } - break; - case CMD_MODELSTXT_DROPV: - default_model_dropv.y = GET_FLOAT_ARG(1); - default_model_dropv.x = GET_FLOAT_ARG(2); - default_model_dropv.z = GET_FLOAT_ARG(3); - break; - case CMD_MODELSTXT_JUMPSPEED: - default_model_jumpspeed = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_JUMPHEIGHT: - default_model_jumpheight = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_CHEATS: - - lcmHandleCommandGlobalConfigCheats(buf + pos); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_FLASH_LAYER_ADJUST: - global_config.flash.layer_adjust = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_FLASH_LAYER_SOURCE: - global_config.flash.layer_source = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_FLASH_Z_SOURCE: - global_config.flash.z_source = GET_INT_ARG(1); - break; - case CMD_MODELSTXT_GLOBAL_CONFIG_GAME_SPEED: - - tempInt = GET_INT_ARG(1); - if (tempInt < 1) { - printf("\nCommand %s %d in %s, line %d value(%d) out of bounds, using default %d.\n", command, tempInt, filename, line, tempInt, GAME_SPEED_DEFAULT); - tempInt = 1; - } - - global_config.game_speed = tempInt; - break; - case CMD_MODELSTXT_GRABDISTANCE: - default_model_grabdistance = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_MNAF: - move_noatk_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_GNAF: - group_noatk_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_ANAF: - agg_noatk_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_MINNA: - min_noatk_chance = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_MAXNA: - max_noatk_chance = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_OSNAF: - offscreen_noatk_factor = GET_FLOAT_ARG(1); - break; - case CMD_MODELSTXT_DEBUG_NAD: - noatk_duration = GET_FLOAT_ARG(1); - break; - default: - if(cmd >= CMD_MODELSTXT_THE_END) - { - printf("command %s not understood in %s, line %d\n", command, filename, line); - } - break; - } - } - - // Go to next line - pos += getNewLineStart(buf + pos); - } - - // Defer load_cached_model, so you can define models after their nested model. - printf("\n"); - - for(i = 0, pos = 0; i < models_cached; i++) - { - //printf("Checking '%s' '%s'\n", model_cache[i].name, model_cache[i].path); - if(stricmp(model_cache[i].name, "global_model") == 0) - { - global_model = i; - } - if(model_cache[i].loadflag) - { - load_cached_model(model_cache[i].name, "models.txt", 0); - update_loading(&loadingbg[0], ++pos, modelLoadCount); - } - } - printf("\nLoading models...............\tDone!\n"); - - - if(buf) - { - free(buf); - } - - return 1; -} - - - - -void unload_levelorder() -{ - int i, j, t; - s_level_entry *le; - s_set_entry *se; - - if(levelsets) - { - for(i = 0; i < num_difficulties; i++) - { - se = levelsets + i; - if(se->name) - { - free(se->name); - } - if(se->numlevels) - { - for(j = 0; j < se->numlevels; j++) - { - le = se->levelorder + j; - if(le->branchname) - { - free(le->branchname); - } - if(le->filename) - { - free(le->filename); - } - //if(le->skipselect) - //{ - for(t = 0; t < MAX_PLAYERS; t++) - { - if(le->skipselect[t]) - { - free(le->skipselect[t]); - } - } - //} - } - free(se->levelorder); - } - } - - free(levelsets); - levelsets = NULL; - } - - num_difficulties = 0; -} - - - -// Add a level to the level order -s_level_entry *add_level(char *filename, s_set_entry *set) -{ - s_level_entry *le = NULL; - int Zs[3] = {0, 0, 0}; - - if(z_coords[0] > 0) - { - Zs[0] = z_coords[0]; - } - else - { - Zs[0] = PLAYER_MIN_Z; - } - - if(z_coords[1] > 0) - { - Zs[1] = z_coords[1]; - } - else - { - Zs[1] = PLAYER_MAX_Z; - } - - if(z_coords[2] > 0) - { - Zs[2] = z_coords[2]; - } - else - { - Zs[2] = PLAYER_MIN_Z; - } - - set->levelorder = realloc(set->levelorder, (++set->numlevels) * sizeof(*set->levelorder)); - le = set->levelorder + set->numlevels - 1; - memset(le, 0, sizeof(*le)); - if(branch_name[0]) - { - le->branchname = NAME(branch_name); - } - le->filename = NAME(filename); - le->z_coords[0] = Zs[0]; - le->z_coords[1] = Zs[1]; - le->z_coords[2] = Zs[2]; - - return le; -} - - - -// Add a scene to the level order -s_level_entry *add_scene(char *filename, s_set_entry *set) -{ - s_level_entry *le = NULL; - - set->levelorder = realloc(set->levelorder, (++set->numlevels) * sizeof(*set->levelorder)); - le = set->levelorder + set->numlevels - 1; - memset(le, 0, sizeof(*le)); - if(branch_name[0]) - { - le->branchname = NAME(branch_name); - } - le->filename = NAME(filename); - le->type = LE_TYPE_CUT_SCENE; - return le; -} - -// Add a select screen file to the level order -s_level_entry *add_select(char *filename, s_set_entry *set) -{ - s_level_entry *le = NULL; - - set->levelorder = realloc(set->levelorder, (++set->numlevels) * sizeof(*set->levelorder)); - le = set->levelorder + set->numlevels - 1; - memset(le, 0, sizeof(*le)); - if(branch_name[0]) - { - le->branchname = NAME(branch_name); - } - le->filename = NAME(filename); - le->type = LE_TYPE_SELECT_SCREEN; - return le; -} - -s_level_entry *add_skipselect(ArgList arglist, s_set_entry *set) -{ - s_level_entry *le = NULL; - char *arg; - int i = 0; - - set->levelorder = realloc(set->levelorder, (++set->numlevels) * sizeof(*set->levelorder)); - le = set->levelorder + set->numlevels - 1; - memset(le, 0, sizeof(*le)); - if(branch_name[0]) - { - le->branchname = NAME(branch_name); - } - - if(arglist.count == 1) - { - le->noselect = 1; - } - else - { - for(i = 0; i < MAX_PLAYERS; i++) - { - if((arg = GET_ARG(i + 1))[0]) - { - le->skipselect[i] = NAME(arg); - } - } - } - - le->type = LE_TYPE_SKIP_SELECT; - return le; -} - -s_level_entry *load_skipselect(char *buf, s_set_entry *set) -{ - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1]; - - ParseArgs(&arglist, buf, argbuf); - - return add_skipselect(arglist, set); -} - -void save_skipselect(char *buf, char skipselect[MAX_PLAYERS][MAX_NAME_LEN]) -{ - int i = 0; - - strcpy(buf,"skipselect"); - - for (i = 0; i < MAX_PLAYERS; i++) - { - strcat(buf," "); strcat(buf,skipselect[i]); - } - - return; -} - -static void _readbarstatus(char *buf, s_barstatus *pstatus) -{ - char *value; - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - - ParseArgs(&arglist, buf, argbuf); - if((value = GET_ARG(1))[0]) - { - pstatus->size.x = atoi(value); - } - else - { - return; - } - if((value = GET_ARG(2))[0]) - { - pstatus->size.y = atoi(value); - } - else - { - return; - } - if((value = GET_ARG(3))[0]) - { - if (atoi(value)) - { - pstatus->config_flags |= STATUS_CONFIG_BORDER_DISABLE; - } - } - else - { - return; - } - if((value = GET_ARG(4))[0]) - { - if (atoi(value)) - { - pstatus->config_flags |= STATUS_CONFIG_GRAPH_RATIO; - } - } - else - { - return; - } - if((value = GET_ARG(5))[0]) - { - if (atoi(value)) - { - pstatus->config_flags |= STATUS_CONFIG_GRAPH_VERTICAL; - } - } - else - { - return; - } - if((value = GET_ARG(6))[0]) - { - pstatus->borderlayer = atoi(value); - } - else - { - return; - } - if((value = GET_ARG(7))[0]) - { - pstatus->shadowlayer = atoi(value); - } - else - { - return; - } - if((value = GET_ARG(8))[0]) - { - pstatus->barlayer = atoi(value); - } - else - { - return; - } - if((value = GET_ARG(9))[0]) - { - pstatus->backlayer = atoi(value); - } - else - { - return; - } -} - -s_set_entry *add_set() -{ - s_set_entry *set = NULL; - ++num_difficulties; - if(levelsets) - { - levelsets = realloc(levelsets, sizeof(*levelsets) * num_difficulties); - } - else - { - levelsets = calloc(1, sizeof(*levelsets)); - } - set = levelsets + num_difficulties - 1; - memset(set, 0, sizeof(*set)); - set->maxplayers = defaultmaxplayers; - return set; -} - -// Load list of levels -void load_levelorder() -{ - const char *defaulterr = "Error in level order: a set must be specified."; -#define CHKDEF if(!set) { errormessage = (char*) defaulterr; goto lCleanup; } - char filename[MAX_BUFFER_LEN] = ""; - int i = 0, j = 0, err = 0; - char *buf; - size_t size; - int pos; - s_set_entry *set = NULL; - s_level_entry *le = NULL; - char *command; - char *arg; - char *errormessage = NULL; - int plifeUsed[2] = {0, 0}; - int elifeUsed[2] = {0, 0}; - int piconUsed[2] = {0, 0}; - int piconwUsed[2] = {0, 0}; - int eiconUsed[4] = {0, 0, 0, 0}; - int pmpUsed[4] = {0, 0, 0, 0}; - int plifeXused[4] = {0, 0, 0, 0}; // 4-7-2006 New custimizable variable for players 'x' - int plifeNused[4] = {0, 0, 0, 0}; // 4-7-2006 New custimizable variable for players 'lives' - int enameused[4] = {0, 0, 0, 0}; // 4-7-2006 New custimizable variable for enemy names - int pnameJused[4] = {0, 0, 0, 0}; // 1-8-2006 New custimizable variable for players name Select Hero - int pscoreUsed[4] = {0, 0, 0, 0}; // 1-8-2006 New custimizable variable for players name Select Hero - - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - levelOrderCommands cmd; - int line = 0; - - unload_levelorder(); - - if(custLevels != NULL) - { - strcpy(filename, "data/"); - strcat(filename, custLevels); - } - else - { - strcpy(filename, "data/levels.txt"); - } - - // Read file - - if(buffer_pakfile(filename, &buf, &size) != 1) - { - borShutdown(1, "Error loading level list from %s", filename); - } - - // Now interpret the contents of buf line by line - pos = 0; - - // Custom lifebar/timebox/icon positioning and size - picon[0][0] = piconw[0][0] = picon[2][0] = piconw[2][0] = eicon[0][0] = eicon[2][0] = 2; - picon[1][0] = piconw[1][0] = picon[3][0] = piconw[3][0] = eicon[1][0] = eicon[3][0] = 2 + P2_STATS_DIST; - picon[0][1] = piconw[0][1] = picon[1][1] = piconw[1][1] = 2; - picon[2][1] = piconw[2][1] = picon[3][1] = piconw[3][1] = 202; - plife[0][0] = pmp[0][0] = plife[2][0] = pmp[2][0] = elife[0][0] = elife[2][0] = 20; - plife[1][0] = pmp[1][0] = plife[3][0] = pmp[3][0] = elife[1][0] = elife[3][0] = 20 + P2_STATS_DIST; - plife[0][1] = plife[1][1] = 10; - plife[2][1] = plife[3][1] = 210; - pmp[0][1] = pmp[1][1] = 18; - pmp[2][1] = pmp[3][1] = 218; - - memset(psmenu, 0, sizeof(psmenu)); - - eicon[0][1] = eicon[1][1] = 19; - eicon[2][1] = eicon[3][1] = 220; - elife[0][1] = elife[1][1] = 27; - elife[2][1] = elife[3][1] = 227; - - timeloc[0] = 149; - timeloc[1] = 4; - timeloc[2] = 21; - timeloc[3] = 20; - timeloc[4] = 0; - - lbarstatus.size.x = mpbarstatus.size.x = 100; - lbarstatus.size.y = 5; - mpbarstatus.size.y = 3; - lbarstatus.config_flags = STATUS_CONFIG_DEFAULT; - mpbarstatus.config_flags = STATUS_CONFIG_DEFAULT; - - // Show Complete Default Values - scomplete[0] = 75; - scomplete[1] = 60; - scomplete[2] = 0; - scomplete[3] = 0; - scomplete[4] = 0; - scomplete[5] = 0; - - // Show Complete Y Values - cbonus[0] = lbonus[0] = rbonus[0] = tscore[0] = 10; - cbonus[1] = cbonus[3] = cbonus[5] = cbonus[7] = cbonus[9] = 100; - lbonus[1] = lbonus[3] = lbonus[5] = lbonus[7] = lbonus[9] = 120; - rbonus[1] = rbonus[3] = rbonus[5] = rbonus[7] = rbonus[9] = 140; - tscore[1] = tscore[3] = tscore[5] = tscore[7] = tscore[9] = 160; - - // Show Complete X Values - cbonus[2] = lbonus[2] = rbonus[2] = tscore[2] = 100; - cbonus[4] = lbonus[4] = rbonus[4] = tscore[4] = 155; - cbonus[6] = lbonus[6] = rbonus[6] = tscore[6] = 210; - cbonus[8] = lbonus[8] = rbonus[8] = tscore[8] = 265; - - while(pos < size) - { - line++; - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - cmd = getLevelOrderCommand(levelordercmdlist, command); - switch(cmd) - { - case CMD_LEVELORDER_BLENDFX: - for(i = 0; i < MAX_BLENDINGS; i++) - { - if(GET_INT_ARG(i + 1)) - { - blendfx[i] = 1; - } - else - { - blendfx[i] = 0; - } - } - blendfx_is_set = 1; - break; - case CMD_LEVELORDER_SET: - set = add_set(); - set->name = NAME(GET_ARG(1)); - set->ifcomplete = 0; - set->saveflag = 1; // default to 1, so the level can be saved - branch_name[0] = 0; - le = NULL; - break; - case CMD_LEVELORDER_IFCOMPLETE: - CHKDEF; - set->ifcomplete = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_SKIPSELECT: - CHKDEF; - le = add_skipselect(arglist, set); - break; - case CMD_LEVELORDER_FILE: - CHKDEF; - le = add_level(GET_ARG(1), set); - break; - case CMD_LEVELORDER_SCENE: - CHKDEF; - le = add_scene(GET_ARG(1), set); - break; - case CMD_LEVELORDER_SELECT: - CHKDEF; - le = add_select(GET_ARG(1), set); - break; - case CMD_LEVELORDER_NEXT: - CHKDEF; - // Set 'gonext' flag of last loaded level - if(le) - { - le->gonext = 1; - } - break; - case CMD_LEVELORDER_END: - CHKDEF; - // Set endgame flag of last loaded level - if(le) - { - le->gonext = 2; - } - break; - case CMD_LEVELORDER_LIVES: - // 7-1-2005 credits/lives/singleplayer start here - // used to read the new # of lives/credits from the levels.txt - CHKDEF; - set->lives = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_DISABLEHOF: - CHKDEF; - set->noshowhof = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_DISABLEGAMEOVER: - CHKDEF; - set->noshowgameover = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_CANSAVE: - // 07-12-31 - // 0 this set can't be saved - // 1 save level only - // 2 save player info and level, can't choose player in select menu - CHKDEF; - set->saveflag = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_Z: - // 2-10-05 adjust the walkable coordinates - CHKDEF; - z_coords[0] = GET_INT_ARG(1); - z_coords[1] = GET_INT_ARG(2); - z_coords[2] = GET_INT_ARG(3); - break; - case CMD_LEVELORDER_BRANCH: - // 2007-2-22 level branch name - CHKDEF; - strncpy(branch_name, GET_ARG(1), MAX_NAME_LEN); - break; - case CMD_LEVELORDER_P1LIFE: - case CMD_LEVELORDER_P2LIFE: - case CMD_LEVELORDER_P3LIFE: - case CMD_LEVELORDER_P4LIFE: - switch(cmd) - { - case CMD_LEVELORDER_P1LIFE: - i = 0; - break; - case CMD_LEVELORDER_P2LIFE: - i = 1; - break; - case CMD_LEVELORDER_P3LIFE: - i = 2; - plifeUsed[0] = 1; - break; - case CMD_LEVELORDER_P4LIFE: - i = 3; - plifeUsed[1] = 1; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - plife[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - plife[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_P1MP: - case CMD_LEVELORDER_P2MP: - case CMD_LEVELORDER_P3MP: - case CMD_LEVELORDER_P4MP: - switch(cmd) - { - case CMD_LEVELORDER_P1MP: - i = 0; - break; - case CMD_LEVELORDER_P2MP: - i = 1; - break; - case CMD_LEVELORDER_P3MP: - i = 2; - break; - case CMD_LEVELORDER_P4MP: - i = 3; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - pmp[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - pmp[i][1] = atoi(arg); - } - pmpUsed[i] = 1; - break; - case CMD_LEVELORDER_P1LIFEX: - case CMD_LEVELORDER_P2LIFEX: - case CMD_LEVELORDER_P3LIFEX: - case CMD_LEVELORDER_P4LIFEX: - switch(cmd) - { - case CMD_LEVELORDER_P1LIFEX: - j = 0; - break; - case CMD_LEVELORDER_P2LIFEX: - j = 1; - break; - case CMD_LEVELORDER_P3LIFEX: - j = 2; - break; - case CMD_LEVELORDER_P4LIFEX: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 3; i++) - if((arg = GET_ARG(i + 1))[0]) - { - plifeX[j][i] = atoi(arg); - } - plifeXused[j] = 1; - break; - case CMD_LEVELORDER_P1LIFEN: - case CMD_LEVELORDER_P2LIFEN: - case CMD_LEVELORDER_P3LIFEN: - case CMD_LEVELORDER_P4LIFEN: - switch(cmd) - { - case CMD_LEVELORDER_P1LIFEN: - j = 0; - break; - case CMD_LEVELORDER_P2LIFEN: - j = 1; - break; - case CMD_LEVELORDER_P3LIFEN: - j = 2; - break; - case CMD_LEVELORDER_P4LIFEN: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 3; i++) - if((arg = GET_ARG(i + 1))[0]) - { - plifeN[j][i] = atoi(arg); - } - plifeNused[j] = 1; - break; - case CMD_LEVELORDER_E1LIFE: - case CMD_LEVELORDER_E2LIFE: - case CMD_LEVELORDER_E3LIFE: - case CMD_LEVELORDER_E4LIFE: - switch(cmd) - { - case CMD_LEVELORDER_E1LIFE: - i = 0; - break; - case CMD_LEVELORDER_E2LIFE: - i = 1; - break; - case CMD_LEVELORDER_E3LIFE: - i = 2; - elifeUsed[0] = 1; - break; - case CMD_LEVELORDER_E4LIFE: - i = 3; - elifeUsed[1] = 1; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - elife[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - elife[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_P1ICON: - case CMD_LEVELORDER_P2ICON: - case CMD_LEVELORDER_P3ICON: - case CMD_LEVELORDER_P4ICON: - switch(cmd) - { - case CMD_LEVELORDER_P1ICON: - i = 0; - break; - case CMD_LEVELORDER_P2ICON: - i = 1; - break; - case CMD_LEVELORDER_P3ICON: - i = 2; - piconUsed[0] = 1; - break; - case CMD_LEVELORDER_P4ICON: - i = 3; - piconUsed[1] = 1; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - picon[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - picon[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_P1ICONW: - case CMD_LEVELORDER_P2ICONW: - case CMD_LEVELORDER_P3ICONW: - case CMD_LEVELORDER_P4ICONW: - switch(cmd) - { - case CMD_LEVELORDER_P1ICONW: - i = 0; - break; - case CMD_LEVELORDER_P2ICONW: - i = 1; - break; - case CMD_LEVELORDER_P3ICONW: - i = 2; - piconwUsed[0] = 1; - break; - case CMD_LEVELORDER_P4ICONW: - i = 3; - piconwUsed[1] = 1; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - piconw[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - piconw[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_MP1ICON: - case CMD_LEVELORDER_MP2ICON: - case CMD_LEVELORDER_MP3ICON: - case CMD_LEVELORDER_MP4ICON: - switch(cmd) - { - case CMD_LEVELORDER_MP1ICON: - i = 0; - break; - case CMD_LEVELORDER_MP2ICON: - i = 1; - break; - case CMD_LEVELORDER_MP3ICON: - i = 2; - break; - case CMD_LEVELORDER_MP4ICON: - i = 3; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - mpicon[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - mpicon[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_P1NAMEJ: - case CMD_LEVELORDER_P2NAMEJ: - case CMD_LEVELORDER_P3NAMEJ: - case CMD_LEVELORDER_P4NAMEJ: - switch(cmd) - { - case CMD_LEVELORDER_P1NAMEJ: - j = 0; - break; - case CMD_LEVELORDER_P2NAMEJ: - j = 1; - break; - case CMD_LEVELORDER_P3NAMEJ: - j = 2; - break; - case CMD_LEVELORDER_P4NAMEJ: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 7; i++) - if((arg = GET_ARG(i + 1))[0]) - { - pnameJ[j][i] = atoi(arg); - } - pnameJused[j] = 1; - break; - case CMD_LEVELORDER_P1SCORE: - case CMD_LEVELORDER_P2SCORE: - case CMD_LEVELORDER_P3SCORE: - case CMD_LEVELORDER_P4SCORE: - switch(cmd) - { - case CMD_LEVELORDER_P1SCORE: - j = 0; - break; - case CMD_LEVELORDER_P2SCORE: - j = 1; - break; - case CMD_LEVELORDER_P3SCORE: - j = 2; - break; - case CMD_LEVELORDER_P4SCORE: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 7; i++) - if((arg = GET_ARG(i + 1))[0]) - { - pscore[j][i] = atoi(arg); - } - pscoreUsed[j] = 1; - break; - case CMD_LEVELORDER_P1SHOOT: - case CMD_LEVELORDER_P2SHOOT: - case CMD_LEVELORDER_P3SHOOT: - case CMD_LEVELORDER_P4SHOOT: - switch(cmd) - { - case CMD_LEVELORDER_P1SHOOT: - j = 0; - break; - case CMD_LEVELORDER_P2SHOOT: - j = 1; - break; - case CMD_LEVELORDER_P3SHOOT: - j = 2; - break; - case CMD_LEVELORDER_P4SHOOT: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 3; i++) - if((arg = GET_ARG(i + 1))[0]) - { - pshoot[j][i] = atoi(arg); - } - break; - case CMD_LEVELORDER_P1RUSH: - case CMD_LEVELORDER_P2RUSH: - case CMD_LEVELORDER_P3RUSH: - case CMD_LEVELORDER_P4RUSH: - switch(cmd) - { - case CMD_LEVELORDER_P1RUSH: - j = 0; - break; - case CMD_LEVELORDER_P2RUSH: - j = 1; - break; - case CMD_LEVELORDER_P3RUSH: - j = 2; - break; - case CMD_LEVELORDER_P4RUSH: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 8; i++) - if((arg = GET_ARG(i + 1))[0]) - { - prush[j][i] = atoi(arg); - } - break; - case CMD_LEVELORDER_E1ICON: - case CMD_LEVELORDER_E2ICON: - case CMD_LEVELORDER_E3ICON: - case CMD_LEVELORDER_E4ICON: - switch(cmd) - { - case CMD_LEVELORDER_E1ICON: - i = 0; - break; - case CMD_LEVELORDER_E2ICON: - i = 1; - break; - case CMD_LEVELORDER_E3ICON: - i = 2; - eiconUsed[0] = 1; - break; - case CMD_LEVELORDER_E4ICON: - i = 3; - eiconUsed[1] = 1; - break; - default: - assert(0); - } - if((arg = GET_ARG(1))[0]) - { - eicon[i][0] = atoi(arg); - } - if((arg = GET_ARG(2))[0]) - { - eicon[i][1] = atoi(arg); - } - break; - case CMD_LEVELORDER_E1NAME: - case CMD_LEVELORDER_E2NAME: - case CMD_LEVELORDER_E3NAME: - case CMD_LEVELORDER_E4NAME: - switch(cmd) - { - case CMD_LEVELORDER_E1NAME: - j = 0; - break; - case CMD_LEVELORDER_E2NAME: - j = 1; - break; - case CMD_LEVELORDER_E3NAME: - j = 2; - break; - case CMD_LEVELORDER_E4NAME: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < 3; i++) - if((arg = GET_ARG(i + 1))[0]) - { - ename[j][i] = atoi(arg); - } - enameused[j] = 1; - break; - case CMD_LEVELORDER_P1SMENU: - case CMD_LEVELORDER_P2SMENU: - case CMD_LEVELORDER_P3SMENU: - case CMD_LEVELORDER_P4SMENU: - switch(cmd) - { - case CMD_LEVELORDER_P1SMENU: - j = 0; - break; - case CMD_LEVELORDER_P2SMENU: - j = 1; - break; - case CMD_LEVELORDER_P3SMENU: - j = 2; - break; - case CMD_LEVELORDER_P4SMENU: - j = 3; - break; - default: - assert(0); - } - for(i = 0; i < MAX_PLAYERS; i++) - if((arg = GET_ARG(i + 1))[0]) - { - psmenu[j][i] = atoi(arg); - } - break; - case CMD_LEVELORDER_TIMEICON: - strncpy(timeicon_path, GET_ARG(1), 127); - timeicon = loadsprite(timeicon_path, 0, 0, pixelformat); - if((arg = GET_ARG(2))[0]) - { - timeicon_offsets[0] = atoi(arg); - } - if((arg = GET_ARG(3))[0]) - { - timeicon_offsets[1] = atoi(arg); - } - break; - case CMD_LEVELORDER_BGICON: - strncpy(bgicon_path, GET_ARG(1), 127); - bgicon = loadsprite(bgicon_path, 0, 0, pixelformat); - if((arg = GET_ARG(2))[0]) - { - bgicon_offsets[0] = atoi(arg); - } - if((arg = GET_ARG(3))[0]) - { - bgicon_offsets[1] = atoi(arg); - } - if((arg = GET_ARG(4))[0]) - { - bgicon_offsets[2] = atoi(arg); - } - else - { - bgicon_offsets[2] = HUD_Z / 2; - } - break; - case CMD_LEVELORDER_OLICON: - strncpy(olicon_path, GET_ARG(1), 127); - olicon = loadsprite(olicon_path, 0, 0, pixelformat); - if((arg = GET_ARG(2))[0]) - { - olicon_offsets[0] = atoi(arg); - } - if((arg = GET_ARG(3))[0]) - { - olicon_offsets[1] = atoi(arg); - } - if((arg = GET_ARG(4))[0]) - { - olicon_offsets[2] = atoi(arg); - } - else - { - olicon_offsets[2] = HUD_Z * 3; - } - break; - case CMD_LEVELORDER_TIMELOC: - for(i = 0; i < 6; i++) - if((arg = GET_ARG(i + 1))[0]) - { - timeloc[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_PAUSEOFFSET: - for(i = 0; i < 7; i++) - if((arg = GET_ARG(i + 1))[0]) - { - pauseoffset[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_LBARSIZE: - _readbarstatus(buf + pos, &lbarstatus); - break; - case CMD_LEVELORDER_OLBARSIZE: - _readbarstatus(buf + pos, &olbarstatus); - break; - case CMD_LEVELORDER_MPBARSIZE: - _readbarstatus(buf + pos, &mpbarstatus); - break; - case CMD_LEVELORDER_LBARTEXT: - for(i = 0; i < 4; i++) - if((arg = GET_ARG(i + 1))[0]) - { - lbartext[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_MPBARTEXT: - for(i = 0; i < 4; i++) - if((arg = GET_ARG(i + 1))[0]) - { - mpbartext[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_SHOWCOMPLETE: - for(i = 0; i < 6; i++) - if((arg = GET_ARG(i + 1))[0]) - { - scomplete[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_CLEARBONUS: - for(i = 0; i < 10; i++) - if((arg = GET_ARG(i + 1))[0]) - { - cbonus[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_RUSHBONUS: - for(i = 0; i < 10; i++) - if((arg = GET_ARG(i + 1))[0]) - { - rbonus[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_LIFEBONUS: - for(i = 0; i < 10; i++) - if((arg = GET_ARG(i + 1))[0]) - { - lbonus[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_SCBONUSES: - for(i = 0; i < 4; i++) - if((arg = GET_ARG(i + 1))[0]) - { - scbonuses[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_TOTALSCORE: - for(i = 0; i < 10; i++) - if((arg = GET_ARG(i + 1))[0]) - { - tscore[i] = atoi(arg); - } - break; - case CMD_LEVELORDER_MUSICOVERLAP: - CHKDEF; - set->musicoverlap = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_SHOWRUSHBONUS: - showrushbonus = 1; - break; - case CMD_LEVELORDER_NOSLOWFX: - noslowfx = 1; - break; - case CMD_LEVELORDER_EQUALAIRPAUSE: - equalairpause = 1; - break; - case CMD_LEVELORDER_HISCOREBG: - hiscorebg = 1; - break; - case CMD_LEVELORDER_COMPLETEBG: - completebg = 1; - break; - case CMD_LEVELORDER_LOADINGBG: - errormessage = fill_s_loadingbar(&loadingbg[0], GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3), GET_INT_ARG(4), GET_INT_ARG(5), GET_INT_ARG(6), GET_INT_ARG(7), GET_INT_ARG(8)); - if(errormessage) - { - goto lCleanup; - } - break; - case CMD_LEVELORDER_LOADINGBG2: - errormessage = fill_s_loadingbar(&loadingbg[1], GET_INT_ARG(1), GET_INT_ARG(2), GET_INT_ARG(3), GET_INT_ARG(4), GET_INT_ARG(5), GET_INT_ARG(6), GET_INT_ARG(7), GET_INT_ARG(8)); - if(errormessage) - { - goto lCleanup; - } - break; - case CMD_LEVELORDER_LOADINGMUSIC: - loadingmusic = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_UNLOCKBG: - unlockbg = 1; - break; - case CMD_LEVELORDER_NOSHARE: - noshare = 1; - break; - case CMD_LEVELORDER_CUSTFADE: - //8-2-2005 custom fade - CHKDEF; - set->custfade = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_CONTINUESCORE: - //8-2-2005 custom fade end - //continuescore - CHKDEF; - set->continuescore = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_CREDITS: - CHKDEF; - set->credits = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_TYPEMP: - //typemp for change for mp restored by time (0) to by enemys (1) or no restore (2) by tails - CHKDEF; - set->typemp = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_SINGLE: - if(set) - { - set->maxplayers = 1; - } - else - { - defaultmaxplayers = 1; - } - break; - case CMD_LEVELORDER_MAXPLAYERS: - if(set) - { - set->maxplayers = GET_INT_ARG(1); - } - else - { - defaultmaxplayers = GET_INT_ARG(1); - } - break; - case CMD_LEVELORDER_NOSAME: - CHKDEF; - set->nosame |= GET_INT_ARG(1) != 0; - set->nosame |= GET_INT_ARG(2) != 0 ? 2 : 0; - break; - case CMD_LEVELORDER_RUSH: - rush[0] = GET_INT_ARG(1); - rush[1] = GET_INT_ARG(2); - strncpy(rush_names[0], GET_ARG(3), MAX_NAME_LEN - 1); - rush[2] = GET_INT_ARG(4); - rush[3] = GET_INT_ARG(5); - strncpy(rush_names[1], GET_ARG(6), MAX_NAME_LEN - 1); - rush[4] = GET_INT_ARG(7); - rush[5] = GET_INT_ARG(8); - break; - case CMD_LEVELORDER_MAXWALLHEIGHT: - MAX_WALL_HEIGHT = GET_INT_ARG(1); - if(MAX_WALL_HEIGHT < 0) - { - MAX_WALL_HEIGHT = 1000; - } - break; - case CMD_LEVELORDER_SCOREFORMAT: - scoreformat = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_GRAVITY: - default_level_gravity = GET_FLOAT_ARG(1); - default_level_maxfallspeed = GET_FLOAT_ARG(2); - default_level_maxtossspeed = GET_FLOAT_ARG(3); - break; - case CMD_LEVELORDER_SKIPTOSET: - skiptoset = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_NOSHOWCOMPLETE: - CHKDEF; - set->noshowcomplete = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_SPAWNOVERRIDE: - spawnoverride = GET_INT_ARG(1); - break; - case CMD_LEVELORDER_MAXENTITIES: - maxentities = GET_INT_ARG(1); - break; - default: - if (command && command[0]) - { - if (err <= 0) printf("\n"); - ++err; - printf("Command '%s' not understood in level order!\n", command); - } - } - - // Go to next line - pos += getNewLineStart(buf + pos); - } - -#undef CHKDEF - - // Variables without defaults will be auto populated. - if(olbarstatus.size.x == 0) - { - olbarstatus = lbarstatus; - } - - if(!plifeUsed[0]) - { - plife[2][0] = plife[0][0]; - plife[2][1] = plife[2][1] + (plife[0][1] - 10); - } - if(!plifeUsed[1]) - { - plife[3][0] = plife[1][0]; - plife[3][1] = plife[3][1] + (plife[1][1] - 10); - } - - if(!elifeUsed[0]) - { - elife[2][0] = elife[0][0]; - elife[2][1] = elife[2][1] + (elife[0][1] - 27); - } - if(!elifeUsed[1]) - { - elife[3][0] = elife[1][0]; - elife[3][1] = elife[3][1] + (elife[1][1] - 27); - } - - if(!piconUsed[0]) - { - picon[2][0] = picon[0][0]; - picon[2][1] = picon[2][1] + (picon[0][1] - 2); - } - if(!piconUsed[1]) - { - picon[3][0] = picon[1][0]; - picon[3][1] = picon[3][1] + (picon[1][1] - 2); - } - - if(!piconwUsed[0]) - { - piconw[2][0] = piconw[0][0]; - piconw[2][1] = piconw[2][1] + (piconw[0][1] - 2); - } - if(!piconwUsed[1]) - { - piconw[3][0] = piconw[1][0]; - piconw[3][1] = piconw[3][1] + (piconw[1][1] - 2); - } - - if(!eiconUsed[0]) - { - eicon[2][0] = eicon[0][0]; - eicon[2][1] = eicon[2][1] + (eicon[0][1] - 19); - } - if(!eiconUsed[1]) - { - eicon[3][0] = eicon[1][0]; - eicon[3][1] = eicon[3][1] + (eicon[1][1] - 19); - } - - if(!pmpUsed[0]) - { - pmp[0][0] = plife[0][0]; - pmp[0][1] = plife[0][1] + 8; - } - if(!pmpUsed[1]) - { - pmp[1][0] = plife[1][0]; - pmp[1][1] = plife[1][1] + 8; - } - if(!pmpUsed[2]) - { - pmp[2][0] = pmp[0][0]; - pmp[2][1] = pmp[2][1] + (pmp[0][1] - 18); - } - if(!pmpUsed[3]) - { - pmp[3][0] = pmp[1][0]; - pmp[3][1] = pmp[1][1] + (pmp[1][1] - 18); - } - - if(!plifeXused[0]) - { - plifeX[0][0] = plife[0][0] + lbarstatus.size.x + 4; - plifeX[0][1] = picon[0][1] + 7; - } - if(!plifeXused[1]) - { - plifeX[1][0] = plife[1][0] + lbarstatus.size.x + 4; - plifeX[1][1] = picon[1][1] + 7; - } - if(!plifeXused[2]) - { - plifeX[2][0] = plife[2][0] + lbarstatus.size.x + 4; - plifeX[2][1] = picon[2][1] + 7; - } - if(!plifeXused[3]) - { - plifeX[3][0] = plife[3][0] + lbarstatus.size.x + 4; - plifeX[3][1] = picon[3][1] + 7; - } - for(i = 0; i < MAX_PLAYERS; i++) if(plifeX[i][2] == -1) - { - plifeX[i][2] = 0; - } - - if(!plifeNused[0]) - { - plifeN[0][0] = plife[0][0] + lbarstatus.size.x + 11; - plifeN[0][1] = picon[0][1]; - } - if(!plifeNused[1]) - { - plifeN[1][0] = plife[1][0] + lbarstatus.size.x + 11; - plifeN[1][1] = picon[1][1]; - } - if(!plifeNused[2]) - { - plifeN[2][0] = plifeN[0][0]; - plifeN[2][1] = picon[2][1]; - } - if(!plifeNused[3]) - { - plifeN[3][0] = plifeN[1][0]; - plifeN[3][1] = picon[3][1]; - } - for(i = 0; i < MAX_PLAYERS; i++) if(plifeN[i][2] == -1) - { - plifeN[i][2] = 3; - } - - if(!pnameJused[0]) - { - pnameJ[0][2] = pnameJ[0][4] = pnameJ[0][0] = plife[0][0] + 1; - pnameJ[0][5] = pnameJ[0][1] = picon[0][1]; - pnameJ[0][3] = 10 + pnameJ[0][5]; - } - if(!pnameJused[1]) - { - pnameJ[1][2] = pnameJ[1][4] = pnameJ[1][0] = plife[1][0] + 1; - pnameJ[1][5] = pnameJ[1][1] = picon[1][1]; - pnameJ[1][3] = 10 + pnameJ[1][5]; - } - if(!pnameJused[2]) - { - pnameJ[2][2] = pnameJ[2][4] = pnameJ[2][0] = plife[2][0] + 1; - pnameJ[2][5] = pnameJ[2][1] = picon[2][1]; - pnameJ[2][3] = 10 + pnameJ[2][5]; - } - if(!pnameJused[3]) - { - pnameJ[3][2] = pnameJ[3][4] = pnameJ[3][0] = plife[3][0] + 1; - pnameJ[3][5] = pnameJ[3][1] = picon[3][1]; - pnameJ[3][3] = 10 + pnameJ[3][5]; - } - for(i = 0; i < MAX_PLAYERS; i++) if(pnameJ[i][6] == -1) - { - pnameJ[i][6] = 0; - } - - if(!pscoreUsed[0]) - { - pscore[0][0] = plife[0][0] + 1; - pscore[0][1] = picon[0][1]; - } - if(!pscoreUsed[1]) - { - pscore[1][0] = plife[1][0] + 1; - pscore[1][1] = picon[1][1]; - } - if(!pscoreUsed[2]) - { - pscore[2][0] = plife[2][0] + 1; - pscore[2][1] = picon[2][1]; - } - if(!pscoreUsed[3]) - { - pscore[3][0] = plife[3][0] + 1; - pscore[3][1] = picon[3][1]; - } - for(i = 0; i < MAX_PLAYERS; i++) if(pscore[i][6] == -1) - { - pscore[i][6] = 0; - } - - if(!enameused[0]) - { - ename[0][0] = elife[0][0] + 1; - ename[0][1] = eicon[0][1]; - } - if(!enameused[1]) - { - ename[1][0] = elife[1][0] + 1; - ename[1][1] = eicon[1][1]; - } - if(!enameused[2]) - { - ename[2][0] = ename[0][0]; - ename[2][1] = eicon[2][1]; - } - if(!enameused[3]) - { - ename[3][0] = ename[1][0]; - ename[3][1] = eicon[3][1]; - } - for(i = 0; i < MAX_PLAYERS; i++) if(ename[i][2] == -1) - { - ename[i][2] = 0; - } - - branch_name[0] = 0; //clear up branch name, so we can use it in game - - for(i = 0; i < MAX_PLAYERS; i++) if(pshoot[i][2] == -1) - { - pshoot[i][2] = 2; - } - if(timeloc[5] == -1) - { - timeloc[5] = 3; - } - - if(!set) - { - errormessage = "No levels were loaded!"; - } - - //assume old mods have same maxplayers for all sets - else if(!psmenu[0][0] && !psmenu[0][1]) - { - for(i = 0; i < set->maxplayers; i++) - { - psmenu[i][0] = (set->maxplayers > 2) ? ((111 - (set->maxplayers * 14)) + ((i * (320 - (166 / set->maxplayers)) / set->maxplayers) + videomodes.hShift)) : - (83 + (videomodes.hShift / 2) + (i * (155 + videomodes.hShift))); - psmenu[i][1] = 230 + videomodes.vShift; - psmenu[i][2] = (set->maxplayers > 2) ? ((95 - (set->maxplayers * 14)) + ((i * (320 - (166 / set->maxplayers)) / set->maxplayers) + videomodes.hShift)) : - (67 + (videomodes.hShift / 2) + (i * (155 + videomodes.hShift))); - psmenu[i][3] = 225 + videomodes.vShift; - } - } - -lCleanup: - - if(buf) - { - free(buf); - } - - if(!savelevel || savelevel_count != (size_t)num_difficulties) - { - clear_saved_allowselect_arguments(); - free(savelevel_allowselect_args); - free(savelevel); - - savelevel_count = (size_t)num_difficulties; - savelevel = calloc(savelevel_count, sizeof(*savelevel)); - savelevel_allowselect_args = calloc( - savelevel_count, - sizeof(*savelevel_allowselect_args) - ); - } - else if(!savelevel_allowselect_args) - { - savelevel_allowselect_args = calloc( - savelevel_count, - sizeof(*savelevel_allowselect_args) - ); - } - - if(errormessage) - { - borShutdown(1, "load_levelorder ERROR in %s at %d, msg: %s\n", filename, line, errormessage); - } -} - - -void free_level(s_level *lv) -{ - int i; - - if(!lv) - { - return; - } - - //offload layers - for(i = 1; i < lv->numlayers; i++) - { - if(lv->layers[i].gfx.handle && lv->layers[i].gfx.handle != background) - { - if(lv->layers[i].gfx.sprite->magic == sprite_magic && - lv->layers[i].gfx.sprite->mask != NULL) - { - free(lv->layers[i].gfx.sprite->mask); - } - free(lv->layers[i].gfx.handle); - lv->layers[i].gfx.handle = NULL; - } - } - - //offload textobjs - for(i = 0; i < lv->numtextobjs; i++) - { - if(lv->textobjs[i].text) - { - free(lv->textobjs[i].text); - lv->textobjs[i].text = NULL; - } - } - - //offload basemaps - for(i = 0; i < lv->numbasemaps; i++) - { - if(lv->basemaps[i].map) - { - free(lv->basemaps[i].map); - } - } - - //offload scripts - Script_Clear(&(lv->update_script), 2); - Script_Clear(&(lv->updated_script), 2); - Script_Clear(&(lv->update_logic_script), 2); - Script_Clear(&(lv->updated_logic_script), 2); - Script_Clear(&(lv->key_script), 2); - Script_Clear(&(lv->level_script), 2); - Script_Clear(&(lv->endlevel_script), 2); - - for(i = 0; i < lv->numspawns; i++) - { - Script_Clear(&(lv->spawnpoints[i].spawnscript), 2); - } - - if(lv->spawnpoints) - { - free(lv->spawnpoints); - } - if(lv->layers) - { - free(lv->layers); - } - if(lv->layersref) - { - free(lv->layersref); - } - if(lv->panels) - { - free(lv->panels); - } - if(lv->frontpanels) - { - free(lv->frontpanels); - } - if(lv->bglayers) - { - free(lv->bglayers); - } - if(lv->fglayers) - { - free(lv->fglayers); - } - if(lv->genericlayers) - { - free(lv->genericlayers); - } - if(lv->waters) - { - free(lv->waters); - } - if(lv->textobjs) - { - free(lv->textobjs); - } - if(lv->holes) - { - free(lv->holes); - } - if(lv->spawn) - { - free(lv->spawn); - } - if(lv->walls) - { - free(lv->walls); - } - if(lv->basemaps) - { - free(lv->basemaps); - } - if(lv->palettes) - { - free(lv->palettes); - } - - free(lv); - lv = NULL; -} - -/* -* Caskey, Damon V. -* 2026-08-09 -* -* Accept model pointer and check if it -* is the model of an active player. If so, -* return true; otherwise, return false. -*/ -static bool model_is_active_player(const s_model *model) { - int i; - - if(!model || !model->name) { - return false; - } - - for(i = 0; i < MAX_PLAYERS; i++) { - if(player[i].lives > 0 - && player[i].name[0] - && stricmp(player[i].name, model->name) == 0) { - return true; - } - } - - return false; -} - - -void unload_level() -{ - s_model *temp; - int i; - - kill_all(); - unload_background(); - - if(level) - { - - level->pos = 0; - level->advancetime = 0; - level->quake = 0; - level->quaketime = 0; - level->waiting = 0; - - printf("Level Unloading: '%s'\n", level->name); - getRamStatus(BYTES); - free(level->name); - level->name = NULL; - free_level(level); - level = NULL; - temp = getFirstModel(); - do - { - if(!temp) - { - break; - } - - // Players carry their model choice into the next level. Keep the - // corresponding model and sprites resident while the player is - // alive, even when the model was loaded with an unload flag. - if(model_is_active_player(temp)) - { - temp = getNextModel(); - continue; - } - - if((temp->unload & 2)) - { - cache_model_sprites(temp, 0); - } - if((temp->unload & 1)) - { - free_model(temp); - temp = getCurrentModel(); - } - else - { - temp = getNextModel(); - } - } - while(temp); - printf("RAM Status:\n"); - getRamStatus(BYTES); - - - } - - advancex = 0; - advancey = 0; - nojoin = 0; - is_total_timeover = 0; - current_spawn = 0; - groupmin = 100; - groupmax = 100; - scrollminz = 0; - scrollmaxz = 0; - scrollminx = 0; - scrollmaxx = 0; - blockade = 0; - level_completed = 0; - level_completed_defeating_boss = 0; - tospeedup = 0; // Reset so it sets to normal speed for the next level - - for (i = 0; i < MAX_PLAYERS; i++){ - reached[i] = false; // TYPE_ENDLEVEL values reset after level completed //4player - } - - showtimeover = 0; - _pause = 0; - endgame = 0; - go_time = 0; - debug_time = 0; - debug_xy_msg.x = -1; - debug_xy_msg.y = -1; - neon_time = 0; - _time = 0; - cameratype = 0; - light.x = 128; - light.y = 64; - gfx_y_offset = gfx_x_offset = gfx_y_offset_adj = 0; // Added so select screen graphics display correctly -} - - -static void addhole(float x, float z, float x1, float x2, float x3, float x4, float depth, float alt, int type) -{ - __realloc(level->holes, level->numholes); - level->holes[level->numholes].x = x; - level->holes[level->numholes].z = z; - level->holes[level->numholes].upperleft = x1; - level->holes[level->numholes].lowerleft = x2; - level->holes[level->numholes].upperright = x3; - level->holes[level->numholes].lowerright = x4; - level->holes[level->numholes].depth = depth; - level->holes[level->numholes].height = alt; - level->holes[level->numholes].type = type; - - level->numholes++; -} - -static void addwall(float x, float z, float x1, float x2, float x3, float x4, float depth, float alt, int type) -{ - __realloc(level->walls, level->numwalls); - level->walls[level->numwalls].x = x; - level->walls[level->numwalls].z = z; - level->walls[level->numwalls].upperleft = x1; - level->walls[level->numwalls].lowerleft = x2; - level->walls[level->numwalls].upperright = x3; - level->walls[level->numwalls].lowerright = x4; - level->walls[level->numwalls].depth = depth; - level->walls[level->numwalls].height = alt; - level->walls[level->numwalls].type = type; - - level->numwalls++; -} - -static void addbasemap(float rx, float rz, float x_size, float z_size, float min_y, float max_y, int x_cont) -{ - __realloc(level->basemaps, level->numbasemaps); - level->numbasemaps++; - generate_basemap(level->numbasemaps-1, rx, rz, x_size, z_size, min_y, max_y, x_cont); -} - -void generate_basemap(int map_index, float rx, float rz, float x_size, float z_size, float min_y, float max_y, int x_cont) { - float x, z; - float delta, y, tmp; - int dir = 0; - - if(map_index >= level->numbasemaps) - { - __reallocto(level->basemaps, level->numbasemaps, map_index + 1); - level->numbasemaps = map_index + 1; - } - - level->basemaps[map_index].position.x = rx; - level->basemaps[map_index].position.z = rz-z_size; - level->basemaps[map_index].size.x = x_size; - level->basemaps[map_index].size.z = z_size; - - if(!level->basemaps[map_index].map) - { - level->basemaps[map_index].map = calloc( 1, (int)(sizeof(*(level->basemaps[map_index].map)) * (x_size+1)*(z_size+1)) ); - } - - if (min_y <= max_y) dir = 1; - else - { - dir = 0; - tmp = min_y; - min_y = max_y; - max_y = tmp; - } - - delta = (max_y - min_y) / ( (x_size <= 0) ? 1 : (x_size-1) ); - - for( x = 0; x < x_size; x++) - { - if ( dir ) - { - if ( x == x_size-1 ) y = max_y; - else y = x*delta + min_y; - } - else - { - y = max_y - (x*delta); - } - - if ( x_cont != 0 ) - { - if ( dir > 0 ) - { - if ( x+rx >= x_cont ) y = max_y; // connect with the wall more smoothly - } - else - { - if ( x+rx <= x_cont ) y = max_y; - } - } - - for ( z = 0; z < z_size; z++) - { - level->basemaps[map_index].map[(int)(x + z*x_size)] = y; - //printf("map[%d] = %f\n",(int)(x + z*x_size),y); - } - //printf("x:%f y:%f delta:%f\n",x,y,delta); - //printf("y: %f\n",y); - } - - return; -} - -void load_level(char *filename) -{ - char *buf = NULL; - size_t size, len, sblen; - ptrdiff_t pos, oldpos; - char *command; - char *value; - char *scriptbuf = NULL; - char string[MAX_BUFFER_LEN] = {""}; - s_spawn_entry next; - s_model *tempmodel, *cached_model; - - int i = 0, j = 0, crlf = 0; - int player_max = MAX_PLAYERS; - char bgPath[MAX_BUFFER_LEN] = {""}, fnbuf[MAX_BUFFER_LEN]; - s_loadingbar bgPosi = {0, 0, {0,0}, {0,0}, 0, 0}; - char musicPath[MAX_BUFFER_LEN] = {""}; - u32 musicOffset = 0; - - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - - ArgList arglist2; - char argbuf2[MAX_ARG_LEN + 1] = ""; - - levelCommands cmd; - levelCommands cmd2; - int line = 0; - char *errormessage = NULL; - char *scriptname = NULL; - Script *tempscript = NULL; - s_drawmethod *dm; - s_layer *bgl; - int (*panels)[3] = NULL; - int *order = NULL; - int panelcount = 0; - int exit_blocked = 0, exit_hole = 0; - char maskPath[MAX_BUFFER_LEN] = {""}; - - unload_level(); - - printf("Level Loading: '%s'\n", filename); - - - - getRamStatus(BYTES); - - if(isLoadingScreenTypeBg(loadingbg[1].set)) - { - if(custBkgrds) - { - strcpy(string, custBkgrds); - strcat(string, "loading2"); - load_background(string); - } - else - { - load_cached_background("data/bgs/loading2"); - } - clearscreen(vscreen); - spriteq_clear(); - standard_palette(1); - } - - if(isLoadingScreenTypeBar(loadingbg[1].set)) - { - lifebar_colors(); - init_colourtable(); - } - - update_loading(&loadingbg[1], -1, 1); // initialize the update screen - - memset(&next, 0, sizeof(next)); - - level = calloc(1, sizeof(*level)); - if(!level) - { - errormessage = "load_level() #1 FATAL: Out of memory!"; - goto lCleanup; - } - len = strlen(filename); - level->name = malloc(len + 1); - - if(!level->name) - { - errormessage = "load_level() #1 FATAL: Out of memory!"; - goto lCleanup; - } - strcpy(level->name, filename); - - // Allocate memory for player spawn - only as much as we need. - player_max = levelsets[current_set].maxplayers; - level->spawn = calloc(player_max, sizeof(*level->spawn)); - - // Default player spawn Y position just above the screen top. - for(i = 0; i < player_max && level->spawn; i++) - { - level->spawn[i].y = videomodes.vRes + 60; - } - - if(buffer_pakfile(filename, &buf, &size) != 1) - { - errormessage = "Unable to load level file!"; - goto lCleanup; - } - - level->settime = 100; // Feb 25, 2005 - Default time limit set to 100 - level->nospecial = 0; // Default set to specials can be used during bonus levels - level->nohurt = DAMAGE_FROM_ENEMY_ON; - level->nohit = DAMAGE_FROM_PLAYER_ON; // Default able to hit the other player - level->setweap = 0; - level->maxtossspeed = default_level_maxtossspeed; - level->maxfallspeed = default_level_maxfallspeed; - level->gravity = default_level_gravity; - level->scrolldir = SCROLL_RIGHT; - level->scrollspeed = 1; - level->cameraxoffset = 0; - level->camerazoffset = 0; - level->boss_slow = BOSS_SLOW_ON; - level->bossescount = 0; - level->numbosses = 0; - blendfx[BLEND_MULTIPLY] = 1; - bgtravelled = 0; - vbgtravelled = 0; - traveltime = 0; - texttime = 0; - nopause = 0; - nofadeout = 0; - noscreenshot = 0; - - panel_width = panel_height = frontpanels_loaded = 0; - - //reset_playable_list(1); - - // Now interpret the contents of buf line by line - pos = 0; - while(pos < size) - { - line++; - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - cmd = getLevelCommand(levelcmdlist, command); - switch(cmd) - { - case CMD_LEVEL_LOADINGBG: - load_background(GET_ARG(1)); - errormessage = fill_s_loadingbar(&bgPosi, GET_INT_ARG(2), GET_INT_ARG(3), GET_INT_ARG(4), GET_INT_ARG(5), GET_INT_ARG(6), GET_INT_ARG(7), GET_INT_ARG(8), GET_INT_ARG(9)); - if (errormessage) - { - goto lCleanup; - } - standard_palette(1); - lifebar_colors(); - init_colourtable(); - update_loading(&bgPosi, -1, 1); // initialize the update screen - break; - case CMD_LEVEL_MUSICFADE: - memset(&next, 0, sizeof(next)); - next.musicfade = GET_FLOAT_ARG(1); - break; - case CMD_LEVEL_MUSIC: - value = GET_ARG(1); - strncpy(string, value, MAX_BUFFER_LEN - 1); - musicOffset = atol(GET_ARG(2)); - if(loadingmusic) - { - music(string, 1, musicOffset); - musicPath[0] = 0; - } - else - { - oldpos = pos; - // Go to next line - pos += getNewLineStart(buf + pos); -#define GET_ARG2(z) arglist2.count > z ? arglist2.args[z] : "" - if(pos < size) - { - ParseArgs(&arglist2, buf + pos, argbuf2); - command = GET_ARG2(0); - cmd2 = getLevelCommand(levelcmdlist, command); - } - else - { - cmd2 = (levelCommands) 0; - } - - if(cmd2 == CMD_LEVEL_AT) - { - if(next.musicfade == 0) - { - memset(&next, 0, sizeof(next)); - } - strncpy(next.music, string, MAX_BUFFER_LEN); - next.musicoffset = musicOffset; - } - else - { - strncpy(musicPath, string, MAX_BUFFER_LEN); - } - pos = oldpos; -#undef GET_ARG2 - } - break; - case CMD_LEVEL_ALLOWSELECT: - load_playable_list(buf + pos); - break; - case CMD_LEVEL_LOAD: -#ifdef DEBUG - printf("load_level: load %s, %s\n", GET_ARG(1), filename); -#endif - tempmodel = findmodel(GET_ARG(1)); - if (!tempmodel) - { - load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2)); - } - else - { - update_model_loadflag(tempmodel, GET_INT_ARG(2)); - } - break; - case CMD_LEVEL_ALPHAMASK: - strncpy(maskPath, GET_ARG(1), MAX_BUFFER_LEN - 1); - break; - case CMD_LEVEL_BACKGROUND: - case CMD_LEVEL_BGLAYER: - case CMD_LEVEL_LAYER: - case CMD_LEVEL_FGLAYER: - __realloc(level->layers, level->numlayers); - bgl = &(level->layers[level->numlayers]); - - if(cmd == CMD_LEVEL_BACKGROUND || cmd == CMD_LEVEL_BGLAYER) - { - i = 0; - bgl->z = MIN_INT; - } - else - { - i = 1; - bgl->z = GET_FLOAT_ARG(2); - if(cmd == CMD_LEVEL_FGLAYER) - { - bgl->z += FRONTPANEL_Z; - } - } - - if(cmd == CMD_LEVEL_BACKGROUND) - { - if(bgPath[0]) - { - errormessage = "Background is already defined!"; - goto lCleanup; - } - value = GET_ARG(1); - strcpy(bgPath, value); - bgl->oldtype = BGT_BACKGROUND; - } - else if(cmd == CMD_LEVEL_BGLAYER) - { - bgl->oldtype = BGT_BGLAYER; - } - else if(cmd == CMD_LEVEL_FGLAYER) - { - bgl->oldtype = BGT_FGLAYER; - } - else if(cmd == CMD_LEVEL_LAYER) - { - bgl->oldtype = BGT_GENERIC; - } - - dm = &(bgl->drawmethod); - *dm = plainmethod; - - bgl->ratio.x = GET_FLOAT_ARG(i + 2); // x ratio - bgl->ratio.z = GET_FLOAT_ARG(i + 3); // z ratio - bgl->offset.x = GET_INT_ARG(i + 4); // x start - bgl->offset.z = GET_INT_ARG(i + 5); // z start - bgl->spacing.x = GET_INT_ARG(i + 6); // x spacing - bgl->spacing.z = GET_INT_ARG(i + 7); // z spacing - dm->xrepeat = GET_INT_ARG(i + 8); // x repeat - dm->yrepeat = GET_INT_ARG(i + 9); // z repeat - - dm->config = GET_INT_ARG(i + 10) ? (dm->config | DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY) : (dm->config & ~DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY); - - - dm->alpha = GET_INT_ARG(i + 11); // alpha - dm->water.watermode = GET_INT_ARG(i + 12); // water - if(dm->water.watermode == WATER_MODE_SHEAR) - { - dm->water.beginsize = GET_FLOAT_ARG(i + 13); // beginsize - dm->water.endsize = GET_FLOAT_ARG(i + 14); // endsize - dm->water.perspective = GET_INT_ARG(i + 15); // perspective - } - else - { - dm->water.amplitude = GET_INT_ARG(i + 13); // amplitude - dm->water.wavelength = GET_FLOAT_ARG(i + 14); // wavelength - dm->water.wavespeed = GET_FLOAT_ARG(i + 15); // waterspeed - } - bgl->bgspeedratio = GET_FLOAT_ARG(i + 16); // moving - bgl->quake = GET_INT_ARG(i + 17); // quake - bgl->neon = GET_INT_ARG(i + 18); // neon - bgl->enabled = 1; // enabled - - if((GET_ARG(i + 2))[0] == 0) - { - bgl->ratio.x = (cmd == CMD_LEVEL_FGLAYER ? 1.5 : 0.5); - } - if((GET_ARG(i + 3))[0] == 0) - { - bgl->ratio.z = (cmd == CMD_LEVEL_FGLAYER ? 1.5 : 0.5); - } - - if((GET_ARG(i + 8))[0] == 0) - { - dm->xrepeat = -1; - } - if((GET_ARG(i + 9))[0] == 0) - { - dm->yrepeat = -1; - } - if(cmd == CMD_LEVEL_BACKGROUND && (GET_ARG(i + 16))[0] == 0) - { - bgl->bgspeedratio = 1.0; - } - - if(blendfx_is_set == 0 && dm->alpha) - { - blendfx[dm->alpha - 1] = 1; - } - - if(cmd != CMD_LEVEL_BACKGROUND) - { - load_layer(GET_ARG(1), maskPath, level->numlayers); - } - level->numlayers++; - break; - case CMD_LEVEL_WATER: - __realloc(level->layers, level->numlayers); - bgl = &(level->layers[level->numlayers]); - dm = &(bgl->drawmethod); - *dm = plainmethod; - - bgl->oldtype = BGT_WATER; - bgl->z = MIN_INT + 1; - - bgl->ratio.x = 0.5; // x ratio - bgl->ratio.z = 0.5; // z ratio - bgl->offset.x = 0; // x start - bgl->offset.z = NaN; // z start - bgl->spacing.x = 0; // x spacing - bgl->spacing.z = 0; // z spacing - dm->xrepeat = -1; // x repeat - dm->yrepeat = 1; // z repeat - dm->config &= ~DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY; // transparency - dm->alpha = BLEND_MODE_NONE; // alpha - dm->water.watermode = WATER_MODE_SINE; - dm->water.amplitude = GET_INT_ARG(2); // amplitude - dm->water.wavelength = 40; // wavelength - dm->water.wavespeed = 1.0; // waterspeed - bgl->bgspeedratio = 0; // moving - bgl->enabled = 1; // enabled - - if(dm->water.amplitude < 1) - { - dm->water.amplitude = 1; - } - - load_layer(GET_ARG(1), maskPath, level->numlayers); - level->numlayers++; - break; - case CMD_LEVEL_DIRECTION: - value = GET_ARG(1); - if(stricmp(value, "up") == 0) - { - level->scrolldir = SCROLL_UP; - } - else if(stricmp(value, "down") == 0) - { - level->scrolldir = SCROLL_DOWN; - } - else if(stricmp(value, "left") == 0) - { - level->scrolldir = SCROLL_LEFT; - } - else if(stricmp(value, "both") == 0 || stricmp(value, "rightleft") == 0) - { - level->scrolldir = SCROLL_BOTH; - } - else if(stricmp(value, "leftright") == 0) - { - level->scrolldir = SCROLL_LEFTRIGHT; - } - else if(stricmp(value, "right") == 0) - { - level->scrolldir = SCROLL_RIGHT; - } - else if(stricmp(value, "in") == 0) - { - level->scrolldir = SCROLL_INWARD; - } - else if(stricmp(value, "out") == 0) - { - level->scrolldir = SCROLL_OUTWARD; - } - else if(stricmp(value, "inout") == 0) - { - level->scrolldir = SCROLL_INOUT; - } - else if(stricmp(value, "outin") == 0) - { - level->scrolldir = SCROLL_OUTIN; - } - break; - case CMD_LEVEL_FACING: - level->facing = GET_INT_ARG(1); - break; - - case CMD_LEVEL_ROCK: - level->rocking = GET_INT_ARG(1); - break; - case CMD_LEVEL_BGSPEED: - level->bgspeed = GET_FLOAT_ARG(1); - if(GET_INT_ARG(2)) - { - level->bgspeed *= -1; - } - break; - case CMD_LEVEL_VBGSPEED: - level->vbgspeed = GET_FLOAT_ARG(1); - if(GET_INT_ARG(2)) - { - level->vbgspeed *= -1; - } - break; - case CMD_LEVEL_SCROLLSPEED: - level->scrollspeed = GET_FLOAT_ARG(1); - break; - case CMD_LEVEL_MIRROR: - level->mirror = GET_INT_ARG(1); - break; - case CMD_LEVEL_BOSSMUSIC: - strncpy(level->bossmusic, GET_ARG(1), 255); - level->bossmusic_offset = atol(GET_ARG(2)); - break; - case CMD_LEVEL_NOSAVE: - nosave = GET_INT_ARG(1); - break; - case CMD_LEVEL_NOFADEOUT: - nofadeout = GET_INT_ARG(1); - break; - case CMD_LEVEL_NOPAUSE: - nopause = GET_INT_ARG(1); - break; - case CMD_LEVEL_NOSCREENSHOT: - noscreenshot = GET_INT_ARG(1); - break; - case CMD_LEVEL_SETTIME: - // If settime is found, overwrite the default 100 for time limit - level->settime = GET_INT_ARG(1); - if(level->settime > 100 || level->settime < 0) - { - level->settime = 100; - } - // Feb 25, 2005 - time limit loaded from individual .txt file - break; - case CMD_LEVEL_SETWEAP: - // Specify a weapon for each level - level->setweap = GET_INT_ARG(1); - break; - case CMD_LEVEL_NOTIME: - // Flag to if the time should be displayed 1 = no, else yes - level->notime = GET_INT_ARG(1); - break; - case CMD_LEVEL_NORESET: - // Flag to if the time should be reset when players respawn 1 = no, else yes - level->noreset = GET_INT_ARG(1); - break; - case CMD_LEVEL_NOSLOW: - - if(GET_INT_ARG(1)) - { - level->boss_slow = BOSS_SLOW_OFF; - } - - break; - case CMD_LEVEL_TYPE: - level->type = GET_INT_ARG(1); // Level type - 1 = bonus, else regular - level->nospecial = GET_INT_ARG(2); // Can use specials during bonus levels (default 0 - yes) - - if(GET_INT_ARG(3)) - { - level->nohurt = DAMAGE_FROM_ENEMY_OFF; - } - - break; - case CMD_LEVEL_NOHIT: - - if(GET_INT_ARG(1)) - { - level->nohit = DAMAGE_FROM_PLAYER_OFF; - } - - break; - case CMD_LEVEL_GRAVITY: - level->gravity = GET_FLOAT_ARG(1); - level->gravity /= 100; - break; - case CMD_LEVEL_MAXFALLSPEED: - level->maxfallspeed = GET_FLOAT_ARG(1); - level->maxfallspeed /= 10; - break; - case CMD_LEVEL_MAXTOSSSPEED: - level->maxtossspeed = GET_FLOAT_ARG(1); - level->maxtossspeed /= 10; - break; - case CMD_LEVEL_CAMERATYPE: - cameratype = GET_INT_ARG(1); - break; - case CMD_LEVEL_CAMERAOFFSET: - level->cameraxoffset = GET_INT_ARG(1); - level->camerazoffset = GET_INT_ARG(2); - break; - case CMD_LEVEL_SPAWN1: - case CMD_LEVEL_SPAWN2: - case CMD_LEVEL_SPAWN3: - case CMD_LEVEL_SPAWN4: - switch(cmd) - { - case CMD_LEVEL_SPAWN1: - i = 0; - break; - case CMD_LEVEL_SPAWN2: - i = 1; - break; - case CMD_LEVEL_SPAWN3: - i = 2; - break; - case CMD_LEVEL_SPAWN4: - i = 3; - break; - default: - assert(0); - } - - // Verify specified player index exists, - // then set values. - if(level->spawn && i < player_max) - { - level->spawn[i].x = GET_INT_ARG(1); - level->spawn[i].z = GET_INT_ARG(2); - level->spawn[i].y = GET_INT_ARG(3); - - if(level->spawn[i].y < 0) level->spawn[i].y = videomodes.vRes + 60; - } - - break; - case CMD_LEVEL_FRONTPANEL: - case CMD_LEVEL_PANEL: - if(level->numlayers == 0) - { - __realloc(level->layers, level->numlayers); - level->numlayers = 1; // reserve for background - } - - __realloc(level->layers, level->numlayers); - bgl = &(level->layers[level->numlayers]); - dm = &(bgl->drawmethod); - *dm = plainmethod; - - bgl->oldtype = (cmd == CMD_LEVEL_FRONTPANEL ? BGT_FRONTPANEL : BGT_PANEL); - - if(bgl->oldtype == BGT_PANEL) - { - bgl->order = panelcount + 1; - __realloc(panels, panelcount); - panels[panelcount++][0] = level->numlayers; - bgl->z = PANEL_Z; - bgl->ratio.x = 0; // x ratio - bgl->ratio.z = 0; // z ratio - dm->xrepeat = 1; // x repeat - } - else - { - frontpanels_loaded++; - bgl->z = FRONTPANEL_Z; - bgl->ratio.x = -0.4; // x ratio - bgl->ratio.z = 1; // z ratio - dm->xrepeat = -1; // x repeat - } - - bgl->bgspeedratio = 0; - bgl->offset.z = 0; - dm->yrepeat = 1; // z repeat - dm->config |= DRAWMETHOD_CONFIG_BACKGROUND_TRANSPARENCY; // transparency - bgl->enabled = 1; // enabled - bgl->quake = 1; // accept quake and rock - - load_layer(GET_ARG(1), maskPath, level->numlayers); - level->numlayers++; - - if(stricmp(GET_ARG(2), "none") != 0 && GET_ARG(2)[0]) - { - __realloc(level->layers, level->numlayers); - bgl = &(level->layers[level->numlayers]); - *bgl = *(bgl - 1); - panels[panelcount - 1][1] = level->numlayers; - - bgl->z = NEONPANEL_Z; - bgl->neon = 1; - bgl->gfx.handle = NULL; - load_layer(GET_ARG(2), maskPath, level->numlayers); - level->numlayers++; - } - - if(stricmp(GET_ARG(3), "none") != 0 && GET_ARG(3)[0]) - { - __realloc(level->layers, level->numlayers); - bgl = &(level->layers[level->numlayers]); - *bgl = *(bgl - 1); - panels[panelcount - 1][2] = level->numlayers; - dm = &(bgl->drawmethod); - - bgl->z = SCREENPANEL_Z; - bgl->neon = 0; - dm->alpha = BLEND_MODE_ALPHA; - bgl->gfx.handle = NULL; - load_layer(GET_ARG(3), maskPath, level->numlayers); - level->numlayers++; - } - break; - case CMD_LEVEL_STAGENUMBER: - current_stage = GET_INT_ARG(1); - break; - case CMD_LEVEL_ORDER: - // Append to order - value = GET_ARG(1); - i = 0; - while(value[i] ) - { - j = value[i]; - // WTF ? - if(j >= 'A' && j <= 'Z') - { - j -= 'A'; - } - else if(j >= 'a' && j <= 'z') - { - j -= 'a'; - } - else - { - errormessage = "Illegal character in panel order!"; - goto lCleanup; - } - __realloc(order, level->numpanels); - __realloc(level->panels, level->numpanels); - order[level->numpanels] = j; - level->numpanels++; - i++; - } - break; - case CMD_LEVEL_HOLE: - /*value = GET_ARG(1); // ltb 1-18-05 adjustable hole sprites - - if(holesprite < 0) - { - if(testpackfile(value, packfile) >= 0) - { - holesprite = loadsprite(value, 0, 0, pixelformat); // ltb 1-18-05 load new hole sprite - } - else - { - holesprite = loadsprite("data/sprites/hole", 0, 0, pixelformat); // ltb 1-18-05 no new sprite load the default - } - }*/ - - addhole(GET_FLOAT_ARG(1), GET_FLOAT_ARG(2), GET_FLOAT_ARG(3), GET_FLOAT_ARG(4), GET_FLOAT_ARG(5), GET_FLOAT_ARG(6), GET_FLOAT_ARG(7), GET_FLOAT_ARG(8), GET_FLOAT_ARG(9)); - break; - case CMD_LEVEL_WALL: - addwall(GET_FLOAT_ARG(1), GET_FLOAT_ARG(2), GET_FLOAT_ARG(3), GET_FLOAT_ARG(4), GET_FLOAT_ARG(5), GET_FLOAT_ARG(6), GET_FLOAT_ARG(7), GET_FLOAT_ARG(8), GET_FLOAT_ARG(9)); - break; - case CMD_LEVEL_BASEMAP: - addbasemap(GET_FLOAT_ARG(1), GET_FLOAT_ARG(2), GET_FLOAT_ARG(3), GET_FLOAT_ARG(4), GET_FLOAT_ARG(5), GET_FLOAT_ARG(6), GET_FLOAT_ARG(7)); - break; - case CMD_LEVEL_PALETTE: - __realloc(level->palettes, level->numpalettes); - if(!load_palette(level->palettes[level->numpalettes], GET_ARG(1))) - { - errormessage = "Failed to create colour conversion tables for level! (Out of memory?)"; - goto lCleanup; - } - level->numpalettes++; - break; - case CMD_LEVEL_UPDATESCRIPT: - case CMD_LEVEL_UPDATEDSCRIPT: - case CMD_LEVEL_UPDATELOGICSCRIPT: - case CMD_LEVEL_UPDATEDLOGICSCRIPT: - case CMD_LEVEL_KEYSCRIPT: - case CMD_LEVEL_LEVELSCRIPT: - case CMD_LEVEL_ENDLEVELSCRIPT: - switch(cmd) - { - case CMD_LEVEL_UPDATESCRIPT: - tempscript = &(level->update_script); - scriptname = "levelupdatescript"; - break; - case CMD_LEVEL_UPDATEDSCRIPT: - tempscript = &(level->updated_script); - scriptname = "levelupdatedscript"; - break; - case CMD_LEVEL_UPDATELOGICSCRIPT: - tempscript = &(level->update_logic_script); - scriptname = "levelupdatelogicscript"; - break; - case CMD_LEVEL_UPDATEDLOGICSCRIPT: - tempscript = &(level->updated_logic_script); - scriptname = "levelupdatedlogicscript"; - break; - case CMD_LEVEL_KEYSCRIPT: - tempscript = &(level->key_script); - scriptname = "levelkeyscript"; - break; - case CMD_LEVEL_LEVELSCRIPT: - tempscript = &(level->level_script); - scriptname = "levelscript"; - break; - case CMD_LEVEL_ENDLEVELSCRIPT: - tempscript = &(level->endlevel_script); - scriptname = "endlevelscript"; - break; - default: - assert(0); - - } - // this function is for model script, but it is OK for now - pos += lcmHandleCommandScripts(&arglist, buf + pos, tempscript, scriptname, filename, 1, 1); - break; - case CMD_LEVEL_BLOCKED: - exit_blocked = GET_INT_ARG(1); - break; - case CMD_LEVEL_ENDHOLE: - exit_hole = GET_INT_ARG(1); - break; - case CMD_LEVEL_WAIT: - // Clear spawn thing, set wait state instead - memset(&next, 0, sizeof(next)); - next.wait = 1; - break; - case CMD_LEVEL_NOJOIN: - // Clear spawn thing, set nojoin state instead - memset(&next, 0, sizeof(next)); - next.nojoin = 1; - break; - case CMD_LEVEL_CANJOIN: - memset(&next, 0, sizeof(next)); - next.nojoin = -1; - break; - case CMD_LEVEL_SHADOWCOLOR: - memset(&next, 0, sizeof(next)); - next.shadowcolor = parsecolor(GET_ARG(1)); - break; - case CMD_LEVEL_SHADOWALPHA: - memset(&next, 0, sizeof(next)); - next.shadowalpha = GET_INT_ARG(1); - if(blendfx_is_set == 0 && next.shadowalpha > 0) - { - blendfx[next.shadowalpha - 1] = 1; - } - break; - case CMD_LEVEL_SHADOWOPACITY: - memset(&next, 0, sizeof(next)); - next.shadowopacity = GET_INT_ARG(1); - break; - case CMD_LEVEL_LIGHT: - memset(&next, 0, sizeof(next)); - next.light.x = GET_INT_ARG(1); - next.light.y = GET_INT_ARG(2); - if(next.light.y == 0) - { - next.light.y = 64; - } - break; - case CMD_LEVEL_SCROLLZ: - memset(&next, 0, sizeof(next)); - next.scrollminz = GET_INT_ARG(1); - next.scrollmaxz = GET_INT_ARG(2); - next.scrollminz |= 0x80000000; - break; - case CMD_LEVEL_SCROLLX: - //shall we keep blockade? - memset(&next, 0, sizeof(next)); - next.scrollminx = GET_INT_ARG(1); - next.scrollmaxx = GET_INT_ARG(2); - next.scrollminx |= 0x80000000; - break; - case CMD_LEVEL_BLOCKADE: - // now x scroll can be limited by this - memset(&next, 0, sizeof(next)); - next.blockade = GET_INT_ARG(1); - if(next.blockade == 0) - { - next.blockade = -1; - } - break; - case CMD_LEVEL_SETPALETTE: - // change system palette - memset(&next, 0, sizeof(next)); - next.palette = GET_INT_ARG(1); - break; - case CMD_LEVEL_GROUP: - // Clear spawn thing, set group instead - memset(&next, 0, sizeof(next)); - next.groupmin = GET_INT_ARG(1); - next.groupmax = GET_INT_ARG(2); - if(next.groupmax < 1) - { - next.groupmax = 1; - } - if(next.groupmin < 1) - { - next.groupmin = 100; - } - break; - case CMD_LEVEL_SPAWN: - // Back to defaults - next.spawnplayer_count = 0; - memset(&next, 0, sizeof(next)); - next.index = next.item_properties.index = next.weaponindex = -1; - // Name of entry to be spawned - // Load model (if not loaded already) - cached_model = findmodel(GET_ARG(1)); -#ifdef DEBUG - printf("load_level: spawn %s, %s, cached: %p\n", GET_ARG(1), filename, cached_model); -#endif - if(cached_model) - { - tempmodel = cached_model; - } - else - { - tempmodel = load_cached_model(GET_ARG(1), filename, 0); - } - if(tempmodel) - { - next.name = tempmodel->name; - next.index = get_cached_model_index(next.name); - next.spawntype = SPAWN_TYPE_LEVEL; //2011_03_23, DC; Spawntype SPAWN_TYPE_LEVEL. - - crlf = 1; - } - break; - case CMD_LEVEL_2PSPAWN: - // Entity only for 2p game - next.spawnplayer_count = 1; - break; - case CMD_LEVEL_3PSPAWN: - // Entity only for 3p game - next.spawnplayer_count = 2; - break; - case CMD_LEVEL_4PSPAWN: - // Entity only for 4p game - next.spawnplayer_count = 3; - break; - case CMD_LEVEL_BOSS: - next.boss = GET_INT_ARG(1); - level->bossescount += next.boss ? 1 : 0; - level->numbosses = level->bossescount; - break; - - case CMD_LEVEL_FACTION_GROUP_DAMAGE_DIRECT: - - next.faction.damage_direct = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_GROUP_DAMAGE_INDIRECT: - - next.faction.damage_indirect = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_GROUP_HOSTILE: - - next.faction.hostile = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_GROUP_MEMBER: - - next.faction.member = faction_get_flags_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_TYPE_DAMAGE_DIRECT: - - next.faction.type_damage_direct = get_type_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_TYPE_DAMAGE_INDIRECT: - - next.faction.type_damage_indirect = get_type_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FACTION_TYPE_HOSTILE: - - next.faction.type_hostile = get_type_from_command_line(buf + pos); - break; - - case CMD_LEVEL_FLIP: - next.flip = GET_INT_ARG(1); - break; - case CMD_LEVEL_HEALTH: - next.health[0] = next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1); - break; - case CMD_LEVEL_2PHEALTH: - // Health the spawned entity will have if 2 people are playing - next.health[1] = next.health[2] = next.health[3] = GET_INT_ARG(1); - break; - case CMD_LEVEL_3PHEALTH: - // Health the spawned entity will have if 2 people are playing - next.health[2] = next.health[3] = GET_INT_ARG(1); //4player - break; - case CMD_LEVEL_4PHEALTH: - // Health the spawned entity will have if 2 people are playing - next.health[3] = GET_INT_ARG(1); //4player - break; - case CMD_LEVEL_MP: - // mp values to put max mp for player by tails - next.mp = GET_INT_ARG(1); - break; - case CMD_LEVEL_SCORE: - // So score can be overriden in the levels .txt file - if(!command_argument_get_int64(GET_ARG(1), &next.score)) - { - borShutdown( - 1, - "Invalid signed 64-bit score '%s' in %s, line %d.\n", - GET_ARG(1), - filename, - line - ); - } - next.multiple = GET_INT_ARG(2); - if(next.multiple == -1) - { - next.multiple = 0; // So negative values cannot be added - } - break; - case CMD_LEVEL_NOLIFE: - // Flag to determine if entity life is shown when hit - next.nolife = GET_INT_ARG(1); - break; - case CMD_LEVEL_ALIAS: - // Alias (name displayed) of entry to be spawned - strncpy(next.alias, GET_ARG(1), MAX_NAME_LEN - 1); - break; - case CMD_LEVEL_MAP: - // Colourmap for new entry - next.colourmap = GET_INT_ARG(1); - break; - case CMD_LEVEL_ALPHA: - // Item to be contained by new entry - next.alpha = GET_INT_ARG(1); - if(blendfx_is_set == 0 && next.alpha) - { - blendfx[next.alpha - 1] = 1; - } - break; - case CMD_LEVEL_DYING: - // Used to store which remake corresponds with the dying flash - next.dying = GET_INT_ARG(1); - next.per1 = GET_INT_ARG(2); - next.per2 = GET_INT_ARG(3); - next.dying2 = GET_INT_ARG(4); - break; - case CMD_LEVEL_ITEM: - case CMD_LEVEL_2PITEM: - case CMD_LEVEL_3PITEM: - case CMD_LEVEL_4PITEM: - switch(cmd) - { - // Item to be contained by new entry - case CMD_LEVEL_ITEM: - next.item_properties.player_count = 0; - break; - case CMD_LEVEL_2PITEM: - next.item_properties.player_count = 1; - break; - case CMD_LEVEL_3PITEM: - next.item_properties.player_count = 2; - break; - case CMD_LEVEL_4PITEM: - next.item_properties.player_count = 3; - break; - default: - assert(0); - } - // Load model (if not loaded already) - cached_model = findmodel(GET_ARG(1)); - if(cached_model) - { - tempmodel = cached_model; - } - else - { - tempmodel = load_cached_model(GET_ARG(1), filename, 0); - } - if(tempmodel) - { - next.item = tempmodel->name; - next.item_properties.index = get_cached_model_index(next.item); - } - break; - case CMD_LEVEL_ITEMMAP: - next.item_properties.colorset = GET_INT_ARG(1); - break; - case CMD_LEVEL_ITEMHEALTH: - next.item_properties.health = GET_INT_ARG(1); - break; - case CMD_LEVEL_ITEMALIAS: - strncpy(next.item_properties.alias, GET_ARG(1), MAX_NAME_LEN - 1); - break; - case CMD_LEVEL_WEAPON: - //spawn with a weapon 2007-2-12 by UTunnels - // Load model (if not loaded already) - cached_model = findmodel(GET_ARG(1)); - if(cached_model) - { - tempmodel = cached_model; - } - else - { - tempmodel = load_cached_model(GET_ARG(1), filename, 0); - } - if(tempmodel) - { - next.weapon = tempmodel->name; - next.weaponindex = get_cached_model_index(next.weapon); - } - break; - case CMD_LEVEL_AGGRESSION: - // Aggression can be set per spawn. - next.aggression = GET_INT_ARG(1); - break; - case CMD_LEVEL_CREDIT: - next.credit = GET_INT_ARG(1); - break; - case CMD_LEVEL_ITEMTRANS: - case CMD_LEVEL_ITEMALPHA: - next.item_properties.alpha = GET_INT_ARG(1); - break; - case CMD_LEVEL_COORDS: - next.position.x = GET_FLOAT_ARG(1); - next.position.z = GET_FLOAT_ARG(2); - next.position.y = GET_FLOAT_ARG(3); - break; - case CMD_LEVEL_SPAWNSCRIPT: - pos += lcmHandleCommandScripts(&arglist, buf + pos, &next.spawnscript, "Level spawn entry script", filename, 0, 1); - break; - case CMD_LEVEL_AT_SCRIPT: - if(!Script_IsInitialized(&next.spawnscript)) - { - Script_Init(&next.spawnscript, "Level spawn entry script", filename, 1); - } - fetchInlineScript(buf, &scriptbuf, &pos, &sblen); - if(!Script_AppendText(&next.spawnscript, scriptbuf, filename)) - { - errormessage = "Unable to parse level spawn entry script.\n"; - goto lCleanup; - } - free(scriptbuf); - scriptbuf = NULL; - break; - case CMD_LEVEL_AT: - // Place entry on queue - next.at = GET_INT_ARG(1); - - if(Script_IsInitialized(&next.spawnscript)) - { - Script_Compile(&next.spawnscript); - } - - __realloc(level->spawnpoints, level->numspawns); - memcpy(&level->spawnpoints[level->numspawns], &next, sizeof(next)); - level->numspawns++; - - // And clear... - memset(&next, 0, sizeof(next)); - break; - default: - if(command && command[0]) - { - if(!handle_txt_include(command, &arglist, &filename, fnbuf, &buf, &pos, &size)) - { - printf("Command '%s' not understood in file '%s'!\n", command, filename); - } - } - } - - // Go to next line - pos += getNewLineStart(buf + pos); - - if(isLoadingScreenTypeBar(bgPosi.set) || isLoadingScreenTypeBg(bgPosi.set)) - { - update_loading(&bgPosi, pos, size); - } - //update_loading(bgPosi[0]+videomodes.hShift, bgPosi[1]+videomodes.vShift, bgPosi[2], bgPosi[3]+videomodes.hShift, bgPosi[4]+videomodes.vShift, pos, size, bgPosi[5]); - else - { - update_loading(&loadingbg[1], pos, size); - } - } - - if(level->numpanels < 1) - { - errormessage = "Level error: level has no panels"; - goto lCleanup; - } - - if(bgPath[0]) - { - clearscreen(vscreen); - spriteq_clear(); - load_background(bgPath); - } - else if(background) - { - unload_background(); - } - - if(level->numlayers) - { - - for(i = 0; i < level->numlayers; i++) - { - bgl = &(level->layers[i]); - switch(bgl->oldtype) - { - case BGT_WATER: // default water hack - bgl->offset.z = background ? background->height : level->layers[0].size.y; - dm = &(bgl->drawmethod); - if(level->rocking) - { - dm->water.watermode = WATER_MODE_SHEAR; - dm->water.beginsize = 1.0; - dm->water.endsize = 1 + bgl->size.y / 11.0; - dm->water.perspective = WATER_PERSPECTIVE_NONE; - bgl->bgspeedratio = 2; - } - break; - case BGT_PANEL: - panel_width = bgl->size.x; - panel_height = bgl->size.y; - case BGT_FRONTPANEL: - if(level->scrolldir & (SCROLL_UP | SCROLL_DOWN)) - { - bgl->ratio.z = 1; - } - break; - case BGT_BACKGROUND: - bgl->gfx.screen = background; - bgl->size.x = background->width; - bgl->size.y = background->height; - level->background = bgl; - break; - default: - break; - } - load_layer(NULL, NULL, i); - } - - if(level->background) - { - __realloc(level->layersref, level->numlayersref); - level->layersref[level->numlayersref] = *(level->background); - level->background = (s_layer *)(size_t)level->numlayersref++; - } - - - // non-panel type layers - for(i = 0; i < level->numlayers; i++) - { - bgl = &(level->layers[i]); - if(bgl->oldtype != BGT_PANEL && bgl->oldtype != BGT_BACKGROUND) - { - __realloc(level->layersref, level->numlayersref); - level->layersref[level->numlayersref] = *bgl; - bgl = &(level->layersref[level->numlayersref]); - switch(bgl->oldtype) - { - case BGT_BGLAYER: - __realloc(level->bglayers, level->numbglayers); - level->bglayers[level->numbglayers++] = (s_layer *)(size_t)level->numlayersref; - break; - case BGT_FGLAYER: - __realloc(level->fglayers, level->numfglayers); - level->fglayers[level->numfglayers++] = (s_layer *)(size_t)level->numlayersref; - break; - case BGT_WATER: - __realloc(level->waters, level->numwaters); - level->waters[level->numwaters++] = (s_layer *)(size_t)level->numlayersref; - break; - case BGT_GENERIC: - __realloc(level->genericlayers, level->numgenericlayers); - level->genericlayers[level->numgenericlayers++] = (s_layer *)(size_t)level->numlayersref; - break; - case BGT_FRONTPANEL: - bgl->offset.x = level->numfrontpanels * bgl->size.x; - bgl->spacing.x = (frontpanels_loaded - 1) * bgl->size.x; - __realloc(level->frontpanels, level->numfrontpanels); - level->frontpanels[level->numfrontpanels++] = (s_layer *)(size_t)level->numlayersref; - break; - default: - break; - } - level->numlayersref++; - } - } - - //panels, normal neon screen - for(i = 0; i < level->numpanels; i++) - { - for(j = 0; j < 3; j++) - { - if(panels[order[i]][j]) - { - __realloc(level->layersref, level->numlayersref); - level->layersref[level->numlayersref] = level->layers[panels[order[i]][j]]; - bgl = &(level->layersref[level->numlayersref]); - bgl->offset.x = panel_width * i; - level->panels[i][j] = (s_layer *)(size_t)level->numlayersref; - level->numlayersref++; - } - } - } - - //fix realloc junk pointers - bgl = level->layersref; - level->background = bgl + (size_t)level->background; - for(i = 0; i < level->numpanels; i++) - for(j = 0; j < 3; j++) - { - level->panels[i][j] = bgl + (size_t)level->panels[i][j]; - } - for(i = 0; i < level->numfrontpanels; i++) - { - level->frontpanels[i] = bgl + (size_t)level->frontpanels[i]; - } - for(i = 0; i < level->numbglayers; i++) - { - level->bglayers[i] = bgl + (size_t)level->bglayers[i]; - } - for(i = 0; i < level->numfglayers; i++) - { - level->fglayers[i] = bgl + (size_t)level->fglayers[i]; - } - for(i = 0; i < level->numgenericlayers; i++) - { - level->genericlayers[i] = bgl + (size_t)level->genericlayers[i]; - } - for(i = 0; i < level->numwaters; i++) - { - level->waters[i] = bgl + (size_t)level->waters[i]; - } - - } - - if(musicPath[0]) - { - music(musicPath, 1, musicOffset); - } - - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - level->width = level->numpanels * panel_width; - - if(level->width < videomodes.hRes) - { - level->width = videomodes.hRes; - } - - scrollmaxx = level->width - videomodes.hRes; - scrollmaxz = panel_height; - - if(level->scrolldir & SCROLL_LEFT) - { - advancex = (float)(level->width - videomodes.hRes); - } - else if(level->scrolldir & SCROLL_INWARD) - { - advancey = (float)(panel_height - videomodes.vRes); - } - - if(exit_blocked) - { - addwall(level->width - 30, PLAYER_MAX_Z, -panel_height, 0, 1000, 1000, panel_height, MAX_WALL_HEIGHT + 1, 0); - } - if(exit_hole) - { - addhole(level->width, PLAYER_MAX_Z, -panel_height, 0, 1000, 1000, panel_height, 0, 0); - } - - if(crlf) - { - printf("\n"); - } - printf("Level Loaded: '%s'\n", level->name); - totalram = getSystemRam(BYTES); - freeram = getFreeRam(BYTES); - usedram = getUsedRam(BYTES); - printf("Total Ram: %11"PRIu64" Bytes ( %5"PRIu64" MB )\n Free Ram: %11"PRIu64" Bytes ( %5"PRIu64" MB )\n Used Ram: %11"PRIu64" Bytes ( %5"PRIu64" MB )\n", - totalram, - totalram >> 20, - freeram, - freeram >> 20, - usedram, - usedram >> 20); - printf("Total sprites mapped: %d\n\n", sprites_loaded); - -lCleanup: - - if (panels) - { - free(panels); - } - if (order) - { - free(order); - } - - if(buf) - { - free(buf); - } - if(scriptbuf) - { - free(scriptbuf); - } - - if(errormessage) - { - borShutdown(1, "ERROR: load_level, file %s, line %d, message: %s", filename, line, errormessage); - } -} - - - - - -///////////////////////////////////////////////////////////////////////////// -// Status // -///////////////////////////////////////////////////////////////////////////// -void bar(int x, int y, int value, int maxvalue, s_barstatus *pstatus) -{ - int max = 100; - int len; - int alphabg = 0; - int bgindex; - int colourindex; - int forex; - int forey; - int forew; - int foreh; - int bkw; - int bkh; - s_drawmethod dm = plainmethod; - - if(pstatus->config_flags & STATUS_CONFIG_GRAPH_VERTICAL) - { - max = pstatus->size.y; - } - else - { - max = pstatus->size.x; - } - - if (value > maxvalue) - { - value = maxvalue; - } - - if(pstatus->config_flags & STATUS_CONFIG_GRAPH_RATIO) - { - colourindex = colorbars ? (value * 5 / maxvalue + 1) : 2; - bgindex = colorbars ? 8 : 1; - len = value * max / maxvalue; - if (!len && value) - { - len = 1; - } - alphabg = BLEND_MULTIPLY + 1; - } - else - { - if (max > maxvalue) - { - max = maxvalue; - } - if (colorbars) - { - if (value <= max / 4) - { - bgindex = 0; - colourindex = 1; - } - else if (value <= max / 2) - { - bgindex = 0; - colourindex = 2; - } - else if (value <= max) - { - bgindex = 0; - colourindex = 3; - } - else - { - colourindex = value / (max + 1) + 3; - bgindex = colourindex - 1; - } - if (colourindex > 10) - { - colourindex = bgindex = 10; - } - } - else - { - colourindex = 2; - bgindex = value > max ? 5 : 1; - } - - len = value % max; - if (!len && value) - { - len = max; - } - alphabg = value > max ? 0 : (BLEND_MULTIPLY + 1); - } - - if(pstatus->config_flags & STATUS_CONFIG_GRAPH_VERTICAL) - { - forex = x; - forey = pstatus->config_flags & STATUS_CONFIG_GRAPH_INVERT ? y : (y + max - len); - bkw = forew = pstatus->size.x; - foreh = len; - bkh = max; - } - else - { - forex = pstatus->config_flags & STATUS_CONFIG_GRAPH_INVERT ? (x + max - len) : x; - forey = y; - forew = len; - bkw = max; - bkh = foreh = pstatus->size.y; - } - - if(!pstatus->colourtable) - { - pstatus->colourtable = &hpcolourtable; - } - - dm.alpha = alphabg; - spriteq_add_box(x + 1, y + 1, bkw, bkh, HUD_Z + 1 + pstatus->backlayer, (*pstatus->colourtable)[bgindex], &dm); - spriteq_add_box(forex + 1, forey + 1, forew, foreh, HUD_Z + 2 + pstatus->barlayer, (*pstatus->colourtable)[colourindex], NULL); - - if(!(pstatus->config_flags & STATUS_CONFIG_BORDER_DISABLE)) - { - spriteq_add_line(x, y, x + bkw + 1, y, HUD_Z + 3 + pstatus->borderlayer, color_white, NULL); //Top border. - spriteq_add_line(x, y + bkh + 1, x + bkw + 1, y + bkh + 1, HUD_Z + 3 + pstatus->borderlayer, color_white, NULL); //Bottom border. - spriteq_add_line(x, y + 1, x, y + bkh, HUD_Z + 3 + pstatus->borderlayer, color_white, NULL); //Left border. - spriteq_add_line(x + bkw + 1, y + 1, x + bkw + 1, y + bkh, HUD_Z + 3 + pstatus->borderlayer, color_white, NULL); //Right border. - spriteq_add_line(x, y + bkh + 2, x + bkw + 1, y + bkh + 2, HUD_Z + pstatus->borderlayer, color_black, NULL); //Bottom shadow. - spriteq_add_line(x + bkw + 2, y + 1, x + bkw + 2, y + bkh + 2, HUD_Z + pstatus->borderlayer, color_black, NULL); //Right shadow. - } -} - -void goto_mainmenu(int flag) -{ - goto_mainmenu_flag = 1|(flag<<1); - escape_flag = flag; //Kratus (20-04-21) Added the new "escape" flag in the select screen, has the same effect as the esc key but now accessible by the "gotomainmenu" function -} - -void static backto_mainmenu() -{ - int i = 0; - s_screen *pausebuffer = allocscreen(videomodes.hRes, videomodes.vRes, PIXEL_32); - - copyscreen(pausebuffer, vscreen); - spriteq_draw(pausebuffer, 0, MIN_INT, MAX_INT, 0, 0); - spriteq_clear(); - spriteq_add_screen(0, 0, MIN_INT, pausebuffer, NULL, 0); - spriteq_lock(); - - sound_pause_music(1); - sound_pause_sample(1); - _pause = 2; - - if ( (goto_mainmenu_flag&1) ) goto_mainmenu_flag -= 1; - - update(1, 0); - - for(i = 0; i < MAX_PLAYERS; i++) - { - player[i].lives = 0; - } - endgame = 2; - //sound_pause_music(0); - //sound_pause_sample(0); - - _pause = 0; - bothnewkeys = 0; - spriteq_unlock(); - spriteq_clear(); - freescreen(&pausebuffer); - - return; -} - -void pausemenu() -{ - int pauselector = 0; - int quit = 0; - int controlp = 0, i; - key_mask_t newkeys; - s_set_entry *set = levelsets + current_set; - s_screen *pausebuffer = allocscreen(videomodes.hRes, videomodes.vRes, PIXEL_32); - - copyscreen(pausebuffer, vscreen); - spriteq_draw(pausebuffer, 0, MIN_INT, MAX_INT, 0, 0); - spriteq_clear(); - spriteq_add_screen(0, 0, MIN_INT, pausebuffer, NULL, 0); - spriteq_lock(); - - for(i = 0; i < set->maxplayers; i++) - { - if(player[i].ent && (player[i].newkeys & FLAG_START)) - { - controlp = i; - break; - } - } - - _pause = 2; - bothnewkeys = 0; - while(!quit) - { - _menutextmshift(pauseoffset[4], -2, 0, pauseoffset[5], pauseoffset[6], Tr("Pause")); - _menutextmshift((pauselector == 0)?pauseoffset[1]:pauseoffset[0], -1, 0, pauseoffset[2], pauseoffset[3], Tr("Continue")); - _menutextmshift((pauselector == 1)?pauseoffset[1]:pauseoffset[0], 0, 0, pauseoffset[2], pauseoffset[3], Tr("End Game")); - - update(1, 0); - - newkeys = player[controlp].newkeys; - - if(newkeys & (FLAG_MOVEUP | FLAG_MOVEDOWN)) - { - pauselector ^= 1; - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(newkeys & FLAG_START) - { - if(pauselector) - { - for(i = 0; i < MAX_PLAYERS; i++) - { - player[i].lives = 0; - } - endgame = 2; - } - quit = 1; - sound_pause_music(0); - sound_pause_sample(0); - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - pauselector = 0; - } - if(newkeys & FLAG_ESC) - { - quit = 1; - sound_pause_music(0); - sound_pause_sample(0); - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - pauselector = 0; - } - if(newkeys & FLAG_SCREENSHOT) - { - _pause = 1; - sound_pause_music(1); - sound_pause_sample(1); - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - menu_options(); - } - } - _pause = 0; - bothnewkeys = 0; - spriteq_unlock(); - spriteq_clear(); - freescreen(&pausebuffer); -} - -unsigned getFPS(void) -{ - static u64 lasttick = 0, framerate = 0; - u64 curtick = timer_uticks(); - if(lasttick > curtick) - { - lasttick = curtick; - } - framerate = (framerate + (curtick - lasttick)) / 2; - lasttick = curtick; - if(!framerate) - { - // if the frame took 0 ms, act like it was 1 ms instead - return 1000; - } - - return round(1.0e6 / framerate); - -} - -void updatestatus() { - - uint64_t display_time; - uint64_t go_phase; - uint64_t i; - s_model *model = NULL; - s_set_entry *set = levelsets + current_set; - - for(i = 0; i < set->maxplayers; i++) { - - /* - * If the player is already in the game, do nothing. - */ - if(player[i].ent) { - continue; - } - - if(player[i].joining && player[i].name[0]) { - model = findmodel(player[i].name); - - if((player[i].playkeys & FLAG_ANYBUTTON || skipselect[i][0]) && !freezeall && !nojoin) { // Can't join while animations are frozen - player[i].lives = PLAYER_LIVES; // to address new lives settings - player[i].joining = 0; - player[i].hasplayed = 1; - player[i].spawnhealth = model->health; - player[i].spawnmp = model->mp; - - spawnplayer(i); - - execute_join_script(i); - - player[i].disablekeys = player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0; - - if(!nodropen) { - drop_all_enemies(); //27-12-2004 If drop enemies is on, drop all enemies - } - - if(!level->noreset) { - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - } - - } else if(player[i].playkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT)) { - - /* PLayer model selection. */ - - model = ((player[i].playkeys & FLAG_MOVELEFT) ? prevplayermodeln : nextplayermodeln)(model, i); - strcpy(player[i].name, model->name); - - player[i].colourmap = (colourselect && (set->nosame & 2)) ? nextcolourmapn(model, -1, i) : 0; - - player[i].playkeys = 0; - - } else if(player[i].playkeys & (FLAG_MOVEUP | FLAG_MOVEDOWN) && colourselect) { - - /* Player color seleciton. */ - - player[i].colourmap = ((player[i].playkeys & FLAG_MOVEUP) ? nextcolourmapn : prevcolourmapn)(model, player[i].colourmap, i); - - player[i].playkeys = 0; - } - - /* - * Player already joining. No reason to process - * any downstream logic in the scan. - */ - continue; - } - - /* - * Begin joining when the player has access to a credit. - */ - if( !nojoin && (player[i].credits || credits || (!player[i].hasplayed && noshare))) { - - if(player[i].playkeys & FLAG_START) { - player[i].lives = 0; - model = skipselect[i][0] ? findmodel(skipselect[i]) : nextplayermodeln(NULL, i); - strncpy(player[i].name, model->name, MAX_NAME_LEN); - - player[i].colourmap = (colourselect && (set->nosame & 2)) ? nextcolourmapn(model, -1, i) : 0; - - player[i].joining = 1; - player[i].disablekeys = player[i].playkeys = player[i].newkeys = player[i].releasekeys = 0; - - if(!level->noreset) { - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - } - - /* - * Player joining active game for first time - * and no credit sharing enabled. Start them - * with default number of continues before - * we deduct a credit from the player or global - * pool. - */ - if(!player[i].hasplayed && noshare) { - player[i].credits = CONTINUES; - } - - /* - * Subtract a credit from the player or global - * pool if cheats are not enabled. - */ - if(!(global_config.cheats & CHEAT_OPTIONS_CREDITS_ACTIVE)) { - - /* - * If credit sharing, deduct from the global - * pool, otherwise deduct from the player. - */ - if(noshare) { - --player[i].credits; - } else { - --credits; - } - - /* - * If continuescore is set to 1, reset the - * player's score to 0, otherwise if set to 2, - * increment the player's score by 1. - */ - if(set->continuescore == 1) { - player[i].score = 0; - } - - if(set->continuescore == 2) { - if(player[i].score < UINT64_MAX) { - player[i].score++; - } - } - } - } - } - } - - /* Get display time from time remaining and cap to 0 - 99 */ - display_time = (timeleft / global_config.counter_speed); - - if(display_time >= 99) { - display_time = 99; - oldtime = 99; - } - if(display_time <= 0) - { - display_time = 0; - oldtime = 99; - } - - if (is_total_timeover){ - timetoshow = 0; - } else { - timetoshow = display_time; - } - - if(timetoshow < oldtime || oldtime == 0) { - execute_timetick_script(timetoshow, go_time); - oldtime = timetoshow; - } - - if(display_time > 0 && !is_total_timeover) { - showtimeover = 0; - } - - - - if(go_time > _time) { - go_phase = (go_time - _time) % global_config.game_speed; - - if(go_phase < global_config.game_speed / 2) { - global_config.showgo = 1; - screen_status |= IN_SCREEN_SHOW_GO_ARROW; //Kratus (04-2022) Added the "showgo" event accessible by script - - if(gosound == 0 ) { - - if(global_sample_list.go >= 0) { - sound_play_sample(global_sample_list.go, 0, savedata.effectvol, savedata.effectvol, 100); // 26-12-2004 Play go sample as arrow flashes - } - - gosound = 1; // 26-12-2004 Sets sample as already played - stops sample repeating too much - } - - } else { - global_config.showgo = gosound = 0; //26-12-2004 Resets go sample after loop so it can be played again next time - screen_status &= ~IN_SCREEN_SHOW_GO_ARROW; //Kratus (04-2022) Added the "showgo" event accessible by script - } - - } else { - global_config.showgo = 0; - screen_status &= ~IN_SCREEN_SHOW_GO_ARROW; //Kratus (04-2022) Added the "showgo" event accessible by script - } -} - - -// Caskey, Damon V. -// 2016-11-16 -// -// Draw dot onto screen to indicate actual entity position, -// with text readout of Base, X, Y, and Z coordinates directly below. -void draw_properties_entity(entity *entity, int offset_z, int color, s_drawmethod *drawmethod) -{ - #define FONT_LABEL 1 - #define FONT_VALUE 0 - #define TEXT_MARGIN_Y 1 - #define OFFSET_LAYER -2 - - // Array keys for the list of items - // we want to display - enum - { - DRAW_PROPERTIES_KEY_NAME, - DRAW_PROPERTIES_KEY_BASE, - DRAW_PROPERTIES_KEY_POS, - DRAW_PROPERTIES_KEY_STATUS, - DRAW_PROPERTIES_ARRAY_SIZE // Array size, so always last. - }; - - typedef struct - { - s_axis_principal_int position; - s_axis_plane_vertical_int size; - } draw_coords; - - s_axis_plane_vertical_int screen_offset; // Base location calculated from screen offsets. - s_axis_plane_vertical_int base_pos; // Entity position with screen offsets applied. - draw_coords box; // On screen coords for display elements. - - int i; // Counter. - int str_offset_x; // Calculated offset of text for centering. - int label_width_max; - int str_width_max; // largest string width. - int str_height_max; // Largest string height. - size_t str_size; // Memory size of string. - - char *output_label[DRAW_PROPERTIES_ARRAY_SIZE]; - const char *output_format[DRAW_PROPERTIES_ARRAY_SIZE]; // Format ("%d, %s .."). - char *output_value[DRAW_PROPERTIES_ARRAY_SIZE]; // Final string to display position. - - // Let's build the format for information - // we want to display. - output_format[DRAW_PROPERTIES_KEY_NAME] = "%s"; - output_format[DRAW_PROPERTIES_KEY_BASE] = "%d"; - output_format[DRAW_PROPERTIES_KEY_POS] = "%d, %d, %d"; - output_format[DRAW_PROPERTIES_KEY_STATUS] = "%d, %d"; - - // Double pass method for unknown string size. - // - // 1. Build the label. - // - // 2. Attempt to copy 0 chars to unallocated - // buffer and record how many characters - // would be needed, plus 1 for the NULL terminator - // and record as a string_size. - // - // 3. Allocate memory using the string size. - // - // 4. Copy formatted string to allocated buffer - // for real. - // - // Repeat for each line item we want to display. - // - // TO: Work this into a loop. Main obstacle is - // the number of format string inputs vary depending - // on type of property. - - // Name - output_label[DRAW_PROPERTIES_KEY_NAME] = "Name: "; - output_value[DRAW_PROPERTIES_KEY_NAME] = NULL; - str_size = snprintf(output_value[DRAW_PROPERTIES_KEY_NAME], 0, output_format[DRAW_PROPERTIES_KEY_NAME], entity->model->name) + 1; - output_value[DRAW_PROPERTIES_KEY_NAME] = malloc(str_size); - snprintf(output_value[DRAW_PROPERTIES_KEY_NAME], str_size, output_format[DRAW_PROPERTIES_KEY_NAME], entity->model->name); - - // Base - output_label[DRAW_PROPERTIES_KEY_BASE] = "Base: "; - output_value[DRAW_PROPERTIES_KEY_BASE] = NULL; - str_size = snprintf(output_value[DRAW_PROPERTIES_KEY_BASE], 0, output_format[DRAW_PROPERTIES_KEY_BASE], (int)entity->base) + 1; - output_value[DRAW_PROPERTIES_KEY_BASE] = malloc(str_size); - snprintf(output_value[DRAW_PROPERTIES_KEY_BASE], str_size, output_format[DRAW_PROPERTIES_KEY_BASE], (int)entity->base); - - // XYZ - output_label[DRAW_PROPERTIES_KEY_POS] = "X,Y,Z: "; - output_value[DRAW_PROPERTIES_KEY_POS] = NULL; - str_size = snprintf(output_value[DRAW_PROPERTIES_KEY_POS], 0, output_format[DRAW_PROPERTIES_KEY_POS], (int)entity->position.x, (int)entity->position.y, (int)entity->position.z) + 1; - output_value[DRAW_PROPERTIES_KEY_POS] = malloc(str_size); - snprintf(output_value[DRAW_PROPERTIES_KEY_POS], str_size, output_format[DRAW_PROPERTIES_KEY_POS], (int)entity->position.x, (int)entity->position.y, (int)entity->position.z); - - // HP & MP - output_label[DRAW_PROPERTIES_KEY_STATUS] = "HP, MP: "; - output_value[DRAW_PROPERTIES_KEY_STATUS] = NULL; - str_size = snprintf(output_value[DRAW_PROPERTIES_KEY_STATUS], 0, output_format[DRAW_PROPERTIES_KEY_STATUS], (int)entity->energy_state.health_current, (int)entity->energy_state.mp_current) + 1; - output_value[DRAW_PROPERTIES_KEY_STATUS] = malloc(str_size); - snprintf(output_value[DRAW_PROPERTIES_KEY_STATUS], str_size, output_format[DRAW_PROPERTIES_KEY_STATUS], (int)entity->energy_state.health_current, (int)entity->energy_state.mp_current); - - - // Get the largest string X and Y space. For X find the largest - // label and value, then add them. For Y, just get height of - // largest font. - label_width_max = font_string_width_max(output_label, DRAW_PROPERTIES_ARRAY_SIZE, FONT_LABEL); - str_width_max = label_width_max + font_string_width_max(output_value, DRAW_PROPERTIES_ARRAY_SIZE, FONT_VALUE); - - if (fontheight(FONT_LABEL) > fontheight(FONT_VALUE)) - { - str_height_max = fontheight(FONT_LABEL); - } - else - { - str_height_max = fontheight(FONT_VALUE); - } - - // Get our base offsets from screen vs. location. - screen_offset.x = screenx - ((entity->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_x_offset); - screen_offset.y = screeny - ((entity->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_y_offset); - - // Get entity position with screen offsets. - base_pos.x = entity->position.x - screen_offset.x; - base_pos.y = (entity->position.z - offset_z) - entity->position.y - screen_offset.y; - - // Get a value of half the text width. - // We can use this to center our text - // on the entity. - str_offset_x = str_width_max / 2; - - // Apply text offset. - box.position.x = base_pos.x - str_offset_x; - - box.position.y = base_pos.y; - box.position.z = entity->position.z + offset_z; - - // Draw position dot. - // The +1 to Z is a quick fix - offset_z - // distorts the dot's vertical position - // instead of just adjusting Z. - spriteq_add_dot(base_pos.x, base_pos.y, box.position.z+1, color, drawmethod); - - // Print each item text. - for(i = 0; i < DRAW_PROPERTIES_ARRAY_SIZE; i++) - { - // If the item string exists then - // we can find a position, print it to - // the screen, and free up allocated memory. - if(output_value[i]) - { - // Add font height and margin to Y position. - base_pos.y += (str_height_max + TEXT_MARGIN_Y); - - // Print label to the screen. The value X - // position adds maximum label width, plus - // 25% the width a single value character. - font_printf(box.position.x, base_pos.y, FONT_LABEL, OFFSET_LAYER, output_label[i]); - font_printf(box.position.x + label_width_max + (fontmonowidth(FONT_VALUE) * 0.25), base_pos.y, FONT_VALUE, OFFSET_LAYER, output_value[i]); - - // Release memory allocated for the value strings. - free(output_value[i]); - } - } - - return; - - // Remove local constants. - #undef FONT - #undef TEXT_MARGIN_Y - #undef OFFSET_LAYER -} - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Screen-space debug box coordinates. -*/ -typedef struct s_debug_draw_box { - s_axis_principal_int position; - s_axis_plane_vertical_int size; -} s_debug_draw_box; - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Convert an entity-relative box into screen-space -* draw coordinates. -*/ -static void debug_box_get_screen_coordinates(entity* const target_entity, - const int pos_x, - const int pos_y, - const int pos_z, - const int size_w, - const int size_h, - const int offset_z, - s_debug_draw_box* const box) { - - s_axis_plane_vertical_int screen_offset; - s_axis_plane_vertical_int base_pos; - - /* - * Guard against invalid targets. The caller should - * already validate these, but keep this helper safe. - */ - if (!target_entity || !box) { - return; - } - - /* - * Get our base offsets from screen vs. world location. - */ - screen_offset.x = screenx - ((target_entity->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_x_offset); - screen_offset.y = screeny - ((target_entity->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_y_offset); - - /* - * Convert entity world position to screen position. - */ - base_pos.x = target_entity->position.x - screen_offset.x; - base_pos.y = (target_entity->position.z - offset_z) - target_entity->position.y - screen_offset.y; - - /* - * Apply box coordinates. - */ - box->size.x = size_w - pos_x; - - /* - * Accommodate entity direction. - */ - if (target_entity->direction == DIRECTION_RIGHT) { - box->position.x = base_pos.x + pos_x; - } - else { - box->position.x = base_pos.x - (box->size.x + pos_x); - } - - box->position.y = base_pos.y + pos_y; - box->size.y = (base_pos.y + size_h) - box->position.y; - box->position.z = pos_z + offset_z; -} - -/* -* Convert an entity-relative box into screen-space coordinates, -* then apply visual-only perspective offset while preserving -* the requested draw layer. -*/ -static void debug_box_get_screen_coordinates_at_layer(entity* const target_entity, - const int pos_x, - const int pos_y, - const int draw_layer, - const int size_w, - const int size_h, - const int visual_offset_x, - const int visual_offset_y, - s_debug_draw_box* const box) { - - if (!box) { - return; - } - - debug_box_get_screen_coordinates( - target_entity, - pos_x, - pos_y, - draw_layer, - size_w, - size_h, - 0, - box); - - box->position.x += visual_offset_x; - box->position.y += visual_offset_y; - box->position.z = draw_layer; -} - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Draw a filled transparent debug box with a hard -* one-pixel border in the same color. -*/ -static void debug_box_draw_filled_with_border(const s_debug_draw_box* const box, const int color, s_drawmethod* const drawmethod) { - int far_x; - int far_y; - - if (!box) { - return; - } - - /* - * Draw the transparent fill first. - */ - spriteq_add_box( - box->position.x, - box->position.y, - box->size.x, - box->size.y, - box->position.z, - color, - drawmethod); - - /* - * Then draw a hard outline over the fill. - */ - far_x = box->position.x + (box->size.x - 1); - far_y = box->position.y + box->size.y; - - spriteq_add_line(box->position.x, box->position.y, far_x, box->position.y, box->position.z, color, NULL); /* Top. */ - spriteq_add_line(box->position.x, far_y, far_x, far_y, box->position.z, color, NULL); /* Bottom. */ - spriteq_add_line(box->position.x, box->position.y, box->position.x, far_y, box->position.z, color, NULL); /* Left. */ - spriteq_add_line(far_x, box->position.y, far_x, far_y, box->position.z, color, NULL); /* Right. */ -} - -/* -* Caskey, Damon V. -* 2016-11-16 -* -* Convert an entity-relative box to screen-space and -* draw it as a transparent rectangle with a hard border. -*/ -void draw_box_on_entity(entity* entity, int pos_x, int pos_y, int pos_z, int size_w, int size_h, int offset_z, int color, s_drawmethod* drawmethod) { - s_debug_draw_box box = { 0 }; - - debug_box_get_screen_coordinates( - entity, - pos_x, - pos_y, - pos_z, - size_w, - size_h, - offset_z, - &box); - - debug_box_draw_filled_with_border(&box, color, drawmethod); -} - -/* -* Caskey, Damon V. -* 2026-07-06 -* -* Draw a wireframe rectangle from prepared debug box coordinates. -*/ -static void debug_box_draw_wireframe(const s_debug_draw_box* const box, const int color, s_drawmethod* const drawmethod) { - int left; - int right; - int top; - int bottom; - int layer; - - if (!box) { - return; - } - - left = box->position.x; - top = box->position.y; - right = box->position.x + box->size.x - 1; - bottom = box->position.y + box->size.y - 1; - layer = box->position.z; - - spriteq_add_line(left, top, right, top, layer, color, drawmethod); - spriteq_add_line(right, top, right, bottom, layer, color, drawmethod); - spriteq_add_line(right, bottom, left, bottom, layer, color, drawmethod); - spriteq_add_line(left, bottom, left, top, layer, color, drawmethod); -} - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Draw a collision hitbox as a simple perspective cube. -* -* The entity's own Z position is the visual and draw-layer -* anchor. Higher draw-layer values are closer to the screen. -* -* Background Z is drawn behind the entity's Z layer. -* Foreground Z is drawn in front of the entity's Z layer. -* -* The screen-space perspective offset is intentionally -* illustrative. It keeps the true X/Y extent centered around -* the entity's Z position while making the depth readable. -* -* 2026-07-02: Disabled until debug menu option implemented. -*/ -static void draw_collision_cube_on_entity(entity* const target_entity, - const s_hitbox* const coords, - const int color, - s_drawmethod* const drawmethod) { - - s_debug_draw_box back_box = { 0 }; - s_debug_draw_box front_box = { 0 }; - - int entity_z; - int z_background; - int z_foreground; - int z_depth; - - int perspective_x_sign; - int perspective_offset_back; - int perspective_offset_front; - int back_layer; - int front_layer; - - int back_left; - int back_right; - int back_top; - int back_bottom; - - int front_left; - int front_right; - int front_top; - int front_bottom; - - if (!target_entity || !coords) { - return; - } - - entity_z = target_entity->position.z; - - z_background = coords->z_background; - z_foreground = coords->z_foreground; - - if (z_background < 0) { - z_background = 0; - } - - if (z_foreground < 0) { - z_foreground = 0; - } - - z_depth = z_background + z_foreground; - - back_layer = entity_z - z_background; - front_layer = entity_z + z_foreground; - - /* - * No depth - draw a wireframe rectangle only. - */ - if (z_depth < 1) { - debug_box_get_screen_coordinates_at_layer( - target_entity, - coords->x, - coords->y, - entity_z + 1, - coords->width, - coords->height, - 0, - 0, - &front_box); - - debug_box_draw_wireframe(&front_box, color, NULL); - return; - } - - /* - * Visual-only perspective. Keep this independent from - * the true Z layer. - * - */ - perspective_offset_back = z_background / 4; - perspective_offset_front = z_foreground / 4; - - if (z_background > 0 && perspective_offset_back < 1) { - perspective_offset_back = 1; - } - - if (z_foreground > 0 && perspective_offset_front < 1) { - perspective_offset_front = 1; - } - - /* - * Mirror only the visual perspective X offset. - * The collision box coordinate conversion already handles - * entity direction, so do not modify coords->x or coords->width. - */ - perspective_x_sign = (target_entity->direction == DIRECTION_RIGHT) ? 1 : -1; - - /* - * Back face: projected from entity Z toward background. - * Front face: projected from entity Z toward foreground. - */ - debug_box_get_screen_coordinates_at_layer( - target_entity, - coords->x, - coords->y, - back_layer, - coords->width, - coords->height, - perspective_offset_back * perspective_x_sign, - -perspective_offset_back, - &back_box); - - debug_box_get_screen_coordinates_at_layer( - target_entity, - coords->x, - coords->y, - front_layer, - coords->width, - coords->height, - -perspective_offset_front * perspective_x_sign, - perspective_offset_front, - &front_box); - - debug_box_draw_wireframe(&back_box, color, NULL); - debug_box_draw_wireframe(&front_box, color, NULL); - - back_left = back_box.position.x; - back_top = back_box.position.y; - back_right = back_box.position.x + back_box.size.x - 1; - back_bottom = back_box.position.y + back_box.size.y - 1; - - front_left = front_box.position.x; - front_top = front_box.position.y; - front_right = front_box.position.x + front_box.size.x - 1; - front_bottom = front_box.position.y + front_box.size.y - 1; - - /* - * Connector lines use the front layer so they remain visible. - */ - spriteq_add_line(back_left, back_top, front_left, front_top, front_layer, color, NULL); - spriteq_add_line(back_right, back_top, front_right, front_top, front_layer, color, NULL); - spriteq_add_line(back_left, back_bottom, front_left, front_bottom, front_layer, color, NULL); - spriteq_add_line(back_right, back_bottom, front_right, front_bottom, front_layer, color, NULL); -} - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Draw every active collision box in a collection -* for visual debug output. -*/ -static void draw_visual_collision_collection(entity* const target_entity, - const s_collision_collection* const collection, - const int color, - s_drawmethod* const drawmethod, - const e_debug_display flat_bit, - const e_debug_display projected_bit) { - - const s_collision_instance* collision = NULL; - const s_hitbox* coords = NULL; - uint64_t active_status; - int collision_index; - - if (!target_entity || !collection || !collection->active_status) { - return; - } - - active_status = collection->active_status; - - while (active_status) { - collision_index = collision_get_lowest_active_index(active_status); - active_status &= active_status - 1; - - collision = collection->slots[collision_index]; - - if (!collision) { - continue; - } - - coords = &collision->coords; - - if (!collision_check_has_coords(coords)) { - continue; - } - - if (savedata.debuginfo & flat_bit) { - draw_box_on_entity( - target_entity, - coords->x, - coords->y, - target_entity->position.z + 1, - coords->width, - coords->height, - 2, - color, - drawmethod); - } - - if (savedata.debuginfo & projected_bit) { - draw_collision_cube_on_entity( - target_entity, - coords, - color, - drawmethod); - } - } -} - -/* -* Caskey, Damon V. -* Unknown date ~2018 -* -* Draw collision on screen as visual boxes. -*/ -void draw_visual_debug(void) { - #define LOCAL_COLOR_BLUE _makecolour(0, 0, 255) - #define LOCAL_COLOR_GREEN _makecolour(0, 255, 0) - #define LOCAL_COLOR_MAGENTA _makecolour(255, 0, 255) - #define LOCAL_COLOR_WHITE _makecolour(255, 255, 255) - - int entity_index; - int range_y_min = 0; - int range_y_max = 0; - int animation_frame = 0; - - s_drawmethod drawmethod = plainmethod; - s_collision_collection* collection = NULL; - entity* target_entity = NULL; - - drawmethod.alpha = BLEND_MODE_ALPHA; - - for (entity_index = 0; entity_index < ent_max; entity_index++) { - target_entity = ent_list[entity_index]; - - /* - * Entity must exist. - */ - if (!target_entity) { - continue; - } - - /* - * Entity must be alive. - */ - if (target_entity->death_state & DEATH_STATE_DEAD) { - continue; - } - - /* - * Most visual debug drawing depends on animation - * frame data. - */ - if (!target_entity->animation) { - continue; - } - - animation_frame = target_entity->animpos; - - /* - * Protect collision frame table lookups. - */ - if (animation_frame < 0 || animation_frame >= target_entity->animation->numframes) { - continue; - } - - /* - * Basic properties: name, position, HP, etc. - */ - if (savedata.debuginfo & DEBUG_DISPLAY_PROPERTIES) { - draw_properties_entity(target_entity, 0, LOCAL_COLOR_WHITE, NULL); - } - - /* - * Range debug requested? - */ - if (savedata.debuginfo & DEBUG_DISPLAY_RANGE) { - - /* - * Range is calculated a bit differently than - * body/attack boxes. For Y axis, invert the - * value and place min/max into the opposite - * drawing parameters. - */ - range_y_min = -target_entity->animation->range.y.min; - range_y_max = -target_entity->animation->range.y.max; - - draw_box_on_entity( - target_entity, - target_entity->animation->range.x.min, - range_y_max, - target_entity->position.z + 1, - target_entity->animation->range.x.max, - range_y_min, - -1, - LOCAL_COLOR_GREEN, - &drawmethod); - } - - /* - * Collision attack debug requested? - */ - if ((savedata.debuginfo & (DEBUG_DISPLAY_COLLISION_ATTACK_2D | DEBUG_DISPLAY_COLLISION_ATTACK_3D)) - && target_entity->animation->collision_attack) { - - collection = target_entity->animation->collision_attack[animation_frame]; - - draw_visual_collision_collection( - target_entity, - collection, - LOCAL_COLOR_MAGENTA, - &drawmethod, - DEBUG_DISPLAY_COLLISION_ATTACK_2D, - DEBUG_DISPLAY_COLLISION_ATTACK_3D); - } - - /* - * Collision body debug requested? - */ - if ((savedata.debuginfo & (DEBUG_DISPLAY_COLLISION_BODY_2D | DEBUG_DISPLAY_COLLISION_BODY_3D)) - && target_entity->animation->collision_body) { - - collection = target_entity->animation->collision_body[animation_frame]; - - draw_visual_collision_collection( - target_entity, - collection, - LOCAL_COLOR_BLUE, - &drawmethod, - DEBUG_DISPLAY_COLLISION_BODY_2D, - DEBUG_DISPLAY_COLLISION_BODY_3D); - } - - if ((savedata.debuginfo & (DEBUG_DISPLAY_COLLISION_SPACE_2D | DEBUG_DISPLAY_COLLISION_SPACE_3D)) - && target_entity->animation->collision_space) { - - collection = target_entity->animation->collision_space[animation_frame]; - - draw_visual_collision_collection( - target_entity, - collection, - LOCAL_COLOR_GREEN, - &drawmethod, - DEBUG_DISPLAY_COLLISION_SPACE_2D, - DEBUG_DISPLAY_COLLISION_SPACE_3D); - } - } - - #undef LOCAL_COLOR_BLUE - #undef LOCAL_COLOR_GREEN - #undef LOCAL_COLOR_MAGENTA - #undef LOCAL_COLOR_WHITE -} - - -void predrawstatus() -{ - - int icon = 0; - int i; - uint64_t tmp; - s_set_entry *set = levelsets + current_set; - s_model *model = NULL; - s_drawmethod drawmethod = plainmethod; - - if(bgicon >= 0) - { - spriteq_add_sprite(videomodes.hShift + bgicon_offsets[0], savedata.windowpos + bgicon_offsets[1], bgicon_offsets[2], bgicon, NULL, 0); - } - if(olicon >= 0) - { - spriteq_add_sprite(videomodes.hShift + olicon_offsets[0], savedata.windowpos + olicon_offsets[1], olicon_offsets[2], olicon, NULL, 0); - } - - for(i = 0; i < set->maxplayers; i++) - { - if(player[i].ent) - { - tmp = player[i].score; //work around issue on 64bit where sizeof(long) != sizeof(int) - if(!pscore[i][2] && !pscore[i][3] && !pscore[i][4] && !pscore[i][5]) - { - font_printf(videomodes.shiftpos[i] + pscore[i][0], savedata.windowpos + pscore[i][1], pscore[i][6], 0, (scoreformat ? "%s - %09" PRIu64 : "%s - %" PRIu64), (char *)(player[i].ent->name), tmp); - } - else - { - font_printf(videomodes.shiftpos[i] + pscore[i][0], savedata.windowpos + pscore[i][1], pscore[i][6], 0, "%s", player[i].ent->name); - font_printf(videomodes.shiftpos[i] + pscore[i][2], savedata.windowpos + pscore[i][3], pscore[i][6], 0, "-"); - font_printf(videomodes.shiftpos[i] + pscore[i][4], savedata.windowpos + pscore[i][5], pscore[i][6], 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), tmp); - } - - if(player[i].ent->energy_state.health_current <= 0) - { - icon = player[i].ent->modeldata.icon.die; - } - else if(player[i].ent->inpain & IN_PAIN_HIT) - { - icon = player[i].ent->modeldata.icon.pain; - } - else if(player[i].ent->getting) - { - icon = player[i].ent->modeldata.icon.get; - } - else - { - icon = player[i].ent->modeldata.icon.def; - } - - if(icon >= 0) - { - drawmethod.table = player[i].ent->modeldata.icon.usemap ? player[i].ent->colourmap : NULL; - spriteq_add_sprite(videomodes.shiftpos[i] + picon[i][0], savedata.windowpos + picon[i][1], 10000, icon, &drawmethod, 0); - } - - if(player[i].ent->weapent) - { - if(player[i].ent->weapent->modeldata.icon.weapon >= 0) - { - drawmethod.table = player[i].ent->weapent->modeldata.icon.usemap ? player[i].ent->weapent->colourmap : NULL; - spriteq_add_sprite(videomodes.shiftpos[i] + piconw[i][0], savedata.windowpos + piconw[i][1], 10000, player[i].ent->weapent->modeldata.icon.weapon, &drawmethod, 0); - } - - if(player[i].ent->weapent->modeldata.weapon_properties.weapon_state & WEAPON_STATE_LIMITED_USE && player[i].ent->weapent->modeldata.weapon_properties.use_count) - { - font_printf(videomodes.shiftpos[i] + pshoot[i][0], savedata.windowpos + pshoot[i][1], pshoot[i][2], 0, "%u", player[i].ent->weapent->modeldata.weapon_properties.use_count); - } - } - - /* - * If the player has MP, let's try to generate - * icons as well. - */ - - if (player[i].ent->modeldata.mp) { - - drawmethod.table = player[i].ent->modeldata.icon.usemap ? player[i].ent->colourmap : NULL; - - const float mp_percentage = (float)player[i].ent->energy_state.mp_old / player[i].ent->modeldata.mp; - - int mp_icon_sprite = ICON_NONE; - - if (mp_percentage <= 0.0 && player[i].ent->modeldata.icon.mpnone != ICON_NONE){ - mp_icon_sprite = player[i].ent->modeldata.icon.mpnone; - } - else if (mp_percentage < 0.25 && player[i].ent->modeldata.icon.mplow != ICON_NONE){ - mp_icon_sprite = player[i].ent->modeldata.icon.mplow; - } - else if (mp_percentage < 0.75 && player[i].ent->modeldata.icon.mpmed != ICON_NONE){ - mp_icon_sprite = player[i].ent->modeldata.icon.mpmed; - } - else if (mp_percentage < 1.0 && player[i].ent->modeldata.icon.mphigh != ICON_NONE){ - mp_icon_sprite = player[i].ent->modeldata.icon.mphigh; - } - else if (mp_percentage >= 1.0 && player[i].ent->modeldata.icon.mpmax != ICON_NONE){ - mp_icon_sprite = player[i].ent->modeldata.icon.mpmax; - } - - /* - * Draw an icon if we found one. - */ - if (mp_icon_sprite > 0) - { - spriteq_add_sprite(videomodes.shiftpos[i] + mpicon[i][0], savedata.windowpos + mpicon[i][1], 10000, mp_icon_sprite, &drawmethod, 0); - } - } - - font_printf(videomodes.shiftpos[i] + plifeX[i][0], savedata.windowpos + plifeX[i][1], plifeX[i][2], 0, "x"); - font_printf(videomodes.shiftpos[i] + plifeN[i][0], savedata.windowpos + plifeN[i][1], plifeN[i][2], 0, "%i", player[i].lives); - - if(rush[0] && player[i].ent->rush.count > 1 && _time <= player[i].ent->rush.time) - { - font_printf(videomodes.shiftpos[i] + prush[i][0], prush[i][1], rush[2], 0, "%s", rush_names[0]); - font_printf(videomodes.shiftpos[i] + prush[i][2], prush[i][3], rush[3], 0, "%i", player[i].ent->rush.count); - - if(rush[0] != 2) - { - font_printf(videomodes.shiftpos[i] + prush[i][4], prush[i][5], rush[4], 0, "%s", rush_names[1]); - font_printf(videomodes.shiftpos[i] + prush[i][6], prush[i][7], rush[5], 0, "%i", player[i].ent->rush.max); - } - } - - if(rush[0] == 2) - { - font_printf(videomodes.shiftpos[i] + prush[i][4], prush[i][5], rush[4], 0, "%s", rush_names[1]); - font_printf(videomodes.shiftpos[i] + prush[i][6], prush[i][7], rush[5], 0, "%i", player[i].ent->rush.max); - } - - if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife) - { - // Displays life unless overridden by flag - font_printf(videomodes.shiftpos[i] + ename[i][0], savedata.windowpos + ename[i][1], ename[i][2], 0, player[i].ent->opponent->name); - if(player[i].ent->opponent->energy_state.health_current <= 0) - { - icon = player[i].ent->opponent->modeldata.icon.die; - } - else if(player[i].ent->opponent->inpain & IN_PAIN_HIT) - { - icon = player[i].ent->opponent->modeldata.icon.pain; - } - else if(player[i].ent->opponent->getting) - { - icon = player[i].ent->opponent->modeldata.icon.get; - } - else - { - icon = player[i].ent->opponent->modeldata.icon.def; - } - - if(icon >= 0) - { - drawmethod.table = player[i].ent->opponent->modeldata.icon.usemap ? player[i].ent->opponent->colourmap : NULL; - spriteq_add_sprite(videomodes.shiftpos[i] + eicon[i][0], savedata.windowpos + eicon[i][1], 10000, icon, &drawmethod, 0); // Feb 26, 2005 - Changed to opponent->map so icons don't pallete swap with die animation - } - } - } - else if(player[i].joining && player[i].name[0]) - { - model = findmodel(player[i].name); - font_printf(videomodes.shiftpos[i] + pnameJ[i][0], savedata.windowpos + pnameJ[i][1], pnameJ[i][6], 0, player[i].name); - if(nojoin) - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][2], savedata.windowpos + pnameJ[i][3], pnameJ[i][6], 0, Tr("Please Wait")); - } - else - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][2], savedata.windowpos + pnameJ[i][3], pnameJ[i][6], 0, Tr("Select Hero")); - } - icon = model->icon.def; - - if(icon >= 0) - { - drawmethod.table = model->icon.usemap ? model_get_colourmap(model, player[i].colourmap) : NULL; - spriteq_add_sprite(videomodes.shiftpos[i] + picon[i][0], picon[i][1], 10000, icon, &drawmethod, 0); - } - } - else if(player[i].credits || credits || (!player[i].hasplayed && noshare)) - { - if(player[i].credits && ((_time / (global_config.game_speed * 2)) & 1)) - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("Credit %i"), player[i].credits); - } - else if(credits && ((_time / (global_config.game_speed * 2)) & 1)) - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("Credit %i"), credits); - } - else if(!player[i].hasplayed && ((_time / (global_config.game_speed * 2)) & 1)) - { - int showcredits = (!noshare) ? credits : CONTINUES; - - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("Credit %i"), showcredits); - } - else if(nojoin) - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("Please Wait")); - } - else - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("Press Start")); - } - } - else - { - font_printf(videomodes.shiftpos[i] + pnameJ[i][4], savedata.windowpos + pnameJ[i][5], pnameJ[i][6], 0, Tr("GAME OVER")); - } - }// end of for - - // If any of the debug flags are enabled, let's - // output debug data to end user. - if(savedata.debuginfo) - { - draw_visual_debug(); - } - - if(timeicon >= 0) - { - spriteq_add_sprite(videomodes.hShift + timeicon_offsets[0], savedata.windowpos + timeicon_offsets[1], 10000, timeicon, NULL, 0); - } - if(!level->notime) - { - font_printf(videomodes.hShift + timeloc[0] + 2, savedata.windowpos + timeloc[1] + 2, timeloc[5], 0, "%02i", timetoshow); - } - if(showtimeover) - { - font_printf(videomodes.hShift + 113, videomodes.vShift + savedata.windowpos + 110, timeloc[5], 0, Tr("TIME OVER")); - } - - if(global_config.showgo) - { - if(level->scrolldir & SCROLL_LEFT) //TODO: upward and downward go - { - - if(golsprite >= 0) - { - spriteq_add_sprite(40, 60 + videomodes.vShift, 10000, golsprite, NULL, 0); // new sprite for left direction - } - else - { - drawmethod.table = 0; - drawmethod.config |= DRAWMETHOD_CONFIG_FLIP_X; - spriteq_add_sprite(40, 60 + videomodes.vShift, 10000, gosprite, &drawmethod, 0); - } - } - else if(level->scrolldir & SCROLL_RIGHT) - { - spriteq_add_sprite(videomodes.hRes - 40, 60 + videomodes.vShift, 10000, gosprite, NULL, 0); - } - } - - // Performance info. - if(savedata.debuginfo & DEBUG_DISPLAY_PERFORMANCE) - { - spriteq_add_box(0, videomodes.dOffset - 12, videomodes.hRes, videomodes.dOffset + 12, LAYER_Z_LIMIT_BOX_MAX, 0, NULL); - font_printf(2, videomodes.dOffset - 10, 0, LAYER_Z_LIMIT_MAX, Tr("FPS: %03d"), getFPS()); - font_printf(videomodes.hRes / 2, videomodes.dOffset - 10, 0, LAYER_Z_LIMIT_MAX, Tr("Free Ram: %s KB"), commaprint(freeram / KBYTES)); - font_printf(2, videomodes.dOffset, 0, LAYER_Z_LIMIT_MAX, Tr("Sprites: %d / %d"), spriteq_get_sprite_count(), spriteq_get_sprite_max()); - font_printf(videomodes.hRes / 2, videomodes.dOffset, 0, LAYER_Z_LIMIT_MAX, Tr("Used Ram: %s KB"), commaprint(usedram / KBYTES)); - } -} - -/* -* Caskey, Damon V. -* 2023-03-08 -* -* Allocate an object. -*/ -s_barstatus* bar_status_allocate_object() -{ - s_barstatus* result; - - /* Allocate memory with 0 values and get the pointer. */ - result = calloc(1, sizeof(*result)); - - return result; -} - -// draw boss status on screen -void drawenemystatus(entity *ent) -{ - s_drawmethod drawmethod; - s_barstatus* status; - int icon; - - status = ent->modeldata.hud_popup; - - if(status->name_position.x > -1000 && status->name_position.y > -1000) - { - font_printf(status->name_position.x, status->name_position.y, 0, 0, "%s", ent->name); - } - - if(ent->modeldata.icon.position.x > -1000 && ent->modeldata.icon.position.y > -1000) - { - if(ent->energy_state.health_current <= 0) - { - icon = ent->modeldata.icon.die; - } - else if(ent->inpain & IN_PAIN_HIT) - { - icon = ent->modeldata.icon.pain; - } - else if(ent->getting) - { - icon = ent->modeldata.icon.get; - } - else - { - icon = ent->modeldata.icon.def; - } - - if(icon >= 0) - { - drawmethod = plainmethod; - drawmethod.table = ent->modeldata.icon.usemap ? ent->colourmap : NULL; - spriteq_add_sprite(ent->modeldata.icon.position.x, ent->modeldata.icon.position.y, HUD_Z, icon, &drawmethod, 0); - } - } - - if(ent->modeldata.health && status->graph_position.x > -1000 && status->graph_position.y > -1000) - { - bar(status->graph_position.x, status->graph_position.y, ent->energy_state.health_old, ent->modeldata.health, status); - } -} - - -void drawstatus() -{ - int i; - - for(i = 0; i < MAX_PLAYERS; i++) - { - if(player[i].ent) - { - // Health bars - bar(videomodes.shiftpos[i] + plife[i][0], savedata.windowpos + plife[i][1], player[i].ent->energy_state.health_old, player[i].ent->modeldata.health, &lbarstatus); - if(player[i].ent->opponent && !player[i].ent->opponent->modeldata.nolife && player[i].ent->opponent->modeldata.health) - { - bar(videomodes.shiftpos[i] + elife[i][0], savedata.windowpos + elife[i][1], player[i].ent->opponent->energy_state.health_old, player[i].ent->opponent->modeldata.health, &olbarstatus); // Tied in with the nolife flag - } - // Draw mpbar - if(player[i].ent->modeldata.mp) - { - bar(videomodes.shiftpos[i] + pmp[i][0], savedata.windowpos + pmp[i][1], player[i].ent->energy_state.mp_old, player[i].ent->modeldata.mp, &mpbarstatus); - } - } - } - - // Time box - if(!level->notime && !timeloc[4]) // Only draw if notime is set to 0 or not specified - { - spriteq_add_line(videomodes.hShift + timeloc[0], savedata.windowpos + timeloc[1], videomodes.hShift + timeloc[0] + timeloc[2], savedata.windowpos + timeloc[1], HUD_Z, color_black, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0], savedata.windowpos + timeloc[1], videomodes.hShift + timeloc[0], savedata.windowpos + timeloc[1] + timeloc[3], HUD_Z, color_black, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0] + timeloc[2], savedata.windowpos + timeloc[1], videomodes.hShift + timeloc[0] + timeloc[2], savedata.windowpos + timeloc[1] + timeloc[3], HUD_Z, color_black, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0], savedata.windowpos + timeloc[1] + timeloc[3], videomodes.hShift + timeloc[0] + timeloc[2], savedata.windowpos + timeloc[1] + timeloc[3], HUD_Z, color_black, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0] - 1, savedata.windowpos + timeloc[1] - 1, videomodes.hShift + timeloc[0] + timeloc[2] - 1, savedata.windowpos + timeloc[1] - 1, HUD_Z + 1, color_white, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0] - 1, savedata.windowpos + timeloc[1] - 1, videomodes.hShift + timeloc[0] - 1, savedata.windowpos + timeloc[1] + timeloc[3] - 1, HUD_Z + 1, color_white, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0] + timeloc[2] - 1, savedata.windowpos + timeloc[1] - 1, videomodes.hShift + timeloc[0] + timeloc[2] - 1, savedata.windowpos + timeloc[1] + timeloc[3] - 1, HUD_Z + 1, color_white, NULL); - spriteq_add_line(videomodes.hShift + timeloc[0] - 1, savedata.windowpos + timeloc[1] + timeloc[3] - 1, videomodes.hShift + timeloc[0] + timeloc[2] - 1, savedata.windowpos + timeloc[1] + timeloc[3] - 1, HUD_Z + 1, color_white, NULL); - } -} - -void update_loading(s_loadingbar *s, int value, int max) -{ - static uint64_t lasttick = 0; - static uint64_t soundtick = 0; - static uint64_t keybtick = 0; - int pos_x = s->bar_position.x + videomodes.hShift; - int pos_y = s->bar_position.y + videomodes.vShift; - int size_x = s->bsize; - int text_x = s->text_position.x + videomodes.hShift; - int text_y = s->text_position.y + videomodes.vShift; - uint64_t ticks = timer_gettick(); - - if(ticks - soundtick > 20) - { - sound_update_music(); - soundtick = ticks; - } - - if(ticks - keybtick > 250) - { - control_update(playercontrolpointers, 1); // Respond to exit and/or fullscreen requests from user/OS - keybtick = ticks; - } - - - if(ticks - lasttick > s->refreshMs || value < 0 || value == max) // Negative value forces a repaint. used when only bg is drawn for the first time - { - spriteq_clear(); - execute_loading_script(value, max); - if(s->set) - { - if (value < 0) - { - value = 0; - } - if(isLoadingScreenTypeBar(s->set)) - { - loadingbarstatus.size.x = size_x; - bar(pos_x, pos_y, value, max, &loadingbarstatus); - } - font_printf(text_x, text_y, s->tf, 0, Tr("Loading...")); - if(isLoadingScreenTypeBg(s->set)) - { - if(background) - { - putscreen(vscreen, background, 0, 0, NULL); - } - else - { - clearscreen(vscreen); - } - } - spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0); - video_copy_screen(vscreen); - spriteq_clear(); - } - else if(value < 0) // Original BOR v1.0029 used this method. Since loadingbg is optional, we should print this one again. - { - clearscreen(vscreen); - font_printf(120 + videomodes.hShift, 110 + videomodes.vShift, 0, 0, Tr("Loading...")); - spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0); - video_copy_screen(vscreen); - spriteq_clear(); - } - lasttick = ticks; - } -} - -/* -* Caskey, Damon V. -* 2026-08-20 -* -* Apply a signed 64-bit score adjustment to an unsigned -* player score. Saturate at zero or UINT64_MAX, award -* crossed life thresholds without an unbounded loop, and -* execute the player's score script. -*/ -void addscore(int playerindex, int64_t add) -{ - uint64_t add_magnitude = 0; - uint64_t life_awards = 0; - uint64_t old_score = 0; - uint64_t s = 0; - ScriptVariant var; // used for execute script - Script *cs; - - if(playerindex < 0) - { - return; //dont score if <0, e.g., npc damage enemy, enemy damage enemy - } - - playerindex &= 3; - - old_score = player[playerindex].score; - s = old_score; - cs = score_script + playerindex; - - if(add >= 0) - { - add_magnitude = (uint64_t)add; - - if(add_magnitude > UINT64_MAX - s) - { - s = UINT64_MAX; - } - else - { - s += add_magnitude; - } - } - else - { - add_magnitude = add == INT64_MIN - ? (uint64_t)INT64_MAX + UINT64_C(1) - : (uint64_t)-add; - - s = add_magnitude > s ? 0 : s - add_magnitude; - } - - /* - * Preserve the legacy strict threshold comparison: a - * life is awarded only after score exceeds the boundary. - */ - if(lifescore > 0 && s > old_score) - { - life_awards = ((s - 1) / lifescore) - (old_score / lifescore); - } - - if(life_awards > 0) - { - if(global_sample_list.one_up >= 0) - { - sound_play_sample(global_sample_list.one_up, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(life_awards > UINT64_MAX - player[playerindex].lives) - { - player[playerindex].lives = UINT64_MAX; - } - else - { - player[playerindex].lives += life_awards; - } - } - - player[playerindex].score = s; - - //execute a script then - if(Script_IsInitialized(cs)) - { - ScriptVariant_Init(&var); - ScriptVariant_ChangeType(&var, VT_INTEGER64); - var.llVal = add; - Script_Set_Local_Variant(cs, "score", &var); - Script_Execute(cs); - ScriptVariant_Clear(&var); - Script_Set_Local_Variant(cs, "score", &var); - } - - execute_score_script_all(playerindex, add); -} - - - - -// ---------------------------- Object handling ------------------------------ - -void free_ent(entity *e) -{ - if(!e) { - return; - } - - recursive_effect_free_collection(e); - - clear_all_scripts(e->scripts, 2); - free_all_scripts(&e->scripts); - - // Item properties. - if(e->item_properties) { - free(e->item_properties); - e->item_properties = NULL; - } - - if(e->waypoints) { - free(e->waypoints); - e->waypoints = NULL; - } - if(e->defense) { - defense_free_object(e->defense); - e->defense = NULL; - } - if(e->offense) { - offense_free_object(e->offense); - e->offense = NULL; - } - - if (e->drawmethod) { - free(e->drawmethod); - e->drawmethod = NULL; - } - - if(e->varlist) { - // Although free_ent will be only called once when the engine is shutting down, - // just clear those in case we forget something - Varlist_Clear(e->varlist); - free(e->varlist); - e->varlist = NULL; - } - free(e); - e = NULL; -} - -void free_ents() -{ - int i; - if(!ent_list) - { - return; - } - for(i = 0; i < ent_list_size; i++) - { - free_ent(ent_list[i]); - } - free(ent_list); - free(ent_stack); - ent_list = ent_stack = NULL; - ent_list_size = ent_max = ent_count = ent_stack_size = 0; -} - -entity *alloc_ent() -{ - entity *ent = malloc(sizeof(*ent)); - memset(ent, 0, sizeof(*ent)); - - ent->object_type = OBJECT_TYPE_ENTITY; - ent->defense = defense_allocate_object(); - ent->offense = offense_allocate_object(); - - ent->varlist = calloc(1, sizeof(*ent->varlist)); - // memset should be OK by know, because VT_EMPTY is zero by value, or else we should use ScriptVariant_Init - Varlist_Init(ent->varlist, max_entity_vars); - alloc_all_scripts(&ent->scripts); - return ent; -} - - - -int alloc_ents() -{ - int i; - - if(ent_list_size >= maxentities) - { - return 0; - } - - ent_list_size += MAX_ENTS; - - ent_list = realloc(ent_list, sizeof(*ent_list) * ent_list_size); - ent_stack = realloc(ent_stack, sizeof(*ent_list) * ent_list_size); - - for(i = ent_list_size - MAX_ENTS; i < ent_list_size; i++) - { - ent_list[i] = alloc_ent(); - ent_list[i]->sortid = i * 100; - ent_stack[i] = NULL; - } - //ent_count = ent_max = 0; - return 1; -} - -int is_walking(int iAni) -{ - int i; - - for(i = 0; i < max_downs; i++) - { - if (iAni == animdowns[i]) return 1; - } - for(i = 0; i < max_ups; i++) - { - if (iAni == animups[i]) return 1; - } - for(i = 0; i < max_walks; i++) - { - if (iAni == animwalks[i]) return 1; - } - for(i = 0; i < max_backwalks; i++) - { - if (iAni == animbackwalks[i]) return 1; - } - - return 0; -} - -// UT: merged DC's common walk/idle functions -// -// Caskey, Damon V. -// 2019-02-09 -// -// Rewritten for greater readability. -static bool common_anim_series(entity *ent, const animation_id_t *alterates, int max_alternates, int force_mode, animation_id_t default_animation) -{ - int i; // Loop cursor. - int loop_min; - int loop_max; - animation_id_t animation_id; // Animation to apply. - - // If we have a forced mode, we'll use it to constrict - // loop options to just the forced mode. - loop_min = force_mode ? force_mode - 1 : 0; - loop_max = force_mode ? force_mode : max_alternates; - - // Loop through available types of series animations (max idles/walks/etc.). - for (i = loop_min; i < loop_max; i++) - { - // Get animation from array of alternates. - animation_id = alterates[i]; - - // If we don't have the selected animation, just - // get out of this loop iteration. - if (!validanim(ent, animation_id)) - { - continue; - } - - // Can't be the default animation. - if (animation_id == default_animation) - { - continue; - } - - // If there's a target in range of this alternate animation, or - // we're forced to use it, switch animations. - if (force_mode || normal_find_target(animation_id, 0)) - { - ent->ducking = DUCK_NONE; - ent_set_anim(ent, animation_id, 0); - if (is_walking(animation_id)) ent->walking = 1; - - // Return true. - return 1; - } - } - - // No alternates were set. Use default if we have it. - if (validanim(ent, default_animation)) - { - ent->ducking = DUCK_NONE; - ent_set_anim(ent, default_animation, 0); - if (is_walking(default_animation)) ent->walking = 1; - - // Return true. - return 1; - } - - return 0; -} - -int common_idle_anim(entity *ent) -{ - /* - common_idle_anim - Damon Vaughn Caskey - 11012009 - Determine and set appropriate idle animation based on condition and range. - Returns 1 if any animation is set. - */ - entity *tempself = self; - - self = ent; - - self->ducking = DUCK_NONE; - if(self->idling) - { - self->idling |= IDLING_ACTIVE; - } - - if (ent->model->subtype != SUBTYPE_BIKER && ent->model->type != TYPE_NONE) // biker fix by Plombo // type none being "idle" prevented contra locked and loaded from working correctly. fixed by anallyst - { - ent->velocity.x = ent->velocity.z = 0; //Stop movement. - } - - if(validanim(ent, ANI_FAINT) && ent->energy_state.health_current <= ent->modeldata.health / 4) //ANI_FAINT and health at/below 25%? - { - ent_set_anim(ent, ANI_FAINT, 0); //Set ANI_FAINT. - goto found; //Return 1 and exit. - } - else if(validanim(ent, ANI_SLEEP) && _time > ent->sleeptime) //ANI_SLEEP, sleeptime up - { - ent_set_anim(ent, ANI_SLEEP, 0); //Set sleep anim. - goto found; //Return 1 and exit. - } - else if(validanim(ent, ANI_EDGE) && ent->edge && (ent->idling & IDLING_ACTIVE) && ent->ducking == DUCK_NONE) - { - if ( (ent->edge & EDGE_RIGHT) && (ent->edge & EDGE_LEFT) ) - { - ent_set_anim(ent, ANI_EDGE, 0); - } - else if (ent->edge & EDGE_RIGHT) - { - if (ent->direction == DIRECTION_RIGHT) - { - ent_set_anim(ent, ANI_EDGE, 0); - } - else - { - if(validanim(ent, ANI_BACKEDGE)) ent_set_anim(ent, ANI_BACKEDGE, 0); - else ent_set_anim(ent, ANI_EDGE, 0); - } - } - else if (ent->edge & EDGE_LEFT) - { - if (ent->direction == DIRECTION_LEFT) - { - ent_set_anim(ent, ANI_EDGE, 0); - } - else - { - if(validanim(ent, ANI_BACKEDGE)) ent_set_anim(ent, ANI_BACKEDGE, 0); - else ent_set_anim(ent, ANI_EDGE, 0); - } - } - goto found; //Return 1 and exit. - } - else if(common_anim_series(ent, animidles, max_idles, ent->idlemode, ANI_IDLE)) - { - goto found; - } - - self = tempself; - return 0; -found: - self = tempself; - return 1; -} - - -#define common_walk_anim(ent) \ - common_anim_series(ent, animwalks, max_walks, ent->walkmode, ANI_WALK) - -#define common_backwalk_anim(ent) \ - common_anim_series(ent, animbackwalks, max_backwalks, ent->walkmode, ANI_BACKWALK) - -#define common_up_anim(ent) \ - common_anim_series(ent, animups, max_ups, ent->walkmode, ANI_UP) - -#define common_down_anim(ent) \ - common_anim_series(ent, animdowns, max_downs, ent->walkmode, ANI_DOWN) - - -// This function find nearst x escape point from the given position -// It assumes the point is already inside the wall -static float find_nearest_wall_x(int wall, float x, float z) -{ - float x1, x2; - - x1 = level->walls[wall].x + level->walls[wall].lowerleft + (level->walls[wall].z - z) * ((level->walls[wall].upperleft - level->walls[wall].lowerleft) / level->walls[wall].depth); - x2 = level->walls[wall].x + level->walls[wall].lowerright + (level->walls[wall].z - z) * ((level->walls[wall].upperright - level->walls[wall].lowerright) / level->walls[wall].depth); - - if(diff(x1, x) > diff(x2, x)) - { - return x2; - } - else - { - return x1; - } -} - -// this method initialize an entity's A.I. behaviors -void ent_default_init(entity *e) -{ - int dodrop; - int wall; - entity *other; - - if(!e) - { - return; - } - - if((!(screen_status & IN_SCREEN_SELECT) && !_time) || e->modeldata.type != TYPE_PLAYER ) - { - if( validanim(e, ANI_SPAWN)) - { - ent_set_anim(e, ANI_SPAWN, 0); // use new playerselect spawn anim - } - else if( validanim(e, ANI_RESPAWN)) - { - ent_set_anim(e, ANI_RESPAWN, 0); - } - //else set_idle(e); - } - else if(!(screen_status & IN_SCREEN_SELECT) && _time && e->modeldata.type == TYPE_PLAYER) // mid-level respawn - { - if( validanim(e, ANI_RESPAWN)) - { - ent_set_anim(e, ANI_RESPAWN, 0); - } - else if( validanim(e, ANI_SPAWN)) - { - ent_set_anim(e, ANI_SPAWN, 0); - } - //else set_idle(e); - } - else if(screen_status & IN_SCREEN_SELECT && validanim(e, ANI_SELECT)) - { - // Play transition if we have one. Default Select otherwise. - if (validanim(e, ANI_SELECTIN)) - { - ent_set_anim(e, ANI_SELECTIN, 0); - } - else - { - ent_set_anim(e, ANI_SELECT, 0); - } - } - //else set_idle(e); - - if(!level) - { - if(!e->animation) - { - set_idle(e); - } - return; - } - - e->nograb_default = 0; // init all entities to 0 by default - e->guardpoints = e->modeldata.guardpoints; - e->jugglepoints = e->modeldata.jugglepoints; - - e->binding.object_type = OBJECT_TYPE_BIND; - - switch(e->modeldata.type) - { - case TYPE_ANY: - case TYPE_NO_COPY: - case TYPE_RESERVED: - case TYPE_UNDECLARED: - case TYPE_UNKNOWN: - //Do nothing. - break; - case TYPE_ENDLEVEL: - case TYPE_ITEM: - e->nograb = 1; - e->nograb_default = e->nograb; - break; - - case TYPE_PLAYER: - //e->direction = (level->scrolldir != SCROLL_LEFT); - e->takedamage = player_takedamage; - e->think = player_think; - e->trymove = player_trymove; - - if(validanim(e, ANI_SPAWN) || validanim(e, ANI_RESPAWN)) - { - e->takeaction = common_spawn; - } - else if(!e->animation) - { - int player_index = (int)e->playerindex; - - if(player_index < levelsets[current_set].maxplayers && level->spawn && _time && level->spawn[player_index].y > e->position.y) - { - e->takeaction = common_drop; - e->position.y = (float)level->spawn[player_index].y; - if(validanim(e, ANI_JUMP)) - { - ent_set_anim(e, ANI_JUMP, 0); - } - } - } - if(_time && e->modeldata.makeinv) - { - // Spawn invincible code - e->invincible |= INVINCIBLE_INTANGIBLE; - e->blink = (e->modeldata.makeinv > 0); - e->invinctime = _time + ABS(e->modeldata.makeinv); - e->arrowon = 1; // Display the image above the player - } - break; - case TYPE_NPC: // use NPC(or A.I. player) instread of an enemy subtype or trap subtype, for further A.I. use - if(e->modeldata.multiple == 0) - { - e->modeldata.multiple = -1; - } - - case TYPE_ENEMY: - e->think = common_think; - if(e->modeldata.subtype == SUBTYPE_BIKER) - { - e->nograb = 1; - e->nograb_default = e->nograb; - e->attacking = ATTACKING_ACTIVE; - //e->direction = (e->position.x<0); - if(e->modeldata.speed.x) - { - e->velocity.x = (e->direction == DIRECTION_RIGHT) ? (e->modeldata.speed.x) : (-e->modeldata.speed.x); - } - else - { - e->velocity.x = (e->direction == DIRECTION_RIGHT) ? (1.7 + randf((float)0.6)) : (-(1.7 + randf((float)0.6))); - } - e->takedamage = biker_takedamage; - e->speedmul = 2; - break; - } - // define new subtypes - else if(e->modeldata.subtype == SUBTYPE_ARROW) - { - e->energy_state.health_current = 1; - if(!e->modeldata.speed.x && !(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE)) - { - e->modeldata.speed.x = 2; // Set default speed to 2 for arrows - } - else if(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - e->modeldata.speed.x = 0; - } - if(e->projectile_prime & PROJECTILE_PRIME_BASE_FLOOR) - { - e->base = 0; - } - else - { - e->base = e->position.y; - } - e->nograb = 1; - e->nograb_default = e->nograb; - e->attacking = ATTACKING_ACTIVE; - e->takedamage = arrow_takedamage; - e->speedmul = 2; - break; - } - else - { - e->trymove = common_trymove; - // Must just be a regular enemy, set defaults accordingly - if(!e->modeldata.speed.x && !(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE)) - { - e->modeldata.speed.x = 1; - } - else if(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - e->modeldata.speed.x = 0; - } - if(e->modeldata.multiple == 0) - { - e->modeldata.multiple = 5; - } - e->takedamage = common_takedamage;//enemy_takedamage; - } - - if(e->modeldata.subtype == SUBTYPE_NOTGRAB) - { - e->nograb = 1; - e->nograb_default = e->nograb; - } - - if(validanim(e, ANI_SPAWN) || validanim(e, ANI_RESPAWN)) - { - e->takeaction = common_spawn; - } - else - { - dodrop = (e->modeldata.subtype != SUBTYPE_ARROW && level && (level->scrolldir == SCROLL_UP || level->scrolldir == SCROLL_DOWN)); - - if(!nodropspawn && (dodrop || (e->position.x > advancex - 30 && e->position.x < advancex + videomodes.hRes + 30 && e->position.y == 0)) ) - { - e->position.y += videomodes.vRes + randf(40); - } - if(inair(e)) - { - e->takeaction = common_drop;//enemy_drop; - if(validanim(e, ANI_JUMP)) - { - ent_set_anim(e, ANI_JUMP, 0); - } - } - } - break; - // define trap type - case TYPE_TRAP: - e->think = trap_think; - e->takedamage = common_takedamage;//enemy_takedamage; - e->speedmul = 2; - break; - case TYPE_OBSTACLE: - e->nograb = 1; - e->nograb_default = e->nograb; - if(e->energy_state.health_current <= 0) - { - e->death_state |= DEATH_STATE_DEAD; // so it won't get hit - } - e->takedamage = obstacle_takedamage;//obstacle_takedamage; - break; - case TYPE_STEAMER: - e->nograb = 1; - e->nograb_default = e->nograb; - e->think = steamer_think; - e->base = e->position.y; - break; - case TYPE_TEXTBOX: // New type for displaying text purposes - e->nograb = 1; - e->nograb_default = e->nograb; - e->think = text_think; - break; - case TYPE_PROJECTILE: - - e->energy_state.health_current = 1; - e->nograb = 1; - e->nograb_default = e->nograb; - e->think = common_think; - e->takedamage = arrow_takedamage; - e->attacking = ATTACKING_ACTIVE; - - if (e->projectile_prime & PROJECTILE_PRIME_BASE_FLOOR) - { - e->base = 0; - } - else - { - e->base = e->position.y; - } - e->speedmul = 2; - e->trymove = common_trymove; - break; - - case TYPE_SHOT: - e->energy_state.health_current = 1; - e->nograb = 1; - e->nograb_default = e->nograb; - e->think = common_think; - e->takedamage = arrow_takedamage; - e->attacking = ATTACKING_ACTIVE; - if(!e->model->speed.x && !(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE)) - { - e->modeldata.speed.x = 2; // Set default speed to 2 for arrows - } - else if(e->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - e->modeldata.speed.x = 0; - } - if(e->projectile_prime & PROJECTILE_PRIME_BASE_FLOOR) - { - e->base = 0; - } - else - { - e->base = e->position.y; - } - e->speedmul = 2; - break; - case TYPE_NONE: - e->nograb = 1; - e->nograb_default = e->nograb; - - //e->base=e->position.y; //complained? - //e->modeldata.move_config_flags |= (MOVE_CONFIG_NO_ADJUST_BASE | MOVE_CONFIG_SUBJECT_TO_GRAVITY); - - if(validanim(e, ANI_WALK)) - { - if(e->direction == DIRECTION_RIGHT) - { - e->velocity.x = e->modeldata.speed.x; - } - else - { - e->velocity.x = -(e->modeldata.speed.x); - } - e->think = anything_walk; - - common_walk_anim(e); - //ent_set_anim(e, ANI_WALK, 0); - } - else - { - e->speedmul = 2; - } - e->trymove = common_trymove; - break; - case TYPE_PANEL: - e->nograb = 1; - e->nograb_default = e->nograb; - break; - } - - /* Faction data. */ - faction_copy_data(&e->faction, &e->modeldata.faction); - - if(!e->animation) - { - set_idle(e); - } - - if(e->modeldata.multiple < 0) - { - e->modeldata.multiple = 0; - } - - if(e->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM && (other = check_platform_below(e->position.x, e->position.z, e->position.y, e))) - { - e->base = other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT]; - } - else if(e->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL && (wall = checkwall_below(e->position.x, e->position.z, T_MAX_CHECK_ALTITUDE)) >= 0) - { - if(level->walls[wall].height > MAX_WALL_HEIGHT) - { - e->position.x = find_nearest_wall_x(wall, e->position.x, e->position.z); - } - else - { - e->base = level->walls[wall].height; - } - } -} - -void ent_spawn_ent(entity *ent) -{ - entity *s_ent = NULL; - s_sub_entity *spawnframe = ent->animation->sub_entity_spawn; - float dy = level ? 4.0 : 0.0; - - // spawn point relative to current entity - if(spawnframe->placement == SUB_ENTITY_PLACEMENT_PARENT) - { - s_ent = spawn(ent->position.x + ((ent->direction == DIRECTION_RIGHT) ? spawnframe->position.x : -spawnframe->position.x), ent->position.z + spawnframe->position.z, ent->position.y + spawnframe->position.y, ent->direction, NULL, ent->animation->sub_entity_model_index, NULL); - } - //relative to screen position - else if(spawnframe->placement == SUB_ENTITY_PLACEMENT_SCREEN) - { - if(level && !(level->scrolldir & SCROLL_UP) && !(level->scrolldir & SCROLL_DOWN)) - { - s_ent = spawn(advancex + spawnframe->position.x, advancey + spawnframe->position.z + dy, spawnframe->position.y, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - else - { - s_ent = spawn(advancex + spawnframe->position.x, spawnframe->position.z + dy, spawnframe->position.y, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - } - //absolute position in level - else - { - s_ent = spawn(spawnframe->position.x, spawnframe->position.z, spawnframe->position.y + 0.001, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - - if(s_ent) - { - //ent_default_init(s_ent); - if(s_ent->modeldata.type & TYPE_SHOT) - { - s_ent->playerindex = ent->playerindex; - } - if(s_ent->modeldata.subtype == SUBTYPE_ARROW) - { - s_ent->owner = ent; - } - s_ent->spawntype = SPAWN_TYPE_CMD_SPAWN; - s_ent->parent = ent; //maybe used by A.I. - execute_onspawn_script(s_ent); - } - -} - -void ent_summon_ent(entity *ent) -{ - entity *s_ent = NULL; - s_sub_entity *spawnframe = ent->animation->sub_entity_summon; - float dy = level ? 4.0 : 0.0; - // spawn point relative to current entity - if(spawnframe->placement == SUB_ENTITY_PLACEMENT_PARENT) - { - s_ent = spawn(ent->position.x + ((ent->direction == DIRECTION_RIGHT) ? spawnframe->position.x : -spawnframe->position.x), ent->position.z + spawnframe->position.z, ent->position.y + spawnframe->position.y, ent->direction, NULL, ent->animation->sub_entity_model_index, NULL); - } - //relative to screen position - else if(spawnframe->placement == SUB_ENTITY_PLACEMENT_SCREEN) - { - if(level && !(level->scrolldir & SCROLL_UP) && !(level->scrolldir & SCROLL_DOWN)) - { - s_ent = spawn(advancex + spawnframe->position.x, advancey + spawnframe->position.z + dy, spawnframe->position.y, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - else - { - s_ent = spawn(advancex + spawnframe->position.x, spawnframe->position.z + dy, spawnframe->position.y, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - } - //absolute position in level - else - { - s_ent = spawn(spawnframe->position.x, spawnframe->position.z, spawnframe->position.y, 0, NULL, ent->animation->sub_entity_model_index, NULL); - } - - if(s_ent) - { - if(spawnframe->placement == SUB_ENTITY_PLACEMENT_PARENT) - { - s_ent->direction = ent->direction; - } - //ent_default_init(s_ent); - if(s_ent->modeldata.type & TYPE_SHOT) - { - s_ent->playerindex = ent->playerindex; - } - if(s_ent->modeldata.subtype == SUBTYPE_ARROW) - { - s_ent->owner = ent; - } - //maybe used by A.I. - s_ent->spawntype = SPAWN_TYPE_CMD_SUMMON; - s_ent->parent = ent; - ent->subentity = s_ent; - execute_onspawn_script(s_ent); - } -} - -/* -* Caskey, Damon V. -* 2026-08-06 -* -* Add a duration to an animation timestamp without entering -* the bit-63 behavior range. An infinite operand propagates -* the canonical infinite flag. Finite overflow stops at the -* largest timestamp below that flag. -*/ -static uint64_t animation_timestamp_add_bounded( - const uint64_t left, - const uint64_t right -) { - if((left & DELAY_FLAG_INFINITE) - || (right & DELAY_FLAG_INFINITE)) { - return DELAY_INFINITE; - } - - if(left > DELAY_TIMESTAMP_MAX - || right > DELAY_TIMESTAMP_MAX - || right > DELAY_TIMESTAMP_MAX - left) { - return DELAY_TIMESTAMP_MAX; - } - - return left + right; -} - -/* -* Convert an encoded frame delay into its absolute next-frame -* timestamp. Behavior bits do not enter clock arithmetic. -*/ -static uint64_t animation_timestamp_from_delay( - const uint64_t current_time, - const uint64_t encoded_delay -) { - if(encoded_delay & DELAY_FLAG_INFINITE) { - return DELAY_INFINITE; - } - - return animation_timestamp_add_bounded( - current_time, - encoded_delay & DELAY_VALUE_MASK - ); -} - -/* -* Multiply a finite delay without exceeding the reserved -* 32-bit range or creating DELAY_INFINITE by overflow. -*/ -static uint64_t delay_multiply_bounded( - const uint64_t left, - const uint64_t right -) { - if(!left || !right) { - return 0; - } - - if(left > DELAY_FINITE_MAX - || right > DELAY_FINITE_MAX - || right > DELAY_FINITE_MAX / left) { - return DELAY_FINITE_MAX; - } - - return left * right; -} - -/* -* Caskey, Damon V. -* Unknown date (~2008) -* -* Get final delay. Revised 2026-08-06 for unsigned -* 64-bit encoded delays, preserved behavior flags, and -* bounded enhanced-delay arithmetic. -*/ -uint64_t calculate_edelay(const entity* const acting_entity, const uint64_t frame) { - const s_anim* const animation = acting_entity->animation; - const s_edelay* const edelay = &acting_entity->modeldata.edelay; - - const uint64_t encoded_delay = animation->delay[frame]; - - const uint64_t behavior_flags = - encoded_delay & DELAY_BEHAVIOR_MASK; - - const uint64_t delay = - encoded_delay & DELAY_VALUE_MASK; - - long double result; - - /* - * Return delay as-is if it falls outside - * of the range defined in the entity's - * edelay structure. This allows for - * certain frames to be exempt from the - * edelay calculations. - */ - if(edelay->range.max < 0 - || (edelay->range.min > 0 - && delay < (uint64_t)edelay->range.min) - || delay > (uint64_t)edelay->range.max) { - return behavior_flags | delay; - } - - /* - * Apply percentage and static delay - * modifier. - */ - result = (long double)delay - * (long double)edelay->factor - + (long double)edelay->modifier; - - /* - * Preserve the unmodified delay if a script supplied - * a non-number multiplier. - */ - if(result != result) { - return behavior_flags | delay; - } - - /* - * Cap results. - */ - - if(result < (long double)edelay->cap.min) { - result = (long double)edelay->cap.min; - } - - if(result > (long double)edelay->cap.max) { - result = (long double)edelay->cap.max; - } - - /* - * Edelay configuration remains signed so negative - * modifiers and caps retain their legacy meaning. - * Final value bits cannot leave the finite 32-bit - * range. Behavior bits remain unchanged. - */ - if(result <= 0.0L) { - return behavior_flags; - } - - if(result >= (long double)DELAY_FINITE_MAX) { - return behavior_flags | DELAY_FINITE_MAX; - } - - return behavior_flags | (uint64_t)result; -} - -/* -* Caskey, Damon V. -* 2018-04-20 -* -* Set up jumping velocity for an animation -* that has jump frame defined and is at the -* designated jump frame. Also spawns effect -* entity if one is defined. -*/ -bool check_jumpframe(entity * const acting_entity, const uint64_t frame) -{ - if (!acting_entity || !acting_entity->animation) - { - return 0; - } - - const s_onframe_move* jump = &acting_entity->animation->jumpframe; - - // Must have jump frame allocated. - if(jump->frame == FRAME_NONE) - { - return 0; - } - - // Must be on assigned jump frame. - if(jump->frame != frame) - { - return 0; - } - - // Chuck entity into the air. - toss(acting_entity, jump->velocity.y); - - // Set left or right horizontal velocity depending on - // current direction. - if(acting_entity->direction == DIRECTION_RIGHT) - { - acting_entity->velocity.x = jump->velocity.x; - } - else - { - acting_entity->velocity.x = -jump->velocity.x; - } - - // Lateral velocity. - acting_entity->velocity.z = jump->velocity.z; - - // Spawn an effect entity if defined. - if(jump->model_index != MODEL_INDEX_NONE) - { - entity* const effect_entity = spawn(acting_entity->position.x, acting_entity->position.z, acting_entity->position.y, acting_entity->direction, NULL, jump->model_index, NULL); - - if(effect_entity) - { - effect_entity->spawntype = SPAWN_TYPE_DUST_JUMP; - effect_entity->base = acting_entity->position.y; - effect_entity->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(effect_entity); - } - } - - return 1; - -} - -// move here to prevent some duplicated code in ent_sent_anim and update_ents -void update_frame(entity *ent, uint64_t f) -{ - entity *tempself; - s_attack attack = emptyattack; - s_axis_principal_float move; - s_anim *anim = ent->animation; - - if(f >= anim->numframes) // prevent a crash with invalid frame index. - { - return; - } - - //important! - tempself = self; - self = ent; - - self->animpos = f; - //self->currentsprite = self->animation->sprite[f]; - - if(self->animating) - { - self->nextanim = animation_timestamp_from_delay( - _time, - calculate_edelay(self, f) - ); - - self->pausetime = 0; - execute_animation_script(self); - } - - if(ent->animation != anim || ent->animpos != f) - { - goto uf_interrupted; - } - - if(level && (anim->move[f]->axis.x || anim->move[f]->axis.z)) - { - move.x = (float)(anim->move[f]->axis.x ? anim->move[f]->axis.x : 0); - move.z = (float)(anim->move[f]->axis.z ? anim->move[f]->axis.z : 0); - if(self->direction == DIRECTION_LEFT) - { - move.x = -move.x; - } - self->movex += move.x; - self->movez += move.z; - } - - if(anim->move[0]->base && anim->move[0]->base >= 0 && self->base <= 0) - { - ent->base = (float)anim->move[0]->base; - } - else if(!anim->move[0]->base || anim->move[0]->base < 0) - { - - move.y = (float)(anim->move[f]->axis.y ? anim->move[f]->axis.y : 0); - - self->base += move.y; - - if(move.y != 0) - { - self->altbase += move.y; - } - else - { - self->altbase = 0; - } - } - - if(anim->flipframe == f) - { - self->direction = !self->direction; - } - - if(anim->weaponframe && anim->weaponframe[0] == f) - { - dropweapon(self, 2); - set_weapon(self, anim->weaponframe[1], 0); - if(!anim->weaponframe[2]) - { - set_idle(self); - } - } - - if(anim->quakeframe.framestart + anim->quakeframe.cnt == f) - { - if(level) - { - if(anim->quakeframe.cnt % 2 || anim->quakeframe.v > 0) - { - level->quake = anim->quakeframe.v; - } - else - { - level->quake = anim->quakeframe.v * -1; - } - } - if((anim->quakeframe.repeat - anim->quakeframe.cnt) > 1) - { - anim->quakeframe.cnt++; - } - else - { - anim->quakeframe.cnt = 0; - } - } - - if(anim->sub_entity_unsummon == f) - { - if(self->subentity) - { - self = self->subentity; - attack.dropv = default_model_dropv; - attack.attack_force = self->energy_state.health_current; - attack.attack_type = ATK_SUB_ENTITY_UNSUMMON; - - if(self->takedamage) { - const s_defense* defense_object = defense_find_current_object(self, NULL, attack.attack_type); - self->takedamage(self, self, &attack, 0, defense_object); - - } else { - kill_entity(self, KILL_ENTITY_TRIGGER_UNSUMMON); - } - self = ent; // lol ... - self->subentity = NULL; - } - } - - //spawn / summon /unsummon features - if(anim->sub_entity_spawn && anim->sub_entity_spawn->frame == f && anim->sub_entity_model_index >= 0) - { - ent_spawn_ent(self); - } - - if(anim->sub_entity_summon && anim->sub_entity_summon->frame == f && anim->sub_entity_model_index >= 0) - { - //subentity is dead - if(!self->subentity || self->subentity->death_state & DEATH_STATE_DEAD) - { - ent_summon_ent(self); - } - } - - /* Child spawn */ - if (anim->child_spawn && anim->child_spawn[f]) - { - child_spawn_execute_list(anim->child_spawn[f], ent); - } - - if(anim->sound) - { - frame_sound_execute_collection(anim->sound[f], ent->unique_id); - } - - // Perform jumping if on a jumpframe. - check_jumpframe(self, f); - - // This animation have projectile settings? - if (anim->projectile) - { - int position_x = anim->projectile->position.x; - - if (self->direction == DIRECTION_LEFT) - { - position_x = -position_x; - } - - if (anim->projectile->throwframe == f) - { - // For backward compatible thing - // throw stars in the air, hmm, strange - // custstar custknife in animation should be checked first - // then if the entity is jumping, check star first, if failed, try knife instead - // well, try knife at last, if still failed, try star, or just let if shutdown? - -#define __trystar star_spawn(self, anim->projectile) -#define __tryknife knife_spawn(self, anim->projectile) - - if (anim->projectile->knife >= 0 || anim->projectile->flash >= 0) - { - __tryknife; - } - else if (anim->projectile->star >= 0) - { - __trystar; - } - else if (self->jumping) - { - if (!__trystar) - { - __tryknife; - } - } - else if (!__tryknife) - { - __trystar; - } - self->weapon_state |= WEAPON_STATE_DEDUCT_USE; - } - - if (anim->projectile->shootframe == f) - { - knife_spawn(self, anim->projectile); - self->weapon_state |= WEAPON_STATE_DEDUCT_USE; - } - - if (anim->projectile->tossframe == f) - { - bomb_spawn(self, anim->projectile); - self->weapon_state |= WEAPON_STATE_DEDUCT_USE; - } - } - -uf_interrupted: - - //important! - self = tempself; - - #undef __trystar - #undef __tryknife -} - - -void ent_set_anim(entity *acting_entity, animation_id_t aninum, bool resetable) { - - s_anim *ani = NULL; - int animpos; - - if(!acting_entity) { - //printf("FATAL: tried to set animation with invalid address (no such object)"); - return; - } - - if(aninum >= max_animations) { - //printf("FATAL: tried to set animation with invalid index (%s, %i)", ent->name, aninum); - return; - } - - if(!validanim(acting_entity, aninum)) { - //printf("FATAL: tried to set animation with invalid address (%s, %i)", acting_entity->name, aninum); - return; - } - - ani = acting_entity->modeldata.animation[aninum]; - - /* - * If reset flag is not enabled and the entity - * is already on the requested animation, then - * just bail. - */ - if(!resetable && acting_entity->animation == ani) { - return; - } - - if(ani->numframes == 0) { - return; - } - - if(acting_entity->animation && ((resetable & 2) || (ani->sync >= 0 && acting_entity->animation->sync == ani->sync))) { - animpos = acting_entity->animpos; - - if(animpos >= ani->numframes) { - animpos = 0; - } - - acting_entity->animnum_previous = acting_entity->animnum; - acting_entity->animnum = aninum; - acting_entity->animation = ani; - acting_entity->animpos = animpos; - acting_entity->walking = false; - - } else { - acting_entity->animnum_previous = acting_entity->animnum; - acting_entity->animnum = aninum; // Stored for nocost usage - acting_entity->animation = ani; - acting_entity->animation->hit_count = 0; - - acting_entity->animating = ANIMATING_FORWARD; - acting_entity->lasthit = acting_entity->grabbing; - acting_entity->altbase = 0; - acting_entity->walking = false; - - update_frame(acting_entity, 0); - } -} - -unsigned char *model_get_colourmap(s_model *model, unsigned which) -{ - if(which <= 0 || which > model->maps_loaded) - { - return model->palette; - } - else - { - return model->colourmap[which - 1]; - } -} - -// 0 = none, 1+ = alternative -void ent_set_colourmap(entity *ent, uint64_t which) -{ - if(which > ent->modeldata.maps_loaded) - { - which = 0; - } - if(which <= 0) - { - ent->colourmap = ent->modeldata.palette; - } - else - { - ent->colourmap = ent->modeldata.colourmap[which - 1]; - } - ent->map = which; -} - -// used by ent_set_model -void ent_copy_uninit(entity *ent, s_model *oldmodel) -{ - if(ent->modeldata.multiple < 0) - { - ent->modeldata.multiple = oldmodel->multiple; - } - - ent->modeldata.move_config_flags = oldmodel->move_config_flags; - - if(ent->modeldata.aimove == AIMOVE1_NONE) - { - ent->modeldata.aimove = oldmodel->aimove; - } - if (ent->modeldata.aiattack == -1) - { - ent->modeldata.aiattack = oldmodel->aiattack; - } - - faction_copy_data(&ent->modeldata.faction, &oldmodel->faction); - faction_copy_data(&ent->faction, &oldmodel->faction); - - if(!ent->modeldata.health) - { - ent->modeldata.health = oldmodel->health; - } - if(!ent->modeldata.mp) - { - ent->modeldata.mp = oldmodel->mp; - } - if(ent->modeldata.risetime.rise == -1) - { - ent->modeldata.risetime.rise = oldmodel->risetime.rise; - } - /* - if(!ent->modeldata.grab_resistance) - ent->modeldata.grab_resistance = oldmodel->antigrab; - if(!ent->modeldata.grab_force) - ent->modeldata.grab_force = oldmodel->grabforce; - if(!ent->modeldata.paingrab) - ent->modeldata.paingrab = oldmodel->paingrab;*/ - - if(ent->energy_state.health_current > ent->modeldata.health) - { - ent->energy_state.health_current = ent->modeldata.health; - } - if(ent->energy_state.mp_current > ent->modeldata.mp) - { - ent->energy_state.mp_current = ent->modeldata.mp; - } - - ent->shadow_config_flags = ent->modeldata.shadow_config_flags; -} - - -//if syncAnim is set, only change animation reference -void ent_set_model(entity *ent, char *modelname, int syncAnim) -{ - if(ent == NULL) - { - borShutdown(1, "FATAL: tried to change model of invalid object"); - } - - s_model* m = findmodel(modelname); - - if(m == NULL) - { - borShutdown(1, "Model not found: '%s'", modelname); - } - - s_model oldmodel = ent->modeldata; - ent->model = m; - ent->modeldata = *m; - ent_copy_uninit(ent, &oldmodel); - ent_set_colourmap(ent, ent->map); - - if(syncAnim && m->animation[ent->animnum]) - { - ent->animation = m->animation[ent->animnum]; - if(ent->animpos >= ent->animation->numframes) - { - ent->animpos = ent->animation->numframes - 1; - } - - ent->nextanim = animation_timestamp_from_delay( - _time, - calculate_edelay(ent, ent->animpos) - ); - - - //update_frame(ent, ent->animpos); - } - else - { - ent->attacking = ATTACKING_NONE; - - if((!(screen_status & IN_SCREEN_SELECT) && !_time) || !(ent->modeldata.type & TYPE_PLAYER)) - { - // use new playerselect spawn anim - if( validanim(ent, ANI_SPAWN)) - { - ent_set_anim(ent, ANI_SPAWN, 0); - } - else - { - if( validanim(ent, ANI_IDLE)) ent_set_anim(ent, ANI_IDLE, 0); - } - } - else if(!(screen_status & IN_SCREEN_SELECT) && _time && (ent->modeldata.type & TYPE_PLAYER)) - { - // mid-level respawn - if( validanim(ent, ANI_RESPAWN)) - { - ent_set_anim(ent, ANI_RESPAWN, 0); - } - else if( validanim(ent, ANI_SPAWN)) - { - ent_set_anim(ent, ANI_SPAWN, 0); - } - else - { - if( validanim(ent, ANI_IDLE)) ent_set_anim(ent, ANI_IDLE, 0); - } - } - else if(screen_status & IN_SCREEN_SELECT && validanim(ent, ANI_SELECT)) - { - // Play transition if we have one. Default Select otherwise. - if (validanim(ent, ANI_SELECTIN)) - { - ent_set_anim(ent, ANI_SELECTIN, 0); - } - else - { - ent_set_anim(ent, ANI_SELECT, 0); - } - } - else - { - if( validanim(ent, ANI_IDLE)) ent_set_anim(ent, ANI_IDLE, 0); - } - } -} - -// Caskey, Damon V. -// ~2018 -// -// Allocate memory for a drawmethod and return pointer. -s_drawmethod *allocate_drawmethod() -{ - s_drawmethod *result; - - // Allocate memory and get the pointer. - result = malloc(sizeof(*result)); - - // Copy default values into new drawmethod. - memcpy(result, &plainmethod, sizeof(*result)); - - return result; -} - -// Caskey, Damon V. -// 2019-12-13 -// -// Allocate memory for a projectile animation setting and return pointer. -s_projectile* allocate_projectile() -{ - s_projectile* result; - - // Allocate memory and get the pointer. - result = malloc(sizeof(*result)); - - // Copy default values into new projectile setting. - memcpy(result, &projectile_default_config, sizeof(*result)); - - return result; -} - -// Caskey, Damon V. -// 2019-12-11 -// -// Allocate memory for a sub entity command and return pointer. -s_sub_entity *allocate_sub_entity() -{ - s_sub_entity *result; - - // Allocate memory and get the pointer. - result = malloc(sizeof(*result)); - - // Set any default values we need. - result->frame = FRAME_NONE; - - return result; -} - -/* -* Caskey, Damon V. -* 2026-08-08 -* -* Return the next process-lifetime entity instance ID. -* Zero and UINT64_MAX remain reserved for no-owner and -* wildcard selectors respectively. -*/ -static uint64_t entity_unique_id_next(void) { - entity_unique_id_counter++; - - if(entity_unique_id_counter == ENTITY_UNIQUE_ID_ALL) { - entity_unique_id_counter = UINT64_C(1); - } - - return entity_unique_id_counter; -} - -entity *spawn(const float pos_x, const float pos_z, const float pos_y, const e_direction direction, char *model_name, const int model_index, s_model* model_pointer) -{ - entity *acting_entity = NULL; - int i, id; - s_defense *dfs; - s_offense *ofs; - e_object_type object_type; - Varlist *vars; - s_scripts *scripts; - - /* - * Prioritize parameter we use to - * spawn: - * - * 1. model_pointer. - * 2. model_index. - * 3. model_name. - */ - - s_model* spawn_model = model_pointer; - - if(!spawn_model) - { - if(model_index >= 0) - { - spawn_model = model_cache[model_index].model; - } - else if(model_name) - { - spawn_model = findmodel(model_name); - } - } - - if(spawn_model == NULL) - { - return NULL; - } - - if(ent_count >= ent_list_size && !alloc_ents()) - { - return NULL; //out of memory ? - } - - for(i = 0; i < ent_list_size; i++) - { - if(!ent_list[i]->exists || (ent_count >= spawnoverride && ent_list[i]->modeldata.priority < 0 && ent_list[i]->modeldata.priority <= spawn_model->priority)) - { - acting_entity = ent_list[i]; - if(acting_entity->exists) - { - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_SPAWN_OVERRIDE); - } - // save these values, or they will loss when memset called - object_type = acting_entity->object_type; - id = acting_entity->sortid; - dfs = acting_entity->defense; - - ofs = acting_entity->offense; - vars = acting_entity->varlist; - Varlist_Cleanup(vars); - - memcpy(dfs, spawn_model->defense, sizeof(*dfs)*max_attack_types); - memcpy(ofs, spawn_model->offense, sizeof(*ofs)*max_attack_types); - - // clear up - clear_all_scripts(acting_entity->scripts, 1); - if(acting_entity->waypoints) - { - free(acting_entity->waypoints); - } - - /* Just to make the recrusive collection is free. */ - recursive_effect_free_collection(acting_entity); - - scripts = acting_entity->scripts; - memset(acting_entity, 0, sizeof(*acting_entity)); - acting_entity->unique_id = entity_unique_id_next(); - - // e->drawmethod = plainmethod; - acting_entity->drawmethod = allocate_drawmethod(); - - acting_entity->drawmethod->config &= ~DRAWMETHOD_CONFIG_ENABLED; - - // add to list and count current entities - acting_entity->exists = 1; - ent_count++; - - acting_entity->modeldata = *spawn_model; // copy the entir model data here - acting_entity->model = spawn_model; - acting_entity->defaultmodel = spawn_model; - - acting_entity->scripts = scripts; - // copy from model a fresh script - - copy_all_scripts(spawn_model->scripts, acting_entity->scripts, 1); - - if(ent_count > ent_max) - { - ent_max = ent_count; - } - acting_entity->timestamp = _time; // log time so update function will ignore it if it is new - - acting_entity->energy_state.health_current = acting_entity->modeldata.health; - acting_entity->energy_state.mp_current = acting_entity->modeldata.mp; - acting_entity->knockdowncount = acting_entity->modeldata.knockdowncount; - acting_entity->position.x = pos_x; - acting_entity->position.z = pos_z; - acting_entity->position.y = pos_y; - acting_entity->shadow_config_flags = acting_entity->modeldata.shadow_config_flags; - acting_entity->direction = direction; - acting_entity->nextthink = _time + 1; - acting_entity->nextmove = _time + 1; - acting_entity->speedmul = 1; - ent_set_colourmap(acting_entity, 0); - acting_entity->lifespancountdown = spawn_model->lifespan; // new life span countdown - - if((acting_entity->modeldata.type & TYPE_PLAYER) && ((level && level->nohit == DAMAGE_FROM_PLAYER_OFF) || savedata.mode)) - { - acting_entity->faction.type_hostile &= ~TYPE_PLAYER; - acting_entity->faction.type_damage_direct &= ~TYPE_PLAYER; - } - - if(acting_entity->modeldata.type & TYPE_PLAYER) - { - acting_entity->playerindex = currentspawnplayer; - } - - if(acting_entity->modeldata.type & TYPE_TEXTBOX) - { - textbox = acting_entity; - } - - strncpy(acting_entity->name, acting_entity->modeldata.name, MAX_NAME_LEN - 1); - // copy back the value - acting_entity->object_type = object_type; - acting_entity->sortid = id; - acting_entity->defense = dfs; - acting_entity->offense = ofs; - acting_entity->varlist = vars; - - ent_default_init(acting_entity); - return acting_entity; - } - } - return NULL; -} - - - -// Break the link an entity has with another one -void ent_unlink(entity *e) -{ - if(e->link) - { - e->link->link = NULL; - e->link->grabbing = NULL; - } - e->link = NULL; - e->grabbing = NULL; -} - - - -// Link two entities together -void ents_link(entity *e1, entity *e2) -{ - ent_unlink(e1); - ent_unlink(e2); - e1->grabbing = e2; // Added for platform layering - e1->link = e2; - e2->link = e1; -} - - - -void kill_entity(entity *victim, e_kill_entity_trigger trigger) -{ - int i = 0; - s_attack attack = emptyattack; - entity *tempent = self; - - if(victim == NULL || !victim->exists) { - return; - } - - execute_onkill_script(victim, trigger); - - recursive_effect_free_collection(victim); - - ent_unlink(victim); - victim->weapent = NULL; - victim->energy_state.health_current = 0; - victim->exists = 0; - ent_count--; - - //UT: caution, script function killentity calls this - clear_all_scripts(victim->scripts, 1); - - if(victim->parent && victim->parent->subentity == victim) { - victim->parent->subentity = NULL; - } - - victim->parent = NULL; - - if(victim->modeldata.summonkill) { - attack.attack_type = ATK_SUB_ENTITY_PARENT_KILL; - attack.dropv = default_model_dropv; - } - - const s_defense* defense_object = defense_find_current_object(self, NULL, attack.attack_type); - - // kill minions - if(victim->modeldata.summonkill == 1 && victim->subentity) { - // kill only summoned one - victim->subentity->parent = NULL; - self = victim->subentity; - attack.attack_force = self->energy_state.health_current; - - if(self->takedamage && !level_completed) { - self->takedamage(self, self, &attack, 0, defense_object); - - } else { - kill_entity(self, KILL_ENTITY_TRIGGER_PARENT_KILL_SUMMON); - } - } - - victim->subentity = NULL; - - for (i = 0; i < MAX_PLAYERS; i++) { - if(victim == player[i].ent) { - player[i].ent = NULL; - break; - } - } - - if(victim == smartbomber) { - smartbomber = NULL; - } - - if(victim == textbox) { - textbox = NULL; - } - - for(i = 0; i < ent_max; i++) { - if(ent_list[i]->exists) { - // kill all minions - self = ent_list[i]; - if(self->parent == victim) { - self->parent = NULL; - if(victim->modeldata.summonkill == 2) { - - attack.attack_force = self->energy_state.health_current; - - if(self->takedamage && !level_completed) { - self->takedamage(self, self, &attack, 0, defense_object); - } else { - kill_entity(self, KILL_ENTITY_TRIGGER_PARENT_KILL_ALL); - } - } - } - - if(self->owner == victim) { - self->owner = victim->owner; - } - - if(self->opponent == victim) { - self->opponent = NULL; - } - - if(self->binding.target == victim) { - self->binding.target = NULL; - } - - if(self->landed_on_platform == victim) { - self->landed_on_platform = NULL; - } - - if(self->hithead == victim) { - self->hithead = NULL; - } - - if(self->lasthit == victim) { - self->lasthit = NULL; - } - - if(!textbox && (self->modeldata.type & TYPE_TEXTBOX)) { - textbox = self; - } - } - } - - victim = NULL; - - //free_ent(victim); - //victim = alloc_ent(); - - self = tempent; -} - - -void kill_all(){ - - int i; - entity *e = NULL; - - for(i = 0; i < ent_max; i++) { - e = ent_list[i]; - if (e && e->exists) { - execute_onkill_script(e, KILL_ENTITY_TRIGGER_ALL); - - recursive_effect_free_collection(e); - ent_unlink(e); - - clear_all_scripts(e->scripts, 1); - } - e->exists = 0; // well, no need to use kill function - } - textbox = smartbomber = NULL; - _time = 0; - ent_count = ent_max = ent_stack_size = 0; - if(ent_list_size > MAX_ENTS) {//shrinking... - free_ents(); - alloc_ents(); //this shouldn't return 0, because the list shrinks... - } -} - -/* -* Caskey, Damon V. -* 2022-04-20 -* -* Replacement for legacy canbegrabbed -* macro. Return true if target entity -* is eligible for grabbing. -*/ -int check_canbegrabbed(entity* acting_entity, entity* target_entity) -{ - if (!target_entity->animation->vulnerable[target_entity->animpos]) - { - return 0; - } - - /* - * Note move refers to "move animation - * commands, not if entity has velocity. - */ - - if (acting_entity->animation->move) - { - if (acting_entity->animation->move[acting_entity->animpos]->axis.x != 0) - { - return 0; - } - - if (acting_entity->animation->move[acting_entity->animpos]->axis.z != 0) - { - return 0; - } - } - - if (target_entity->nograb) - { - return 0; - } - - if (target_entity->invincible & INVINCIBLE_INTANGIBLE) - { - return 0; - } - - if (target_entity->link) - { - return 0; - } - - if (target_entity->model->weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - return 0; - } - - if (inair(target_entity)) - { - return 0; - } - - /* - * DC 2022-04-20. - * - * This check seems very open-ended. I would - * think savedata.mode should equal something - * specific and not just "true". Will need to - * look over the menu options code to make - * sure this is behaving as intended. - */ - - if (acting_entity->modeldata.type & TYPE_PLAYER && target_entity->modeldata.type & TYPE_PLAYER) - { - if (savedata.mode) - { - return 0; - } - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2022-04-09 -* -* Replacement for legacy cangrab -* macro. Return true if acting -* entity can grab target entity. -*/ -int check_cangrab(entity* acting_entity, entity* target_entity) -{ - int grab_resistance = 0; - - if (!check_canbegrabbed(acting_entity, target_entity)) - { - return 0; - } - - if (inair_range(acting_entity)) - { - return 0; - } - - if (diff(target_entity->position.y, acting_entity->position.y) > T_WALKOFF) - { - return 0; - } - - /* - * Grab resistance. Acting entity's grab force - * must exceed target's total grab resistance. - * - * If the target as paingrab property, we add - * its value to grab resistance property if - * the target's pain flag is not active. - */ - - grab_resistance = target_entity->modeldata.grab_resistance; - - if (target_entity->modeldata.paingrab) - { - if ((target_entity->inpain & IN_PAIN_HIT) == 0) - { - grab_resistance += target_entity->modeldata.paingrab; - } - } - - if (grab_resistance > acting_entity->modeldata.grab_force) - { - return 0; - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2020-02-04 -* -* Test collision between two boxes. If any overlap is found, -* populates collision_check_data->return_overlap with overlap -* position and returns true. -*/ -int check_collision(s_collision_check_data* collision_data) -{ - s_box seek_pos; - s_box detect_pos; - - /* - * X axis. - * - * Before we can check X positions, we need to - * accomidate handle left/right flipping of - * both the seeker and target. - */ - - if (collision_data->seeker_direction == DIRECTION_LEFT) - { - seek_pos.left = collision_data->seeker_pos->x - collision_data->seeker_coords->width; - seek_pos.right = collision_data->seeker_pos->x - collision_data->seeker_coords->x; - } - else - { - seek_pos.left = collision_data->seeker_pos->x + collision_data->seeker_coords->x; - seek_pos.right = collision_data->seeker_pos->x + collision_data->seeker_coords->width; - } - - if (collision_data->target_direction == DIRECTION_LEFT) - { - detect_pos.left = collision_data->target_pos->x - collision_data->target_coords->width; - detect_pos.right = collision_data->target_pos->x - collision_data->target_coords->x; - } - else - { - detect_pos.left = collision_data->target_pos->x + collision_data->target_coords->x; - detect_pos.right = collision_data->target_pos->x + collision_data->target_coords->width; - } - - // If we are out of bounds, there's no collision. - if (seek_pos.left > detect_pos.right || seek_pos.right < detect_pos.left) - { - return 0; - } - - /* - * Y axis. - * - * This looks backwards, but we're not crazy. - * - * The text input treats box as starting from - * a Y position with a Y size that proceeds - * downward, but when checking for collision - * we do the opposite. So here the Y position - * is our lower coordinate and Y size is the - * top coordinate. - */ - - seek_pos.bottom = collision_data->seeker_pos->y + -(collision_data->seeker_coords->height); - seek_pos.top = collision_data->seeker_pos->y + - (collision_data->seeker_coords->y); - - detect_pos.bottom = collision_data->target_pos->y + -(collision_data->target_coords->height); - detect_pos.top = collision_data->target_pos->y + - (collision_data->target_coords->y); - - // If we are out of bounds, there's no collision. - if (seek_pos.bottom > detect_pos.top || seek_pos.top < detect_pos.bottom) - { - return 0; - } - - /* - * Z axis. - * - * Same principal as the left and right sides of X - * axis, except we don't have to worry about flipping - * direction. - */ - - seek_pos.background = collision_data->seeker_pos->z - collision_data->seeker_coords->z_background; - seek_pos.foreground = collision_data->seeker_pos->z + collision_data->seeker_coords->z_foreground; - - detect_pos.background = collision_data->target_pos->z - collision_data->target_coords->z_background; - detect_pos.foreground = collision_data->target_pos->z + collision_data->target_coords->z_foreground; - - // If we are out of bounds, there's no collision. - if (seek_pos.background > detect_pos.foreground || seek_pos.foreground < detect_pos.background) - { - return 0; - } - - /* - * If we got this far, find the collision area and apply - * values to collision area box supplied by parent function. - * - * We do this by treating the collision area as a third - * box set of coordinates between the attack and detect - * boxes. Then we find the center of our third box. This - * gives us a calculated center of the collision detection - * point. - */ - - collision_data->return_overlap->left = seek_pos.left < detect_pos.left ? detect_pos.left : seek_pos.left; - collision_data->return_overlap->right = seek_pos.right > detect_pos.right ? detect_pos.right : seek_pos.right; - collision_data->return_overlap->center_x = (collision_data->return_overlap->left + collision_data->return_overlap->right) / 2; - - collision_data->return_overlap->bottom = seek_pos.bottom < detect_pos.bottom ? detect_pos.bottom : seek_pos.bottom; - collision_data->return_overlap->top = seek_pos.top > detect_pos.top ? detect_pos.top : seek_pos.top; - collision_data->return_overlap->center_y = (collision_data->return_overlap->top + collision_data->return_overlap->bottom) / 2; - - collision_data->return_overlap->background = seek_pos.background < detect_pos.background ? detect_pos.background : seek_pos.background; - collision_data->return_overlap->foreground = seek_pos.foreground > detect_pos.foreground ? detect_pos.foreground : seek_pos.foreground; - collision_data->return_overlap->center_z = (collision_data->return_overlap->background + collision_data->return_overlap->foreground) / 2; - - return 1; -} - -/* -* Caskey, Damon V. -* 2020-02-04 -* -* Send collision and entity data to last hit structure. -* This data is vital for checking hit reactions, spawning -* flash effects, performing hit overrides, populating -* script variables and other post hit functionality. -*/ -void populate_lasthit(const s_collision_check_data* const collision_data, s_collision_instance* const collision_attack, s_collision_instance* const detect_collision_body, s_collision_instance* const detect_collision_attack) { - - /* - * Why have both attack and collision_attack when - * attack is a member of collision_attack? - * - * There are times (like damage on landing) where - * the lasthit structure is populated manually - * and we don't have a collision container, only - * the property object. - */ - lasthit.collision_attack = collision_attack; - lasthit.attack = collision_attack ? collision_attack->attack : NULL; - - lasthit.detect_collision_body = detect_collision_body; - lasthit.detect_body = detect_collision_body ? detect_collision_body->body : NULL; - - lasthit.detect_collision_attack = detect_collision_attack; - - lasthit.position.x = collision_data->return_overlap->center_x; - lasthit.position.y = collision_data->return_overlap->center_y; - lasthit.position.z = collision_data->return_overlap->center_z; - - lasthit.target = collision_data->target_ent; - lasthit.attacker = collision_data->seeker_ent; - lasthit.confirm = 1; -} - -/* -* Caskey, Damon V. -* 2026-07-01 -* -* Check one seeking collision box against all active -* body collision boxes on the target's current frame. -* -* This replaces the old linked-list walk with an active -* mask scan. The function only visits slots marked active -* in the target frame's body collision collection. -* -* Returns: -* - Pointer to the body collision instance that was hit. -* - NULL if no body collision is found. -*/ -s_collision_instance* check_collision_vs_body(s_collision_check_data* const collision_check_data) { - s_anim* animation = NULL; - s_collision_collection* collection = NULL; - s_collision_instance* detect_collision = NULL; - uint64_t active_status; - int frame; - int collision_index; - - /* - * No collision check data means there is nothing - * meaningful to evaluate. - */ - if (!collision_check_data) { - return NULL; - } - - animation = collision_check_data->target_animation; - frame = collision_check_data->target_frame; - - /* - * Guard the animation and frame table lookup. - */ - if (!animation || frame < 0 || frame >= animation->numframes) { - return NULL; - } - - /* - * If the animation has no body collision frame - * table, then there are no body boxes to check. - */ - if (!animation->collision_body) { - return NULL; - } - - /* - * Get the body collision collection for the requested - * target frame. - */ - collection = animation->collision_body[frame]; - - /* - * No collection, or no active slots in the collection, - * means there are no target body boxes on this frame. - */ - if (!collection || !collection->active_status) { - return NULL; - } - - /* - * Work from a local copy of the active mask. - * - * The frame collection itself must not be modified by - * collision checks. Each loop consumes one active bit - * from this local copy. - */ - active_status = collection->active_status; - - while (active_status) { - - /* - * Get the lowest active slot index from the local - * active mask copy. - */ - collision_index = collision_get_lowest_active_index(active_status); - - /* - * Clear the lowest active bit so the next loop - * moves to the next active body slot. - */ - active_status &= active_status - 1; - - /* - * Active mask and pointer slots should agree, but - * guard against damaged or script-modified data. - */ - detect_collision = collection->slots[collision_index]; - - if (!detect_collision) { - continue; - } - - /* - * Empty coordinates mean this slot does not have - * a usable collision box for this frame. - */ - if (!collision_check_has_coords(&detect_collision->coords)) { - continue; - } - - /* - * Populate the target coordinate pointer and run - * the shared collision test. - * - * Coordinates live inline on the collision instance, - * so pass the address of the embedded coords member. - */ - collision_check_data->target_coords = &detect_collision->coords; - - if (check_collision(collision_check_data)) { - return detect_collision; - } - } - - /* - * No active target body slot collided with the seeker. - */ - return NULL; -} - -/* -* Caskey, Damon V. -* 2026-07-01 -* -* Check one seeking collision box against all active -* attack collision boxes on the target's current frame. -* -* This replaces the old linked-list walk with an active -* mask scan. The function only visits slots marked active -* in the target frame's attack collision collection. -* -* Returns: -* - Pointer to the attack collision instance that was hit. -* - NULL if no attack collision is found. -*/ -s_collision_instance* check_collision_vs_attack(s_collision_check_data* const collision_check_data) { - s_anim* animation = NULL; - s_collision_collection* collection = NULL; - s_collision_instance* detect_collision = NULL; - uint64_t active_status; - int frame; - int collision_index; - - /* - * No collision check data means there is nothing - * meaningful to evaluate. - */ - if (!collision_check_data) { - return NULL; - } - - animation = collision_check_data->target_animation; - frame = collision_check_data->target_frame; - - /* - * Guard the animation and frame table lookup. - */ - if (!animation || frame < 0 || frame >= animation->numframes) { - return NULL; - } - - /* - * If the animation has no attack collision - * frame table, then there are no attack boxes - * to check. - */ - if (!animation->collision_attack) { - return NULL; - } - - /* - * Get the attack collision collection for the requested - * target frame. - */ - collection = animation->collision_attack[frame]; - - /* - * No collection, or no active slots in the collection, - * means there are no target attack boxes on this frame. - */ - if (!collection || !collection->active_status) { - return NULL; - } - - /* - * Work from a local copy of the active mask. - * - * The frame collection itself must not be modified by - * collision checks. Each loop consumes one active bit - * from this local copy. - */ - active_status = collection->active_status; - - while (active_status) { - - /* - * Get the lowest active slot index from the local - * active mask copy. - */ - collision_index = collision_get_lowest_active_index(active_status); - - /* - * Clear the lowest active bit so the next loop - * moves to the next active attack slot. - */ - active_status &= active_status - 1; - - /* - * Active mask and pointer slots should agree, but - * guard against damaged or script-modified data. - */ - detect_collision = collection->slots[collision_index]; - - if (!detect_collision) { - continue; - } - - /* - * Empty coordinates mean this slot does not have - * a usable collision box for this frame. - */ - if (!collision_check_has_coords(&detect_collision->coords)) { - continue; - } - - /* - * An attack collision scan should only report - * instances that actually carry attack data. - */ - if (!detect_collision->attack) { - continue; - } - - /* - * Populate the target coordinate pointer and run - * the shared collision test. - * - * Coordinates live inline on the collision instance, - * so pass the address of the embedded coords member. - */ - collision_check_data->target_coords = &detect_collision->coords; - - if (check_collision(collision_check_data)) { - return detect_collision; - } - } - - /* - * No active target attack slot collided with the seeker. - */ - return NULL; -} - -/* -* Caskey, Damon V. -* 2026-07-02 -* -* Check whether an attacker's active attack collision -* boxes hit a target's active body collision boxes. -* -* This replaces the old linked-list walk with an active -* mask scan over the attacker's current frame attack -* collision collection. -*/ -int checkhit(entity* attacker, entity* target) { - s_collision_collection* seek_collection = NULL; - s_collision_instance* seek_collision = NULL; - s_collision_instance* detect_collision_attack = NULL; - s_collision_instance* detect_collision_body = NULL; - s_collision_check_data collision_check_data; - s_axis_principal_int seeker_pos; - s_axis_principal_int target_pos; - s_box return_overlap; - uint64_t active_status; - int collision_index; - - int attacker_frame; - int target_frame; - - /* - * Basic guards. - * - * Do not touch animation frame tables until both - * animation pointers and frame indexes are valid. - */ - if (!attacker - || !target - || attacker == target - || !attacker->animation - || !target->animation) { - return FALSE; - } - - attacker_frame = attacker->animpos; - target_frame = target->animpos; - - /* - * Guard animation frame table lookups. - */ - if (attacker_frame < 0 - || attacker_frame >= attacker->animation->numframes - || target_frame < 0 - || target_frame >= target->animation->numframes) { - return FALSE; - } - - /* - * Now it is safe to inspect per-frame animation tables. - */ - if (!attacker->animation->collision_attack - || !target->animation->collision_body - || !target->animation->vulnerable - || !target->animation->vulnerable[target_frame]) { - return FALSE; - } - - /* - * Get the attacker's attack collision collection for - * the current animation frame. - */ - seek_collection = attacker->animation->collision_attack[attacker_frame]; - - /* - * No collection, or no active slots, means the attacker - * has no attack boxes to test on this frame. - */ - if (!seek_collection || !seek_collection->active_status) { - return FALSE; - } - - /* - * We'll use these in collision check data structure - * in lieu of memory allocations. - */ - seeker_pos.x = (int)attacker->position.x; - seeker_pos.y = (int)attacker->position.y; - seeker_pos.z = (int)attacker->position.z; - - target_pos.x = (int)target->position.x; - target_pos.y = (int)target->position.y; - target_pos.z = (int)target->position.z; - - /* - * Populate collision check data with everything - * that does not change during the active-slot scan. - */ - collision_check_data.seeker_pos = &seeker_pos; - collision_check_data.target_pos = &target_pos; - collision_check_data.return_overlap = &return_overlap; - - collision_check_data.seeker_ent = attacker; - collision_check_data.target_ent = target; - collision_check_data.target_animation = target->animation; - collision_check_data.target_frame = target_frame; - - collision_check_data.seeker_direction = attacker->direction; - collision_check_data.target_direction = target->direction; - - /* - * Work from a local copy of the active mask. - * - * Collision checks must not modify the animation frame's - * collision collection. Each loop consumes one active bit - * from this local mask copy. - */ - active_status = seek_collection->active_status; - - while (active_status) { - - /* - * Get the lowest active attack slot index from the - * local active mask copy. - */ - collision_index = collision_get_lowest_active_index(active_status); - - /* - * Clear the lowest active bit so the next loop - * moves to the next active attack slot. - */ - active_status &= active_status - 1; - - /* - * Active mask and pointer slots should agree, but - * guard against damaged or script-modified data. - */ - seek_collision = seek_collection->slots[collision_index]; - - if (!seek_collision) { - continue; - } - - /* - * The seeker side must have both usable coordinates - * and an attack property. Coordinates live inline on - * the collision instance. - */ - if (!seek_collision->attack - || !collision_check_has_coords(&seek_collision->coords)) { - continue; - } - - /* - * Populate the seeker coordinate pointer for this - * active attack slot. - */ - collision_check_data.seeker_coords = &seek_collision->coords; - - /* - * Reset per-slot detection outputs before checking. - */ - detect_collision_attack = NULL; - detect_collision_body = NULL; - - /* - * Check this attack box against the target's active - * body boxes. - */ - detect_collision_body = check_collision_vs_body(&collision_check_data); - - if (detect_collision_body) { - populate_lasthit( - &collision_check_data, - seek_collision, - detect_collision_body, - detect_collision_attack); - - return TRUE; - } - - /* - * Counterattack collision checks are disabled - * pending a rewrite of the old linked-list walk - * to the new active-mask scan pattern. - * - * If/when this path is restored, check_collision_vs_attack() - * now returns s_collision_instance* and already uses the - * active-mask scan pattern. - */ - /* - detect_collision_attack = check_collision_vs_attack(&collision_check_data); - - if (detect_collision_attack) { - populate_lasthit( - &collision_check_data, - seek_collision, - detect_collision_body, - detect_collision_attack); - - return TRUE; - } - */ - } - - /* - * No active attacker attack slot collided with any - * active target collision slot. - */ - return FALSE; -} - - -/* -* Calculates the coef relative to the bottom left -* point. This is done by figuring out how far the -* entity is from the bottom of the platform and -* multiplying the result by the difference of the -* bottom left point and the top left point divided -* by depth of the platform. The same is done for -* the right side, and checks to see if they are -* within the bottom/top and the left/right area. -*/ -int testhole(int hole, float x, float z) -{ - float coef1, coef2; - if(z <= level->holes[hole].z && z >= level->holes[hole].z - level->holes[hole].depth) - { - coef1 = (level->holes[hole].z - z) * ((level->holes[hole].upperleft - level->holes[hole].lowerleft) / level->holes[hole].depth); - coef2 = (level->holes[hole].z - z) * ((level->holes[hole].upperright - level->holes[hole].lowerright) / level->holes[hole].depth); - if(x >= level->holes[hole].x + level->holes[hole].lowerleft + coef1 && x <= level->holes[hole].x + level->holes[hole].lowerright + coef2) - { - return 1; - } - } - return 0; -} - -// find all holes here and return the count -int checkholes(float x, float z) -{ - int i, c; - - for(i = 0, c = 0; i < level->numholes; i++) - { - c += testhole(i, x, z); - } - - return c; -} - -// find the 1st hole here -int checkhole(float x, float z) -{ - int i; - - if(level == NULL) - { - return 0; - } - - for(i = 0; i < level->numholes; i++) - { - if(testhole(i, x, z)) - { - holez = i; - return 1; - } - } - return 0; -} - -// find all holes here within altitude1 and 2, return the count -int checkhole_between(float x, float z, float a1, float a2) -{ - int i, c; - - for(i = 0, c = 0; i < level->numholes; i++) - { - c += (testhole(i, x, z) && level->holes[i].height >= a1 && level->holes[i].height <= a2); - } - - return c; -} - -// get a highest hole below this altitude -int checkhole_in(float x, float z, float a) -{ - float maxa; - int i, ind; - - if(level == NULL) - { - return 0; - } - - maxa = -1; - ind = -1; - for(i = 0; i < level->numholes; i++) - { - if(testhole(i, x, z) && level->holes[i].height+T_WALKOFF >= a && level->holes[i].height > maxa) // && level->holes[i].height+T_WALKOFF >= a - { - maxa = level->holes[i].height; - ind = i; - } - } - - if ( ind >= 0 ) { - holez = ind; - return 1; - } else return 0; -} - -// find the hole id for highest hole -int checkholeindex_in(float x, float z, float a) -{ - float maxa; - int i, ind; - - if(level == NULL) - { - return -1; - } - - maxa = -1; - ind = -1; - for(i = 0; i < level->numholes; i++) - { - if(testhole(i, x, z) && level->holes[i].height+T_WALKOFF >= a && level->holes[i].height > maxa) // && level->holes[i].height+T_WALKOFF >= a - { - maxa = level->holes[i].height; - ind = i; - } - } - - return ind; -} - -// find the 1st hole id here -int checkhole_index(float x, float z) -{ - int i; - - if(level == NULL) - { - return -1; - } - - for(i = 0; i < level->numholes; i++) - { - if(testhole(i, x, z)) - { - //holez = i; - return i; - } - } - return -1; -} - -/* -Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from -the bottom of the platform and multiplying the result by the difference of the bottom left point and the top -left point divided by depth of the platform. The same is done for the right side, and checks to see if they are -within the bottom/top and the left/right area. -*/ -int testwall(int wall, float x, float z) -{ - float coef1, coef2; - - //if(wall >= level->numwalls || wall < 0) return 0; - if(z <= level->walls[wall].z && z >= level->walls[wall].z - level->walls[wall].depth) - { - coef1 = (level->walls[wall].z - z) * ((level->walls[wall].upperleft - level->walls[wall].lowerleft) / level->walls[wall].depth); - coef2 = (level->walls[wall].z - z) * ((level->walls[wall].upperright - level->walls[wall].lowerright) / level->walls[wall].depth); - if(x >= level->walls[wall].x + level->walls[wall].lowerleft + coef1 && x <= level->walls[wall].x + level->walls[wall].lowerright + coef2) - { - return 1; - } - } - - return 0; -} - -// find all walls here within altitude1 and 2, return the count -int checkwalls(float x, float z, float a1, float a2) -{ - int i, c; - - for(i = 0, c = 0; i < level->numwalls; i++) - { - c += (testwall(i, x, z) && level->walls[i].height >= a1 && level->walls[i].height <= a2); - } - - return c; -} - -// get a highest wall below this altitude -int checkwall_below(float x, float z, float a) -{ - float maxa; - int i, ind; - - if(level == NULL) - { - return -1; - } - - maxa = 0; - ind = -1; - for(i = 0; i < level->numwalls; i++) - { - if(testwall(i, x, z) && level->walls[i].height <= a && level->walls[i].height > maxa) - { - maxa = level->walls[i].height; - ind = i; - } - } - - return ind; -} - -// return the 1st wall found here -int checkwall_index(float x, float z) -{ - int i; - if(level == NULL) - { - return WALL_INDEX_NONE; - } - - for (i = 0; i < level->numwalls; i++) - { - if (testwall(i, x, z)) - { - return i; - } - } - - return WALL_INDEX_NONE; -} - -/* -Calculates the coef relative to the bottom left point. This is done by figuring out how far the entity is from -the bottom of the platform and multiplying the result by the difference of the bottom left point and the top -left point divided by depth of the platform. The same is done for the right side, and checks to see if they are -within the bottom/top and the left/right area. -*/ -int testplatform(entity *plat, float x, float z, entity *exclude) -{ - float coef1, coef2; - float offz, offx; - if(plat == exclude) - { - return 0; - } - if(!plat->animation || !plat->animation->platform || !plat->animation->platform[plat->animpos][PLATFORM_HEIGHT]) - { - return 0; - } - offz = plat->position.z + plat->animation->platform[plat->animpos][PLATFORM_Z]; - offx = plat->position.x + plat->animation->platform[plat->animpos][PLATFORM_X]; - if(z <= offz && z >= offz - plat->animation->platform[plat->animpos][PLATFORM_DEPTH]) - { - coef1 = (offz - z) * ((plat->animation->platform[plat->animpos][PLATFORM_UPPERLEFT] - - plat->animation->platform[plat->animpos][PLATFORM_LOWERLEFT]) / plat->animation->platform[plat->animpos][PLATFORM_DEPTH]); - coef2 = (offz - z) * ((plat->animation->platform[plat->animpos][PLATFORM_UPPERRIGHT] - - plat->animation->platform[plat->animpos][PLATFORM_LOWERRIGHT]) / plat->animation->platform[plat->animpos][PLATFORM_DEPTH]); - - if(x >= offx + plat->animation->platform[plat->animpos][PLATFORM_LOWERLEFT] + coef1 && - x <= offx + plat->animation->platform[plat->animpos][PLATFORM_LOWERRIGHT] + coef2) - { - return 1; - } - } - return 0; -} - -//find the first platform between these 2 altitudes -entity *check_platform_between(float x, float z, float amin, float amax, entity *exclude) -{ - entity *plat = NULL; - int i; - - if(level == NULL) - { - return NULL; - } - - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) ) - { - plat = ent_list[i]; - if(plat->position.y <= amax && plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT] > amin) - { - return plat; - } - } - } - return NULL; -} - -//find a lowest platform above this altitude -entity *check_platform_above(float x, float z, float a, entity *exclude) -{ - float mina; - entity *plat = NULL; - int i, ind; - - if(level == NULL) - { - return NULL; - } - - mina = 9999999; - ind = -1; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) ) - { - plat = ent_list[i]; - if(plat->position.y >= a && plat->position.y < mina) - { - mina = plat->position.y; - ind = i; - } - } - } - return (ind >= 0) ? ent_list[ind] : NULL; -} - -//find a highest platform below this altitude -entity *check_platform_below(float x, float z, float a, entity *exclude) -{ - float maxa; - entity *plat = NULL; - int i, ind; - - if(level == NULL) - { - return NULL; - } - - maxa = MIN_INT; - ind = -1; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude) ) - { - plat = ent_list[i]; - if(plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT] <= a && - plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT] > maxa) - { - maxa = plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT]; - ind = i; - } - } - } - return (ind >= 0) ? ent_list[ind] : NULL; -} - -entity *check_platform_above_entity(entity *e) -{ - float mina; - int heightvar; - entity *plat = NULL; - int i, ind; - - if(level == NULL) - { - return NULL; - } - if(e->animation->size.y) - { - heightvar = e->animation->size.y; - } - else - { - heightvar = e->modeldata.size.y; - } - - mina = T_MAX_CHECK_ALTITUDE; - ind = -1; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], e->position.x, e->position.z, e) ) - { - plat = ent_list[i]; - if(plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT] > e->position.y + heightvar && plat->position.y < mina) - { - mina = plat->position.y; - ind = i; - } - } - } - return (ind >= 0) ? ent_list[ind] : NULL; -} - -entity *check_platform_below_entity(entity *e) -{ - float maxa, a; - entity *plat = NULL; - int i, ind; - - if(level == NULL) - { - return NULL; - } - - maxa = MIN_INT; - ind = -1; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], e->position.x, e->position.z, e) ) - { - plat = ent_list[i]; - a = plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT]; - if(a < e->position.y + T_WALKOFF && plat->position.y < e->position.y && a > maxa) - { - maxa = a; - ind = i; - } - } - } - return (ind >= 0) ? ent_list[ind] : NULL; -} - -float checkbase(float x, float z, float y, entity *ent) -{ - float maxbase = -1.0f, base = -1.0f; - int index = -1; - entity *platform = NULL; - - base = (checkhole(self->position.x, self->position.z)) ? -1.0f : 0.0f; - if (base > maxbase) maxbase = base; - - base = check_basemap(self->position.x, self->position.z); - if (base > maxbase) maxbase = base; - - base = -1.0f; - if((index = checkwall_below(x, z, T_MAX_CHECK_ALTITUDE)) >= 0) - { - base = level->walls[index].height; - if (base > maxbase) maxbase = base; - } - - base = -1.0f; - platform = check_platform_below(x, z, y, ent); - if (platform != NULL) - { - base = get_platform_base(platform); - if (base > maxbase) maxbase = base; - } - - return maxbase; -} - -// find the 1st platform entity here -entity *check_platform(float x, float z, entity *exclude) -{ - int i; - if(level == NULL) - { - return NULL; - } - - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && testplatform(ent_list[i], x, z, exclude)) - { - return ent_list[i]; - } - } - return NULL; -} - -float get_platform_base(entity *plat) -{ - float alt = 0; - - alt = plat->position.y; - alt += plat->animation->platform[plat->animpos][PLATFORM_HEIGHT]; - - return alt; -} - -int is_on_platform(entity *ent) -{ - entity *plat = check_platform_below(ent->position.x,ent->position.z,ent->position.y+T_WALKOFF,ent); - if (plat) - { - if ( diff(ent->base,get_platform_base(plat)) <= T_WALKOFF ) return 1; - } - - return 0; -} - -entity *get_platform_on(entity *ent) -{ - entity *plat = check_platform_below(ent->position.x,ent->position.z,ent->position.y+T_WALKOFF,ent); - if (plat) - { - if ( diff(ent->base,get_platform_base(plat)) <= T_WALKOFF ) return plat; - } - - return NULL; -} - -// for adjust grab position function, test if an entity can move from a to b -// TODO: check points between the two pionts, if necessary -// special return values: -// -1: ent can jump over walls, for jump check -// -2: for hole ai reaction check -int testmove(entity *ent, float sx, float sz, float x, float z) -{ - entity *other = NULL, *platbelow = NULL; - int wall, heightvar; - float xdir, zdir; - - xdir = x - sx; - zdir = z - sz; - - if(!xdir && !zdir) - { - return 1; - } - - // -----------bounds checking--------------- - // Subjec to Z and out of bounds? Return to level! - if (ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MIN_Z) - { - if(zdir && z < PLAYER_MIN_Z) - { - return 0; - } - } - - if (ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MAX_Z) - { - if(zdir && z > PLAYER_MAX_Z) - { - return 0; - } - } - - // screen checking - // Kratus (29-04-21) Reduced the "screen checking" range from 10 to 5 to avoid the entities to stuck in the edge of the screen - // This change was made because the "common_trymove" function also has another "screen checking" with a range of 10 too - // If the "testmove" function has a equal or bigger range than the "common_trymove" function, sometimes the entities will stuck - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_SCREEN) - { - if(x < advancex + 5) - { - return 0; - } - else if(x > advancex + (videomodes.hRes - 5)) - { - return 0; - } - } - //-----------end of bounds checking----------- - - //-------------hole checking --------------------- - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_HOLE) - { - if(checkhole(x, z) && checkwall_index(x, z) < 0 && !check_platform_below(x, z, ent->position.y, ent)) - { - return -2; - } - } - //-----------end of hole checking--------------- - - //--------------obstacle checking ------------------ - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_OBSTACLE) - { - if((other = find_ent_here(ent, x, z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) && - (!other->animation->platform || !other->animation->platform[other->animpos][PLATFORM_HEIGHT])) - { - return 0; - } - } - //-----------end of obstacle checking-------------- - - // ---------------- platform checking---------------- - - if(ent->animation->size.y) - { - heightvar = ent->animation->size.y; - } - else - { - heightvar = ent->modeldata.size.y; - } - - // Check for obstacles with platform code and adjust base accordingly - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM && (other = check_platform_between(x, z, ent->position.y, ent->position.y + heightvar, ent)) ) - { - platbelow = check_platform_below(x, z, ent->position.y+T_WALKOFF, ent); - if ( !platbelow ) return 0; - else - { - float palt = get_platform_base(platbelow); - if ( other != platbelow && diff(ent->position.y,palt) > T_WALKOFF ) return 0; - } - } - //-----------end of platform checking------------------ - - // ------------------ wall checking --------------------- - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL && (wall = checkwall_below(x, z, T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[wall].height > ent->position.y) - { - if(validanim(ent, ANI_JUMP) && sz < level->walls[wall].z && sz > level->walls[wall].z - level->walls[wall].depth) //Can jump? - { - //rmin = (float)ent->modeldata.animation[ANI_JUMP]->range.x.min; - //rmax = (float)ent->modeldata.animation[ANI_JUMP]->range.x.max; - if(level->walls[wall].height < ent->position.y + ent->modeldata.animation[ANI_JUMP]->range.x.max) - { - return -1; - } - } - return 0; - } - //----------------end of wall checking-------------- - - return 1; - -} - -// find real opponent -void set_opponent(entity *ent, entity *other) -{ - entity *realself, *realother; - - if(!ent) - { - return; - } - - realself = ent; - while(realself->owner) - { - realself = realself->owner; - } - - realother = other; - while(realother && realother->owner) - { - realother = realother->owner; - } - - realself->opponent = ent->opponent = realother; - if(realother) - { - realother->opponent = other->opponent = realself; - } - -} - -/* -* Caskey, Damon V. -* 2023-04-10 -* -* Accept string input and return -* matching constant. -*/ -e_pain_config_flags pain_get_config_flag_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_pain_config_flags flag; - } item_lookup_table[] = { - {"none", PAIN_CONFIG_NONE}, - {"back_pain", PAIN_CONFIG_BACK_PAIN}, - {"fall_disable", PAIN_CONFIG_FALL_DISABLE}, - {"fall_disable_air", PAIN_CONFIG_FALL_DISABLE_AIR}, - {"pain_disable", PAIN_CONFIG_PAIN_DISABLE} - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown pain config flag (%s). \n", value); - return PAIN_CONFIG_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read pain configuration arguments directly from the source - line and combine their corresponding behavior flags. -*/ -e_pain_config_flags pain_get_config_flags_from_command_line( - const char* command_line -) -{ - const char* value; - s_command_argument_reader reader; - e_pain_config_flags result = PAIN_CONFIG_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= pain_get_config_flag_from_string(value); - } - - return result; -} - - -/* -* Caskey, Damon V. -* 2023-04-05 -* -* Accept string input and return -* matching constant. -*/ -e_block_config_flags block_get_config_flag_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_block_config_flags flag; - } item_lookup_table[] = { - {"none", BLOCK_CONFIG_NONE}, - {"active", BLOCK_CONFIG_ACTIVE}, - {"back", BLOCK_CONFIG_BACK}, - {"disabled", BLOCK_CONFIG_DISABLED}, - {"hold_impact", BLOCK_CONFIG_HOLD_IMPACT}, - {"hold_infinite", BLOCK_CONFIG_HOLD_INFINITE} - }; - - const size_t list_count = sizeof(item_lookup_table) / sizeof(*item_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, item_lookup_table[i].text_name) == 0) - { - return item_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * unknown flag. - */ - - printf("\n\n Unknown block config flag (%s). \n", value); - return BLOCK_CONFIG_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read blocking configuration arguments directly from the - source line and combine their corresponding behavior flags. -*/ -e_block_config_flags block_get_config_flags_from_command_line( - const char* command_line -) -{ - const char* value; - s_command_argument_reader reader; - e_block_config_flags result = BLOCK_CONFIG_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= block_get_config_flag_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2018-12-31 -* -* Initialize appropriate block animation and flags. Called when -* entity blocks actively (blocking before attack hits). Used -* by all player controlled entities or AI controlled entities -* with active block enabled. -*/ -void do_active_block(entity *ent) -{ - /* Run blocking action. */ - ent->takeaction = common_block; - - /* Stop movement. */ - ent->velocity.x = 0; - ent->velocity.z = 0; - - /* Set flags. */ - set_blocking(ent); - - /* End combo. */ - ent->combostep[0] = 0; - - /* - * If we have a block tranisiton animation, use it. Otherwise - * go right to block. - */ - if (validanim(ent, ANI_BLOCKSTART)) - { - ent_set_anim(ent, ANI_BLOCKSTART, 0); - } - else - { - ent_set_anim(ent, ANI_BLOCK, 0); - } -} - -/* -* Caskey, Damon V. -* 2018-09-16 -* -* Find out if attack can be blocked by entity. -* This function is concerned with the attack -* vs. entity in terms of game mechanics like -* guard break, attack type vs. defense, and -* so on. It does not handle rules for AI blocking. -*/ -bool check_blocking_eligible(entity *ent, entity *other, s_attack *attack, s_body *body, e_block_state_flags block_state) { - int temp_block_threshold = 0; - - /* Blocking must be active regardless of behavior overrides. */ - if (!(block_state & BLOCK_STATE_ACTIVE)) { - return false; - } - - /* Guard points only limit native blocking unless explicitly ignored. */ - if ((block_state & BLOCK_STATE_NATIVE) - && !(block_state & BLOCK_STATE_IGNORE_GUARD_POINTS) - && ent->modeldata.guardpoints > 0 - && ent->guardpoints <= 0) { - return false; - } - - /* Attack from behind? Can't block without an applicable override. */ - if (!(block_state & BLOCK_STATE_IGNORE_DIRECTION) - && ent->direction == other->direction - && !(ent->modeldata.block_config_flags & BLOCK_CONFIG_BACK)) { - return false; - } - - /* - * Attack eligibility consists of penetration vs. power and the - * combined model plus defense threshold. Direction and guard - * points have independent override flags above. - */ - if (!(block_state & BLOCK_STATE_IGNORE_ATTACK_ELIGIBILITY)) { - const s_defense* defense_object = defense_find_current_object(ent, body, attack->attack_type); - - if ((attack->no_block || defense_object->blockpower) - && attack->no_block >= defense_object->blockpower) { - return false; - } - - temp_block_threshold = ent->modeldata.thold + defense_object->blockthreshold; - - if (temp_block_threshold > attack->attack_force) { - return false; - } - } - - return true; -} - -// Caskey, Damon V. -// 2018-09-19 -// -// Mandatory conditions the AI must pass before it -// can decide to block. These are not rules for -// blocking in general. -bool check_blocking_rules(entity *ent) { - // If already blocking we can - // forget the rest and return - // true right away. - if (ent->blocking & BLOCK_STATE_ACTIVE) { - return true; - } - - // No blocking animation? - if (!validanim(ent, ANI_BLOCK)) { - return false; - } - - // Have to be idle. - if (!ent->idling) { - return false; - } - - // AI can't be attacking. - if (ent->attacking == ATTACKING_ACTIVE) { - return false; - } - - // Grappling? - if (ent->link) { - return false; - } - - // Airborne? - if (inair(ent)) { - return false; - } - - // Frozen? - if (ent->frozen) { - return false; - } - - // Falling? - if (ent->falling) { - return false; - } - - return true; -} - -// Caskey, Damon V. -// 2018-09-17 -// -// AI blocking decision. Handles AI's chances -// to block. Returns true if AI chooses to attempt -// a block. -bool check_blocking_decision(entity *ent) { - /* Per-instance override supplied through the blocking state. */ - if (ent->blocking & BLOCK_STATE_IGNORE_CHANCE) { - return true; - } - - // If we have active block enabled and we're - // already blocking, then we want the AI to - // keep blocking (like most players would). - if (ent->modeldata.block_config_flags & BLOCK_CONFIG_ACTIVE) { - if (ent->blocking & BLOCK_STATE_ACTIVE) { - return true; - } - } - - // Kratus (10-2021) Fixed the random blocking chance according with the "blockodds" value defined by the modder - // Now it works as intended (1 = block all / 2147483647 = never block) - // Run random chance against blockodds. If it - // passes, AI will block. - if ((rand32()&ent->modeldata.blockodds) == 0) { - return true; - } - - // If we got this far, we never decided to - // block, so return false. - return false; -} - -// Caskey, Damon V. -// 2018-09-17 -// -// Runs all blocking conditions and returns the active -// blocking state, or BLOCK_STATE_NONE if the attack -// should not be blocked. -e_block_state_flags check_blocking_master(entity *ent, entity *other, s_attack *attack, s_body *body) { - e_entity_type entity_type; - e_block_state_flags block_state; - - entity_type = ent->modeldata.type; - block_state = ent->blocking; - - if (ent->modeldata.block_config_flags & BLOCK_CONFIG_DISABLED) { - return BLOCK_STATE_NONE; - } - - /* - * Script-controlled blocking is already an explicit choice. It - * bypasses native initiation rules and chance while retaining - * common attack eligibility unless its individual bits disable it. - */ - if ((block_state & BLOCK_STATE_ACTIVE) - && !(block_state & BLOCK_STATE_NATIVE)) { - if (!check_blocking_eligible(ent, other, attack, body, block_state)) { - return BLOCK_STATE_NONE; - } - - return block_state; - } - - /* Players must have entered native blocking before impact. */ - if (entity_type & TYPE_PLAYER) { - if (!(block_state & BLOCK_STATE_ACTIVE)) { - return BLOCK_STATE_NONE; - } - } else { - /* AI either continues native blocking or chooses it on impact. */ - if (!check_blocking_rules(ent) || !check_blocking_decision(ent)) { - return BLOCK_STATE_NONE; - } - - block_state |= BLOCK_STATE_ACTIVE | BLOCK_STATE_NATIVE; - } - - if (!check_blocking_eligible(ent, other, attack, body, block_state)) { - return BLOCK_STATE_NONE; - } - - return block_state; -} - -/* -* Caskey, Damon V. -* 2018-09-18 -* -* Apply primary block settings, animations, -* actions, and scripts. -*/ -void set_blocking_action(entity *ent, entity *other, s_attack *attack, e_block_state_flags block_state) -{ - /* Execute the attacker's didhit script with blocked flag. */ - execute_didhit_script(other, ent, attack, 1); - - /* Native blocking owns the action, movement, and guard system. */ - if (block_state & BLOCK_STATE_NATIVE) { - ent->blocking |= block_state; - set_blocking(ent); - block_state = ent->blocking; - ent->takeaction = common_block; - - ent->velocity.x = 0; - ent->velocity.z = 0; - - if (!(block_state & BLOCK_STATE_IGNORE_GUARD_POINTS) - && ent->modeldata.guardpoints > 0) { - ent->guardpoints -= attack->guardcost; - } - } - - /* - * Blocked hit is still a hit, so - * increment the attacker's hit counter. - */ - ++other->animation->hit_count; - - /* Execute our block script. */ - execute_didblock_script(ent, other, attack); -} - -/* -* Caskey, Damon V. -* 2018-09-18 -* -* Return true if attack force is sufficient -* to cause blocking pain. Otherwise return false. -*/ -bool check_blocking_pain(const entity *ent, const s_attack *attack) { - - if (attack->attack_force >= ent->modeldata.blockpain) { - return true; - } - - return false; -} - -// Caskey, Damon V. -// 2018-09-21 -// -// Place entity into appropriate blocking animation. -void set_blocking_animation(entity *acting_entity, s_attack *attack, e_block_state_flags block_state) { - - /* - * Entity must have a valid blockpain and - * attack must meet or exceed the blockpain - * threshold. Otherwise, we just go to the - * normal block animation. - */ - - if(!(block_state & BLOCK_STATE_IGNORE_BLOCKPAIN) - && check_blocking_pain(acting_entity, attack) - && set_blockpain(acting_entity, attack->attack_type, 1)) { - return; - } - - ent_set_anim(acting_entity, ANI_BLOCK, 0); -} - -// Caskey, Damon V. -// 2018-09-21 -// -// Perform a block. -void do_passive_block(entity *ent, entity *other, s_attack *attack, e_block_state_flags block_state) -{ - /* Script-controlled blocks preserve the creator-controlled action. */ - if (block_state & BLOCK_STATE_NATIVE) { - set_blocking_animation(ent, attack, block_state); - } - - // Spawn the blocking flash. - spawn_attack_flash(ent, attack, attack->flash.model_block, ent->modeldata.flash.model_block); - - // Run blocking actions and scripts. - set_blocking_action(ent, other, attack, block_state); -} - -/* -* Caskey, Damon V. -* 2018-09-18 -* -* Handle flash spawning for hits. If conditions -* are met, spawns and prepares an appropriate -* flash effect entity at hit location. -* -* Returns pointer to flash entity if spawned, -* or NULL if not. -*/ -entity *spawn_attack_flash(entity *ent, s_attack *attack, int attack_flash, int model_flash) -{ - //printf("\n\n spawn_attack_flash(%p, %p, %d, %d)", ent, attack, attack_flash, model_flash); - - int model_index = MODEL_INDEX_NONE; // THe model we will spawn as flash entity. - entity *flash = NULL; // Flash entity pointer. - float attacker_position_z = lasthit.position.z; - float target_position_z = lasthit.position.z; - int set_layer = 0; - float position_z = 0.0; - int flash_layer_source = 0; - int flash_z_source = 0; - - /* - * Flash disabled by attack? - * We're done. Do nothing and exit. - */ - - if (attack->no_flash) - { - return NULL; - } - - /* - * If the model doesn't allow incoming custom - * flash effects, default to the model's global - * flash. - * - * Otherwise we need to see if the custom - * attack flash index is valid. If it is, then - * we will use it to spawn a flash effect. - */ - - if (!ent->modeldata.noatflash) - { - /* Valid custom flash index ? */ - if (attack_flash >= 0) - { - model_index = attack_flash; - } - else - { - model_index = model_flash; - } - } - else - { - model_index = model_flash; - } - - /* - * Get the attacker and target Z position. - * We are using local variables here just - * in case the attacker or target are not - * populated with valid entities. - */ - - if (lasthit.attacker) - { - attacker_position_z = lasthit.attacker->position.z; - } - - if (ent) - { - target_position_z = ent->position.z; - } - - /* - * Base Z position. This is the starting Z location - * to spawn flash. Start with global config value - * then apply adjustments (if any) from collison - * objects. Then we determine source for base Z - * using the total. - */ - - flash_z_source = global_config.flash.z_source; - flash_z_source += lasthit.attack ? lasthit.attack->flash.z_source : 0; - flash_z_source += lasthit.detect_body ? lasthit.detect_body->flash.z_source : 0; - - if (!flash_z_source) - { - position_z = lasthit.position.z; - } - else if (flash_z_source <= -255) - { - position_z = attacker_position_z < target_position_z ? attacker_position_z : target_position_z; - } - else if (flash_z_source > -255 && flash_z_source < 0) - { - position_z = attacker_position_z; - } - else if (flash_z_source > 0 && flash_z_source < 255) - { - position_z = target_position_z; - } - else // >= 255 - { - position_z = attacker_position_z > target_position_z ? attacker_position_z : target_position_z; - } - - flash = spawn(lasthit.position.x, position_z, lasthit.position.y, DIRECTION_LEFT, NULL, model_index, NULL); - - if (!flash) - { - return NULL; - } - - /* - * Adjust the layer (sort id). Combine values - * from attack, defense and global adjustment. - * - * Then we decide what to do from the total: - * - * 0: Use highest Z (attacker vs. recipient). - * <0: Use attacker. - * >0: Use defender. - * - * Then we combine all static adjustments and - * apply to flash model's sort ID. - */ - - //printf("\n\t global_config.flash_layer_source: %d", global_config.flash_layer_source); - - flash_layer_source = global_config.flash.layer_source; - flash_layer_source += lasthit.attack ? lasthit.attack->flash.layer_source : 0; - flash_layer_source += lasthit.detect_body ? lasthit.detect_body->flash.layer_source : 0; - - //printf("\n\t flash_layer_source: %d", flash_layer_source); - - if (!flash_layer_source) - { - set_layer = position_z; - } - else if (flash_layer_source <= -255) - { - set_layer = attacker_position_z < target_position_z ? attacker_position_z : target_position_z; - } - else if (flash_layer_source > -255 && flash_layer_source < 0) - { - set_layer = attacker_position_z; - } - else if (flash_layer_source > 0 && flash_layer_source < 255) - { - set_layer = target_position_z; - } - else // >= 255 - { - set_layer = attacker_position_z > target_position_z ? attacker_position_z : target_position_z; - } - - //printf("\n\t set_layer: %d", set_layer); - - set_layer += global_config.flash.layer_adjust + lasthit.attack->flash.layer_adjust + lasthit.detect_body->flash.layer_adjust; - - //printf("\n\t set_layer (adjusted): %d", set_layer); - - flash->modeldata.setlayer = set_layer; - - //printf("\n\t flash->modeldata.setlayer: %d", flash->modeldata.setlayer); - - /* - * We have a valid flash entity, let's - * set up its basic properties. - */ - - flash->spawntype = SPAWN_TYPE_FLASH; - flash->base = lasthit.position.y; - flash->autokill |= AUTOKILL_ANIMATION_COMPLETE; - - /* - * If flipping enabled, flip the flash right - * if hit is to right of target entity's - * position. - */ - - if (flash->modeldata.toflip) - { - if (lasthit.position.x > ent->position.x) - { - flash->direction = DIRECTION_RIGHT; - } - } - else - { - /* - * Kratus (10-2021) If the flag is 0, the flash will get the same direction as the defender - * This change was made to avoid the "random" direction applied by "toflip 1", because it depends on the "lasthit" position - * Without this line, the flash will never change the direction according to the defender's facing when "toflip" is 0 - */ - - flash->direction = (ent->direction); - } - - /* - * Run flash's spawn script and - * return the flash pointer. - */ - - execute_onspawn_script(flash); - - return flash; -} - -/* -* Caskey, Damon V. -* 2019-11-24 -* -* Check follow up conditions. Return true -* if all conditions pass, false otherwise. -*/ -int check_follow_up_condition(entity *ent, entity *target, s_anim *animation, int blocked) -{ - if (!animation->followup.animation) - { - return 0; - } - - /* No follow up allowed. */ - - if (animation->followup.condition & FOLLOW_CONDITION_NONE) - { - return 0; - } - - /* Always do follow up. */ - - if (animation->followup.condition & FOLLOW_CONDITION_ANY) - { - return 1; - } - - /* Block attack. */ - - if (animation->followup.condition & FOLLOW_CONDITION_BLOCK_FALSE) - { - if (blocked) - { - return 0; - } - } - - if (animation->followup.condition & FOLLOW_CONDITION_BLOCK_TRUE) - { - if (!blocked) - { - return 0; - } - } - - /* Possible to grab target. */ - - if (animation->followup.condition & FOLLOW_CONDITION_GRAB_FALSE) - { - if (check_cangrab(ent, target)) - { - return 0; - } - } - - if (animation->followup.condition & FOLLOW_CONDITION_GRAB_TRUE) - { - if (!check_cangrab(ent, target)) - { - return 0; - } - } - - /* We are hostile toward target. */ - - if (animation->followup.condition & FOLLOW_CONDITION_HOSTILE_ATTACKER_FALSE) - { - if (faction_check_is_hostile(ent, target)) - { - return 0; - } - } - - if (animation->followup.condition & FOLLOW_CONDITION_HOSTILE_ATTACKER_TRUE) - { - if (!faction_check_is_hostile(ent, target)) - { - return 0; - } - } - - /* Target is hostile toward us. */ - - if (animation->followup.condition & FOLLOW_CONDITION_HOSTILE_TARGET_FALSE) - { - if (faction_check_is_hostile(target, ent)) - { - return 0; - } - } - - if (animation->followup.condition & FOLLOW_CONDITION_HOSTILE_TARGET_TRUE) - { - if (!faction_check_is_hostile(target, ent)) - { - return 0; - } - } - - /* Lethal damage. */ - - if (animation->followup.condition & FOLLOW_CONDITION_LETHAL_FALSE) - { - if (target->energy_state.health_current <= 0) - { - return 0; - } - } - - if (animation->followup.condition & FOLLOW_CONDITION_LETHAL_TRUE) - { - if (target->energy_state.health_current > 0) - { - return 0; - } - } - - /* If all checks passed, return true. */ - - return 1; -} - -/* -* Caskey, Damon V. -* 2019-11-24 -* -* Attempt to perform follow up animation. -* If successful, sets entity animation to -* appropriate follow up and returns true. -*/ -int try_follow_up(entity *ent, entity *target, s_anim *animation, int didblock) -{ - animation_id_t animation_id = ANI_NONE; - - /* If we don't have a follow action, get out. */ - - if (!animation->followup.animation) - { - return 0; - } - - /* Must meet follow up conditions. */ - - if (!check_follow_up_condition(ent, target, animation, didblock)) - { - return 0; - } - - /* If we have the animation, then execute it now. */ - - animation_id = animfollows[animation->followup.animation - 1]; - - if (validanim(ent, animation_id)) - { - ent_set_anim(ent, animation_id, 1); - - return 1; - } - - return 0; -} - -/* -* Caskey, Damon V. -* 2019-12-03 -* -* Verify an attack meets conditions to trigger a counter action. -*/ -bool check_counter_condition(entity* target, entity* attacker, s_attack* attack_object, s_body* body_object) { - - s_counter_action* counter = &target->animation->counter_action; - int64_t force = 0; - - /* If there's no condition, get out now. */ - if (!counter->condition) { - return false; - } - - /* Verify in the frame range. */ - if (target->animpos < counter->frame.min || target->animpos > counter->frame.max) { - return false; - } - - /* Now we verify condition flags. */ - - /* Always is always... */ - if (counter->condition == COUNTER_ACTION_CONDITION_ANY) { - return true; - } - - /* In the back ? */ - if (counter->condition & COUNTER_ACTION_CONDITION_BACK_FALSE) { - if (target->direction == attacker->direction) { - return false; - } - } - - if (counter->condition & COUNTER_ACTION_CONDITION_BACK_TRUE) { - if (target->direction != attacker->direction) { - return false; - } - } - - /* We need defense object for subsequent checks. */ - const s_defense* defense_object = defense_find_current_object(target, body_object, attack_object->attack_type); - - /* Blockable ? */ - if (counter->condition & COUNTER_ACTION_CONDITION_BLOCK_FALSE) { - if (attack_object->no_block <= defense_object->blockpower) { - return false; - } - } - - if (counter->condition & COUNTER_ACTION_CONDITION_BLOCK_TRUE) { - if (attack_object->no_block > defense_object->blockpower) { - return false; - } - } - - /* Vs.lethal / non - lethal damage. */ - force = calculate_force_damage(target, attacker, attack_object, defense_object, FALSE); - - if (counter->condition & COUNTER_ACTION_CONDITION_DAMAGE_LETHAL_FALSE) { - if (target->energy_state.health_current <= force) { - return false; - } - } - - if (counter->condition & COUNTER_ACTION_CONDITION_DAMAGE_LETHAL_TRUE) { - if (target->energy_state.health_current > force) { - return false; - } - } - - /* Freeze attack ? */ - if (counter->condition & COUNTER_ACTION_CONDITION_FREEZE_FALSE) { - if (attack_object->freeze) { - return false; - } - } - - if (counter->condition & COUNTER_ACTION_CONDITION_FREEZE_TRUE) { - if (!attack_object->freeze) { - return false; - } - } - - /* Attacker hostile to us ? */ - if (counter->condition == COUNTER_ACTION_CONDITION_HOSTILE_ATTACKER_FALSE) { - if (faction_check_is_hostile(attacker, target)) { - return false; - } - } - - if (counter->condition == COUNTER_ACTION_CONDITION_HOSTILE_ATTACKER_TRUE) { - if (!faction_check_is_hostile(attacker, target)) { - return false; - } - } - - /* Hostile to attacker ? */ - if (counter->condition == COUNTER_ACTION_CONDITION_HOSTILE_TARGET_FALSE) { - if (faction_check_is_hostile(target, attacker)) { - return false; - } - } - - if (counter->condition == COUNTER_ACTION_CONDITION_HOSTILE_TARGET_TRUE) { - if (!faction_check_is_hostile(target, attacker)) { - return false; - } - } - - /* Passed all checks. We can return true. */ - return true; -} - -/* -* Caskey, Damon V. -* 2019-12-04 -* -* Attempt to perform counter action animation. -* If successful, sets entity animation to -* appropriate counter and returns true. -*/ -bool try_counter_action(entity* target, entity* attacker, s_attack* attack_object, s_body* body_object) { - - /* - * If we don't have a follow animation to use - * for counter, get out. - */ - - if (!target->animation->followup.animation) { - return false; - } - - /* Must meet counter action conditions. */ - - if (!check_counter_condition(target, attacker, attack_object, body_object)) { - return false; - } - - /* Take damage from attack ? */ - - if (target->animation->counter_action.damaged == COUNTER_ACTION_TAKE_DAMAGE_NORMAL) { - - /* We need the real damage. */ - const s_defense* defense_object = defense_find_current_object(target, body_object, attack_object->attack_type); - - const int64_t force = calculate_force_damage(target, attacker, attack_object, defense_object, FALSE); - - /* Revert lethal damage to 1. */ - if (target->energy_state.health_current - force <= 0) { - target->energy_state.health_current = 1; - - } else { - target->energy_state.health_current -= force; - } - } - - /* Set counter animation if we can. */ - - const animation_id_t current_follow_id = animfollows[target->animation->followup.animation - 1]; - - if (validanim(target, current_follow_id)) { - if (!target->modeldata.animation[current_follow_id]->attack_one) { - target->modeldata.animation[current_follow_id]->attack_one = target->animation->attack_one; - } - ent_set_anim(target, current_follow_id, 0); - } - - /* Flash spawn. */ - spawn_attack_flash(target, attack_object, attack_object->flash.model_block, target->modeldata.flash.model_block); - - return true; -} - -/* -* Caskey, Damon V. -* 2021-09-04 -* -* Update attack IDs to avoid single attack -* hitting on every update. Original concept -* of multiple attack IDs by Kratus. Migrated -* to array and encapsulated into function -* by DC. -*/ -void attack_update_id(entity* acting_entity, int attack_id) -{ - int i = 0; - int i_source = 0; - - /* - * Loop backward from highest element to second lowest. - * At each iteration, update the current attack ID - * element in array with value from element one lower - * in order. - * - * Ex: array[4] = array[3] - */ - for(i = MAX_ATTACK_IDS-1; i > 0; i--) - { - i_source = i - 1; - - acting_entity->attack_id_incoming[i] = acting_entity->attack_id_incoming[i_source]; - } - - /* Update element 0 with supplied ID. */ - acting_entity->attack_id_incoming[0] = attack_id; -} - -/* -* Caskey, Damon V. -* 2021-09-04 -* -* Compare supplied attack ID with existing -* attack IDs. Returns true if any match or -* if rule exceptions from attack or multihit -* are enabled. -*/ -int attack_id_check_match(entity* acting_entity, s_attack* attack_object, int attack_id, int multihit) -{ - int i = 0; - int max_id = MAX_ATTACK_IDS; - - /* - * Attack is allowed to ignore ID checks, so - * just return true now. - */ - if (attack_object->ignore_attack_id) - { - return 1; - } - - /* - * If mutihit is enabled, we only want - * check the first ID. Set our max to 1 - * so loop only runs for element 0. - */ - if (multihit) - { - max_id = 1; - } - - /* - * If any array element value matches supplied - * attack ID, we return true. - */ - for (i = 0; i < max_id; i++) - { - if (acting_entity->attack_id_incoming[i] == attack_id) - { - return 1; - } - } - - /* Couldn't find any match or exception. Return false. */ - return 0; -} - -/* -* Caskey, Damon V. -* 2026-07-23 -* -* Invoke legacy item collection with the -* collecting entity as self. -* -* didfind_item() does not yet accept the -* collector explicitly. Isolate that compatibility -*requirement here instead of exposing do_attack() to self. -*/ -static void do_attack_invoke_didfind_item(entity* target_entity, entity* item_entity) { - entity* previous_self = self; - - self = target_entity; - didfind_item(item_entity); - self = previous_self; -} - -void do_attack(entity *attacking_entity) { - int i = 0; - int64_t force = 0; - e_blocktype blocktype = BLOCK_TYPE_MP_FIRST; - entity* def = NULL; - entity* topowner = NULL; - entity* otherowner = NULL; - entity* target = NULL; - s_anim* current_anim = NULL; - s_attack* attack = NULL; - s_body* target_body_object = NULL; - const s_defense* defense_object = NULL; - bool didhit = false; // So a different sound effect can be played when an attack hits - bool didblock = false; // So a different sound effect can be played when an attack is blocked - e_block_state_flags block_state = BLOCK_STATE_NONE; - uint64_t current_attack_id = 0; - //int hit_detected = 0; // Has a hit been detected? - - -#define followed (current_anim!=attacking_entity->animation) - static uint64_t new_attack_id = 1; - - // Can't get hit after this - if(level_completed) { - return; - } - - topowner = attacking_entity; // trace the top owner, for projectile combo checking :) - while(topowner->owner) { - topowner = topowner->owner; - } - - // If any blast active, use indirect damage downstream. - const bool indirect = attacking_entity->projectile != BLAST_NONE ? true : false; - - // Every attack gets a unique ID to make sure no one - // gets hit more than once by the same attack - current_attack_id = attacking_entity->attack_id_outgoing; - - if(!current_attack_id) { - ++new_attack_id; - if(new_attack_id == 0) { - new_attack_id = 1; - } - attacking_entity->attack_id_outgoing = current_attack_id = new_attack_id; - } - - - current_anim = attacking_entity->animation; - - for(i = 0; i < ent_max && !followed; i++) { - target = ent_list[i]; - - if(!target->exists) { - continue; - } - - // Check collision. If a collision - // is found, the impacting - // collision pointers are also - // populated into lasthit, which - // we will use below. - if(!checkhit(attacking_entity, target)) { - continue; - } - - attack = lasthit.attack; - force = attack->attack_force; - target_body_object = lasthit.detect_collision_body->body; - defense_object = defense_find_current_object(target, target_body_object, attack->attack_type); - - // Verify target is alive. - if(target->death_state & DEATH_STATE_DEAD) { - continue; - } - - // Verify target is invincible, - // or attack type is an item. - // This is to allow item collection - // even while invincible. - if(target->invincible & INVINCIBLE_INTANGIBLE) { - if(attack->attack_type != ATK_ITEM) { - continue; - } - } - - // If attack is set to only hit - // one entity at a time (attack_one), - // we verify last hit (lasthit) is - // set. If last hit is set and - // differs from current target, - // then we are trying to hit - // another entity and should exit. - if(current_anim->attack_one) { - if(attacking_entity->lasthit) { - if(target != attacking_entity->lasthit) { - continue; - } - } - } - - /* - * Verify this is a faction we - * can hit. - */ - if (!faction_check_can_damage(attacking_entity, target, indirect)) { - continue; - } - - /* - * Pain time must have expired. - * This is to allow reasonable delay - * between hits so engine will not - * run hit on every update. - */ - if(target->next_hit_time >= _time) { - continue; - } - - // Target takedamage flag - // must be set. - if(!target->takedamage) { - continue; - } - - /* - * Avoid mutiple hits per update for a single collision. - * If any last incoming attack IDs match current attack ID - * then we exit iteration. - * - * Note that function includes exceptions for an attacks - * that ignore IDs and the global mutlihit cheat. - */ - const bool multihit_enabled = (global_config.cheats & CHEAT_OPTIONS_MULTIHIT_ACTIVE) != 0; - const bool attack_id_match = attack_id_check_match(target, attack, current_attack_id, multihit_enabled); - - if(attack_id_match) { - continue; - } - - // Target laying down? Exit if - // attack only hits standing targets. - // Otherwise exit if attack only hits - // grounded targets. - if(target->takeaction == common_lie) { - if(attack->otg == OTG_NONE) { - continue; - } - - } else { - if(attack->otg == OTG_GROUND_ONLY) { - continue; - } - } - - //printf("\n\n Check"); - - if(inair(target)) { - //printf("\n\n In air. \n\t Jugglecost: %d \n\t Jugglepoints: %d", attack->jugglecost, target->jugglepoints); - - if(attack->jugglecost > target->jugglepoints) { - //printf("\n\n Continue."); - continue; - } - } - - // Execute the doattack scripts so author can set take action - // before the hit code below does. - execute_ondoattack_script(target, attacking_entity, attack, EXCHANGE_RECIPIANT, current_attack_id); - execute_ondoattack_script(attacking_entity, target, attack, EXCHANGE_CONFERRER, current_attack_id); - - // 2010-12-31 - // Damon V. Caskey - - // If lasthit.confirm is not true, it must have been turned off by the author; almost - // certainly with the ondoattack event scripts above. Skip the engine's - // default hit handling below. Useful for scripting parry systems, alternate blocking, - // or other custom collision events. - if(lasthit.confirm) { - didhit = true; - - } else { - continue; - } - - otherowner = target; // trace top owner for opponent - while(otherowner->owner) { - otherowner = otherowner->owner; - } - - // Ensure projectile can't hit its owner. Important since projectile attack - // boxes usualy overlap owner's body boxes as the projectile is first thrown. - // Note if an author wants to add projectile reflection feature, they need to - // change the projectile's owner when reflect effect occurs, or the reflected - // projectile won't be able to hit its original owner. If they need to know the - // original owner after changing the owner property, they can check the parent - // property. - if(topowner == otherowner) { - didhit = false; - } - - //Ground missle checking, and bullets wont hit each other - - const bool both_owners_exist = attacking_entity->owner && target->owner; - const bool ground_attack_is_airborne = attacking_entity->modeldata.ground && inair(attacking_entity); - - if(both_owners_exist || ground_attack_is_airborne) { - didhit = false; - } - - // Blocking code section. - if(didhit) { - if(attack->attack_type == ATK_ITEM) { - do_item_script(target, attacking_entity); - - do_attack_invoke_didfind_item(target, attacking_entity); - return; - } - - /* - * Set bomb projectile to detonate status if it - * hits. Set to detonate if it takes a hit and - * has the "take hit" detonate animation. - * - * Bombs that don't have detonate animation take - * hits normally. - */ - - if(target->toexplode & EXPLODE_PREPARE_TOUCH) { - if (validanim(target, ANI_ATTACK2)) { - target->toexplode |= EXPLODE_DETONATE_DAMAGED; - } - } - - if(attacking_entity->toexplode & EXPLODE_PREPARE_TOUCH) { - attacking_entity->toexplode |= EXPLODE_DETONATE_HIT; - } - - /* - * Reduce available juggle points. - */ - if(inair(target)) { - target->jugglepoints -= attack->jugglecost; - } - - block_state = check_blocking_master(target, attacking_entity, attack, target_body_object); - didblock = (block_state & BLOCK_STATE_ACTIVE) != 0; - - // Blocking the attack? - if(didblock) { - // Perform the blocking actions. - do_passive_block(target, attacking_entity, attack, block_state); - - } else if(try_counter_action(target, attacking_entity, attack, target_body_object)) { // Counter action? - - /* Kratus(20 - 04 - 21) used by the multihit glitch memorization. */ - attack_update_id(target, current_attack_id); - - } else if(target->takedamage(target, attacking_entity, attack, 0, defense_object)) { - - - // This is the code block for normal hits. - // The hit was not blocked, countered, or - // otherwise nullified, and this entity - // has takedamage() function. Let's - // process the hit. - - execute_didhit_script(attacking_entity, target, attack, 0); - ++attacking_entity->animation->hit_count; - - attacking_entity->lasthit = target; - - // Flash spawn. - spawn_attack_flash(target, attack, attack->flash.model_hit, target->modeldata.flash.model_hit); - - // Add to owner's combo time. - topowner->combotime = _time + combodelay; - - // If equalairpause is set, inair(attacking_entity) is nolonger a condition for extra pausetime. - if(attacking_entity->pausetime < _time || (inair(attacking_entity) && !equalairpause)) { - // Adds pause to the current animation - attacking_entity->toss_time += attack->pause_add; // So jump height pauses in midair - attacking_entity->nextmove += attack->pause_add; // xdir, zdir - - attacking_entity->nextanim = animation_timestamp_add_bounded( - attacking_entity->nextanim, - attack->pause_add - ); - - attacking_entity->nextthink += attack->pause_add; // So anything that auto moves will pause - attacking_entity->pausetime = _time + attack->pause_add ; //UT: temporary solution - } - - target->toss_time += attack->pause_add; // So jump height pauses in midair - target->nextmove += attack->pause_add; // xdir, zdir - target->nextanim = animation_timestamp_add_bounded( - target->nextanim, - attack->pause_add - ); // Pause animation for a bit. - target->nextthink += attack->pause_add; // So anything that auto moves will pause - - } else { - // If we made it to this block the hit was - // not countered or blocked, but the entity - // does not have a takedamage() function. It - // therefore must be a type that is meant - // to ignore hits. - - didhit = false; - continue; - } - - // 2007 3 24, hmm, def should be like this - if(didblock && !def) { - def = target; - } - - // Attacker executes a follow up animation if it can. - try_follow_up(attacking_entity, target, attacking_entity->animation, didblock); - - /* Kratus(20 - 04 - 21) used by the multihit glitch memorization. */ - attack_update_id(target, current_attack_id); - - /* - * Utunnels - * 2011-11-24 UT - * - * Move the next_hit_time logic here, because block needs this - * as well. Otherwise, blockratio causes instant death - */ - target->next_hit_time = _time + (attack->next_hit_time ? attack->next_hit_time : (global_config.game_speed / 5)); - target->nextattack = 0; // reset this, make it easier to fight back - } - - } - - - // Did we get a hit? let's process it. - if(didhit) { - // Handle energy cost if attacking animation has any. - - // Caskey, Damon V. - // 2020-01-22 - // - // I'm honestly not sure how the legacy logic works. Will need to spend - // some more time breaking it down. - - if(current_anim->energy_cost.cost > 0) { - - // well, dont check player or not - UTunnels. TODO: take care of that health cheat - if(attacking_entity == topowner && nocost && !(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE)) { - attacking_entity->tocost = 1; // Set flag so life is subtracted when animation is finished - - } else if(attacking_entity != topowner && nocost && !(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE) && !attacking_entity->tocost) { // if it is not top, then must be a shot. - - if(current_anim->energy_cost.mponly != COST_TYPE_MP_THEN_HP && topowner->energy_state.mp_current > 0) { - - topowner->energy_state.mp_current -= current_anim->energy_cost.cost; - if(topowner->energy_state.mp_current < 0) { - topowner->energy_state.mp_current = 0; - } - - } else { - topowner->energy_state.health_current -= current_anim->energy_cost.cost; - - if(topowner->energy_state.health_current <= 0) { - topowner->energy_state.health_current = 1; - } - } - - // Little backwards, but set to 1 so cost doesn't get subtracted multiple times. - attacking_entity->tocost = 1; - } - } - - /* - * Caskey, Damon V. - * 2008-04-27 - * - * Added checks for defense property specific blockratio and type. - * Could probably use some cleaning. - */ - if(didblock && level->nohurt == DAMAGE_FROM_ENEMY_ON) { - - /* Gets total force after offense and defense adjustments. */ - force = calculate_force_damage(def, attacking_entity, attack, defense_object, true); - - /* - * Handle block type. Global blocktype is a - * legacy true/false set by "mpblock", so If - * our defense object defaults to global we - * will need to get the correct constant - * before we run downstream switch statement. - * - * True = MP then HP. - * False = HP. - */ - - if (defense_object->blocktype == BLOCK_TYPE_GLOBAL) { - blocktype = global_config.block_type ? BLOCK_TYPE_MP_FIRST : BLOCK_TYPE_HP; - - } else { - blocktype = defense_object->blocktype; - } - - switch (blocktype) { - case BLOCK_TYPE_GLOBAL: - case BLOCK_TYPE_HP: - /* - * Do nothing. This allows creators to overidde energy_cost - * mponly 1 with health only. - */ - break; - - case BLOCK_TYPE_MP_ONLY: - - def->energy_state.mp_current -= force; - force = 0; - - if(def->energy_state.mp_current < 0) { - def->energy_state.mp_current = 0; - } - - break; - - case BLOCK_TYPE_MP_FIRST: - - def->energy_state.mp_current -= force; - - /* - * If there isn't enough MP to cover force, subtract remaining - * MP from force and set MP to 0. - */ - if(def->energy_state.mp_current < 0) { - force = -def->energy_state.mp_current; - def->energy_state.mp_current = 0; - - } else { - force = 0; - } - - break; - - case BLOCK_TYPE_BOTH: - - def->energy_state.mp_current -= force; - - if(def->energy_state.mp_current < 0) { - def->energy_state.mp_current = 0; - } - - break; - } - - // Apply remaining damage force to HP after blocking calculations. - // - // 1. Damage force < HP: Subtract directly - Don't use take - // damage because we don't want a visible reaction in game. - // - // 2. Damage force > HP, but nochipdeath is enabled (meaning - // chip death is not allowed) - Set HP to 1. Again, we don't - // want a reaction. - // - // 3. Damage force > HP, chip death is allowed - Set take - // damage so engine will apply damage normally and KO the - // entity. - if(force < def->energy_state.health_current) { - def->energy_state.health_current -= force; - } else if(nochipdeath) { - def->energy_state.health_current = 1; - } else { - def->takedamage(def, attacking_entity, attack, 0, defense_object); - } - } - - // If the attack was not blocked, let's increment the - // attacker's combo counter and time. - if(!didblock) { - - topowner->rush.time = _time + (global_config.game_speed * rush[1]); - topowner->rush.count++; - - if(topowner->rush.count > topowner->rush.max && topowner->rush.count > 1) { - topowner->rush.max = topowner->rush.count; - } - } - - /* Choose the sound and playback speed for hit. */ - play_hit_impact_sound(attack, attacking_entity, didblock); - - /* - * If the auto kill flag is set, attacker - * kills itself instantly. Used mainly for - * projectiles. - */ - if(attacking_entity->autokill & AUTOKILL_ATTACK_HIT) { - kill_entity(attacking_entity, KILL_ENTITY_TRIGGER_AUTOKILL_ATTACK_HIT); - } - } -#undef followed -} - -/* -* Caskey, Damon V -* 2021-11-16 -* -* Play appropriate hit impact sound -* based on hit/block, attack force, -* and defined samples. -*/ -int play_hit_impact_sound(s_attack* attack_object, entity* attacking_entity, int attack_blocked) -{ -#define PLAYBACK_PRIORITY 0 -#define PLAYBACK_SPEED_MIN 60 -#define PLAYBACK_SPEED_MAX 100 -#define PLAYBACK_SPEED_MODIFIER 5 - - int sound_index = SAMPLE_ID_NONE; - int playback_speed = PLAYBACK_SPEED_MAX; - - /* - * Play the impact sound effect. - * - * 1. Attack blocked. - * a) Attack has block sound - play attack block sound. - * b) Attack does not have block sound - play global block sound. - * - * 2. Attacker is actually a "projectile" (as in, thrown or knocked - * through the air by a blasting attack) - play global indirect sound. - * - * 3. Typical attack hit. - * a) Attack has hit sound - play attack hit sound. - * b) Attack does not have hit sound - play global hit sound. - */ - - if (attack_blocked) - { - if (attack_object->blocksound >= 0) - { - sound_index = attack_object->blocksound; - } - else if (global_sample_list.block >= 0) - { - sound_index = global_sample_list.block; - } - } - else if (attacking_entity->projectile != BLAST_NONE && global_sample_list.indirect >= 0) - { - sound_index = global_sample_list.indirect; - } - else if (attack_object->hitsound >= 0) - { - sound_index = attack_object->hitsound; - - /* - * If noslofx is enabled, then just play sound at default speed. - * Otherwise, subtract 5 from damage force, and then subtract - * that result from default play speed. - * - * This has the effect of slowing down the sound playback as damage - * increases to give it a slightly lower tone and more impact. - */ - - playback_speed = PLAYBACK_SPEED_MAX - (noslowfx ? 0 : (attack_object->attack_force - PLAYBACK_SPEED_MODIFIER)); - - if (playback_speed > PLAYBACK_SPEED_MAX) - { - playback_speed = PLAYBACK_SPEED_MAX; - } - else if (playback_speed < PLAYBACK_SPEED_MIN) - { - playback_speed = PLAYBACK_SPEED_MIN; - } - } - - if (sound_index != SAMPLE_ID_NONE) - { - sound_play_sample(sound_index, PLAYBACK_PRIORITY, savedata.effectvol, savedata.effectvol, playback_speed); - } - - return sound_index; - -#undef PLAYBACK_PRIORITY -#undef PLAYBACK_SPEED_MIN -#undef PLAYBACK_SPEED_MAX -#undef PLAYBACK_SPEED_MODIFIER -} - -// it can be useful for next changes -/*static int is_obstacle_around(entity* ent, float threshold) -{ - int i, j; - int heightvar; - - if(ent->animation->size.y) - { - heightvar = ent->animation->size.y; - } - else - { - heightvar = ent->modeldata.size.y; - } - - for(i = -1; i <= 1; i++ ) - { - for(j = -1; j <= 1; j++ ) - { - int w; - entity *hito = find_ent_here(ent, ent->position.x+(i*threshold), ent->position.z+(j*threshold), (TYPE_OBSTACLE | TYPE_TRAP), NULL); - entity *hitp = check_platform_between(ent->position.x+(i*threshold), ent->position.z+(j*threshold), ent->position.y, ent->position.y + heightvar, ent); - int hitw = (int)( (w = checkwall_below(ent->position.x+(i*threshold), ent->position.z+(j*threshold), T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[w].height > ent->position.y ); - - if ( hito || hitp || hitw ) return 1; - } - } - - return 0; -}*/ - -// Caskey, Damon V. -// 2018-04-20 -// -// Go to landing frame if available. Also spawns an effect ("dust") entity if set. -bool check_landframe(entity *ent) -{ - entity *effect; - - s_onframe_set* land; - - land = &ent->animation->landframe; - - // Must have a landframe. - if(land->frame == FRAME_NONE) - { - return 0; - } - - // Can't be bound with a landframe override. - if(check_bind_override(ent, BIND_CONFIG_OVERRIDE_LANDFRAME)) - { - return 0; - } - - // Can't be passed over current animation's frame count. - if(land->frame > ent->animation->numframes) - { - return 0; - } - - // Can't be already at or passed land frame. - if(ent->animpos >= land->frame) - { - return 0; - } - - // If a land frame dust effect entity is set, let's spawn it here. - if(land->model_index >= 0) - { - effect = spawn(ent->position.x, ent->position.z, ent->position.y, ent->direction, NULL, land->model_index, NULL); - - if(effect) - { - effect->spawntype = SPAWN_TYPE_DUST_LAND; - effect->base = ent->position.y; - effect->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(effect); - } - } - - update_frame(ent, land->frame); - - return 1; -} - -// Caskey, Damon V. -// 2018-04-20 -// -// Go to landing frame if available. Also spawns an effect ("dust") entity if set. -bool check_frame_set_drop(entity* ent) -{ - entity* effect; - - s_onframe_set* drop; - - drop = &ent->animation->dropframe; - - // Dropframe set? - if (drop->frame == FRAME_NONE) - { - return 0; - } - - // Falling? - if (ent->velocity.y > 0) - { - return 0; - } - - /* Can't be bound with a drop frame override. */ - if (check_bind_override(ent, BIND_CONFIG_OVERRIDE_DROPFRAME)) - { - return 0; - } - - // Can't be passed over current animation's frame count. - if (drop->frame > ent->animation->numframes) - { - return 0; - } - - // Can't be already at or passed drop frame. - if (ent->animpos >= drop->frame) - { - return 0; - } - - // Passed all checks. Let's update frame and spawn model (if available). - - update_frame(ent, drop->frame); - - // If a frame set effect entity is set, let's spawn it here. - if (drop->model_index != MODEL_INDEX_NONE) - { - effect = spawn(ent->position.x, ent->position.z, ent->position.y, ent->direction, NULL, drop->model_index, NULL); - - if (effect) - { - effect->spawntype = SPAWN_TYPE_DUST_DROP; - effect->base = ent->position.y; - effect->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(effect); - } - } - - return 1; -} - - -int check_edge(entity *ent) -{ - float x = ent->position.x; - float z = ent->position.z; - float y = ent->position.y; - e_direction dir = ent->direction; - float height = 0.0f; - float t_alt = 1.0f, t_walkoff = 1.0f, t_edge_default = 8.0f; - float t_edge_x = t_edge_default, t_edge_z = t_edge_default / 2; - - if (ent->modeldata.edgerange.x > t_edge_x) t_edge_x = ent->modeldata.edgerange.x; - if (ent->modeldata.edgerange.z > t_edge_z) t_edge_z = ent->modeldata.edgerange.z; - - if(ent->animation->size.y) height = ent->animation->size.y; - else height = ent->modeldata.size.y; - - //test base - float base_left = checkbase(x - t_edge_x, z, y + t_walkoff, ent); - float base_right = checkbase(x + t_edge_x, z, y + t_walkoff, ent); - float base_up = checkbase(x, z - t_edge_z, y + t_walkoff, ent); - float base_down = checkbase(x, z + t_edge_z, y + t_walkoff, ent); - - entity *plat_left = check_platform_between(x - t_edge_x, z, y + t_walkoff, y + height, ent); - entity *plat_right = check_platform_between(x + t_edge_x, z, y + t_walkoff, y + height, ent); - entity *plat_up = check_platform_between(x, z - t_edge_z, y + t_walkoff, y + height, ent); - entity *plat_down = check_platform_between(x, z + t_edge_z, y + t_walkoff, y + height, ent); - - if ( (base_left < y - t_alt) && plat_left == NULL ) return EDGE_LEFT; - else if ( (base_right < y - t_alt) && plat_right == NULL ) return EDGE_RIGHT; - - // priority based on direction check - if (dir == DIRECTION_LEFT) - { - if ( (base_left < y - t_alt) && plat_left == NULL ) return EDGE_LEFT; - else if ( (base_right < y - t_alt) && plat_right == NULL ) return EDGE_RIGHT; - } - else - { - if ( (base_right < y - t_alt) && plat_right == NULL ) return EDGE_RIGHT; - else if ( (base_left < y - t_alt) && plat_left == NULL ) return EDGE_LEFT; - } - - if ( - ((base_up < y - t_alt) && plat_up == NULL) || - ((base_down < y - t_alt) && plat_down == NULL) - ) return EDGE_LEFT + EDGE_RIGHT; - - return EDGE_NONE; -} - -void check_gravity(entity *e) -{ - - int heightvar; - entity *other = NULL, *dust, *tempself, *plat = NULL; - float gravity; - float fmin, fmax; - - if(e->update_mark & UPDATE_MARK_CHECK_GRAVITY) - { - return; - } - - tempself = self; - self = e; - - adjust_base(self, &plat); - if (self->position.y <= self->base) self->edge = check_edge(self); // && self->idling & IDLING_ACTIVE - else self->edge = EDGE_NONE; - - if(!is_frozen(self) )// Incase an entity is in the air, don't update animations - { - if(self->animation->size.y) - { - heightvar = self->animation->size.y; - } - else - { - heightvar = self->modeldata.size.y; - } - - // White Dragon: turn-off the hitwall flag if you're not near a obstacle. this help to avoid a hit loop - /*if( (self->position.y <= self->base || !inair(self)) && self->velocity.y <= 0) - { - if ( self->hitwall && !is_obstacle_around(self,1.0) ) self->hitwall = 0; - }*/ - - if((self->falling || self->velocity.y || self->position.y != self->base) && self->toss_time <= _time) - { - if(heightvar && self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM && self->velocity.y > 0) - { - other = check_platform_above_entity(self); - } - else - { - other = NULL; - } - - if( other && other->position.y <= self->position.y + heightvar && !(other->modeldata.move_config_flags & MOVE_CONFIG_NO_HIT_HEAD)) - { - if(self->hithead == NULL) // bang! Hit the ceiling. - { - self->velocity.y = 0; - self->hithead = other; - execute_onblocky_script(self, other); - } - } - else - { - self->hithead = NULL; - } - - // gravity, antigravity factors - self->position.y += self->velocity.y * 100.0 / global_config.game_speed; - if(!(self->animation->move_config_flags & MOVE_CONFIG_SUBJECT_TO_GRAVITY)) - { - gravity = 0; - } - else - { - gravity = (level ? level->gravity : default_level_gravity) * (1.0 - self->modeldata.antigravity); - } - - if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_GRAVITY) - { - self->velocity.y += gravity * 100.0 / global_config.game_speed; - } - - fmin = (level ? level->maxfallspeed : default_level_maxfallspeed); - fmax = (level ? level->maxtossspeed : default_level_maxtossspeed); - - if(self->velocity.y < fmin) - { - self->velocity.y = fmin; - } - else if(self->velocity.y > fmax) - { - self->velocity.y = fmax; - } - - // Evaluate and apply drop frame settings if we have them. - check_frame_set_drop(self); - - if (self->velocity.y) - { - execute_onmovea_script(self); //Move A event. - } - - if( self->idling && validanim(self, ANI_WALKOFF) && diff(self->position.y, self->base) > T_WALKOFF ) - { - entity *cplat = check_platform_below(self->position.x,self->position.z-1.0,self->position.y,self); - - // White Dragon: fix for too low velocityz - if ( !cplat || (cplat && diff(get_platform_base(cplat),self->position.y) > T_WALKOFF) ) - { - self->idling = IDLING_NONE; - self->ducking = DUCK_NONE; - self->takeaction = common_walkoff; - ent_set_anim(self, ANI_WALKOFF, 0); - self->landed_on_platform = plat = NULL; - } - } - - // UTunnels: tossv <= 0 means land, while >0 means still rising, so - // you wont be stopped if you are passing the edge of a wall - if( self->position.y <= self->base || !inair(self)) - { - // 0+ means still rising. We need to be falling. - if(self->velocity.y <=0) - { - // No bind target, or binding set to ignore fall lands. - if(!check_bind_override(self, BIND_CONFIG_OVERRIDE_FALL_LAND)) - { - self->position.y = self->base; - self->falling = 0; - - if ( self->hitwall ) self->hitwall = 0; - - // cust dust entity - if(self->modeldata.dust.fall_land >= 0 && self->velocity.y < -1 && self->drop) - { - dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.fall_land, NULL); - if(dust) - { - dust->spawntype = SPAWN_TYPE_DUST_FALL; - dust->base = self->position.y; - dust->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(dust); - } - } - - // bounce/quake - if(tobounce(self) && self->modeldata.bounce) - { - int i; - self->velocity.x /= self->animation->bounce_factor; - self->velocity.z /= self->animation->bounce_factor; - toss(self, (-self->velocity.y) / self->animation->bounce_factor); - if(level && !(self->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SCREEN)) - { - level->quake = 4; // Don't shake if specified - } - if(global_sample_list.fall >= 0) - { - sound_play_sample(global_sample_list.fall, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(self->modeldata.type & TYPE_PLAYER) - { - if (savedata.joyrumble[self->playerindex]) control_rumble(self->playerindex, 1, 100 * (int)self->velocity.y / 2); - } - for(i = 0; i < MAX_PLAYERS; i++) - { - if (savedata.joyrumble[i]) control_rumble(i, 1, 75 * (int)self->velocity.y / 2); - } - } - else if((!self->animation->move[self->animpos]->base || self->animation->move[self->animpos]->base < 0) && - (!self->animation->move[self->animpos]->axis.y || self->animation->move[self->animpos]->axis.y <= 0)) - { - self->velocity.x = 0; - self->velocity.z = 0; - self->velocity.y = 0; - } - else - { - self->velocity.y = 0; - } - - if(plat && !self->landed_on_platform && self->position.y <= plat->position.y + plat->animation->platform[plat->animpos][PLATFORM_HEIGHT]) - { - self->landed_on_platform = plat; - } - - // Set landing frame if we have one. - check_landframe(self); - - // Taking damage on a landing? - // Kratus (01-2024) Now the damage_on_landing is affected by infinite health cheat - // Kratus (02-2024) Minor fix to make health cheat affect players only - if(((self->modeldata.type & TYPE_PLAYER) && !(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE))|| - !(self->modeldata.type & TYPE_PLAYER)) - { - checkdamageonlanding(self); - } - - // in case landing, set hithead to NULL - self->hithead = NULL; - } - } - }// end of if - land checking - }// end of if - in-air checking - - if(self->toss_time <= _time) - { - self->toss_time = _time + 1; - } - - }//end of if - - self->update_mark |= UPDATE_MARK_CHECK_GRAVITY; - - self = tempself; -} - -bool check_lost() { - - s_attack attack = emptyattack; - int osk = self->modeldata.offscreenkill ? self->modeldata.offscreenkill : DEFAULT_OFFSCREEN_KILL; - - if((self->position.z != ITEM_HIDE_POSITION_Z && (advancex - self->position.x > osk || self->position.x - advancex - videomodes.hRes > osk || - (level->scrolldir != SCROLL_UP && level->scrolldir != SCROLL_DOWN && (advancey - self->position.z + self->position.y > osk || self->position.z - self->position.y - advancey - videomodes.vRes > osk)) || - ((level->scrolldir == SCROLL_UP || level->scrolldir == SCROLL_DOWN) && (self->position.z - self->position.y < -osk || self->position.z - self->position.y > videomodes.vRes + osk)) ) ) - || self->position.y < 2 * PIT_DEPTH) { - - if(self->modeldata.type & TYPE_PLAYER) { - player_die(); - - } else { - kill_entity(self, KILL_ENTITY_TRIGGER_OUT_OF_BOUNDS); - } - return true; - } - - const s_defense* defense_object = defense_find_current_object(self, NULL, attack.attack_type); - - // fall into a pit - if(self->position.y < PIT_DEPTH) { - - if(!self->takedamage) { - kill_entity(self, KILL_ENTITY_TRIGGER_PIT); - - } else { - attack.dropv = default_model_dropv; - attack.attack_force = self->energy_state.health_current; - attack.attack_type = ATK_PIT; - - self->takedamage(self, self, &attack, 0, defense_object); - } - return true; - - } else if(self->lifespancountdown < 0) { //Lifespan expired. - - if(!self->takedamage) { - kill_entity(self, KILL_ENTITY_TRIGGER_LIFESPAN); - - } else { - attack.dropv = default_model_dropv; - attack.attack_force = self->energy_state.health_current; - attack.attack_type = ATK_LIFESPAN; - self->takedamage(self, self, &attack, 0, defense_object); - } - return true; - } - - // Doom count down - if(!is_frozen(self) && self->lifespancountdown != LIFESPAN_DEFAULT) { - self->lifespancountdown--; - } - - return false; -} - -// grab walk check -void check_link_move(float xdir, float zdir) -{ - float x, z, gx, gz; - int tryresult; - entity *tempself = self; - - gx = self->grabbing->position.x; - gz = self->grabbing->position.z; - x = self->position.x; - z = self->position.z; - self = self->grabbing; - tryresult = self->trymove(xdir, zdir); - self = tempself; - - if(tryresult != 1) // changed - { - xdir = self->grabbing->position.x - gx; - zdir = self->grabbing->position.z - gz; - } - tryresult = self->trymove(xdir, zdir); - if(tryresult != 1) - { - self->grabbing->position.x = self->position.x - x + gx; - self->grabbing->position.z = self->position.z - z + gz; - } -} - -/* -* Caskey, Damon V. -* 2022-04-21 -* -* Return true if currently in any -* active game or menu screen. -*/ -int check_in_screen() -{ - /* - * Check the screen status first. - * It should be faster. - */ - - if (screen_status & (IN_SCREEN_BUTTON_CONFIG_MENU | IN_SCREEN_SELECT | IN_SCREEN_TITLE | IN_SCREEN_HALL_OF_FAME | IN_SCREEN_GAME_OVER | IN_SCREEN_SHOW_COMPLETE | IN_SCREEN_SHOW_GO_ARROW | IN_SCREEN_ENGINE_CREDIT | IN_SCREEN_MENU | IN_SCREEN_GAME_START_MENU | IN_SCREEN_NEW_GAME_MENU | IN_SCREEN_LOAD_GAME_MENU | IN_SCREEN_OPTIONS_MENU | IN_SCREEN_CONTROL_OPTIONS_MENU | IN_SCREEN_SOUND_OPTIONS_MENU | IN_SCREEN_VIDEO_OPTIONS_MENU | IN_SCREEN_SYSTEM_OPTIONS_MENU)) - { - return 1; - } - - if (currentScene) - { - return 1; - } - - return 0; - -} - -void check_ai() -{ - if(self->nextthink <= _time && !endgame) - { - self->update_mark |= UPDATE_MARK_CHECK_AI; //mark it - - // take actions - if(self->takeaction) - { - self->takeaction(); - } - - // A.I. think - if(self->think) - { - if(self->nextthink <= _time) - { - self->nextthink = _time + THINK_SPEED; - } - // use noaicontrol flag to turn of A.I. think - if(!self->noaicontrol) - { - self->think(); - } - } - - // Execute think script - execute_think_script(self); - - // Used so all entities can have a spawn animation, and then just changes to the idle animation when done - // move here to so players wont get stuck - if((self->animation == self->modeldata.animation[ANI_SPAWN] || self->animation == self->modeldata.animation[ANI_RESPAWN]) && !self->animating /*&& (!inair(self)||!(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_GRAVITY))*/) - { - set_idle(self); - } - } -} - -float check_basemap(int x, int z) -{ - float maxbase = 0, base = T_MIN_BASEMAP; - int i; - - if(!level) - { - return 0; - } - - for(i = 0; i < level->numbasemaps; i++) - { - if(x >= level->basemaps[i].position.x && x < level->basemaps[i].position.x + level->basemaps[i].size.x && - z >= level->basemaps[i].position.z && z < level->basemaps[i].position.z + level->basemaps[i].size.z) - { - base = level->basemaps[i].map[x - level->basemaps[i].position.x + level->basemaps[i].size.x * (z - level->basemaps[i].position.z)]; - if(base > maxbase) - { - maxbase = base; - } - } - } - return base == T_MIN_BASEMAP ? base : maxbase; -} - -int check_basemap_index(int x, int z) -{ - float maxbase = 0, base = T_MIN_BASEMAP; - int i, index = -1; - - if(!level) - { - return -1; - } - - for(i = 0; i < level->numbasemaps; i++) - { - if(x >= level->basemaps[i].position.x && x < level->basemaps[i].position.x + level->basemaps[i].size.x && - z >= level->basemaps[i].position.z && z < level->basemaps[i].position.z + level->basemaps[i].size.z) - { - base = level->basemaps[i].map[x - level->basemaps[i].position.x + level->basemaps[i].size.x * (z - level->basemaps[i].position.z)]; - if(base > maxbase) - { - maxbase = base; - index = i; - } - } - } - return base == T_MIN_BASEMAP ? -1 : index; -} - - - -void adjust_base(entity *acting_entity, entity **pla) -{ - int wall = WALL_INDEX_NONE; - int in_hole = 0; - int hole_index = HOLE_INDEX_NONE; - float seta = 0; - float maxbase = 0; - float base_adjust = 0.0; - entity* other = NULL; - entity* platform = NULL; - - if(acting_entity->velocity.y > 0) - { - acting_entity->landed_on_platform = NULL; - } - - /* - * If no platform found below entity - * then clear our local platform and - * the platform argument. - * - * If entity isn't subject to platform - * at all, then clear entity's last - * landed platform, platform parameter, - * and the local other entity. - */ - if(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM) - { - other = check_platform_below_entity(acting_entity); - if(!other && acting_entity->landed_on_platform) - { - *pla = NULL; - acting_entity->landed_on_platform = NULL; - } - } - else - { - *pla = NULL; - other = NULL; - acting_entity->landed_on_platform = NULL; - } - - if(other && !(other->update_mark & UPDATE_MARK_CHECK_GRAVITY)) - { - check_gravity(other); - } - - //no longer underneath? - if(acting_entity->landed_on_platform && !testplatform(acting_entity->landed_on_platform, acting_entity->position.x, acting_entity->position.z, NULL)) - { - *pla = acting_entity->landed_on_platform = NULL; - } - - if(other - && !acting_entity->landed_on_platform - && acting_entity->position.y <= other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT]) - { - acting_entity->landed_on_platform = other; - } - - if( (platform = acting_entity->landed_on_platform) ) - { - if(!(platform->update_mark & UPDATE_MARK_CHECK_GRAVITY)) - { - check_gravity(platform); - } - acting_entity->position.y = acting_entity->base = platform->position.y + platform->animation->platform[platform->animpos][PLATFORM_HEIGHT]; - } - - *pla = other; - - // adjust base - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_ADJUST_BASE) - { - return; - } - - if (acting_entity->animation->move[acting_entity->animpos]->base) - { - seta = (float)acting_entity->animation->move[acting_entity->animpos]->base; - } - else - { - seta = -1; - } - - // Checks to see if entity is over a wall and or obstacle, and adjusts the base accordingly - //wall = checkwall_below(acting_entity->position.x, acting_entity->position.z); - //find a wall below us - if(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL) - { - wall = checkwall_below(acting_entity->position.x, acting_entity->position.z, T_MAX_CHECK_ALTITUDE); - } - else - { - wall = WALL_INDEX_NONE; - } - /* - * If we can't adjust base, nothing downstream - * matters. Just exit. - */ - - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_BASEMAP) - { - maxbase = check_basemap(acting_entity->position.x, acting_entity->position.z); - } - - /* - * Fall into a hole? - */ - - if(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_HOLE && - ((acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_BASEMAP && maxbase == T_MIN_BASEMAP) || !(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_BASEMAP)) - ) - { - in_hole = (wall < 0 && !other) ? checkhole_in(acting_entity->position.x, acting_entity->position.z, acting_entity->position.y) : 0; - - if (in_hole) - { - hole_index = checkholeindex_in(acting_entity->position.x, acting_entity->position.z, acting_entity->position.y); - - if (hole_index >= 0) - { - execute_inhole_script(acting_entity, &level->holes[hole_index], hole_index); - } - } - - if(seta < 0 && in_hole) - { - acting_entity->base = T_MIN_BASEMAP; - ent_unlink(acting_entity); - } - else if(!in_hole && acting_entity->base == T_MIN_BASEMAP) - { - if(acting_entity->position.y >= 0) - { - acting_entity->base = 0; - } - else - { - acting_entity->velocity.x = acting_entity->velocity.z = 0; // hit the hole border - } - } - } - - /* - * Apply platform, wall, and manual base - * adjustments. - */ - - if(acting_entity->base != T_MIN_BASEMAP || wall >= 0) - { - base_adjust = (seta + acting_entity->altbase >= 0) * (seta + acting_entity->altbase); - - /* - * If (wall > position Y) - * Explode. - * Else - * Adjust base. - */ - if(other != NULL && other != acting_entity) - { - acting_entity->base = base_adjust + other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT]; - } - else if(wall >= 0) - { - /* - * Bombs normally need to adjust base to control - * detonation when landing, but this has a side - * effect: Bombs that hit the side of walls or - * platforms instantly warp to the top of wall - * as they detonate. - * - * Legacy projectile wall bounce has a similar - * issue. - * - * To fix this, we check to see if wall is higher - * than current position of entities with their - * detonation flags on. If so, then reset entity - * base. - */ - - if ((acting_entity->toexplode & (EXPLODE_PREPARE_GROUND | EXPLODE_DETONATE_HIT) || acting_entity->modeldata.move_config_flags & MOVE_CONFIG_PROJECTILE_WALL_BOUNCE) && level->walls[wall].height > acting_entity->position.y) - { - acting_entity->base = 0; - } - else - { - acting_entity->base = base_adjust + level->walls[wall].height; - } - } - else if(seta >= 0) - { - acting_entity->base = base_adjust; - } - else if(!acting_entity->animation->move[acting_entity->animpos]->axis.y) - { - // No obstacle/wall or seta, so just set to 0 - acting_entity->base = 0; - } - } - - if(acting_entity->base != T_MIN_BASEMAP && maxbase > acting_entity->base) - { - acting_entity->base = maxbase; - // White Dragon: fix bug for floating entity on basemaps using a threshold - if (acting_entity->velocity.y <= 0 && acting_entity->position.y - acting_entity->base <= T_WALKOFF) - { - acting_entity->position.y = acting_entity->base; - } - //debug_printf("y:%f maxbase:%f",acting_entity->position.y,maxbase); - } -} - -// Caskey Damon V. -// 2018-04-08 -// -// If entity has a timed color set, check -// to see if colorset has expired. If so, -// revert to default colorset and clear -// the timer. -int colorset_timed_expire(entity *ent) -{ - // No color set time? Nothing to do. - if(!ent->maptime) - { - return 0; - } - - // If elapsed time has surpassed color - // set time, then color set time is expired. - // Revert entity back to default color set - // and reset the color set timer. - if(_time >= ent->maptime) - { - ent_set_colourmap(ent, ent->map); - ent->maptime = 0; - - return 1; - } - - // Color set _time was not expired. - return 0; -} - - -void update_animation() -{ - int f; - float scrollv = 0; - - if(level) - { - if(self->modeldata.facing == FACING_ADJUST_RIGHT || level->facing == FACING_ADJUST_RIGHT) - { - self->direction = DIRECTION_RIGHT; - } - else if(self->modeldata.facing == FACING_ADJUST_LEFT || level->facing == FACING_ADJUST_LEFT) - { - self->direction = DIRECTION_LEFT; - } - else if((self->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_RIGHT)) - { - self->direction = DIRECTION_RIGHT; - } - else if((self->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_LEFT)) - { - self->direction = DIRECTION_LEFT; - } - if(self->modeldata.type & TYPE_PANEL) - { - scrollv += self->modeldata.speed.x; - } - if(self->modeldata.scroll) - { - scrollv += self->modeldata.scroll; - } - if(scrollv) - { - self->position.x += scrolldx * scrollv; - if(level->scrolldir == SCROLL_UP) - { - scrollv = -scrollv; - } - self->position.y -= scrolldy * scrollv; - self->base = -99999; // temporary fix otherwise it won't go underground - } - } - - if(!(self->idling & IDLING_ACTIVE) || (self->animnum == ANI_SLEEP && !self->animating)) - { - self->sleeptime = _time + self->modeldata.sleepwait; - } - - // Invincible time has run out, turn off. - if(self->invincible != INVINCIBLE_NONE && _time >= self->invinctime) - { - self->invincible = INVINCIBLE_NONE; - self->blink = 0; - self->invinctime = 0; - self->arrowon = 0; - } - - if(self->freezetime && _time >= self->freezetime) - { - unfrozen(self); - } - - // Check for forced color set expiring. - colorset_timed_expire(self); - - if(self->sealtime && _time >= self->sealtime) //Remove seal, special moves are available again. - { - self->seal = 0; - } - // Reset their escapecount if they aren't being spammed anymore. - if(self->modeldata.escapehits && self->inpain == IN_PAIN_NONE) - { - self->escapecount = 0; - } - - /* - * Cycle frame if the frame time is not infinite - * and the nextanim time has been reached, or if - * the entity is a textbox and the player has - * pressed a key to skip the text. - */ - if((!(self->nextanim & DELAY_FLAG_INFINITE) - && self->nextanim <= _time) || - ((self->modeldata.type & TYPE_TEXTBOX) - && self->modeldata.subtype != SUBTYPE_NOSKIP - && (bothnewkeys - & (FLAG_JUMP - | FLAG_ATTACK - | FLAG_ATTACK2 - | FLAG_ATTACK3 - | FLAG_ATTACK4 - | FLAG_SPECIAL)))) { - - f = self->animpos + self->animating; - - //Specified loop break frame. - if(self->animation->loop.mode && self->animation->loop.frame.max) - { - if (f == self->animation->loop.frame.max) - { - if(f < 0) - { - f = self->animation->numframes - 1; - } - else - { - f = 0; - } - - if (self->animation->loop.frame.min) - { - f = self->animation->loop.frame.min; - } - } - else if((unsigned)f >= (unsigned)self->animation->numframes) - { - self->animating = ANIMATING_NONE; - - if(self->autokill & AUTOKILL_ANIMATION_COMPLETE) - { - kill_entity(self, KILL_ENTITY_TRIGGER_AUTOKILL_ANIMATION_COMPLETE_DEFINED_LOOP_MAX); - return; - } - } - } - else if((unsigned)f >= (unsigned)self->animation->numframes) - { - if(f < 0) - { - f = self->animation->numframes - 1; - } - else - { - f = 0; - } - - if(!self->animation->loop.mode) - { - self->animating = ANIMATING_NONE; - - if(self->autokill & AUTOKILL_ANIMATION_COMPLETE) - { - kill_entity(self, KILL_ENTITY_TRIGGER_AUTOKILL_ANIMATION_COMPLETE_UNDEFINED_LOOP_MAX); - return; - } - } - else - { - if (self->animation->loop.frame.min) - { - f = self->animation->loop.frame.min; - } - } - } - - if(self->animating) - { - //self->nextanim = _time + (self->animation->delay[f]); - self->update_mark |= UPDATE_MARK_UPDATE_ANIMATION; // frame updated, mark it - // just switch frame to f, if frozen, expand_time will deal with it well - update_frame(self, f); - bothnewkeys = 0; //stop mutiple skips. - } - } - -} - -void check_attack(void) { - s_collision_collection* collision_attack = NULL; - int animation_frame; - - /* - * Basic guards. - */ - if (!self || !self->animation) { - return; - } - - /* - * If falling, we don't attack unless - * in a projectile state (as in, thrown - * or blasted by another entity). This - * is how we handle throwing a guy into - * his buddies. - */ - if (self->falling && self->projectile == BLAST_NONE) { - self->attack_id_outgoing = 0; - return; - } - - /* - * On ground after drop. - */ - if (self->drop && !self->falling) { - self->attack_id_outgoing = 0; - return; - } - - /* - * Can't hit an opponent if frozen. - */ - if (is_frozen(self)) { - self->attack_id_outgoing = 0; - return; - } - - animation_frame = self->animpos; - - /* - * Protect animation frame table lookup. - */ - if (animation_frame < 0 || animation_frame >= self->animation->numframes) { - self->attack_id_outgoing = 0; - return; - } - - /* - * Attack collision table must exist, and this frame - * must have at least one active attack slot. - */ - if (self->animation->collision_attack) { - collision_attack = self->animation->collision_attack[animation_frame]; - - if (collision_attack && collision_attack->active_status) { - do_attack(self); - return; - } - } - - self->attack_id_outgoing = 0; -} - -// Caskey, Damon V. -// 2018-04-08 -// -// If actively charging, add energy to -// entity based on chargerate property -// and elapsed time. Returns 1 if -// energy was added, 0 otherwise. -int do_energy_charge(entity *ent) -{ - #define ENERGY_CHARGE_RATE 0.25 - - // Must be charging. - if (!ent->charging) - { - return 0; - } - - // Must be time for a charge tick. - if (_time < ent->mpchargetime) - { - return 0; - } - - // Add charge rate to current mp. - ent->energy_state.mp_current += ent->modeldata.chargerate; - - // Time for next charge tick. - ent->mpchargetime = _time + (global_config.game_speed * ENERGY_CHARGE_RATE); - - return 1; - - #undef ENERGY_CHARGE_RATE -} - - -void update_health() -{ - /* - * 12/30/2008: Guardrate by OX. Guardpoints increase over time. - * - * 2024-01-08, DC: Split max/current between model and - * entity. Remove some redudant code. - * - * Only bother recovering if guardpoints are set in - * the first place (model has guardpoint value > 0). - */ - if(self->modeldata.guardpoints > 0 && _time >= self->guardtime) - { - /* - * Recover guardpoints. Half rate if - * blocking. - */ - if((self->blocking & (BLOCK_STATE_ACTIVE | BLOCK_STATE_NATIVE)) - == (BLOCK_STATE_ACTIVE | BLOCK_STATE_NATIVE) - && !(self->blocking & BLOCK_STATE_IGNORE_GUARD_POINTS)) - { - self->guardpoints += (self->modeldata.guardrate / 2); - } - else - { - self->guardpoints += self->modeldata.guardrate; - } - - /* Cap to maximum. */ - if (self->guardpoints > self->modeldata.guardpoints) - { - self->guardpoints = self->modeldata.guardpoints; - } - - /* Reset guardtime. */ - self->guardtime = _time + global_config.game_speed; - } - - //Damage over time. - recursive_entity_effect_update(self); - - // this is for restoring mp by _time by tails - // Cleaning and addition of mpstable by DC, 08172008. - // stabletype 4 added by OX 12272008 - - if(magic_type == 0 && !self->charging) - { - if(_time >= self->magictime) - { - - // 1 Only recover MP > mpstableval. - // 2 No recover. Drop MP if MP < mpstableval. - // 3 Both: recover if MP < mpstableval and drop if MP > mpstableval. - // 4 Gain until stable, then fall to stable. - // 0 Default. Recover MP at all times. - - if (self->modeldata.mpstable == 1) - { - if (self->energy_state.mp_current < self->modeldata.mpstableval) - { - self->energy_state.mp_current += self->modeldata.mprate; - } - } - else if(self->modeldata.mpstable == 2) - { - if (self->energy_state.mp_current > self->modeldata.mpstableval) - { - self->energy_state.mp_current -= self->modeldata.mpdroprate; - } - } - else if (self->modeldata.mpstable == 3) - { - if (self->energy_state.mp_current < self->modeldata.mpstableval) - { - - self->energy_state.mp_current += self->modeldata.mprate; - } - else if (self->energy_state.mp_current > self->modeldata.mpstableval) - { - self->energy_state.mp_current -= self->modeldata.mpdroprate; - } - } - - // OX. Stabletype 4. Gain mp until it reaches max. Then it drops down to mpstableval. - else if (self->modeldata.mpstable == 4) - { - if(self->energy_state.mp_current <= self->modeldata.mpstableval) - { - self->modeldata.mpswitch = 0; - } - else if(self->energy_state.mp_current == self->modeldata.mp) - { - self->modeldata.mpswitch = 1; - } - - if(self->modeldata.mpswitch == 1) - { - self->energy_state.mp_current -= self->modeldata.mpdroprate; - } - else if(self->modeldata.mpswitch == 0) - { - self->energy_state.mp_current += self->modeldata.mprate; - } - } - else - { - self->energy_state.mp_current += self->modeldata.mprate; - } - - self->magictime = _time + global_config.game_speed; //Reset magictime. - } - } - - // Active MP charging? - do_energy_charge(self); - - /* Energy cheat keeps MP at maximum. */ - if (global_config.cheats & CHEAT_OPTIONS_ENERGY_ACTIVE && self->modeldata.type & TYPE_PLAYER) - { - self->energy_state.mp_current = self->modeldata.mp; - } - - if(self->energy_state.mp_current > self->modeldata.mp) - { - self->energy_state.mp_current = self->modeldata.mp; // Don't want to add more than the max - } - - if(self->energy_state.health_old < self->energy_state.health_current) - { - self->energy_state.health_old++; - } - else if(self->energy_state.health_old > self->energy_state.health_current) - { - self->energy_state.health_old--; - } - - if(self->energy_state.mp_old < self->energy_state.mp_current) - { - self->energy_state.mp_old++; - } - else if(self->energy_state.mp_old > self->energy_state.mp_current) - { - self->energy_state.mp_old--; - } -} - -/* ***** Binding ***** */ - -/* -* Caskey, Damon V. -* 2022-05-27 -* -* Allocate a bind property structure and return pointer. -*/ -s_bind* bind_allocate_object() -{ - s_bind* result; - size_t alloc_size; - - /* Get amount of memory we'll need. */ - alloc_size = sizeof(*result); - - /* Allocate memory and get pointer. */ - result = malloc(alloc_size); - - /* - * Make sure the data members are - * zero'd out. - */ - - memset(result, 0, alloc_size); - - result->object_type = OBJECT_TYPE_BIND; - - return result; -} - -/* -* Caskey, Damon V. -* 2022-05-27 -* -* Allocate new bind object with same values (but not -* same pointers) as received object. Returns pointer -* to new object. -*/ -s_bind* bind_clone_object(s_bind* source) -{ - s_bind* result = NULL; - - if (!source) - { - return result; - } - - result = bind_allocate_object(); - - /* - * Rather than do everything piecemeal, we'll memcopy - * to get all the basic values, and then overwrite - * members individually as needed. - */ - - memcpy(result, source, sizeof(*result)); - - return result; -} - -/* -* Caskey, Damon V -* 2022-05-27 -* -* Send all bind data to log for debugging. -*/ -void bind_dump_object(s_bind* object) { - - printf("\n\n -- Bind (%p) dump --", object); - - if (object) { - printf("\n\t ->animation: %d", object->animation); - printf("\n\t ->config: %" PRIu64, object->config); - printf("\n\t ->direction_adjust: %d", object->direction_adjust); - printf("\n\t ->frame: %d", object->frame); - printf("\n\t ->meta_data: %p", object->meta_data); - printf("\n\t ->meta_tag: %d", object->meta_tag); - printf("\n\t ->offset.x: %d", object->offset.x); - printf("\n\t ->offset.y: %d", object->offset.y); - printf("\n\t ->offset.z: %d", object->offset.z); - printf("\n\t ->sortid: %d", object->sortid); - printf("\n\t ->target: %p", object->target); - } - - printf("\n\n -- Bind (%p) dump complete... -- \n", object); -} - -/* -* Caskey, Damon V. -* 2022-05-27 -* -* Free bind properties from memory. -*/ -void bind_free_object(s_bind* object) -{ - free(object); -} - -/* -* Caskey, Damon V. -* 2022-05-06 -* -* Full rewrite of orginal function by uTunnels -* and its later modifications by me (Damon). -* -* Acting entity binds itself to a target -* depending on bind property settings. Also -* executes bind scripts for acting and target. -*/ -void adjust_bind(entity* acting_entity) { - - #define ADJUST_BIND_SET_ANIM_RESETABLE 1 - #define ADJUST_BIND_NO_FRAME_MATCH -1 - - int frame = 0; - animation_id_t animation = ANI_NONE; - - s_bind *const acting_bind = &acting_entity->binding; - - if (!acting_bind->target) { - return; - } - - execute_on_bind_update_other_to_self(acting_bind->target, acting_entity, acting_bind); - execute_on_bind_update_self_to_other(acting_entity, acting_bind->target, acting_bind); - - if (!acting_bind->target) { - return; - } - - const bind_config_t bind_config = acting_bind->config; - - /* - * Check config flags for removal. Legacy bindentity() - * used values 4 and 8 for animation and frame removal, - * respectively. These values are now defined as - * BIND_CONFIG_ANIMATION_REMOVE and BIND_CONFIG_ANIMATION_FRAME_REMOVE. - * The removal flags imply target matching for legacy - * bindentity() values 4 and 8, even when no explicit - * matching flag is set. - */ - if (bind_config & (BIND_CONFIG_ANIMATION_DEFINED - | BIND_CONFIG_ANIMATION_TARGET - | BIND_CONFIG_ANIMATION_REMOVE - | BIND_CONFIG_ANIMATION_FRAME_DEFINED - | BIND_CONFIG_ANIMATION_FRAME_TARGET - | BIND_CONFIG_ANIMATION_FRAME_REMOVE)) { - - /* - * If a defined value is requested, - * use the binding member value. - * Otherwise use target's current value. - */ - if (bind_config & BIND_CONFIG_ANIMATION_DEFINED) { - animation = acting_bind->animation; - } else { - animation = acting_bind->target->animnum; - } - - /* Are we NOT currently playing the target animation? */ - if (acting_entity->animnum != animation) { - - /* - * If we don't have the target animation - * and animation kill flag is set, then - * we kill ourselves and exit the function. - */ - if (!validanim(acting_entity, animation)) { - - /* Don't have the animation? Kill self. */ - if (bind_config & BIND_CONFIG_ANIMATION_REMOVE) { - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_BIND_ANIMATION_MATCH); - } - - /* Cancel the bind and exit. */ - acting_entity->binding.target = NULL; - return; - } - - /* - * Made it this far, we must have the target - * animation, so let's apply it. - */ - ent_set_anim(acting_entity, animation, ADJUST_BIND_SET_ANIM_RESETABLE); - } - - - /* - * If a defined value is requested, - * use the binding member value. - * If target value is requested use - * target's current value (duh). - * if no frame match at all requested - * then set ADJUST_BIND_NO_FRAME_MATCH - * so frame matching logic is skipped. - */ - - if (bind_config & BIND_CONFIG_ANIMATION_FRAME_DEFINED) { - frame = acting_bind->frame; - } else if (bind_config & BIND_CONFIG_ANIMATION_FRAME_TARGET) { - frame = acting_bind->target->animpos; - } else { - frame = ADJUST_BIND_NO_FRAME_MATCH; - } - - /* - * Any frame match flag set? - */ - if (frame != ADJUST_BIND_NO_FRAME_MATCH) { - - /* Are we NOT currently playing the target frame ? */ - if (acting_entity->animpos != frame) { - - /* - * If we don't have the frame and frame kill flag is - * set, kill self. - */ - if ((acting_entity->animation->numframes -1) < frame) { - if (bind_config & BIND_CONFIG_ANIMATION_FRAME_REMOVE) { - - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_BIND_FRAME_MATCH); - return; - } - } - - /* - * Made it this far, let's try to - * apply the frame. - */ - update_frame(acting_entity, frame); - } - } - } - - /* Apply sort ID adjustment. */ - acting_entity->sortid = acting_bind->target->sortid + acting_bind->sortid; - - /* Getand apply direction adjustment. */ - acting_entity->direction = direction_get_adjustment_result(acting_entity, acting_bind->target, acting_bind->direction_adjust); - - /* - * Apply positioning based on config. For - * the X axis, we invert adjustment when - * target faces left. - */ - - // X - const int offset_x = acting_bind->offset.x; - - if (bind_config & BIND_CONFIG_AXIS_X_TARGET) { - - const float target_x = acting_bind->target->position.x; - - if (acting_bind->target->direction == DIRECTION_LEFT) { - - acting_entity->position.x = target_x - (float)offset_x; - - } else { - - acting_entity->position.x = target_x + (float)offset_x; - - } - - } else if (bind_config & BIND_CONFIG_AXIS_X_LEVEL) { - - acting_entity->position.x = (float)offset_x; - - } - - // Y - const int offset_y = acting_bind->offset.y; - - if (bind_config & BIND_CONFIG_AXIS_Y_TARGET) { - - acting_entity->position.y = acting_bind->target->position.y + (float)offset_y; - - } else if (bind_config & BIND_CONFIG_AXIS_Y_LEVEL) { - - acting_entity->position.y = (float)offset_y; - - } - - // Z - const int offset_z = acting_bind->offset.z; - - if (bind_config & BIND_CONFIG_AXIS_Z_TARGET) { - - acting_entity->position.z = acting_bind->target->position.z + (float)offset_z; - - } else if (bind_config & BIND_CONFIG_AXIS_Z_LEVEL) { - - acting_entity->position.z = (float)offset_z; - - } - - #undef ADJUST_BIND_SET_ANIM_RESETABLE - #undef ADJUST_BIND_NO_FRAME_MATCH -} - -/* -* Caskey, Damon V. -* 2021-08-24 -* -* Read a text argument for direction and output -* appropriate direction constant. If input is -* legacy integer, we just pass it on. -*/ -e_direction direction_get_direction_from_argument(const char* filename, const char* command, const char* value) { - e_direction result = DIRECTION_NONE; - - if (stricmp(value, "left") == 0) { - result = DIRECTION_LEFT; - } else if (stricmp(value, "right") == 0) { - result = DIRECTION_RIGHT; - } else { - /* Just pass through for legacy integer. */ - result = getValidInt(value, filename, command); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2021-08-24 -* -* Read a text argument for direction and output -* appropriate direction adjustment constant. If -* input is legacy integer, we just pass it on. -*/ -e_direction_adjust direction_get_adjustment_from_argument(const char* filename, const char* command, const char* value) { - e_direction_adjust result = DIRECTION_ADJUST_NONE; - - if (stricmp(value, "left") == 0) { - result = DIRECTION_ADJUST_LEFT; - } else if (stricmp(value, "none") == 0) { - result = DIRECTION_ADJUST_NONE; - } else if (stricmp(value, "opposite") == 0) { - result = DIRECTION_ADJUST_OPPOSITE; - } else if (stricmp(value, "right") == 0) { - result = DIRECTION_ADJUST_RIGHT; - } else if (stricmp(value, "same") == 0) { - result = DIRECTION_ADJUST_SAME; - } else if (stricmp(value, "toward") == 0) { - result = DIRECTION_ADJUST_TOWARD; - } else if (stricmp(value, "away") == 0) { - result = DIRECTION_ADJUST_AWAY; - } else { - result = getValidInt(value, filename, command); - } - - return result; -} - -// Caskey, Damon V. -// 2018-10-13 -// -// Return an adjusted entity direction based -// on original direction, target direction -// and direction adjust setting. -e_direction direction_get_adjustment_result(entity* acting_entity, const entity* target_entity, const e_direction_adjust adjustment) -{ - if (!acting_entity || !target_entity) - { - borShutdown(1, "direction_get_adjustment_result() was passed a NULL pointer."); - } - - const e_direction acting_direction = acting_entity->direction; - const e_direction target_direction = target_entity->direction; - - const float acting_position_x = acting_entity->position.x; - const float target_position_x = target_entity->position.x; - - // Apply direction adjustment. - switch (adjustment) - { - default: - case DIRECTION_ADJUST_NONE: - - // Use original direction. - return acting_direction; - break; - - case DIRECTION_ADJUST_SAME: - - // Same as target direction. - return target_direction; - break; - - case DIRECTION_ADJUST_OPPOSITE: - - // Opposite of target direction. - if (target_direction == DIRECTION_LEFT) - { - return DIRECTION_RIGHT; - } - else - { - return DIRECTION_LEFT; - } - - break; - - case DIRECTION_ADJUST_RIGHT: - - return DIRECTION_RIGHT; - break; - - case DIRECTION_ADJUST_LEFT: - - return DIRECTION_LEFT; - break; - - case DIRECTION_ADJUST_TOWARD: - - if (acting_position_x < target_position_x) - { - return DIRECTION_RIGHT; - } - else if (acting_position_x > target_position_x) - { - return DIRECTION_LEFT; - } - else - { - return acting_direction; - } - - break; - - case DIRECTION_ADJUST_AWAY: - - if (acting_position_x < target_position_x) - { - return DIRECTION_LEFT; - } - else if (acting_position_x > target_position_x) - { - return DIRECTION_RIGHT; - } - else - { - return acting_direction; - } - - break; - } -} - -/* -* Caskey, Damon V. -* 2018-09-08 -* -* Return true if the target entity has a valid -* bind target and match for the override argument. -*/ -bool check_bind_override(entity *ent, bind_config_t bind_config) { - - if(ent->binding.target) { - if(ent->binding.config & bind_config) { - return TRUE; - } - } - - return FALSE; -} - -void check_move(entity *e) -{ - float x, z; - entity *plat, *tempself; - - if((e->update_mark & UPDATE_MARK_CHECK_MOVE)) - { - return; - } - tempself = self; - self = e; - - x = self->position.x; - z = self->position.z; - - // check moving platform - if((plat = self->landed_on_platform) ) // on the platform? - { - //update platform first to get actual movex and movez - if(!(plat->update_mark & UPDATE_MARK_CHECK_MOVE)) - { - check_move(plat); - } - if(plat->movex || plat->movez) - { - if(self->trymove) - { - if(self->grabbing) - { - check_link_move(plat->movex, plat->movez); - } - else if(!self->link) - { - self->trymove(plat->movex, plat->movez); - } - } - else - { - self->position.x += plat->movex; - self->position.z += plat->movez; - } - } - } - if(!is_frozen(self) ) - { - if(self->nextmove <= _time && (self->movex || self->movez) ) - { - if(self->trymove) - { - // only do linked move while grabwalking for now, - // otherwise some grab moves that use move/movez command may act strangely - if(self->grabbing && self->grabwalking) - { - check_link_move(self->movex, self->movez); - } - else// if(!self->link || self->grabbing) - { - if(1 != self->trymove(self->movex, self->movez) && self->idling) - { - self->pathblocked += _time % 2; - } - else - { - self->pathblocked = 0; - } - } - } - else - { - self->position.x += self->movex; - self->position.z += self->movez; - } - } - if(self->nextmove <= _time) - { - self->nextmove = _time + 1; - } - - } - self->movex = self->position.x - x; - self->movez = self->position.z - z; - self->update_mark |= UPDATE_MARK_CHECK_MOVE; - self = tempself; -} - -void ent_post_update(entity *e) { - - check_gravity(e);// check gravity - //check_entity_collision_for(e); - check_move(e); -} - -// arrange the list and reduce its length -void arrange_ents() { - - int i, ind = -1; - entity *temp; - - if(ent_count == 0) { - return; - } - - /* - * Finish movement for every entity before - * resolving binds. Movement may change a - * bind target's animation, such as entering - * ANI_HITWALL, and all bound entities must - * observe the completed target state regardless - * of their order in ent_list. - */ - for(i = 0; i < ent_max; i++) { - if(ent_list[i]->exists) { - ent_post_update(ent_list[i]); - } - } - - /* - * Resolve binding after all target movement - * and animation changes. - */ - for(i = 0; i < ent_max; i++) { - if(ent_list[i]->exists) { - adjust_bind(ent_list[i]); - } - } - - if(ent_max != ent_count) { - - for(i = 0; i < ent_max; i++) { - - if(!ent_list[i]->exists && ind < 0) { - - ind = i; - - } else if(ent_list[i]->exists && ind >= 0) { - temp = ent_list[i]; - ent_list[i] = ent_list[ind]; - ent_list[ind] = temp; - ind++; - } - } - ent_max = ent_count; - } - - for(i = 0; i < ent_max; i++) { - ent_list[i]->movex = ent_list[i]->movez = 0; - } -} - -// Update all entities that wish to think or animate in this cycle. -// All loops are separated because "self" might die during a pass. -void update_ents() -{ - int i; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && _time != ent_list[i]->timestamp)// dont update fresh entity - { - self = ent_list[i]; - self->update_mark = UPDATE_MARK_NONE; - if(level) - { - check_lost(); // check lost caused by level scrolling or lifespan - } - if(!self->exists) - { - continue; - } - // expand _time incase being frozen - if(is_frozen(self)) - { - expand_time(self); - } - else - { - - execute_updateentity_script(self);// execute a script - if(!self->exists) - { - continue; - } - check_ai();// check ai - if(!self->exists) - { - continue; - } - update_animation(); // if not frozen, update animation - if(!self->exists) - { - continue; - } - check_attack();// Collission detection - if(!self->exists) - { - continue; - } - update_health();// Update displayed health - self->movex += self->velocity.x * self->speedmul * (100.0 / global_config.game_speed); - self->movez += self->velocity.z * self->speedmul * (100.0 / global_config.game_speed); - } - } - }//end of for - arrange_ents(); - /* - if(time>=nextplan){ - plan(); - nextplan = time+global_config.game_speed/2; - }*/ -} - - -void display_ents() -{ - unsigned f; - int i, z, wall = 0, wall2; - entity *e = NULL; - entity *other = NULL; - int qx; - int qy; - int sy; - int sz; - int alty; - int in_air; - int sortid; - float basemap; - float temp1, temp2; - int useshadow = 0; - int can_mirror = 0; - int shadowz; - s_drawmethod *drawmethod = NULL; - s_drawmethod commonmethod; - s_drawmethod shadowmethod; - int use_mirror = (level && level->mirror); - - int o_scrx = screenx, o_scry = screeny, scrx, scry; - - if(level) - { - shadowz = SHADOW_Z; - } - else - { - shadowz = MIN_INT + 100; - } - - for(i = 0; i < ent_max; i++) - { - if(ent_list[i] && ent_list[i]->exists) - { - e = ent_list[i]; - // in a loop need to initialize to reset prev val. to avoid bugs. - z = basemap = qx = qy = sy = sz = alty = sortid = temp1 = temp2 = 0; - - if(Script_IsInitialized(e->scripts->ondraw_script)) - { - ent_stack[ent_stack_size++] = e; - } - //if(!e->exists) continue; // just in case kill is called in the script - - /* - * If we have status, draw to screen (ex. boss life). - */ - - if(e->modeldata.hud_popup) - { - drawenemystatus(e); - } - - sortid = e->sortid; - scrx = o_scrx - ((e->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_x_offset); - scry = o_scry - ((e->modeldata.quake_config & QUAKE_CONFIG_DISABLE_SELF) ? 0 : gfx_y_offset); - - if(freezeall || !(e->blink && (_time % (global_config.game_speed / 10)) < (global_config.game_speed / 20))) - { - float eheight = T_WALKOFF, eplatheight = 0; - - // get the height of the entity - if ( e->animation->platform ) - { - s_anim *anim = e->animation; - - if (anim->platform[e->animpos][PLATFORM_HEIGHT]) - { - eplatheight += anim->platform[e->animpos][PLATFORM_HEIGHT]; - } - - } - if ( e->modeldata.size.y && eplatheight <= 0 ) eheight += e->modeldata.size.y; - else eheight += eplatheight; - - // If special is being executed, display all entities regardless - f = e->animation->sprite[e->animpos]; - - //other = check_platform(e->position.x, e->position.z, e); - other = check_platform_below(e->position.x, e->position.z, e->position.y+eheight, e); - wall = checkwall_index(e->position.x, e->position.z); - - if (e->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_BASEMAP) - { - basemap = check_basemap(e->position.x, e->position.z); - } - - if(f < sprites_loaded) - { - // var "z" takes into account whether it has a setlayer set, whether there are other entities on - // the same "z", in which case there is a layer offset, whether the entity is on an obstacle, and - // whether the entity is grabbing someone and has grabback set - - z = (int)e->position.z; // Set the layer offset - - if(other && e->position.y >= other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT] && !other->modeldata.setlayer) - { - float zdepth = (float)( (float)e->position.z - (float)other->position.z + - (float)other->animation->platform[other->animpos][PLATFORM_DEPTH] - - (float)other->animation->platform[other->animpos][PLATFORM_Z] ); - - if( - e->link // Linked to entity. - && ((e->modeldata.grabback && !e->grabbing) // Have grab back AND not grabbing. - || (e->link->modeldata.grabback && e->link->grabbing) // Linked has grab back and is grabbing. - || e->grabbing) // Grabbing. - ) - { - - // Make sure entities get displayed in front of obstacle and grabbee - sortid = other->sortid + zdepth + 2; - e->sortid = sortid; - z = (int)( other->position.z + 2 ); - } - - else - { - //if ( e->model->type == TYPE_PLAYER ) debug_printf("zdepth: %f",zdepth); - - // Entity should always display in front of the obstacle - sortid = other->sortid + zdepth + 1; - e->sortid = sortid; - z = (int)( other->position.z + 1 ); - } - - } - - // In most cases we want any spawned entity to - // default in front of owner. - if(e->owner) - { - // If this entity is not an exception to the rule, - // move its display order in front of owner. - if (!(self->modeldata.aimove & AIMOVE1_STAR)) - { - sortid = e->owner->sortid + 1; - } - } - - if(e->modeldata.setlayer) - { - z = HOLE_Z + e->modeldata.setlayer; // Setlayer takes precedence - } - - drawmethod = e->animation->drawmethods ? getDrawMethod(e->animation, e->animpos) : NULL; - - if(e->drawmethod->config & DRAWMETHOD_CONFIG_ENABLED) - { - drawmethod = (e->drawmethod); - } - if(!drawmethod) - { - commonmethod = plainmethod; - } - else - { - commonmethod = *drawmethod; - } - drawmethod = &commonmethod; - - if(e->modeldata.alpha >= 1 && e->modeldata.alpha <= MAX_BLENDINGS) - { - if(drawmethod->alpha == BLEND_MODE_MODEL) - { - drawmethod->alpha = e->modeldata.alpha; - } - } - - // Color selection. If drawmethod does not yet have a color table pointer, then - // we need to find one here. - if(!drawmethod->table) - { - // Drawmethod remap by index. Is there a value? - if(drawmethod->remap >= 1) - { - // Does the value fall within range of tables loaded? If so, use - // value to locate the color table by index, and then populate - // drawmethod table value with the color table pointer. - if (drawmethod->remap <= e->modeldata.maps_loaded) - { - drawmethod->table = model_get_colourmap(&(e->modeldata), drawmethod->remap); - } - } - - // Color selection by entity property. Does it have a value? Note that script functions - // and most text values in OpenBOR give the appearance this property is an integer index. - // In actuality those functions accept an index, but immediately use it to locate a color - // table pointer to populate this property. See ent_set_colourmap. - if(e->colourmap) - { - // We don't want to override drawmethods, so first check drawmethod - // remap to make sure it is disabled (0 = force default, 1+ force alternates). - // If it is (dsiabled) then use property value to populate drawmethod table. - if(drawmethod->remap < 0) - { - drawmethod->table = e->colourmap; - } - } - - // If we haven't populated the drawmethod table yet, use - // model's default color table. - if(!drawmethod->table) - { - drawmethod->table = e->modeldata.palette; - } - - // If globalmap is true, then author wants entity to use the current - // global color table. - if(e->modeldata.globalmap) - { - // If we are in a level and the level has a palette index specified, - // then use that index to find the color table pointer and populate - // drawmethod table. Otherwise, just get the global color table pointer. - if(level && current_palette) - { - drawmethod->table = level->palettes[current_palette - 1]; - } - else - { - drawmethod->table = pal; - } - } - } - - // If we have a dying remap, let's check for the dying flash effect. - if(e->dying) - { - // This checks against both dying percentage thresholds and their associated - // timing. If any pass, then we can move on and apply a flash. - if((e->energy_state.health_current <= e->per1 && e->energy_state.health_current > e->per2 && (_time % (global_config.game_speed / 5)) < (global_config.game_speed / 10)) || - (e->energy_state.health_current <= e->per2 && (_time % (global_config.game_speed / 10)) < (global_config.game_speed / 20))) - { - // Have any HP left? - if(e->energy_state.health_current > 0 ) - { - // Do we have a second dying map? If not, we just use map 1. - if(e->dying2 > 0) - { - // If health is between percentage 1 and 2, use map 1. Otherwise - // use map 2. - if(e->energy_state.health_current <= e->per1 && e->energy_state.health_current > e->per2) - { - drawmethod->table = model_get_colourmap(&(e->modeldata), e->dying); - } - else if(e->energy_state.health_current <= e->per2) - { - drawmethod->table = model_get_colourmap(&(e->modeldata), e->dying2); - } - } - else - { - drawmethod->table = model_get_colourmap(&(e->modeldata), e->dying); - } - } - } - } - - // Draw the entity according to its facing. - if(e->direction == DIRECTION_LEFT) - { - // Reverse the drawmethod flipx. - drawmethod->config ^= DRAWMETHOD_CONFIG_FLIP_X; - - // If the flip rotate is enabled, reverse the - // rotation setting. - if(drawmethod->config & DRAWMETHOD_CONFIG_FLIP_ROTATE && drawmethod->rotate) - { - drawmethod->rotate = 360 - drawmethod->rotate; - } - } - - // don't display if behind the mirror - if(!use_mirror || z > MIRROR_Z) - { - //just a simple check, doesn't work with mirror nor gfxshadow - if(drawmethod->clipw) - { - drawmethod->clipx += (int)(e->position.x - scrx); - drawmethod->clipy += (int)(e->position.z - e->position.y - scry); - } - spriteq_add_sprite((int)(e->position.x - scrx), (int)(e->position.z - e->position.y - scry), z, f, drawmethod, sortid); - } - - can_mirror = (use_mirror && self->position.z > MIRROR_Z); - if(can_mirror) - { - spriteq_add_sprite((int)(e->position.x - scrx), (int)((2 * MIRROR_Z - e->position.z) - e->position.y - scry), 2 * PANEL_Z - z , f, drawmethod, ent_list_size * 100 - sortid); - } - }//end of if(fshadow_config_flags & SHADOW_CONFIG_DISABLED)) - { - if (e->shadow_config_flags & (SHADOW_CONFIG_GRAPHIC_REPLICA_AIR | SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND) && f < sprites_loaded) //gfx shadow - { - useshadow = (e->animation->shadow ? e->animation->shadow[e->animpos] : 1) && shadowcolor && light.y; - //printf("\n %d, %d, %d\n", shadowcolor, light.x, light.y); - - if (useshadow && e->position.y >= 0) - { - in_air = inair(e); - - if ((e->shadow_config_flags & SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND && !in_air) || (e->shadow_config_flags & SHADOW_CONFIG_GRAPHIC_REPLICA_AIR && in_air)) - { - wall = checkwall_below(e->position.x, e->position.z, e->position.y); - if (wall < 0) - { - alty = (int)e->position.y; - temp1 = -1 * e->position.y * light.x / 256; // xshift - temp2 = (float)(-alty * light.y / 256); // zshift - qx = (int)(e->position.x - scrx/* + temp1*/); - qy = (int)(e->position.z - scry/* + temp2*/); - } - else - { - alty = (int)(e->position.y - level->walls[wall].height); - temp1 = -1 * (e->position.y - level->walls[wall].height) * light.x / 256; // xshift - temp2 = (float)(-alty * light.y / 256); // zshift - qx = (int)(e->position.x - scrx/* + temp1*/); - qy = (int)(e->position.z - scry /*+ temp2*/ - level->walls[wall].height); - } - - wall2 = checkwall_below(e->position.x + temp1, e->position.z + temp2, e->position.y); // check if the shadow drop into a hole or fall on another wall - - if (other && other != e && e->position.y >= other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT] && !(e->shadow_config_flags & SHADOW_CONFIG_BASE_STATIC)) - { - alty = (int)(e->position.y - (other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT])); - temp1 = -1 * (e->position.y - (other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT])) * light.x / 256; // xshift - temp2 = -e->position.y * light.y / 256; - - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - scry - other->position.y - other->animation->platform[other->animpos][PLATFORM_HEIGHT]); // + (other->animation->platform[other->animpos][PLATFORM_DEPTH]/2) - //qy = (int)( e->position.z - e->position.y - scry + (e->position.y-e->base) ); - } - - if (basemap > 0 && !(e->shadow_config_flags & SHADOW_CONFIG_BASE_STATIC)) - { - alty = (int)(e->position.y - basemap); - temp1 = -1 * (e->position.y - basemap) * light.x / 256; // xshift - temp2 = (float)(-alty * light.y / 256); // zshift - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - scry - basemap); - } - - //TODO check platforms, don't want to go through the entity list again right now // && !other after wall2 - if (!(checkhole(e->position.x + temp1, e->position.z + temp2) && wall2 < 0 && !other)) //&& !(wall>=0 && level->walls[wall].height>e->position.y)) - { - if (wall >= 0 && wall2 >= 0) - { - alty += (int)(level->walls[wall].height - level->walls[wall2].height); - /*qx += -1*(level->walls[wall].height-level->walls[wall2].height)*light.x/256; - qy += (level->walls[wall].height-level->walls[wall2].height) - (level->walls[wall].height-level->walls[wall2].height)*light.y/256;*/ - } - else if (wall >= 0) - { - alty += (int)(level->walls[wall].height); - /*qx += -1*level->walls[wall].height*light.x/256; - qy += level->walls[wall].height - level->walls[wall].height*light.y/256;*/ - } - else if (wall2 >= 0) - { - alty -= (int)(level->walls[wall2].height); - /*qx -= -1*level->walls[wall2].height*light.x/256; - qy -= level->walls[wall2].height - level->walls[wall2].height*light.y/256;*/ - } - - /*if (other) - { - alty += (int)(other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT]); - }*/ - - // set 2D-LIKE shadow - if ((e->shadow_config_flags & SHADOW_CONFIG_BASE_PLATFORM)) alty = temp1 = temp2 = 0; - - sy = (2 * MIRROR_Z - qy) - 2 * scry; - - if (other && !(e->shadow_config_flags & SHADOW_CONFIG_BASE_STATIC)) z = other->position.z + 1; - else z = shadowz; - - sz = PANEL_Z - HUD_Z; - - if (e->animation->shadow_coords) - { - if (e->direction == DIRECTION_RIGHT) - { - qx += e->animation->shadow_coords[e->animpos][0]; - } - else - { - qx -= e->animation->shadow_coords[e->animpos][0]; - } - qy += e->animation->shadow_coords[e->animpos][1]; - sy -= e->animation->shadow_coords[e->animpos][1]; - } - shadowmethod = plainmethod; - shadowmethod.fillcolor = (shadowcolor > 0 ? shadowcolor : 0); - shadowmethod.alpha = shadowalpha; - shadowmethod.channelb = shadowmethod.channelg = shadowmethod.channelr = shadowopacity; - shadowmethod.table = drawmethod->table; - shadowmethod.scalex = drawmethod->scalex; - shadowmethod.scaley = light.y * drawmethod->scaley / 256; - shadowmethod.config = (shadowmethod.config & ~DRAWMETHOD_CONFIG_FLIP_X) | (drawmethod->config & DRAWMETHOD_CONFIG_FLIP_X); - shadowmethod.config = (shadowmethod.config & ~DRAWMETHOD_CONFIG_FLIP_Y) | (drawmethod->config & DRAWMETHOD_CONFIG_FLIP_Y); - shadowmethod.centery += alty; - - if (shadowmethod.config & DRAWMETHOD_CONFIG_FLIP_Y) - { - shadowmethod.centery = -shadowmethod.centery; - } - if (shadowmethod.scaley < 0) - { - shadowmethod.scaley = -shadowmethod.scaley; - shadowmethod.config ^= DRAWMETHOD_CONFIG_FLIP_Y; - } - shadowmethod.rotate = drawmethod->rotate; - shadowmethod.shiftx = drawmethod->shiftx + light.x; - - spriteq_add_sprite(qx, qy, z, f, &shadowmethod, 0); - if (use_mirror) - { - shadowmethod.config ^= DRAWMETHOD_CONFIG_FLIP_Y; - - shadowmethod.centery = -shadowmethod.centery; - spriteq_add_sprite(qx, sy, sz, f, &shadowmethod, 0); - } - } - } - }//end of gfxshadow - } - - /* Plain (sprite) shadow. */ - if (e->shadow_config_flags & (SHADOW_CONFIG_GRAPHIC_STATIC_AIR | SHADOW_CONFIG_GRAPHIC_STATIC_GROUND)) - { - useshadow = e->animation->shadow ? e->animation->shadow[e->animpos] : e->modeldata.shadow; - if (useshadow < 0) - { - useshadow = e->modeldata.shadow; - } - if (useshadow && e->position.y >= 0 && !(checkhole(e->position.x, e->position.z) && checkwall_below(e->position.x, e->position.z, e->position.y) < 0)) - { - in_air = inair(e); - - if ((e->shadow_config_flags & SHADOW_CONFIG_GRAPHIC_STATIC_GROUND && !in_air) || (e->shadow_config_flags & SHADOW_CONFIG_GRAPHIC_STATIC_AIR && in_air)) - { - - if (other && other != e && e->position.y >= other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT] && !(e->shadow_config_flags & SHADOW_CONFIG_BASE_STATIC)) - { - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - other->position.y - other->animation->platform[other->animpos][PLATFORM_HEIGHT] - scry); - sy = (int)((2 * MIRROR_Z - e->position.z) - other->position.y - other->animation->platform[other->animpos][PLATFORM_HEIGHT] - scry); - - z = (int)(other->position.z + 1); - sz = 2 * PANEL_Z - z; - } - else if (level && wall >= 0)// && e->position.y >= level->walls[wall].height) - { - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - level->walls[wall].height - scry); - sy = (int)((2 * MIRROR_Z - e->position.z) - level->walls[wall].height - scry); - z = shadowz; - sz = PANEL_Z - HUD_Z; - } - else if (level && basemap > 0 && !(e->shadow_config_flags & SHADOW_CONFIG_BASE_STATIC)) - { - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - basemap - scry); - sy = (int)((2 * MIRROR_Z - e->position.z) - basemap - scry); - z = shadowz; - sz = PANEL_Z - HUD_Z; - } - else - { - qx = (int)(e->position.x - scrx); - qy = (int)(e->position.z - scry); - sy = (int)((2 * MIRROR_Z - e->position.z) - scry); - z = shadowz; - sz = PANEL_Z - HUD_Z; - } - if (e->animation->shadow_coords) - { - if (e->direction == DIRECTION_RIGHT) - { - qx += e->animation->shadow_coords[e->animpos][0]; - } - else - { - qx -= e->animation->shadow_coords[e->animpos][0]; - } - qy += e->animation->shadow_coords[e->animpos][1]; - sy -= e->animation->shadow_coords[e->animpos][1]; - } - - shadowmethod = plainmethod; - shadowmethod.alpha = BLEND_MULTIPLY + 1; - shadowmethod.config = e->direction == DIRECTION_RIGHT ? (shadowmethod.config | DRAWMETHOD_CONFIG_FLIP_X) : (shadowmethod.config & ~DRAWMETHOD_CONFIG_FLIP_X); - - spriteq_add_sprite(qx, qy, z, shadowsprites[useshadow - 1], &shadowmethod, 0); - if (use_mirror) - { - spriteq_add_sprite(qx, sy, sz, shadowsprites[useshadow - 1], &shadowmethod, 0); - } - } - }//end of plan shadow - } - } - - }// end of blink checking - - if(e->arrowon) // Display the players image while invincible to indicate player number - { - if(e->modeldata.player_arrow[(int)e->playerindex].sprite && e->invincible & INVINCIBLE_INTANGIBLE) - { - spriteq_add_sprite((int)(e->position.x - scrx + e->modeldata.player_arrow[(int)e->playerindex].position.x), (int)(e->position.z - e->position.y - scry + e->modeldata.player_arrow[(int)e->playerindex].position.y), (int)e->position.z, e->modeldata.player_arrow[(int)e->playerindex].sprite, NULL, sortid * 2); - } - } - }// end of if(ent_list[i]->exists) - - // reset vars for next loop - - }// end of for - - //defer ondraw script so it can manage spriteq better - for(i = 0; i < ent_stack_size; i++) - { - execute_ondraw_script(ent_stack[i]); - } - ent_stack_size = 0; -} - - - -void toss(entity *ent, float lift) -{ - if(!lift) - { - return; //zero? - } - ent->toss_time = _time + 1; - ent->velocity.y = lift; - ent->position.y += 0.5; // Get some altitude (needed for checks) -} - -entity *findent(int types) -{ - int i; - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists // Must exist. - && (ent_list[i]->modeldata.type & types) // Be a type we are looking for. - && !((ent_list[i]->death_state & (DEATH_STATE_DEAD | DEATH_STATE_CORPSE)) == (DEATH_STATE_DEAD | DEATH_STATE_CORPSE))) // Ignore dead corpses. - { - return ent_list[i]; - } - } - return NULL; -} - - - -int count_ents(int types) -{ - int i; - int count = 0; - for(i = 0; i < ent_max; i++) - { - - count += (ent_list[i]->exists && (ent_list[i]->modeldata.type & types) && !(ent_list[i]->death_state & DEATH_STATE_CORPSE)); - } - return count; -} - -int isItem(entity *e) -{ - return e->modeldata.type & TYPE_ITEM; -} - -int isSubtypeTouch(entity *e) -{ - return e->modeldata.subtype == SUBTYPE_TOUCH; -} - -int isSubtypeWeapon(entity *e) -{ - return e->modeldata.subtype == SUBTYPE_WEAPON; -} - -int isSubtypeProjectile(entity *e) -{ - return e->modeldata.subtype == SUBTYPE_PROJECTILE; -} - -//check if an item is usable by the entity -int normal_test_item(entity *ent, entity *item) -{ - return ( - isItem(item) && - (item->modeldata.stealth.hide <= ent->modeldata.stealth.detect) && - diff(item->position.x, ent->position.x) + diff(item->position.z, ent->position.z) < videomodes.hRes / 2 && - item->animation->vulnerable[item->animpos] && !item->blink && - (validanim(ent, ANI_GET) || (isSubtypeTouch(item) && faction_check_can_damage(item, ent, 0))) && - ( - (isSubtypeWeapon(item) && !ent->weapent && ent->modeldata.weapon_properties.weapon_list && - ent->modeldata.weapon_properties.weapon_count >= item->modeldata.weapon_properties.weapon_index && ent->modeldata.weapon_properties.weapon_list[item->modeldata.weapon_properties.weapon_index - 1] >= 0) - || (isSubtypeProjectile(item) && !ent->weapent) - || (item->energy_state.health_current && (ent->energy_state.health_current < ent->modeldata.health) && ! isSubtypeProjectile(item) && ! isSubtypeWeapon(item)) - ) - ); -} - -int test_item(entity *ent, entity *item) -{ - if (!( - isItem(item) && - item->animation->vulnerable[item->animpos] && !item->blink && - (validanim(ent, ANI_GET) || (isSubtypeTouch(item) && faction_check_can_damage(item, ent, 0))) - )) - { - return 0; - } - if(isSubtypeProjectile(item) && ent->weapent) - { - return 0; - } - if(isSubtypeWeapon(item) && - (ent->weapent || !ent->modeldata.weapon_properties.weapon_list || - ent->modeldata.weapon_properties.weapon_count < item->modeldata.weapon_properties.weapon_index || - ent->modeldata.weapon_properties.weapon_list[item->modeldata.weapon_properties.weapon_index - 1] < 0) - ) - { - return 0; - } - return 1; -} - -int player_test_pickable(entity *ent, entity *item) -{ - if(isSubtypeTouch(item)) - { - return 0; - } - - if(isSubtypeWeapon(item) && ent->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - return 0; - } - - if(diff(ent->base , item->position.y) > 0.1) - { - return 0; - } - - return test_item(ent, item); -} - -int player_test_touch(entity *ent, entity *item) -{ - if(!isSubtypeTouch(item)) - { - return 0; - } - - if(isSubtypeWeapon(item) && ent->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - return 0; - } - - if(diff(ent->base , item->position.y) > 1) - { - return 0; - } - return test_item(ent, item); -} - -entity *find_ent_here(entity *exclude, float x, float z, e_entity_type types, int (*test)(entity *, entity *)) -{ - int i; - for(i = 0; i < ent_max; i++) - { - if( ent_list[i]->exists - && ent_list[i] != exclude - && (ent_list[i]->modeldata.type & types) - && diff(ent_list[i]->position.x, x) < (self->modeldata.grabdistance * 0.83333) - && diff(ent_list[i]->position.z, z) < (self->modeldata.grabdistance / 3) - && ent_list[i]->animation->vulnerable[ent_list[i]->animpos] - && (!test || test(exclude, ent_list[i])) - ) - { - return ent_list[i]; - } - } - return NULL; -} - -int set_idle(entity *ent) -{ - ent->idling = IDLING_PREPARED; - ent->attacking = ATTACKING_NONE; - ent->inpain = IN_PAIN_NONE; - ent->rising = RISING_NONE; - ent->ducking = DUCK_NONE; - ent->inbackpain = 0; - ent->falling = 0; - ent->jumping = 0; - ent->blocking = BLOCK_STATE_NONE; - common_idle_anim(ent); - - /* - Kratus (02-2024) Reset the aiflag running when landing after jumping - Works only if the RUN_CONFIG_LAND is enabled but no directional keys are held - If the RUN_CONFIG_LAND is disabled, the common_jump() function will reset it - */ - if (ent->modeldata.run_config_flags & RUN_CONFIG_LAND) - { - if (!((player[ent->playerindex].keys & FLAG_MOVELEFT) || (player[ent->playerindex].keys & FLAG_MOVERIGHT))) - { - ent->running = RUN_STATE_NONE; - } - } - - return 1; -} - -int set_death(entity *iDie, int type, int reset) -{ - int die = 0; - - //iDie->velocity.x = iDie->velocity.z = iDie->velocity.y = 0; // stop the target - if((iDie->blocking & BLOCK_STATE_ACTIVE) && validanim(iDie, ANI_CHIPDEATH)) - { - ent_set_anim(iDie, ANI_CHIPDEATH, reset); - iDie->idling = IDLING_NONE; - iDie->getting = 0; - iDie->jumping = 0; - iDie->charging = 0; - iDie->attacking = ATTACKING_NONE; - iDie->blocking = BLOCK_STATE_NONE; - iDie->inpain = IN_PAIN_NONE; - iDie->falling = 0; - iDie->rising = RISING_NONE; - iDie->ducking = DUCK_NONE; - return 1; - } - - if(type < 0 || type >= max_attack_types) - { - type = 0; - } - - if ( iDie->inbackpain ) die = animbackdies[type]; - else die = animdies[type]; - - if(validanim(iDie, die)) - { - ent_set_anim(iDie, die, reset); - } - else if( iDie->inbackpain && validanim(iDie, animbackdies[0]) ) - { - ent_set_anim(iDie, animbackdies[0], reset); - } - else if(validanim(iDie, animdies[type])) - { - if ( iDie->inbackpain ) reset_backpain(iDie); - iDie->inbackpain = 0; - ent_set_anim(iDie, animdies[type], reset); - } - else if(validanim(iDie, animdies[0])) - { - if ( iDie->inbackpain ) reset_backpain(iDie); - iDie->inbackpain = 0; - ent_set_anim(iDie, animdies[0], reset); - } - else - { - return 0; - } - - iDie->idling = IDLING_NONE; - iDie->getting = 0; - iDie->jumping = 0; - iDie->charging = 0; - iDie->attacking = ATTACKING_NONE; - iDie->blocking = BLOCK_STATE_NONE; - iDie->inpain = IN_PAIN_NONE; - iDie->falling = 0; - iDie->rising = RISING_NONE; - iDie->ducking = DUCK_NONE; - if(iDie->frozen) - { - unfrozen(iDie); - } - return 1; -} - - -int set_fall(entity *ent, entity *other, s_attack *attack, int reset) -{ - int fall = 0; - - if ( ent->inbackpain ) fall = animbackfalls[attack->attack_type]; - else fall = animfalls[attack->attack_type]; - - if(validanim(ent, fall)) - { - ent_set_anim(ent, fall, reset); - } - else if( ent->inbackpain && validanim(ent, animbackfalls[0]) ) - { - ent_set_anim(ent, animbackfalls[0], reset); - } - else if( validanim(ent, animfalls[attack->attack_type]) ) - { - if ( ent->inbackpain ) reset_backpain(ent); - ent->inbackpain = 0; - ent_set_anim(ent, animfalls[attack->attack_type], reset); - } - else if(validanim(ent, animfalls[0])) - { - if ( ent->inbackpain ) reset_backpain(ent); - ent->inbackpain = 0; - ent_set_anim(ent, animfalls[0], reset); - } - else - { - return 0; - } - - ent->drop = 1; - ent->inpain = IN_PAIN_NONE; - ent->rising = RISING_NONE; - ent->idling = IDLING_NONE; - ent->falling = 1; - ent->jumping = 0; - ent->ducking = DUCK_NONE; - ent->getting = 0; - ent->charging = 0; - ent->attacking = ATTACKING_NONE; - ent->blocking = BLOCK_STATE_NONE; - ent->nograb = 1; - ent->running = RUN_STATE_NONE; //Kratus (01-2024) Resets the aiflag running when falling - - if(ent->frozen) - { - unfrozen(ent); - } - execute_onfall_script(ent, other, attack); - - return 1; -} - -int set_rise(entity *iRise, int type, int reset) -{ - int rise = 0; - - if(type < 0 || type >= max_attack_types) - { - type = 0; - } - - if ( iRise->inbackpain ) rise = animbackrises[type]; - else rise = animrises[type]; - - if(validanim(iRise, rise)) - { - ent_set_anim(iRise, rise, reset); - } - else if( iRise->inbackpain && validanim(iRise, animbackrises[0]) ) - { - ent_set_anim(iRise, animbackrises[0], reset); - } - else if( validanim(iRise, animrises[type]) ) - { - if ( iRise->inbackpain ) reset_backpain(iRise); - iRise->inbackpain = 0; - ent_set_anim(iRise, animrises[type], reset); - } - else if(validanim(iRise, animrises[0])) - { - if ( iRise->inbackpain ) reset_backpain(iRise); - iRise->inbackpain = 0; - ent_set_anim(iRise, animrises[0], reset); - } - else - { - return 0; - } - - iRise->takeaction = common_rise; - // Get up again - iRise->drop = 0; - iRise->falling = 0; - iRise->rising |= RISING_RISE; - iRise->rising &= ~RISING_ATTACK; - iRise->projectile = BLAST_NONE; - iRise->nograb = iRise->nograb_default; //iRise->nograb = 0; - iRise->velocity.x = self->velocity.z = self->velocity.y = 0; - iRise->jugglepoints = iRise->modeldata.jugglepoints; //reset jugglepoints - return 1; -} - -int set_riseattack(entity *iRiseattack, int type, int reset) -{ - int riseattack = 0; - - if( (!validanim(iRiseattack, animriseattacks[type]) || - (iRiseattack->inbackpain && !validanim(iRiseattack, animbackriseattacks[type]) && !validanim(iRiseattack, animriseattacks[type]))) && - iRiseattack->modeldata.riseattacktype == 1 ) - { - type = 0; - } - if(iRiseattack->modeldata.riseattacktype == 0 || type < 0 || type >= max_attack_types) - { - type = 0; - } - - if ( iRiseattack->inbackpain ) riseattack = animbackriseattacks[type]; - else riseattack = animriseattacks[type]; - - if(validanim(iRiseattack, riseattack)) - { - ent_set_anim(iRiseattack, riseattack, reset); - } - else if( iRiseattack->inbackpain && validanim(iRiseattack, animbackriseattacks[0]) ) - { - ent_set_anim(iRiseattack, animbackriseattacks[0], reset); - } - else if( validanim(iRiseattack, animriseattacks[type]) ) - { - if ( iRiseattack->inbackpain ) reset_backpain(iRiseattack); - iRiseattack->inbackpain = 0; - ent_set_anim(iRiseattack, animriseattacks[type], reset); - } - else if(validanim(iRiseattack, animriseattacks[0])) - { - if ( iRiseattack->inbackpain ) reset_backpain(iRiseattack); - iRiseattack->inbackpain = 0; - ent_set_anim(iRiseattack, animriseattacks[0], reset); - } - else - { - return 0; - } - - iRiseattack->takeaction = common_attack_proc; - self->staydown.riseattack_stall = 0; //Reset riseattack delay. - set_attacking(iRiseattack); - iRiseattack->inpain = IN_PAIN_NONE; - iRiseattack->falling = 0; - iRiseattack->ducking = DUCK_NONE; - iRiseattack->rising &= ~RISING_RISE; - iRiseattack->rising |= RISING_ATTACK; - iRiseattack->drop = 0; - iRiseattack->nograb = iRiseattack->nograb_default; //iRiseattack->nograb = 0; - iRiseattack->jugglepoints = iRiseattack->modeldata.jugglepoints; //reset jugglepoints - return 1; -} - -/* -* Caskey, Damon V. -* 2018 -* -* Place entity into appropriate block pain animation -* based on attack type and direction of attack. -* -* Returns true if successful, false if no valid block pain -* animation was found. -*/ -bool set_blockpain(entity *acting_entity, attack_type_t attack_type, int reset) { - animation_id_t animation; - - // If attack type is out of bounds we - // just use normal. - if(attack_type >= max_attack_types) { - attack_type = ATK_NORMAL; - } - - // In front or back? - if (acting_entity->inbackpain) { - animation = animbackblkpains[attack_type]; - - } else { - animation = animblkpains[attack_type]; - } - - if(validanim(acting_entity, animation)) { - ent_set_anim(acting_entity, animation, reset); - - } else if( acting_entity->inbackpain - && validanim(acting_entity, animbackblkpains[ATK_NORMAL]) ) { - - ent_set_anim(acting_entity, animbackblkpains[ATK_NORMAL], reset); - - } else if(validanim(acting_entity, animblkpains[attack_type])) { - - if (acting_entity->inbackpain) { - reset_backpain(acting_entity); - } - - acting_entity->inbackpain = 0; - ent_set_anim(acting_entity, animblkpains[attack_type], reset); - - } else if(validanim(acting_entity, animblkpains[ATK_NORMAL])) { - if (acting_entity->inbackpain) { - reset_backpain(acting_entity); - } - - acting_entity->inbackpain = 0; - ent_set_anim(acting_entity, animblkpains[ATK_NORMAL], reset); - } else { - return false; - } - - acting_entity->takeaction = common_block; - set_blocking(acting_entity); - acting_entity->inpain = IN_PAIN_BLOCK; - acting_entity->rising = RISING_NONE; - acting_entity->ducking = DUCK_NONE; - return true; -} - -int reset_backpain(entity *ent) -{ - if (ent->normaldamageflipdir >= 0) - { - if (ent->normaldamageflipdir == DIRECTION_RIGHT) - { - ent->direction = DIRECTION_RIGHT; - } - else - { - ent->direction = DIRECTION_LEFT; - } - if(ent->direction == DIRECTION_RIGHT) ent->velocity.x = -1*fabsf(ent->velocity.x); - else ent->velocity.x = fabsf(ent->velocity.x); - - return 1; - } - - return 0; -} - -int check_backpain(entity* attacker, entity* defender) { - if ( !(defender->modeldata.pain_config_flags & PAIN_CONFIG_BACK_PAIN)) return 0; - if ( defender->inpain & IN_PAIN_HIT) return 0; - if ( defender->falling ) return 0; - if ( defender->death_state & DEATH_STATE_DEAD) return 0; - if ( ((!defender->direction && attacker->position.x > defender->position.x) || (defender->direction && attacker->position.x < defender->position.x)) ) - { - defender->inbackpain = 1; - return 1; - } else if ( defender->inbackpain ) defender->inbackpain = 0; - - return 0; -} - -int set_pain(entity *iPain, int type, int reset) -{ - int pain = 0; - - iPain->velocity.x = iPain->velocity.z = iPain->velocity.y = 0; // stop the target - if(iPain->modeldata.guardpoints > 0 && iPain->guardpoints <= 0) - { - pain = ANI_GUARDBREAK; - iPain->guardpoints = iPain->modeldata.guardpoints; - } - else if(type == -1 || type >= max_attack_types) - { - pain = ANI_GRABBED; - } - else - { - if ( iPain->inbackpain ) pain = animbackpains[type]; - else pain = animpains[type]; - } - - - if(validanim(iPain, pain)) - { - ent_set_anim(iPain, pain, reset); - } - else if( iPain->inbackpain && validanim(iPain, animbackpains[0]) ) - { - ent_set_anim(iPain, animbackpains[0], reset); - } - else if( (type != -1 && type < max_attack_types) && validanim(iPain, animpains[type]) ) - { - if ( iPain->inbackpain ) reset_backpain(iPain); - iPain->inbackpain = 0; - ent_set_anim(iPain, animpains[type], reset); - } - else if(validanim(iPain, animpains[0])) - { - if ( iPain->inbackpain ) reset_backpain(iPain); - iPain->inbackpain = 0; - ent_set_anim(iPain, animpains[0], reset); - } - else if(validanim(iPain, ANI_IDLE)) - { - if ( iPain->inbackpain ) reset_backpain(iPain); - iPain->inbackpain = 0; - ent_set_anim(iPain, ANI_IDLE, reset); - } - else - { - return 0; - } - - iPain->idling = IDLING_NONE; - iPain->falling = 0; - iPain->rising = RISING_NONE; - iPain->ducking = DUCK_NONE; - iPain->projectile = BLAST_NONE; - iPain->drop = 0; - iPain->attacking = ATTACKING_NONE; - iPain->getting = 0; - iPain->charging = 0; - iPain->jumping = 0; - iPain->blocking = BLOCK_STATE_NONE; - iPain->inpain = IN_PAIN_HIT; - if(iPain->frozen) unfrozen(iPain); - - if(pain == ANI_GRABBED) - { - iPain->inpain = IN_PAIN_NONE; - iPain->rising = RISING_NONE; - iPain->ducking = DUCK_NONE; - if ( iPain->inbackpain ) reset_backpain(iPain); - iPain->inbackpain = 0; - } - - execute_onpain_script(iPain, type, reset); - return 1; -} - -/* - * Copy animations from newmodel to model. If newmodel has anim that is not in model, - * then copy that anim (but no frames with alloc_anim()) from newmodel to model - */ -void normalize_anim_models(s_model *model, s_model *newmodel) -{ - int i = 0; - - for(i = 0; i < max_animations; i++) - { - if(!model->animation[i] && newmodel->animation[i]) - { - model->animation[i] = alloc_anim(); - } - } - - return; -} - -//change model, anim_flag 1: reset animation 0: use original animation -void set_model_ex(entity *ent, char *modelname, int index, s_model *newmodel, int anim_flag) -{ - s_model *model = NULL; - entity tempe; - s_defense *dfs = NULL; - s_offense *ofs = NULL; - int i; - int type = ent->modeldata.type; - - model = ent->model; - tempe.exists = 0; - - if(!newmodel) - { - if(index >= 0) - { - newmodel = model_cache[index].model; - } - else - { - newmodel = findmodel(modelname); - } - } - if(!newmodel) - { - borShutdown(1, "Can't set model for entity '%s', model not found.\n", ent->name); - } - if(newmodel == model) - { - return; - } - - if(!(newmodel->model_flag & MODEL_COPY_FLAG_NO_BASIC)) - { - newmodel->move_config_flags = model->move_config_flags; - - if(!newmodel->speed.x) - { - newmodel->speed.x = model->speed.x; - } - if(!newmodel->runspeed) - { - newmodel->runspeed = model->runspeed; - newmodel->runjumpheight = model->runjumpheight; - newmodel->runjumpdist = model->runjumpdist; - newmodel->run_config_flags = model->run_config_flags; - } - if(newmodel->icon.def < 0) - { - newmodel->icon.def = model->icon.def; - } - if(newmodel->icon.pain < 0) - { - newmodel->icon.pain = model->icon.pain; - } - if(newmodel->icon.get < 0) - { - newmodel->icon.get = model->icon.get; - } - if(newmodel->icon.die < 0) - { - newmodel->icon.die = model->icon.die; - } - if(newmodel->shadow < 0) - { - newmodel->shadow = model->shadow; - } - if(newmodel->knife < 0) - { - newmodel->knife = model->knife; - } - if(newmodel->pshotno < 0) - { - newmodel->pshotno = model->pshotno; - } - if(newmodel->bomb < 0) - { - newmodel->bomb = model->bomb; - } - if(newmodel->star < 0) - { - newmodel->star = model->star; - } - if(newmodel->flash.model_hit < 0) - { - newmodel->flash.model_hit = model->flash.model_hit; - } - if(newmodel->flash.model_block < 0) - { - newmodel->flash.model_block = model->flash.model_block; - } - if(newmodel->dust.fall_land < 0) - { - newmodel->dust.fall_land = model->dust.fall_land; - } - if(newmodel->dust.jump_land < 0) - { - newmodel->dust.jump_land = model->dust.jump_land; - } - if(newmodel->diesound < 0) - { - newmodel->diesound = model->diesound; - } - - for(i = 0; i < max_animations; i++) - { - if(!newmodel->animation[i] && model->animation[i] && model->animation[i]->numframes > 0) - { - newmodel->animation[i] = model->animation[i]; - } - } - //normalize_anim_models(model, newmodel); - } - - // copy the weapon list if model flag is not set to use its own weapon list - if (!(newmodel->model_flag & MODEL_COPY_FLAG_NO_WEAPON)) - { - newmodel->weapon_properties.weapon_index = model->weapon_properties.weapon_index; - if (!newmodel->weapon_properties.weapon_list) - { - newmodel->weapon_properties.weapon_list = model->weapon_properties.weapon_list; - newmodel->weapon_properties.weapon_count = model->weapon_properties.weapon_count; - } - } - - //Make a shallow copy of old entity values, not safe but easy. - //Also copy offense and defense because they are more likely be used by weapons, - //other references are left alone for now - if(Script_IsInitialized(newmodel->scripts->onmodelcopy_script)) - { - tempe = *ent; - dfs = malloc(sizeof(*dfs) * max_attack_types); - ofs = malloc(sizeof(*ofs) * max_attack_types); - - memcpy(dfs, ent->defense, sizeof(*dfs)*max_attack_types); - memcpy(ofs, ent->offense, sizeof(*ofs)*max_attack_types); - - tempe.defense = dfs; - tempe.offense = ofs; - } - - ent_set_model(ent, newmodel->name, anim_flag); - - ent->modeldata.type = type; - - if((newmodel->model_flag & MODEL_COPY_FLAG_NO_SCRIPT)) - { - clear_all_scripts(ent->scripts, 0); - } - - copy_all_scripts(newmodel->scripts, ent->scripts, 0); - - memcpy(ent->defense, ent->modeldata.defense, sizeof(*ent->defense)*max_attack_types); - memcpy(ent->offense, ent->modeldata.offense, sizeof(*ent->offense)*max_attack_types); - - ent_set_colourmap(ent, ent->map); - if(Script_IsInitialized(ent->scripts->onmodelcopy_script)) - { - execute_onmodelcopy_script(ent, &tempe); - if(ofs) - { - free(ofs); - } - if(dfs) - { - free(dfs); - } - } -} - -void set_weapon(entity *ent, int wpnum, int anim_flag) // anim_flag added for scripted midair weapon changing -{ - if(!ent) - { - return; - } -//printf("setweapon: %d \n", wpnum); - - if(ent->modeldata.type & TYPE_PLAYER) // save current weapon for player's weaploss WEAPON_LOSS_CONDITION_STAGE - { - if(ent->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_STAGE) - { - player[(int)ent->playerindex].weapnum = wpnum; - } - else - { - player[(int)ent->playerindex].weapnum = level->setweap; - } - } - - if(ent->modeldata.weapon_properties.weapon_list && wpnum > 0 && wpnum <= ent->modeldata.weapon_properties.weapon_count && ent->modeldata.weapon_properties.weapon_list[wpnum - 1]) - { - set_model_ex(ent, NULL, ent->modeldata.weapon_properties.weapon_list[wpnum - 1], NULL, !anim_flag); - } - else - { - set_model_ex(ent, NULL, -1, ent->defaultmodel, 1); - } -} - -////////////////////////////////////////////////////////////////////////// -// common A.I. code for enemies & NPCs -////////////////////////////////////////////////////////////////////////// - - -entity *melee_find_target() -{ - return NULL; -} - -entity *long_find_target() -{ - return NULL; -} - -entity *block_find_target(int anim, int detect_adj) -{ - int i; - int min; - int max; - int detect; - int index = -1; - min = 0; - max = 9999; - float diffx, diffz, diffd, diffo = 0; - entity *attacker; - - detect = detect_adj + self->modeldata.stealth.detect; - - //find the 'nearest' attacking one - for(i = 0; i < ent_max; i++) - { - attacker = ent_list[i]; - - if (attacker && attacker->exists && attacker != self // Can't target self - && (faction_check_can_damage(attacker, self, 0)) // Type is something attacker can damage. - && (anim < 0 || (anim >= 0 && check_range_target_all(self, attacker, anim, 0, 0))) // Valid animation ID and in range. - && !(attacker->death_state & DEATH_STATE_DEAD) // Must be alive. - && attacker->attacking != ATTACKING_NONE // Must be attacking. - && collision_attack_find_no_block_on_frame(attacker->animation, attacker->animpos, 1) != NULL // Valid blockable attack. - && (diffd = (diffx = diff(attacker->position.x, self->position.x)) + (diffz = diff(attacker->position.z, self->position.z))) >= min - && diffd <= max - && (attacker->modeldata.stealth.hide <= detect) // Stealth factor less then perception factor (allows invisibility). - ) - { - if (index < 0 || diffd < diffo) - { - index = i; - diffo = diffd; - - continue; - } - } - } - if( index >= 0) - { - return ent_list[index]; - } - return NULL; -} - -entity *normal_find_target(int anim, int detect_adj) -{ - - /* - normal_find_target - Author unknown - Date unknown - ~Damon Caskey, 2011_07_22: Add support for detect adjustment. - - int anim: Animation find range will be calculated by. Default to current animation if not passed. - int detect_adj: Local detection adjustment. Allows lesser or greater penetration of target's stealth for location. - */ - - int i; - int min; - int max; - int detect; - int index = -1; - float diffx = 0; - float diffz = 0; - float diffd = 0; - float diffo = 0; - - min = 0; - max = 9999; - - detect = detect_adj + self->modeldata.stealth.detect; - - //find the 'nearest' one - for(i = 0; i < ent_max; i++) - { - // Must exist. - if(!ent_list[i]->exists) - { - continue; - } - - // Can't be self. - if(ent_list[i] == self) - { - continue; - } - - /* Must be hostile toward it. */ - if (!faction_check_is_hostile(self, ent_list[i])) - { - continue; - } - - // If anim is defined, then target must be - // in range of animation. - if(anim >= 0) - { - if(!check_range_target_all(self, ent_list[i], anim, 0, 0)) - { - continue; - } - } - - // Can't be dead. - if(ent_list[i]->death_state & DEATH_STATE_DEAD) - { - continue; - } - - // Get X and Z differences between us and target. We then - // add them up to get a total distance. - diffx = diff(ent_list[i]->position.x, self->position.x); - diffz = diff(ent_list[i]->position.z, self->position.z); - diffd = diffx + diffz; - - // Distance must be within min and max. - if(diffd <= min || diffd >= max) - { - continue; - } - - // Stealth must not be greater than perception. - if(ent_list[i]->modeldata.stealth.hide > detect) - { - continue; - } - - - if(index < 0 - || (index >= 0 && (!ent_list[index]->animation->vulnerable[ent_list[index]->animpos] || ent_list[index]->invincible & INVINCIBLE_INTANGIBLE)) - // don't turn to the one on the back - || ((self->position.x < ent_list[i]->position.x) == (self->direction == DIRECTION_RIGHT) && diffd < diffo) - ) - { - index = i; - diffo = diffd; - } - - - } - - if(index >= 0) - { - return ent_list[index]; - } - return NULL; -} - -//Used by default A.I. pattern -// A.I. characters try to find a pickable item -entity *normal_find_item() -{ - - int i; - int index = -1; - entity *ce = NULL; - //find the 'nearest' one - for(i = 0; i < ent_max; i++) - { - ce = ent_list[i]; - - if( ce->exists && normal_test_item(self, ce) ) - { - if(index < 0 || diff(ce->position.x, self->position.x) + diff(ce->position.z, self->position.z) < diff(ent_list[index]->position.x, self->position.x) + diff(ent_list[index]->position.z, self->position.z)) - { - index = i; - } - } - } - if( index >= 0) - { - return ent_list[index]; - } - return NULL; -} - -int long_attack() -{ - return 0; -} - -int melee_attack() -{ - return 0; -} - -// chose next attack in atchain, if succeeded, return 1, otherwise return 0. -int perform_atchain() -{ - int pickanim = 0; - - if(self->modeldata.chainlength <= 0) { - return 0; - } - - /* - * Even if we miss, cotinue the combo chain - * unless time has expired. - */ - if(self->combotime > _time) { - self->combostep[0]++; - } else { - self->combostep[0] = 1; - } - - if(self->modeldata.atchain[self->combostep[0] - 1] == 0) { // 0 means the chain ends - self->combostep[0] = 1; - } - - if(validanim(self, animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1]) ) { - if(((self->combostep[0] == 1 || !(self->modeldata.combostyle & 1)) && (self->modeldata.type & TYPE_PLAYER)) || // player should use attack 1st step without checking range - - (!(self->modeldata.combostyle & 1) && normal_find_target(animattacks[self->modeldata.atchain[0] - 1], 0)) || // normal chain just checks the first attack in chain(guess no one like it) - - ((self->modeldata.combostyle & 1) && normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1], 0))) { // combostyle 1 checks all anyway. - pickanim = 1; - - } else if((self->modeldata.combostyle & 1) && self->combostep[0] != 1) { // ranged combo? search for a valid attack - - while(++self->combostep[0] <= self->modeldata.chainlength) { - if(self->modeldata.atchain[self->combostep[0] - 1] && - validanim(self, animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1]) && - (self->combostep[0] == self->modeldata.chainlength || - normal_find_target(animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1], 0))) { - pickanim = 1; - break; - } - } - } - - } else { - self->combostep[0] = 0; - } - - if(pickanim && validanim(self, animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1])){ - self->takeaction = common_attack_proc; - set_attacking(self); - ent_set_anim(self, animattacks[self->modeldata.atchain[self->combostep[0] - 1] - 1], 1); - } - - if(!pickanim || self->combostep[0] > self->modeldata.chainlength) { - self->combostep[0] = 0; - } - - if((self->modeldata.combostyle & 2)) { - self->combotime = _time + combodelay; - } - - return pickanim; -} - -void upper_prepare() -{ - int predir = self->direction; - - entity *target = normal_find_target(ANI_UPPER, 0); - - self->velocity.x = self->velocity.z = 0; //stop - - if(!target) - { - self->idling = IDLING_PREPARED; - self->takeaction = NULL; - return; - } - - //check if target is behind, so we can perform a turn back animation - if(!(self->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP)) - { - self->direction = (self->position.x < target->position.x); - } - if(predir != self->direction && validanim(self, ANI_TURN)) - { - self->takeaction = common_turn; - self->direction = predir; - set_turning(self); - ent_set_anim(self, ANI_TURN, 0); - return; - } - - // Wait... - if(_time < self->stalltime) - { - return; - } - - // Target jumping? Try uppercut! - if(target && target->jumping) - { - self->takeaction = common_attack_proc; - set_attacking(self); - self->velocity.z = self->velocity.x = 0; - // Don't waste any time! - ent_set_anim(self, ANI_UPPER, 0); - return; - } -} - -/* -* Add one animation to the temporary AI attack-choice -* table. A capacity failure is fatal because continuing -* would overwrite unrelated memory. -*/ -static void ai_attack_choice_append(int* choice_count, const int animation) -{ - if(!choice_count - || *choice_count < 0 - || !ai_attack_choices - || (size_t)*choice_count >= ai_attack_choice_capacity) { - borShutdown( - 1, - "AI attack-choice table exceeds its capacity of %zu animations.\n", - ai_attack_choice_capacity - ); - - return; - } - - ai_attack_choices[*choice_count] = animation; - (*choice_count)++; -} - -void normal_prepare() -{ - int i, j; - int found = 0, special = 0; - int predir = self->direction; - - entity *target = normal_find_target(-1, 0); - - self->velocity.x = self->velocity.z = 0; //stop - - if(!target) - { - self->idling = IDLING_PREPARED; - self->takeaction = NULL; - return; - } - - //check if target is behind, so we can perform a turn back animation - if(!(self->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP)) - { - self->direction = (self->position.x < target->position.x); - } - if(predir != self->direction && validanim(self, ANI_TURN)) - - { - self->takeaction = common_turn; - self->direction = predir; - set_turning(self); - ent_set_anim(self, ANI_TURN, 0); - return; - } - - // Wait... - if(_time < self->stalltime) - { - return; - } - // let go the projectile, well - if( self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && - validanim(self, ANI_THROWATTACK) && - check_range_target_all(self, target, ANI_THROWATTACK, 0, 0)) - { - self->takeaction = common_attack_proc; - set_attacking(self); - ent_set_anim(self, ANI_THROWATTACK, 0); - return ; - } - - // move freespecial check here - - for(i = 0; i < max_freespecials; i++) - { - if(validanim(self, animspecials[i]) && - (check_energy(ENERGY_TYPE_MP, animspecials[i]) || - check_energy(ENERGY_TYPE_HP, animspecials[i])) && - check_range_target_all(self, target, animspecials[i], 0, 0)) - { - ai_attack_choice_append(&found, animspecials[i]); - } - } - if((rand32() & 7) < 2) - { - if(found && check_costmove(ai_attack_choices[(rand32() & 0xffff) % found], 1, 0) ) - { - return; - } - } - special = found; - - if(self->modeldata.chainlength > 1) // have a chain? - { - if(perform_atchain()) - { - return; - } - } - else if (self->ducking & DUCK_ACTIVE) - { - self->takeaction = common_attack_proc; - set_attacking(self); - ent_set_anim(self, ANI_DUCKATTACK, 0); - return; - } - else // dont have a chain so just select an attack randomly - { - // Pick an attack - for(i = 0; i < max_attacks; i++) - { - if( validanim(self, animattacks[i]) && - check_range_target_all(self, target, animattacks[i], 0, 0)) - { - // a trick to make attack 1 has a greater chance to be chosen - // 6 5 4 3 2 1 1 1 1 1 .... - for(j = ((5 - i) >= 0 ? (5 - i) : 0); j >= 0; j--) - { - ai_attack_choice_append(&found, animattacks[i]); - } - } - } - if(found > special) - { - self->takeaction = common_attack_proc; - set_attacking(self); - ent_set_anim(self, ai_attack_choices[special + (rand32() & 0xffff) % (found - special)], 0); - return; - } - } - - // if no attack was picked, just choose a random one from the valid list - if(special && check_costmove(ai_attack_choices[(rand32() & 0xffff) % special], 1, 0)) - { - return; - } - - // No attack to perform, return to A.I. root - self->idling = IDLING_PREPARED; - self->takeaction = NULL; -} - -void common_jumpland() -{ - if(self->animating) - { - return; - } - self->takeaction = NULL; - set_idle(self); -} - -//A.I characters play the jump animation -void common_jump() -{ - entity *dust; - - if(inair(self)) - { - //printf("%f %f %f %d\n", self->base, self->position.y, self->velocity.y, self->landed_on_platform); - return; - } - - if(self->velocity.y <= 0) // wait if it is still go up - { - self->velocity.y = 0; - self->position.y = self->base; - - self->jumping = 0; - self->ducking = DUCK_NONE; - self->attacking = ATTACKING_NONE; - - if (!(self->modeldata.run_config_flags & RUN_CONFIG_LAND)) - { - self->running = RUN_STATE_NONE; - } - - self->velocity.z = self->velocity.x = 0; - - // check if jumpland animation exists and not using landframe - if(validanim(self, ANI_JUMPLAND) && self->animation->landframe.frame == FRAME_NONE) - { - self->takeaction = common_jumpland; - ent_set_anim(self, ANI_JUMPLAND, 0); - if(self->modeldata.dust.jump_land >= 0) - { - dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.jump_land, NULL); - if(dust) - { - dust->spawntype = SPAWN_TYPE_DUST_LAND; - dust->base = self->position.y; - dust->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(dust); - } - } - } - else - { - if(self->modeldata.dust.jump_land >= 0 && self->animation->landframe.frame == FRAME_NONE) - { - dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.jump_land, NULL); - if(dust) - { - dust->spawntype = SPAWN_TYPE_DUST_LAND; - dust->base = self->position.y; - dust->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(dust); - } - } - if(self->animation->landframe.frame != FRAME_NONE && self->animating) - { - return; - } - - self->takeaction = NULL; // back to A.I. root - set_idle(self); - } - } -} - -//A.I. characters spawn -void common_spawn() -{ - self->idling = IDLING_NONE; - if(self->animating) - { - return; - } - self->takeaction = NULL; // come to life - set_idle(self); -} - -//A.I. characters drop from the sky -void common_drop() -{ - if(inair(self)) - { - return; - } - self->idling = IDLING_PREPARED; - self->takeaction = NULL; - if(self->energy_state.health_current <= 0) - { - kill_entity(self, KILL_ENTITY_TRIGGER_DROP_NO_HEALTH); - } -} - -//Similar as above, walk off a wall/cliff -void common_walkoff() -{ - if(inair(self) || self->animating) - { - return; - } - self->takeaction = NULL; - set_idle(self); -} - -// play turn animation and then flip -void common_turn() -{ - if(!self->animating) - { - self->takeaction = NULL; - self->velocity.x = self->velocity.z = 0; - self->direction = !self->direction; - set_idle(self); - } -} - -// switch to land animation, land safely -void doland() -{ - self->velocity.x = self->velocity.z = 0; - self->drop = 0; - self->projectile = BLAST_NONE; - self->damage_on_landing.attack_force = 0; - self->damage_on_landing.attack_type = ATK_NONE; - if(validanim(self, ANI_LAND)) - { - self->takeaction = common_land; - self->direction = !self->direction; - ent_set_anim(self, ANI_LAND, 0); - } - else - { - self->takeaction = NULL; - set_idle(self); - } -} - -void common_fall() -{ - // Still falling? - if(self->falling || inair(self) || self->velocity.y) - { - return; - } - - // Landed. Let's see if we could land - // safely. - if(self->projectile != BLAST_NONE) - { - if (self->projectile & BLAST_TOSS) - { - // damage_on_landing.attack_force==-2 means a player has pressed up+jump and has a land animation - if ((autoland == 1 && self->damage_on_landing.attack_force == ATTACK_FORCE_LAND_AUTO) || self->damage_on_landing.attack_force == ATTACK_FORCE_LAND_COMMAND) - { - // Added autoland option for landing - doland(); - return; - } - - self->falling = 0; - } - } - - // Drop Weapon due to Enemy Falling. - //if(self->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_FALL) dropweapon(1); - - if(self->boss && level_completed) - { - tospeedup = 1; - } - - // Pause a bit... - self->takeaction = common_lie; - self->stalltime = _time + MAX(0, (int)(self->staydown.rise + global_config.game_speed - self->modeldata.risetime.rise)); //Set rise delay. - self->staydown.riseattack_stall = _time + MAX(0, (int)(self->staydown.riseattack - self->modeldata.risetime.riseattack)); //Set rise attack delay. - self->staydown.rise = 0; //Reset staydown. - self->staydown.riseattack = 0; //Reset staydown atk. -} - -void common_try_riseattack() -{ - entity *target; - if(!validanim(self, ANI_RISEATTACK)) - { - return; - } - - target = normal_find_target(ANI_RISEATTACK, 0); - if(!target) - { - self->direction = !self->direction; - target = normal_find_target(ANI_RISEATTACK, 0); - self->direction = !self->direction; - } - - if(target) - { - self->direction = (target->position.x > self->position.x); // Stands up and swings in the right direction depending on chosen target - set_riseattack(self, self->last_damage_type, 0); - } -} - -/* -* Caskey, Damon V. -* 2023-03-28 -* -* Run death sequece (if any) for entity. -*/ -int death_try_sequence_damage(entity* acting_entity, e_death_config_flags death_sequence, e_death_sequence_acting_event acting_event) -{ - int result = 0; - attack_type_t attack_type = acting_entity->last_damage_type; - e_death_state death_state = acting_entity->death_state; - - if (death_state & DEATH_STATE_AIR) - { - /* - * Fall first? This works by just turning - * control back over to the damage function - * and letting it handle fall routines. - */ - if ((death_sequence & DEATH_CONFIG_FALL_LAND_AIR && acting_event != DEATH_TRY_SEQUENCE_ACTING_EVENT_LIE) || (death_sequence & DEATH_CONFIG_FALL_LIE_AIR && acting_entity->animating)) - { - /* Turn on blinking? */ - if (death_sequence & DEATH_CONFIG_BLINK_FALL_AIR) - { - acting_entity->blink = 1; - } - - result = 0; - return result; - } - - /* Play death animation? */ - if (death_sequence & DEATH_CONFIG_DEATH_AIR) - { - /* Turn on blinking? */ - if (death_sequence & DEATH_CONFIG_BLINK_DEATH_AIR) - { - acting_entity->blink = 1; - } - - acting_entity->velocity.x = 0; - acting_entity->velocity.y = 0; - acting_entity->velocity.z = 0; - - set_death(acting_entity, attack_type, 0); - - result = 1; - - /* Allow death animation to finish. */ - if (acting_entity->animating) - { - return result; - } - } - - /* - * Remove entity from the screen? - */ - if (death_sequence & DEATH_CONFIG_REMOVE_VANISH_AIR) - { - acting_entity->takeaction = (acting_entity->modeldata.type & TYPE_PLAYER) ? player_blink : suicide; - - /* - * If blink requested, we turn on blink - * effect and set a delay before killing - * self. - */ - if (death_sequence & DEATH_CONFIG_BLINK_REMOVE_AIR) - { - acting_entity->blink = 1; - acting_entity->stalltime = _time + global_config.game_speed * 2; - } - } - else if (death_sequence & DEATH_CONFIG_REMOVE_CORPSE_AIR) - { - /* Turn on blinking? */ - if (death_sequence & DEATH_CONFIG_BLINK_REMOVE_AIR) - { - acting_entity->blink = 1; - } - - /* Set corpse flag and disable AI control. */ - if (acting_entity->modeldata.type & TYPE_PLAYER) - { - acting_entity->takeaction = player_die; - } - else - { - acting_entity->death_state |= DEATH_STATE_CORPSE; - acting_entity->noaicontrol = 1; - } - } - } - else - { - if ((death_sequence & DEATH_CONFIG_FALL_LAND_GROUND && acting_event != DEATH_TRY_SEQUENCE_ACTING_EVENT_LIE) || (death_sequence & DEATH_CONFIG_FALL_LIE_GROUND && acting_entity->animating)) - { - result = 0; - return result; - } - - /* Play death animation? */ - if (death_sequence & DEATH_CONFIG_DEATH_GROUND) - { - /* Turn on blinking? */ - if (death_sequence & DEATH_CONFIG_BLINK_DEATH_GROUND) - { - acting_entity->blink = 1; - } - - acting_entity->velocity.x = 0; - acting_entity->velocity.y = 0; - acting_entity->velocity.z = 0; - - set_death(acting_entity, attack_type, 0); - - result = 1; - - /* Allow death animation to finish. */ - if (acting_entity->animating) - { - return result; - } - } - - /* - * Remove entity from the screen? - */ - if (death_sequence & DEATH_CONFIG_REMOVE_VANISH_GROUND) - { - acting_entity->takeaction = (acting_entity->modeldata.type & TYPE_PLAYER) ? player_blink : suicide; - - /* - * If blink requested, we turn on blink - * effect and set a delay before killing - * self. - */ - if (death_sequence & DEATH_CONFIG_BLINK_REMOVE_GROUND) - { - acting_entity->blink = 1; - acting_entity->stalltime = _time + global_config.game_speed * 2; - } - } - else if (death_sequence & DEATH_CONFIG_REMOVE_CORPSE_GROUND) - { - /* Turn on blinking? */ - if (death_sequence & DEATH_CONFIG_BLINK_REMOVE_GROUND) - { - acting_entity->blink = 1; - } - - /* Set corpse flag and disable AI control. */ - if (acting_entity->modeldata.type & TYPE_PLAYER) - { - acting_entity->takeaction = player_die; - } - else - { - acting_entity->death_state |= DEATH_STATE_CORPSE; - acting_entity->noaicontrol = 1; - } - } - } - - return result; -} - -void common_lie() { - - entity* acting_entity = self; - e_death_config_flags death_config; - - // Died? - if(acting_entity->energy_state.health_current <= 0) { - - const s_defense* defense_object = defense_find_current_object(acting_entity, NULL, acting_entity->last_damage_type); - - death_config = defense_object->death_config_flags; - - if (death_config & DEATH_CONFIG_SOURCE_MODEL) { - death_config = acting_entity->modeldata.death_config_flags; - } - - death_try_sequence_damage(acting_entity, death_config, DEATH_TRY_SEQUENCE_ACTING_EVENT_LIE); - - /* - * Apply KO (death) map if we have one. - */ - if (acting_entity->modeldata.colorsets.ko != COLORSET_INDEX_NONE) { - /* - * Wait for animation to finish unless type is set to - * apply map immediately. - */ - - if (acting_entity->modeldata.colorsets.kotype == KO_COLORSET_CONFIG_INSTANT || !acting_entity->animating) { - acting_entity->colourmap = model_get_colourmap(&(acting_entity->modeldata), acting_entity->modeldata.colorsets.ko); - } - } - - return; - } - - if(_time < acting_entity->stalltime || acting_entity->position.y != acting_entity->base || acting_entity->velocity.y) { - return; - } - - set_rise(acting_entity, acting_entity->last_damage_type, 0); -} - -// rise proc -void common_rise() -{ - if(self->animating) - { - return; - } - self->takeaction = NULL; - self->staydown.riseattack_stall = 0; //Reset riseattack delay. - if(self->modeldata.riseinv) - { - self->blink = self->modeldata.riseinv > 0; - self->invinctime = _time + ABS(self->modeldata.riseinv); - self->invincible |= INVINCIBLE_INTANGIBLE; - } - set_idle(self); -} - -// pain proc -void common_pain() -{ - //self->velocity.x = self->velocity.z = 0; // complained - - if(self->animating || inair(self)) - { - return; - } - - self->inpain = IN_PAIN_HIT; - self->rising = RISING_NONE; - self->ducking = DUCK_NONE; - self->inbackpain = 0; - if(self->link) - { -// set_pain(self, -1, 0); - self->takeaction = common_grabbed; - } - else if((self->blocking & (BLOCK_STATE_ACTIVE | BLOCK_STATE_NATIVE)) - == (BLOCK_STATE_ACTIVE | BLOCK_STATE_NATIVE)) - { - self->inpain = IN_PAIN_BLOCK; - self->takeaction = common_block; - ent_set_anim(self, ANI_BLOCK, 1); - } - else - { - self->takeaction = NULL; - set_idle(self); - } -} - -void doprethrow() -{ - entity *other = self->link; - other->takeaction = common_prethrow; - self->takeaction = common_throw_wait; - self->velocity.x = self->velocity.z = self->velocity.y = other->velocity.x = other->velocity.z = other->velocity.y = 0; - ent_set_anim(self, ANI_THROW, 0); -} - -// 1 grabattack 2 grabforward 3 grabup 4 grabdown 5 grabbackward -// other means grab finisher at once - -// Unknown author (utunnels?). -// -// Retooled by Caskey, Damon V. to use named constants -// for selecting which grab attack. -// 2019-05-31 -// -// Perform a grab attack action depending on request and -// current number already performed for of a given -// grab attack. -void dograbattack(int which) -{ - entity *other = self->link; - self->takeaction = common_grabattack; - self->attacking = ATTACKING_ACTIVE; - other->velocity.x = other->velocity.z = self->velocity.x = self->velocity.z = 0; - - // If we requested finish attack, do it now. Otherwise - // we'll look at current combostep for the selected grab - // attack. If we're at the combo limit, then we finish. - // If not, do the requested attack. - if (which == GRAB_ACTION_SELECT_FINISH) - { - do_grab_attack_finish(self, 0); - } - else - { - ++self->combostep[which]; - if (self->combostep[which] < 3 && validanim(self, grab_attacks[which][0])) - { - ent_set_anim(self, grab_attacks[which][0], 0); - } - else - { - do_grab_attack_finish(self, which); - } - } -} - -// Caskey, Damon V. -// 2018-04-11 -// -// Choose appropriate grab finish animation -// or do nothing if we can't find one. Returns -// selected animation. -animation_id_t do_grab_attack_finish(entity *ent, int which) -{ - animation_id_t animation; - - // Clear out the combostep array since this is - // the finishing attack. - memset(ent->combostep, 0, sizeof(*ent->combostep) * 5); - - // Get the finisher animation. - animation = grab_attacks[which][1]; - - // If selected attack animation exists then - // that's what we use. Otherwise default to - // attack3. If THAT fails, we don't do anything. - // The target entity is already unlinked from - // grab before this function was called, so in - // game they are let go with no finishing attack. - if(validanim(ent, animation)) - { - ent_set_anim(ent, animation, 0); - return animation; - } - else if(validanim(ent, ANI_ATTACK3)) - { - // Get the finisher animation. - ent_set_anim(ent, ANI_ATTACK3, 0); - return ANI_ATTACK3; - } - - // Could not find a valid finisher. Return none. - return ANI_NONE; -} - -void common_grab_check() -{ - int rnum, which; - entity *other = self->link; - - if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) - { - return; - } - - if(self->base != other->base) - { - // Change this from ->position.y to ->base - self->takeaction = NULL; - ent_unlink(self); - set_idle(self); - return; - } - - if(!nolost && self->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_GRABBING) - { - dropweapon(self, 1); - } - - self->attacking = ATTACKING_NONE; //for checking - - rnum = rand32() & 31; - - if(_time > self->releasetime) - { - if(rnum < 12) - { - // Release - self->takeaction = NULL; - ent_unlink(self); - set_idle(self); - return; - } - else - { - self->releasetime = _time + (global_config.game_speed / 2); - } - } - - if(validanim(self, ANI_THROW) && rnum < 7) - { - if(self->modeldata.throwframewait >= 0) - { - doprethrow(); - } - else - { - dothrow(); - } - return; - } - - // Kratus (04-2023) Implemented vault animation to all A.I. controlled characters - if(validanim(self, ANI_VAULT) && rnum < 6) - { - self->attacking = ATTACKING_ACTIVE; - self->takeaction = common_grabattack; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - ent_set_anim(self, ANI_VAULT, 0); - return; - } - - //grab finisher - if(rnum < 4) - { - dograbattack(GRAB_ACTION_SELECT_FINISH); - return; - } - which = rnum % GRAB_ACTION_SELECT_MAX; - // grab attacks - if(rnum > 12 && validanim(self, grab_attacks[which][0])) - { - dograbattack(which); - return; - } -} - -//grabbing someone -void common_grab() -{ - // if(self->link) return; - if(self->link || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) - { - return; - } - - self->takeaction = NULL; - self->attacking = ATTACKING_NONE; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - set_idle(self); -} - -// being grabbed -void common_grabbed() -{ - // Just check if we're still grabbed... - if(self->link) - { - return; - } - - self->stalltime = 0; - self->takeaction = NULL; - set_idle(self); -} - -// picking up something -void common_get() -{ - if(self->animating) - { - return; - } - - self->getting = 0; - self->takeaction = NULL; - set_idle(self); -} - -// Continue or release block. -void common_block() -{ - // Player type with holdblock, also not in pain - // or has post blockpain holdblock ability. - int player_hold_block_eligible = self->modeldata.block_config_flags & (BLOCK_CONFIG_HOLD_IMPACT | BLOCK_CONFIG_HOLD_INFINITE) - && (self->modeldata.type & TYPE_PLAYER) - && (self->inpain == IN_PAIN_NONE || (self->modeldata.block_config_flags & BLOCK_CONFIG_HOLD_INFINITE)); - - // Controlling player is holding special key. - int player_holding_special = ((player + self->playerindex)->keys & FLAG_SPECIAL); - - // If we are in a block transition, let's see if it is finished. - // If it is, apply block animation. - if (self->animnum == ANI_BLOCKSTART && !self->animating) { - ent_set_anim(self, ANI_BLOCK, 0); - } - - /* - * In "Blockstun", at last frame of animation, and - * have holdblock after blockpain ability? Then we - * return to block. - * - * Otherwise, entity is a player with various other - * flags (see player_hold_block_eligible) but not - * holding special key, or the entity has finihsed - * animation and doesn't match any of the player - * holdblock criteria. It could be another entity - * type, doesn't have holdblock ability, or the - * controlling player isn't holding special key. - * - * In any of those cases, we disable blocking flag - * and return to idle. - */ - - if(self->inpain & IN_PAIN_BLOCK - && (self->modeldata.block_config_flags & BLOCK_CONFIG_HOLD_INFINITE) - && !self->animating - && validanim(self, ANI_BLOCK)) { - - self->inpain = IN_PAIN_NONE; - self->rising = RISING_NONE; - self->inbackpain = 0; - ent_set_anim(self, ANI_BLOCK, 0); - - } else if((player_hold_block_eligible && !player_holding_special) - || (!self->animating && (!player_hold_block_eligible || !player_holding_special))) { - - /* - * Is blockstun complete (no blockpain and - * animation finished)? If yes, play the block - * release animation. If we don't have a block - * release or the block release is finished, - * return to idle. - */ - - if (self->inpain == IN_PAIN_NONE || !self->animating) { - - if (self->animnum == ANI_BLOCKRELEASE && !self->animating) { - self->blocking = BLOCK_STATE_NONE; - self->takeaction = NULL; - set_idle(self); - - } else { - - if (validanim(self, ANI_BLOCKRELEASE)) { - - ent_set_anim(self, ANI_BLOCKRELEASE, 0); - - } else { - - self->blocking = BLOCK_STATE_NONE; - self->takeaction = NULL; - set_idle(self); - } - } - } - } -} - - -void common_charge() -{ - if(self->animating) - { - return; - } - - self->charging = 0; - self->takeaction = NULL; - set_idle(self); -} - -// common code for entities hold an item -entity *drop_item(entity *e) -{ - s_spawn_entry p; - entity *item; - memset(&p, 0, sizeof(p)); - - // Just to make sure there is an item so - // we don't look for data on a NULL pointer. - if(!e->item_properties) - { - return NULL; - } - - p.index = e->item_properties->index; - p.item_properties.index = p.weaponindex = -1; - strcpy(p.alias, e->item_properties->alias); - p.position.y = e->position.y + 0.01; // For check, or an enemy "item" will drop from the sky - p.health[0] = e->item_properties->health; - p.alpha = e->item_properties->alpha; - p.colourmap = e->item_properties->colorset; - p.flip = e->direction; - - item = smartspawn(&p); - - if(item) - { - item->spawntype = SPAWN_TYPE_ITEM; - - item->position.x = e->position.x; - item->position.z = e->position.z; - if(item->position.x < advancex) - { - item->position.x = advancex + 10; - } - else if(item->position.x > advancex + videomodes.hRes) - { - item->position.x = advancex + videomodes.hRes - 10; - } - if(!(level->scrolldir & (SCROLL_UP | SCROLL_DOWN))) - { - if(item->position.z - item->position.y < advancey) - { - item->position.z = advancey + 10; - } - else if(item->position.z - item->position.y > advancey + videomodes.vRes) - { - item->position.z = advancey + videomodes.vRes - 10; - } - } - if(e->boss && (item->modeldata.type & TYPE_ENEMY)) - { - item->boss = 1; - } - } - return item; -} - -//drop the driver, just spawn, dont takedamage -// damage will adjust by the biker -entity *drop_driver(entity *e) -{ - int i; - s_spawn_entry p; - entity *driver; - memset(&p, 0, sizeof(p)); - - if(e->modeldata.rider >= 0) - { - p.index = e->modeldata.rider; - } - else - { - return NULL; // should not happen, just in case - } - p.position.y = e->position.y + 10; - p.weaponindex = -1; - strcpy(p.alias, e->name); - - // Carrying an item, so let's transfer that to spawn - // entry for the driver. - if(e->item_properties) - { - strcpy(p.item_properties.alias, e->item_properties->alias); - - p.item_properties.index = e->item_properties->index; - p.item_properties.colorset = e->item_properties->colorset; - p.item_properties.alpha = e->item_properties->alpha; - p.item_properties.health = e->item_properties->health; - p.item_properties.player_count = e->item_properties->player_count; - } - - /* Match driver color to entity color. */ - p.colourmap = e->map; - - for(i = 0; i < MAX_PLAYERS; i++) - { - p.health[i] = e->modeldata.health; - } - p.boss = e->boss; - - driver = smartspawn(&p); - if(driver) - { - driver->spawntype = SPAWN_TYPE_BIKER; - driver->position.x = e->position.x; - driver->position.z = e->position.z; - } - return driver; -} - - -void checkdeath(entity* target_entity) -{ - if(target_entity->energy_state.health_current > 0) - { - return; - } - target_entity->death_state |= DEATH_STATE_DEAD; - - /* Killed in the air? */ - if (inair(target_entity)) - { - target_entity->death_state |= DEATH_STATE_AIR; - } - - /* In the back? D*** move banner! */ - if (target_entity->inbackpain) - { - target_entity->death_state |= DEATH_STATE_BACK; - } - - //be careful, since the opponent can be other types - if(target_entity->opponent && (target_entity->opponent->modeldata.type & TYPE_PLAYER)) - { - addscore(target_entity->opponent->playerindex, target_entity->modeldata.score); // Add score to the player - } - target_entity->nograb = 1; - target_entity->idling = IDLING_NONE; - target_entity->ducking = DUCK_NONE; - - if(target_entity->modeldata.diesound >= 0) - { - sound_play_sample(target_entity->modeldata.diesound, 0, savedata.effectvol, savedata.effectvol, 100); - } - - // Drop an item if we have one. - if(target_entity->item_properties) - { - if(count_ents(TYPE_PLAYER) > target_entity->item_properties->player_count) - { - drop_item(target_entity); - } - } - - - if(target_entity->boss) - { - target_entity->boss = 0; - --level->bossescount; - if(level->bossescount <= 0 && (target_entity->modeldata.type & TYPE_ENEMY)) - { - kill_all_enemies(); - level_completed = 1; - level_completed_defeating_boss |= 1; - } - } -} - -void checkdamageflip(entity* target_entity, entity *other, s_attack *attack_object, const s_defense* defense_object) -{ - /* Debuging info */ - //attack_dump_object(attack_object); - - target_entity->normaldamageflipdir = DIRECTION_RIGHT; - - int pain_check = 0; - - /* - * Check all the following conditions before we - * take further actions. - */ - - /* - * No damage entity source, or we are the - * damage source. - */ - if (other == NULL || other == target_entity) - { - return; - } - - /* - * Attack did not knock down and - * won't put us into a pain reaction. - */ - if(!target_entity->drop) - { - if (attack_object->no_pain) - { - return; - } - - if (target_entity->modeldata.pain_config_flags & PAIN_CONFIG_PAIN_DISABLE) - { - return; - } - - pain_check = defense_result_pain(attack_object, defense_object); - - if (!pain_check) - { - return; - } - } - - /* We're frozen. */ - if (target_entity->frozen) - { - return; - } - - /* We can't turn. */ - if (target_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP) - { - return; - } - - - /* Apply appropriate direction switch (if any). */ - - //printf("\n\t attack_object->force_direction: %d", attack_object->force_direction); - - switch(attack_object->force_direction) - { - case DIRECTION_ADJUST_TOWARD: - - if (other->position.x < target_entity->position.x) - { - target_entity->direction = DIRECTION_RIGHT; - } - else if (other->position.x > target_entity->position.x) - { - target_entity->direction = DIRECTION_LEFT; - } - else - { - // target_entity->direction = target_entity->direction; - } - - break; - - case DIRECTION_ADJUST_AWAY: - - if (other->position.x < target_entity->position.x) - { - target_entity->direction = DIRECTION_LEFT; - } - else if (other->position.x > target_entity->position.x) - { - target_entity->direction = DIRECTION_RIGHT; - } - else - { - //target_entity->direction = target_entity->direction; - } - - break; - - case DIRECTION_ADJUST_NONE: - - //printf("\n\t DIRECTION_ADJUST_NONE"); - - if(!target_entity->inbackpain ) - { - if(target_entity->position.x < other->position.x) - { - target_entity->direction = DIRECTION_RIGHT; - } - else if(target_entity->position.x > other->position.x) - { - target_entity->direction = DIRECTION_LEFT; - } - } - else - { - if(target_entity->position.x < other->position.x) - { - target_entity->normaldamageflipdir = DIRECTION_RIGHT; - } - else if(target_entity->position.x > other->position.x) - { - target_entity->normaldamageflipdir = DIRECTION_LEFT; - } - } - break; - - case DIRECTION_ADJUST_SAME: - - //printf("\n\t DIRECTION_ADJUST_SAME"); - - target_entity->direction = other->direction; - break; - - case DIRECTION_ADJUST_OPPOSITE: - - //printf("\n\t DIRECTION_ADJUST_OPPOSITE"); - - target_entity->direction = !other->direction; - break; - - case DIRECTION_ADJUST_RIGHT: - - //printf("\n\t DIRECTION_ADJUST_RIGHT"); - - target_entity->direction = DIRECTION_RIGHT; - break; - - case DIRECTION_ADJUST_LEFT: - - //printf("\n\t DIRECTION_ADJUST_LEFT"); - - target_entity->direction = DIRECTION_LEFT; - break; - } - -} - -void checkdamageeffects(entity* target_entity, s_attack* attack) -{ -#define _freeze attack->freeze -#define _maptime attack->maptime -#define _freezetime attack->freezetime -#define _remap attack->forcemap -#define _blast attack->blast -#define _steal attack->steal -#define _seal attack->seal -#define _sealtime attack->sealtime -#define _staydown_rise attack->staydown.rise -#define _staydown_rise_attack attack->staydown.riseattack - - entity *opp = target_entity->opponent; - - // Steal. Take HP from the entity and add it to attacker. - if(_steal && opp && opp != target_entity) - { - // If we have enough HP to withstand the attack, give attacker - // the same amount as attack force. Otherwise just give them - // whatever HP we have left. - if(target_entity->energy_state.health_current >= attack->attack_force) - { - opp->energy_state.health_current += attack->attack_force; - } - else - { - opp->energy_state.health_current += target_entity->energy_state.health_current; - } - - // Cap the effect so attacker doesn't go over their maximum HP. - if(opp->energy_state.health_current > opp->modeldata.health) - { - opp->energy_state.health_current = opp->modeldata.health; - } - } - - // Freeze effect. If this is a freeze attack and we're - // not already frozen, apply a freeze effect and possibly - // remap to freeze palette. If we ARE frozen, then - // unfreeze and knock down instead. - if(_freeze && !target_entity->frozen) - { - - // Set freeze status and expire time. - target_entity->frozen = 1; - if(target_entity->freezetime == 0) - { - target_entity->freezetime = _time + _freezetime; - } - - // 2007-12-14 - // Caskey, Damon V. - // - // If opponents frozen map = -1 or only stun, then don't change the color map. - - if(_remap == -1 && target_entity->modeldata.colorsets.frozen != -1) - { - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), target_entity->modeldata.colorsets.frozen); - } - - target_entity->drop = 0; - } - else if(target_entity->frozen) - { - unfrozen(target_entity); - target_entity->drop = 1; - } - - // If we want to apply a remap without freezing (forcemap attack command) then - // set the map and expire time here. - if(_remap != 0 && !_freeze) - { - /* - * Caskey, Damon V. - * 2020-10-20 - * - * Apply named map if available - * or fall back to direct index. - * - * TODO: Code is pretty messy and - * repetitive. Needs some refinement - * and offloading to a function. - */ - switch (_remap) - { - case MAP_TYPE_BURN: - if (target_entity->modeldata.colorsets.burn != COLORSET_INDEX_NONE) - { - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), target_entity->modeldata.colorsets.burn); - } - break; - case MAP_TYPE_FREEZE: - if (target_entity->modeldata.colorsets.frozen != COLORSET_INDEX_NONE) - { - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), target_entity->modeldata.colorsets.frozen); - } - break; - case MAP_TYPE_KO: - if (target_entity->modeldata.colorsets.ko != COLORSET_INDEX_NONE) - { - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), target_entity->modeldata.colorsets.ko); - } - break; - case MAP_TYPE_SHOCK: - if (target_entity->modeldata.colorsets.shock != COLORSET_INDEX_NONE) - { - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), target_entity->modeldata.colorsets.shock); - } - break; - default: - target_entity->colourmap = model_get_colourmap(&(target_entity->modeldata), _remap); - break; - } - - target_entity->maptime = _time + _maptime; - } - - // Disable specials. Apply seal (Any animation with - // energy_cost > seal) is disabled and time to expire. - if(_seal) - { - target_entity->sealtime = _time + _sealtime; - target_entity->seal = _seal; - } - - // Apply any recursive (damage over time) effects. - recursive_effect_check_apply(target_entity, opp, attack); - - // Static enemies/nodrop enemies cannot be knocked down - if(target_entity->modeldata.pain_config_flags & PAIN_CONFIG_FALL_DISABLE) - { - target_entity->drop = 0; - } - - // Always knock airborne entities down unless we're freezeing them - // or they are specfically immune to in air knockdowns. - if(inair(target_entity) && !target_entity->frozen && !(target_entity->modeldata.pain_config_flags & PAIN_CONFIG_FALL_DISABLE_AIR)) - { - target_entity->drop = 1; - } - - // Immune to hit stun? No knockdown either. - if(attack->no_pain) - { - target_entity->drop = 0; - } - - // If entity will be knocked down, let's apply knockdown specific effects here. - if(target_entity->drop) - { - target_entity->projectile = _blast; - - target_entity->staydown.rise = _staydown_rise; //Staydown: Add to risetime until next rise. - target_entity->staydown.riseattack = _staydown_rise_attack; - } - -#undef _freeze -#undef _maptime -#undef _freezetime -#undef _remap -#undef _blast -#undef _steal -#undef _seal -#undef _sealtime -#undef _staydown_rise -#undef _staydown_rise_attack -} - -/* -* Orginal author and date unknown. -* -* Determines fall status after taking damage. -* -* Caskey, Damon V. -* 2021-09-08 -* -* Slightly reworked to accept the target entity -* as parameter rather than referencing the -* global "self" variable. -* -* Accepts defense object to pass on into -* total damage calculation functions. -*/ -void checkdamagedrop(entity* target_entity, s_attack* attack_object, const s_defense* defense_object) -{ - int attack_drop = attack_object->attack_drop; - float defense_knockdown = defense_object->knockdown; - - /* - * If already falling or attack is a "no reflect", then - * do nothing and exit. - */ - - if (target_entity->drop || attack_object->no_pain) - { - return; - } - - /* - * Legacy behavior. Always fall if in "animal" mode. - */ - - if(target_entity->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - target_entity->drop = 1; - } - - /* Make sure guard break doesn't knock target down. */ - - if(target_entity->modeldata.guardpoints > 0 && target_entity->guardpoints <= 0) - { - attack_drop = 0; - } - - /* - * Reset knockdown count if the knockdowntime - * is expired. - */ - - if(target_entity->knockdowntime && target_entity->knockdowntime < _time) - { - target_entity->knockdowncount = target_entity->modeldata.knockdowncount; - } - - /* - * Defense knockdown works just like damage. It - * is a mutiplier we apply to the attack's drop - * power. We then subjtract the result from target's - * current knockdowncount. - * - * We also update the expire time for resetting - * target's current knockdown. - * - * If target's knockdown count reaches 0, we - * set target's drop status true, and target - * falls in game. - */ - - target_entity->knockdowncount -= (attack_drop * defense_knockdown); - target_entity->knockdowntime = _time + global_config.game_speed; - - if (target_entity->knockdowncount < 0) - { - target_entity->drop = 1; - } -} - -void checkmpadd(entity* target_entity) -{ - entity *other = target_entity->opponent; - if(other == NULL || other == target_entity) - { - return; - } - - if(magic_type == 1 ) - { - other->energy_state.mp_current += other->modeldata.mprate; - - if(other->energy_state.mp_current > other->modeldata.mp) - { - other->energy_state.mp_current = other->modeldata.mp; - } - else if(other->energy_state.mp_current < 0) - { - other->energy_state.mp_current = 0; - } - } -} - -void checkhitscore(entity* target_entity, entity* attacking_entity, s_attack* attack_object) -{ - entity *opp = target_entity->opponent; - if(!opp) - { - return; - } - if(opp != target_entity && (opp->modeldata.type & TYPE_PLAYER)) - { - // Added obstacle so explosions can hurt enemies - addscore(opp->playerindex, attack_object->attack_force * target_entity->modeldata.multiple); // New multiple variable - if (savedata.joyrumble[opp->playerindex]) control_rumble(opp->playerindex, 1, attack_object->attack_force * 2); - } - // Don't animate or fall if hurt by self, since - // it means self fell to the ground already. :) - // Add throw score to the player - else if(attacking_entity == target_entity && target_entity->damage_on_landing.attack_force > 0) - { - addscore(opp->playerindex, attack_object->attack_force); - } -} - -/* -* Caskey, Damon V. -* 2023-04-03 -* -* Accept string input and return -* matching constant. -*/ -e_death_config_flags death_get_config_flag_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_death_config_flags flag; - } flag_lookup_table[] = { - {"none", DEATH_CONFIG_NONE}, - {"default", DEATH_CONFIG_MACRO_DEFAULT}, - {"blink_death_air", DEATH_CONFIG_BLINK_DEATH_AIR}, - {"blink_death_ground", DEATH_CONFIG_BLINK_DEATH_GROUND}, - {"blink_fall_air", DEATH_CONFIG_BLINK_FALL_AIR}, - {"blink_fall_ground", DEATH_CONFIG_BLINK_FALL_GROUND}, - {"blink_remove_air", DEATH_CONFIG_BLINK_REMOVE_AIR}, - {"blink_remove_ground", DEATH_CONFIG_BLINK_REMOVE_GROUND}, - {"death_air", DEATH_CONFIG_DEATH_AIR}, - {"death_ground", DEATH_CONFIG_DEATH_GROUND}, - {"fall_land_air", DEATH_CONFIG_FALL_LAND_AIR}, - {"fall_land_ground", DEATH_CONFIG_FALL_LAND_GROUND}, - {"fall_lie_air", DEATH_CONFIG_FALL_LIE_AIR}, - {"fall_lie_ground", DEATH_CONFIG_FALL_LIE_GROUND}, - {"remove_corpse_air", DEATH_CONFIG_REMOVE_CORPSE_AIR}, - {"remove_corpse_ground", DEATH_CONFIG_REMOVE_CORPSE_GROUND}, - {"remove_vanish_air", DEATH_CONFIG_REMOVE_VANISH_AIR}, - {"remove_vanish_ground", DEATH_CONFIG_REMOVE_VANISH_GROUND}, - {"source_model", DEATH_CONFIG_SOURCE_MODEL}, - }; - - const size_t list_count = sizeof(flag_lookup_table) / sizeof(*flag_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, flag_lookup_table[i].text_name) == 0) - { - return flag_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * none flag. - */ - - printf("\n\n Unknown death config option (%s). \n", value); - return DEATH_CONFIG_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read death configuration arguments directly from the source - line, beginning at the requested item, and combine their flags. -*/ -e_death_config_flags death_get_config_flags_from_command_line( - const char* command_line, - const size_t start_position -) -{ - const char* value; - s_command_argument_reader reader; - e_death_config_flags result = DEATH_CONFIG_NONE; - - command_argument_reader_initialize( - &reader, - command_line, - start_position - ); - - while(command_argument_reader_next(&reader, &value)) { - result |= death_get_config_flag_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-20 -* -* Accept current value and a legacy falldie. -* Returns appropriate config flags to match -* expected legacy behavior. -*/ -e_death_config_flags death_config_get_value_from_falldie(e_death_config_flags current_value, e_falldie_config acting_value) -{ - //printf("\n\n death_config_get_value_from_falldie(%d, %d)", current_value, acting_value); - - e_death_config_flags result = current_value & ~DEATH_CONFIG_MACRO_DEATH_FALL_ALL; - - switch (acting_value) - { - - case FALLDIE_CONFIG_NONE: - result |= DEATH_CONFIG_MACRO_DEFAULT; - break; - - case FALLDIE_CONFIG_DEATH_INSTANT: - result |= DEATH_CONFIG_MACRO_DEATH | DEATH_CONFIG_SOURCE_MODEL; - break; - - case FALLDIE_CONFIG_DEATH_FALL: - result |= DEATH_CONFIG_MACRO_DEATH_FALL_LAND | DEATH_CONFIG_SOURCE_MODEL; - break; - } - - //printf("\n\t result: %d", result); - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-20 -* -* Accept current value. Returns a legacy -* value based on active flags. -*/ -e_falldie_config death_config_get_falldie_from_value(e_death_config_flags acting_value) -{ - //printf("\n\n death_config_get_falldie_from_value(%d)", acting_value); - e_falldie_config result = FALLDIE_CONFIG_NONE; - - if ((acting_value & DEATH_CONFIG_MACRO_DEATH_FALL_LAND) == DEATH_CONFIG_MACRO_DEATH_FALL_LAND) - { - result = FALLDIE_CONFIG_DEATH_FALL; - } - else if ((acting_value & DEATH_CONFIG_MACRO_DEATH) == DEATH_CONFIG_MACRO_DEATH) - { - result = FALLDIE_CONFIG_DEATH_INSTANT; - } - else if ((acting_value & (DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND)) == (DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND)) - { - result = FALLDIE_CONFIG_NONE; - } - - //printf("\n\t result: %d", result); - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-20 -* -* Accept current value and a legacy falldie. -* Returns appropriate config flags to match -* expected legacy behavior. -*/ -e_death_config_flags death_config_get_value_from_nodieblink(e_death_config_flags current_value, e_nodieblink_config acting_value) -{ - //printf("\n\n death_config_get_value_from_nodieblink(%d, %d)", current_value, acting_value); - - e_death_config_flags result = (current_value &= ~(DEATH_CONFIG_MACRO_BLINK | DEATH_CONFIG_MACRO_FALL | DEATH_CONFIG_MACRO_REMOVE)); - - switch (acting_value) - { - - case NODIEBLINK_CONFIG_NONE: - result |= DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND; - break; - - case NODIEBLINK_CONFIG_FALL_LIE_BLINK: - result |= DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND; - break; - - case NODIEBLINK_CONFIG_FALL_LIE_CORPSE: - result |= DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_CORPSE_AIR | DEATH_CONFIG_REMOVE_CORPSE_GROUND; - break; - - case NODIEBLINK_CONFIG_FALL_LIE_VANISH: - result |= DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND; - break; - } - - //printf("\n\t result: %d", result); - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-20 -* -* Accept current value. Returns a legacy -* value based on active flags. -*/ -e_nodieblink_config death_config_get_nodieblink_from_value(e_death_config_flags acting_value) -{ - //printf("\n\n death_config_get_falldie_from_value(%d)", acting_value); - e_nodieblink_config result = NODIEBLINK_CONFIG_NONE; - - if ((acting_value & (DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) == (DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) - { - result = NODIEBLINK_CONFIG_FALL_LIE_VANISH; - } - else if ((acting_value & (DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_CORPSE_AIR | DEATH_CONFIG_REMOVE_CORPSE_GROUND)) == (DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_CORPSE_AIR | DEATH_CONFIG_REMOVE_CORPSE_GROUND)) - { - result = NODIEBLINK_CONFIG_FALL_LIE_CORPSE; - } - else if ((acting_value & (DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) == (DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LIE_AIR | DEATH_CONFIG_FALL_LIE_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) - { - result = NODIEBLINK_CONFIG_FALL_LIE_BLINK; - } - else if ((acting_value & (DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) == (DEATH_CONFIG_BLINK_REMOVE_AIR | DEATH_CONFIG_BLINK_REMOVE_GROUND | DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) - { - result = NODIEBLINK_CONFIG_NONE; - } - - //printf("\n\t result: %d", result); - - return result; -} - -/* -* Caskey, Damon V. -* 2023-04-03 -* -* Accept string input and return -* matching constant. -*/ -e_run_config_flags run_get_config_flag_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_run_config_flags flag; - } flag_lookup_table[] = { - {"none", RUN_CONFIG_NONE}, - {"land", RUN_CONFIG_LAND}, - {"x_left_dash_command", RUN_CONFIG_X_LEFT_DASH_COMMAND}, - {"x_left_dash_fixed", RUN_CONFIG_X_LEFT_DASH_FIXED}, - {"x_left_enabled", RUN_CONFIG_X_LEFT_ENABLED}, - {"x_left_initial", RUN_CONFIG_X_LEFT_INITIAL}, - {"x_right_dash_command", RUN_CONFIG_X_RIGHT_DASH_COMMAND}, - {"x_right_dash_fixed", RUN_CONFIG_X_RIGHT_DASH_FIXED}, - {"x_right_enabled", RUN_CONFIG_X_RIGHT_ENABLED}, - {"x_right_initial", RUN_CONFIG_X_RIGHT_INITIAL}, - {"z_down_dash_command", RUN_CONFIG_Z_DOWN_DASH_COMMAND}, - {"z_down_dash_fixed", RUN_CONFIG_Z_DOWN_DASH_FIXED}, - {"z_down_enabled", RUN_CONFIG_Z_DOWN_ENABLED}, - {"z_down_initial", RUN_CONFIG_Z_DOWN_INITIAL}, - {"z_up_dash_command", RUN_CONFIG_Z_UP_DASH_COMMAND}, - {"z_up_dash_fixed", RUN_CONFIG_Z_UP_DASH_FIXED}, - {"z_up_enabled", RUN_CONFIG_Z_UP_ENABLED}, - {"z_up_initial", RUN_CONFIG_Z_UP_INITIAL}, - }; - - const size_t list_count = sizeof(flag_lookup_table) / sizeof(*flag_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, flag_lookup_table[i].text_name) == 0) - { - return flag_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * none flag. - */ - - printf("\n\n Unknown run config option (%s). \n", value); - return RUN_CONFIG_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read running configuration arguments directly from the source - line, beginning at the requested item, and combine their flags. -*/ -e_run_config_flags run_get_config_flags_from_command_line( - const char* command_line, - const size_t start_position -) -{ - const char* value; - s_command_argument_reader reader; - e_run_config_flags result = RUN_CONFIG_NONE; - - command_argument_reader_initialize( - &reader, - command_line, - start_position - ); - - while(command_argument_reader_next(&reader, &value)) { - result |= run_get_config_flag_from_string(value); - } - - return result; -} - - -/* -* Caskey, Damon V. -* 2023-03-20 -* -* Accept string input and return -* matching constant. -*/ -e_shadow_config_flags shadow_get_config_flag_from_string(const char* value) -{ - const struct - { - const char* text_name; - e_shadow_config_flags flag; - } flag_lookup_table[] = { - {"none", SHADOW_CONFIG_NONE}, - {"default", SHADOW_CONFIG_DEFAULT}, - {"base_platform", SHADOW_CONFIG_BASE_PLATFORM}, - {"base_static", SHADOW_CONFIG_BASE_STATIC}, - {"disabled", SHADOW_CONFIG_DISABLED}, - {"replica_air", SHADOW_CONFIG_GRAPHIC_REPLICA_AIR}, - {"replica_ground", SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND}, - {"static_air", SHADOW_CONFIG_GRAPHIC_STATIC_AIR}, - {"static_ground", SHADOW_CONFIG_GRAPHIC_STATIC_GROUND} - }; - - const size_t list_count = sizeof(flag_lookup_table) / sizeof(*flag_lookup_table); - - for (size_t i = 0; i < list_count; i++) - { - if (stricmp(value, flag_lookup_table[i].text_name) == 0) - { - return flag_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * none flag. - */ - - printf("\n\n Unknown death config option (%s). \n", value); - return SHADOW_CONFIG_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read shadow configuration arguments directly from the source - line and combine their corresponding behavior flags. -*/ -e_shadow_config_flags shadow_get_config_flags_from_command_line( - const char* command_line -) -{ - const char* value; - s_command_argument_reader reader; - e_shadow_config_flags result = SHADOW_CONFIG_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= shadow_get_config_flag_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-19 -* -* Accept current shadow config -* state and a legacy air only -* property. Returns appropriate -* shadow config value. -*/ -e_shadow_config_flags shadow_get_config_from_legacy_aironly(e_shadow_config_flags shadow_config_flags, int legacy_value) -{ - e_shadow_config_flags result = shadow_config_flags; - - if (!legacy_value) - { - /* - * Don't do anything. Text "aironly 0" doesn't - * mean no air shadows, and fortunatly there - * is no legacy aironly script access, so - * we don't need to worry about that. - */ - - return result; - } - - /* - * If either type of ground shadow is turned on, - * then disable it here. - */ - - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND) - { - result &= ~SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND; - result |= SHADOW_CONFIG_GRAPHIC_REPLICA_AIR; - } - - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_STATIC_GROUND) - { - result &= ~SHADOW_CONFIG_GRAPHIC_STATIC_GROUND; - result |= SHADOW_CONFIG_GRAPHIC_STATIC_AIR; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-19 -* -* Accept current shadow config -* state and a legacy gfxshadow -* property. Returns appropriate -* shadow config value. -*/ -e_shadow_config_flags shadow_get_config_from_legacy_gfxshadow(e_shadow_config_flags shadow_config_flags, int legacy_value) -{ - e_shadow_config_flags result = shadow_config_flags; - - /* - * Creator wants to turn off "gfx", so swap any - * existing replica flags for static. - */ - - if (!legacy_value) - { - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_REPLICA_AIR) - { - result |= SHADOW_CONFIG_GRAPHIC_STATIC_AIR; - result &= ~SHADOW_CONFIG_GRAPHIC_REPLICA_AIR; - } - - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND) - { - result |= SHADOW_CONFIG_GRAPHIC_STATIC_GROUND; - result &= ~SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND; - } - - /* - * If no shadow at all set, creator expects - * gfxshadow 0 to set up static shadow. Let's - * initialize the flags here. - */ - - if (!(shadow_config_flags & SHADOW_CONFIG_GRAPHIC_ALL)) - { - result |= (SHADOW_CONFIG_GRAPHIC_STATIC_GROUND | SHADOW_CONFIG_GRAPHIC_STATIC_AIR); - } - - return result; - } - - - /* - * Creator wants to turn on "gfx", so swap any - * existing static flags for replica. - */ - - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_STATIC_GROUND) - { - result &= ~SHADOW_CONFIG_GRAPHIC_STATIC_GROUND; - result |= SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND; - } - - if (shadow_config_flags & SHADOW_CONFIG_GRAPHIC_STATIC_AIR) - { - result &= ~SHADOW_CONFIG_GRAPHIC_STATIC_AIR; - result |= SHADOW_CONFIG_GRAPHIC_REPLICA_AIR; - } - - /* - * If no shadow at all set, creator expects - * gfxshadow to set up replica shadow. Let's - * initialize the flags here. - */ - if (!(shadow_config_flags & SHADOW_CONFIG_GRAPHIC_ALL)) - { - result |= (SHADOW_CONFIG_GRAPHIC_REPLICA_GROUND | SHADOW_CONFIG_GRAPHIC_REPLICA_AIR); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-03-19 -* -* Accept current shadow config -* state and a legacy property. -* Returns appropriate shadow -* config value. -*/ -e_shadow_config_flags shadow_get_config_from_legacy_shadowbase(e_shadow_config_flags shadow_config_flags, e_shadowbase_config legacy_value) -{ - e_shadow_config_flags result = shadow_config_flags; - - /* Remove all existing base flags.*/ - result &= ~SHADOW_CONFIG_BASE_ALL; - - switch (legacy_value) - { - default: - case SHADOWBASE_CONFIG_NONE: - - /* Do nothing. */ - break; - - case SHADOWBASE_CONFIG_NO_CHANGE: - - result |= SHADOW_CONFIG_BASE_STATIC; - break; - - case SHADOWBASE_CONFIG_PLATFORM: - - result |= SHADOW_CONFIG_BASE_PLATFORM; - break; - - case SHADOWBASE_COMBINE: - - result |= (SHADOW_CONFIG_BASE_STATIC | SHADOW_CONFIG_BASE_PLATFORM); - break; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2025-05-21 -* -* Remove trigger parameter reading. As -* of 2025-05-21, this is a bit much, but -* we may want to expand with more options -* later on. -*/ -static const s_remove_config_map remove_config_map[] = { - { "None", REMOVE_CONFIG_NONE }, - { "Hit", REMOVE_CONFIG_HIT }, -}; - -#define REMOVE_CONFIG_MAP_SIZE (sizeof(remove_config_map) / sizeof(remove_config_map[0])) - -e_remove_config get_remove_config_from_string(const char* value) { - if (!value) return REMOVE_CONFIG_NONE; - - // Try to match string (case-insensitive) - for (size_t i = 0; i < REMOVE_CONFIG_MAP_SIZE; i++) { - if (stricmp(value, remove_config_map[i].name) == 0) { - return remove_config_map[i].trigger; - } - } - - // Try to parse as an integer fallback - char* endptr = NULL; - long val = strtol(value, &endptr, 10); - if (endptr != value && *endptr == '\0' && val >= 0) { - return (e_remove_config)val; - } - - // Default fallback - printf("Warning: Unknown Remove value '%s', defaulting to Hit\n", value); - return REMOVE_CONFIG_HIT; -} - -#undef REMOVE_CONFIG_MAP_SIZE - -/* -* Caskey, Damon V. -* 2021-08-30 -* -* Allocate a defense object and return pointer. -*/ -s_defense* defense_allocate_object(void) { - int attack_type; - s_defense* result = NULL; - - /* - * Allocate one extra slot because several legacy paths - * historically expect max_attack_types + 1 storage. - */ - result = calloc(max_attack_types + 1, sizeof(*result)); - - if (!result) { - borShutdown(1, E_OUT_OF_MEMORY); - } - - for (attack_type = 0; attack_type < max_attack_types + 1; attack_type++) { - result[attack_type] = default_defense; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2021-08-30 -* -* Applies value to an attack type element -* of defense. -*/ -void defense_apply_setup_to_property( - char* filename, - char* command, - const char* command_line, - s_defense* defense, - ArgList* arglist, - e_defense_parameters target_parameter -) -{ - //printf("\n\n defense_apply_setup_to_property(%s, %s, %p, %p, %d)", filename, command, defense, arglist, target_parameter); - //printf("\n\t GET_FLOAT_ARGP(2): %f", GET_FLOAT_ARGP(2)); - - /* - * If a NULL pointer gets through, lets - * get out before we cause a NULL pointer - * error - */ - if (!defense) - { - return; - } - - /* - * As of 2021-08-30, the up to date method - * sets one parameter at a time. This is more - * readable in the model text files. It also - * allows easier debug and expansion in the future. - * - * Defense is a bit clunky since we have to send - * a constant to tell us which parameter to update - * but it still beats the legacy method. - */ - - switch (target_parameter) - { - case DEFENSE_PARAMETER_BLOCK_DAMAGE_ADJUST: - defense->block_damage_adjust = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_DAMAGE_MAX: - defense->block_damage_max = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_DAMAGE_MIN: - defense->block_damage_min = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_POWER: - defense->blockpower = GET_FLOAT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_RATIO: - defense->blockratio = GET_FLOAT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_THRESHOLD: - defense->blockthreshold = GET_FLOAT_ARGP(2); - break; - - case DEFENSE_PARAMETER_BLOCK_TYPE: - defense->blocktype = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_DAMAGE_ADJUST: - defense->damage_adjust = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_DAMAGE_MAX: - defense->damage_max = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_DAMAGE_MIN: - defense->damage_min = GET_INT_ARGP(2); - break; - - case DEFENSE_PARAMETER_DEATH_CONFIG: - defense->death_config_flags = death_get_config_flags_from_command_line(command_line, 2); - break; - - case DEFENSE_PARAMETER_FACTOR: - defense->factor = GET_FLOAT_ARGP(2); - break; - - case DEFENSE_PARAMETER_KNOCKDOWN: - defense->knockdown = GET_FLOAT_ARGP(2); - break; - - case DEFENSE_PARAMETER_LEGACY: - - /* - * Legacy read. Populate values from single - * line muti-parameter command. - * - * Please do not expand the legacy read. We - * want to encourage creators to use up to - * date methods. - */ - - if (arglist->count >= 2) - { - defense->factor = GET_FLOAT_ARGP(2); - } - if (arglist->count >= 3) - { - defense->pain = GET_FLOAT_ARGP(3); - } - if (arglist->count >= 4) - { - defense->knockdown = GET_FLOAT_ARGP(4); - } - if (arglist->count >= 5) - { - defense->blockpower = GET_FLOAT_ARGP(5); - } - if (arglist->count >= 6) - { - defense->blockthreshold = GET_FLOAT_ARGP(6); - } - if (arglist->count >= 7) - { - defense->blockratio = GET_FLOAT_ARGP(7); - } - if (arglist->count >= 8) - { - defense->blocktype = GET_FLOAT_ARGP(8); - } - break; - - case DEFENSE_PARAMETER_PAIN: - defense->pain = GET_FLOAT_ARGP(2); - break; - } - -} - -/* -* Caskey, Damon V. -* 2021-08-30 -* -* Free defense from memory. -*/ -void defense_free_object(s_defense* target) -{ - if (!target) - { - return; - } - - free(target); -} - -/* -* Caskey, Damon V. -* 2021-09-08 -* -* Accept animation object and frame. Returns -* the defense object from animation frame's -* collision, or NULL if not available. -*/ -//s_defense* defense_get_current_body_defense_from_animation(s_anim* animation_object, int animation_frame) -//{ -// s_collision_body* collision_body_object = NULL; -// s_body* body_object = NULL; -// -// /* Animation frame has a collision body allocated? */ -// -// collision_body_object = animation_object->collision_body[animation_frame]; -// -// if (!collision_body_object) -// { -// return NULL; -// } -// -// /* -// * Collision body should always have body -// * allocated, but let's make certain. -// */ -// -// body_object = collision_body_object->body; -// -// if (!body_object) -// { -// return NULL; -// } -// -// /* -// * Return body's defense property. In most -// * cases there won't be a defense allocated -// * for individual bodies, so this is likely -// * a NULL pointer value. Be very careful -// * when referencing downstream. -// */ -// -// return body_object->defense; -//} -// -///* -//* Caskey, Damon V. -//* 2021-09-08 -//* -//* Accept entity pointer. Returns defense object -//* from current animation frame's collision, or -//* NULL if not available. -//*/ -//s_defense* defense_get_current_body_defense_object_from_entity(entity* target_entity) -//{ -// s_anim* animation_object = NULL; -// -// /* -// * Every entity should have an animation -// * allocated, but let's make certain. -// */ -// -// animation_object = target_entity->animation; -// -// if (!animation_object) -// { -// return NULL; -// } -// -// /* -// * Send animation pointer to the defense get -// * function for animations and return its -// * result. Most animation frames won't have -// * a defense allocated, so this is likely a -// * NULL pointer value. Be very careful -// * when referencing downstream. -// */ -// -// return defense_get_current_body_defense_from_animation(animation_object, target_entity->animpos); -//} - - -/* -* Caskey, Damon V. -* 2023-02-09 -* -* Return final damage output from -* after offense adjustments. -*/ -int offense_result_damage(s_offense* offense_object, int attack_force) -{ - int result = attack_force; - - if (!offense_object) - { - return result; - } - - result = (int)(result * offense_object->factor); - - result += offense_object->damage_adjust; - - if (result < offense_object->damage_min) - { - result = offense_object->damage_min; - } - - if (result > offense_object->damage_max) - { - result = offense_object->damage_max; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2021-09-08 -* -* Return final damage output from -* after defense adjustments. If the attack -* was blocked, then the block ratio and -* block damage adjustments are applied. If -* the attack was not blocked, then the defense -* factor and damage adjustments are applied. -*/ -int64_t defense_result_damage(const s_defense* defense_object, int64_t attack_force, bool blocked) { - const float DEFENSE_GLOBAL_BLOCK_RATIO = 0.25f; - - int64_t result = attack_force; - float ratio = 0.0f; - int64_t damage_adjust = 0; - int64_t damage_min = INT64_MIN; - int64_t damage_max = INT64_MAX; - - /* - * Fall back to global default if defense - * object is NULL. - */ - const s_defense* const defense_object_local = defense_object ? defense_object : &default_defense; - - /* - * Get the ratio and adjustments for a hit - * or successfully blocked attack. - */ - if (blocked) { - if (defense_object_local->blockratio == - DEFENSE_BLOCKRATIO_COMPATABILITY_DEFAULT) { - ratio = global_config.block_ratio - ? DEFENSE_GLOBAL_BLOCK_RATIO - : 0.0f; - } else { - ratio = defense_object_local->blockratio; - } - - damage_adjust = defense_object_local->block_damage_adjust; - damage_min = defense_object_local->block_damage_min; - damage_max = defense_object_local->block_damage_max; - } else { - ratio = defense_object_local->factor; - damage_adjust = defense_object_local->damage_adjust; - damage_min = defense_object_local->damage_min; - damage_max = defense_object_local->damage_max; - } - - /* - * Apply ratio, round to the nearest whole damage - * value, apply adjustment, and enforce bounds. - */ - result = (int64_t)round((double)result * ratio); - result += damage_adjust; - - if (result < damage_min) { - result = damage_min; - } - - if (result > damage_max) { - result = damage_max; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2021-09-08 -* -* Return true if entity should enter pain reaction -* after applying defense pain property. -*/ -int defense_result_pain(s_attack* attack_object, const s_defense* defense_object) -{ - const int attack_force = attack_object->attack_force; - const attack_type_t attack_type = attack_object->attack_type; - - /* - * Make sure attack types are in bounds and defense - * object is valid. - */ - - if (!defense_object) - { - return 1; - } - - if (attack_type >= (attack_type_t)max_attack_types) - { - return 1; - } - - /* - * Defense pain 0 is default, so we don't have any - * resistance to pain. - */ - - if (!defense_object->pain) - { - return 1; - } - - /* - * Attack force meets or beats pain? Then return true - * and downstream functions will set up pain reactions. - */ - if (attack_force >= defense_object->pain) - { - return 1; - } - - /* - * Nothing passed, so defense is available and sufficient - * to resist attack force. Return false. Downstream functions - * can skip pain reaction setup. - */ - - return 0; -} - -/* -* Caskey, Damon V. -* 2021-09-01 -* -* Locate the appropriate pointer for dereferencing -* an "at the moment" defense property. Meant for -* hit logic, so we know which defense value to use. -* Returns one of the following, first to last. -* -* 1. Supplied body object's defense member. -* Presumably the body object that detected -* incoming hit. Return if defense pointer -* is valid. -* -* 2. Target entity's model level defense member. -* Return if pointer is valid. -* -* 3. Global defense_default constant. -*/ -const s_defense* defense_find_current_object(const entity* ent, const s_body* body_object, const attack_type_t attack_type) { - //printf("\n\n defense_find_current_object(%p, %p, %d)", ent, body_object, attack_type); - - /* - * Runtime attack types may include creator-defined - * values, but they must remain within the configured - * defense collection capacity. - */ - if (attack_type >= (attack_type_t)max_attack_types) { - return &default_defense; - } - - /* Supplied body. */ - - if (body_object && body_object->defense) { - //printf("\n\t &body_object->defense[%d]: %p", attack_type, &body_object->defense[attack_type]); - - return &body_object->defense[attack_type]; - } - - /* Entity defense */ - - if (ent && ent->defense) { - //printf("\n\t ent->defense: %p", &ent->defense[attack_type]); - - return &ent->defense[attack_type]; - } - - /* Global default. */ - - //printf("\n\t &default_defense: %p", &default_defense); - - return &default_defense; -} - -// attack_type_map.h - -#ifndef ATTACK_TYPE_MAP_H -#define ATTACK_TYPE_MAP_H - -typedef struct { - const char* name; - attack_type_t attack_type; -} s_attack_type_map; - -static const s_attack_type_map attack_type_map[] = { - { "NORMAL", ATK_NORMAL }, - { "NORMAL0", ATK_NORMAL }, - { "NORMAL1", ATK_NORMAL }, - { "NORMAL2", ATK_NORMAL2 }, - { "NORMAL3", ATK_NORMAL3 }, - { "NORMAL4", ATK_NORMAL4 }, - { "NORMAL5", ATK_NORMAL5 }, - { "NORMAL6", ATK_NORMAL6 }, - { "NORMAL7", ATK_NORMAL7 }, - { "NORMAL8", ATK_NORMAL8 }, - { "NORMAL9", ATK_NORMAL9 }, - { "NORMAL10", ATK_NORMAL10 }, - { "BLAST", ATK_BLAST }, - { "STEAL", ATK_STEAL }, - { "BURN", ATK_BURN }, - { "SHOCK", ATK_SHOCK }, - { "FREEZE", ATK_FREEZE }, - { "BOSS_DEATH", ATK_BOSS_DEATH }, - { "ITEM", ATK_ITEM }, - { "LAND", ATK_LAND }, - { "LIFESPAN", ATK_LIFESPAN }, - { "LOSE", ATK_LOSE }, - { "PIT", ATK_PIT }, - { "SUB_ENTITY_PARENT_KILL", ATK_SUB_ENTITY_PARENT_KILL }, - { "SUB_ENTITY_UNSUMMON", ATK_SUB_ENTITY_UNSUMMON }, - { "TIMEOVER", ATK_TIMEOVER } -}; - -#define ATTACK_TYPE_MAP_SIZE (sizeof(attack_type_map) / sizeof(attack_type_map[0])) - -#endif // ATTACK_TYPE_MAP_H - -/* - * Converts a string into a valid attack type index. - * - * Input formats supported: - * - A case-insensitive match to a predefined attack name in attack_type_map[] - * - A numeric string (e.g., "3"), interpreted as a 1-based index - * - A special case-insensitive prefix format: - * "normal" or "attack", where is an integer value - * - * Behavior: - * - The function first checks against known names in attack_type_map. - * - If not found, it looks for "attack" or "normal" prefixes and parses the suffix. - * - If still unresolved, it attempts to parse the entire input as a numeric string. - * - In all cases, the resulting attack type is adjusted to be 0-based. - * - If the final index exceeds max_attack_types or is invalid, it falls back to 0. - */ -int get_attack_type_from_string(const char* value, const char* filename) -{ - const char* prefixes[] = { "normal", "attack" }; - const size_t num_prefixes = sizeof(prefixes) / sizeof(prefixes[0]); - char normalized_input[64]; - char* endptr = NULL; - long val = -1; - int parsed_type = -1; - const char* input = value; - - //printf("\n\nParsing attack type from string '%s' (file: %s)\n", value, filename); - - // ========================================================================= - // Step 1: Normalize known prefixes OR numeric-only values into "normal" - // ========================================================================= - // This allows "attack3", "normal3", and even just "3" to resolve through LUT - // to entries like "NORMAL3". Special cases like "attack1" now work because - // "NORMAL1" is present in the LUT and maps to ATK_NORMAL. - for (size_t i = 0; i < num_prefixes; i++) { - const char* prefix = prefixes[i]; - size_t prefix_len = strlen(prefix); - - if (strnicmp(value, prefix, prefix_len) == 0) { - if (value[prefix_len] == '\0') { - // Case: "attack" or "normal" with no suffix: treat as "normal1" - snprintf(normalized_input, sizeof(normalized_input), "normal1"); - } - else if (isdigit((unsigned char)value[prefix_len])) { - // Case: "attackX" or "normalX": normalize to "normalX" - snprintf(normalized_input, sizeof(normalized_input), "normal%s", value + prefix_len); - } - else { - continue; - } - - input = normalized_input; - //printf("Normalized prefixed form '%s' to '%s'\n", value, input); - break; - } - } - - // If no prefix match occurred, check for numeric-only input - if (input == value && isdigit((unsigned char)value[0])) { - errno = 0; - val = strtol(value, &endptr, 10); - if (errno == 0 && endptr != value && *endptr == '\0' && val >= 0) { - snprintf(normalized_input, sizeof(normalized_input), "normal%ld", val); - input = normalized_input; - //printf("Normalized numeric-only string '%s' to '%s' for LUT match\n", value, input); - } - } - - // ========================================================================= - // Step 2: Lookup the normalized input in attack_type_map - // ========================================================================= - for (size_t i = 0; i < ATTACK_TYPE_MAP_SIZE; i++) { - if (stricmp(input, attack_type_map[i].name) == 0) { - //printf("Match found in attack_type_map: '%s' => %d\n", input, attack_type_map[i].attack_type); - return attack_type_map[i].attack_type; - } - } - - // ========================================================================= - // Step 3: If no LUT match, attempt to extract a number from: - // - "normal" - // - "attack" - // - plain "" - // ========================================================================= - const char* numeric_ptr = NULL; - - for (size_t i = 0; i < num_prefixes; i++) { - const char* prefix = prefixes[i]; - size_t len = strlen(prefix); - - if (strnicmp(value, prefix, len) == 0 && isdigit((unsigned char)value[len])) { - numeric_ptr = value + len; - break; - } - } - - if (!numeric_ptr && isdigit((unsigned char)value[0])) { - numeric_ptr = value; - } - - if (numeric_ptr) { - errno = 0; - val = strtol(numeric_ptr, &endptr, 10); - if (errno == 0 && endptr != numeric_ptr && *endptr == '\0' && val >= 0) { - parsed_type = (int)val; - //printf("Extracted numeric attack type: %d\n", parsed_type); - } - } - - // ========================================================================= - // Step 4: Fallback if nothing valid could be parsed - // ========================================================================= - if (parsed_type == -1) { - printf("Warning: Could not resolve attack type '%s' in file '%s'. Defaulting to ATK_NORMAL.\n", - value, filename); - return ATK_NORMAL; - } - - // ========================================================================= - // Step 5: Adjust for 1-based indexing used by designers/scripts - // ========================================================================= - if (parsed_type > 0) { - parsed_type--; - //printf("Adjusted for 1-based input: %d\n", parsed_type); - } - else { - parsed_type = 0; - //printf("Clamped type to 0 due to non-positive value.\n"); - } - - // ========================================================================= - // Step 6: Remap into user-defined attack type ID range - // ========================================================================= - const int user_input_cutoff = MAX_ATKS - STA_ATKS + 1; - if (parsed_type < user_input_cutoff) { - parsed_type = user_input_cutoff; - //printf("Input below remap threshold (%d); adjusted to %d\n", user_input_cutoff, parsed_type); - } - - parsed_type += STA_ATKS; - //printf("Remapped to user-defined attack type ID: %d\n", parsed_type); - - // ========================================================================= - // Step 7: Final bounds check against engine maximum - // ========================================================================= - if (parsed_type >= max_attack_types) { - printf("Warning: Attack type ID %d exceeds max (%d) in file '%s'. Using default.\n", - parsed_type, max_attack_types, filename); - return ATK_NORMAL; - } - - // ========================================================================= - // Step 8: Success - return resolved attack type ID - // ========================================================================= - return parsed_type; -} - - - - - -/* -* Caskey, Damon V. -* 2021-08-30 (Original) -* 2025-05-04 (Refactor) -* -* Read first argument in supplied argument list -* for type, and determines which attack type or -* attack types to assign a defense value. -*/ -void defense_setup_from_arg( - char* filename, - char* command, - const char* command_line, - s_defense* target_defense, - ArgList* arglist, - e_defense_parameters target_parameter -) { - int tempInt = 0; - int i = 0; - char* value = GET_ARGP(1); - - /* - * First try to match the value using the attack type map. - */ - for (i = 0; i < ATTACK_TYPE_MAP_SIZE; i++) - { - if (stricmp(value, attack_type_map[i].name) == 0) - { - defense_apply_setup_to_property( - filename, - command, - command_line, - &target_defense[attack_type_map[i].attack_type], - arglist, - target_parameter - ); - return; - } - } - - /* - * If no direct match, check for dynamic "normalN" pattern. - */ - if (starts_with(value, "normal")) - { - get_tail_number(tempInt, value, "normal"); - - defense_apply_setup_to_property( - filename, - command, - command_line, - &target_defense[tempInt + STA_ATKS - 1], - arglist, - target_parameter - ); - } - /* - * Handle "ALL" case - apply to all non-special attack types. - */ - else if (stricmp(value, "ALL") == 0) - { - for (i = 0; i < max_attack_types; i++) - { - if (is_attack_type_special(i)) - { - continue; - } - - defense_apply_setup_to_property( - filename, - command, - command_line, - &target_defense[i], - arglist, - target_parameter - ); - } - } -} - -/* -* Caskey, Damon V. -* 2023-02-07 -* -* Dump object data to log. -*/ -void defense_dump_object(const s_defense* object) -{ - const int space_label = 20; - - printf("\n\n -- Defense dump object (%p) Dump --\n", object); - - if (object) - { - printf("\n\t %-*s %d", space_label, "->block_damage_adjust", object->block_damage_adjust); - printf("\n\t %-*s %d", space_label, "->block_damage_max", object->block_damage_max); - printf("\n\t %-*s %d", space_label, "->block_damage_min", object->block_damage_min); - printf("\n\t %-*s %d", space_label, "->blockpower", object->blockpower); - printf("\n\t %-*s %f", space_label, "->blockratio", object->blockratio); - printf("\n\t %-*s %d", space_label, "->blockthreshold", object->blockthreshold); - printf("\n\t %-*s %d", space_label, "->blocktype", object->blocktype); - printf("\n\t %-*s %d", space_label, "->damage_adjust", object->damage_adjust); - printf("\n\t %-*s %d", space_label, "->damage_max", object->damage_max); - printf("\n\t %-*s %d", space_label, "->damage_min", object->damage_min); - printf("\n\t %-*s %d", space_label, "->death_config_flags", object->death_config_flags); - printf("\n\t %-*s %f", space_label, "->factor", object->factor); - printf("\n\t %-*s %f", space_label, "->knockdown", object->knockdown); - printf("\n\t %-*s %p", space_label, "->meta_data", object->meta_data); - printf("\n\t %-*s %d", space_label, "->meta_tag", object->meta_tag); - printf("\n\t %-*s %d", space_label, "->pain", object->pain); - } - - printf("\n\n -- Defense dump object (%p) dump complete! -- \n", object); -} - -/* -* Caskey, Damon V. -* 2023-02-07 -* -* Allocate an offense object and return pointer. -*/ -s_offense* offense_allocate_object(void) { - int attack_type; - s_offense* result = NULL; - - /* - * Allocate one extra slot because several legacy paths - * historically expect max_attack_types + 1 storage. - */ - result = calloc(max_attack_types + 1, sizeof(*result)); - - if (!result) { - borShutdown(1, E_OUT_OF_MEMORY); - } - - for (attack_type = 0; attack_type < max_attack_types + 1; attack_type++) { - result[attack_type] = default_offense; - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-02-07 -* -* Free offense from memory. -*/ -void offense_free_object(s_offense* target) -{ - if (!target) - { - return; - } - - free(target); -} - -/* -* Caskey, Damon V. -* 2023-02-07 -* -* Read first argument in supplied argument list -* for type, and determines which attack type or -* attack types to assign an offense value. -*/ -void offense_setup_from_arg( - char* filename, - char* command, - s_offense* target_offense, - ArgList* arglist, - e_offense_parameters target_parameter -) { - int tempInt = 0; - int i = 0; - char* value = GET_ARGP(1); - - /* - * First, try to match using the shared attack type map. - */ - for (i = 0; i < ATTACK_TYPE_MAP_SIZE; i++) - { - if (stricmp(value, attack_type_map[i].name) == 0) - { - offense_apply_setup_to_property( - filename, - command, - &target_offense[attack_type_map[i].attack_type], - arglist, - target_parameter - ); - return; - } - } - - /* - * Handle dynamic "normalN" pattern. - */ - if (starts_with(value, "normal")) - { - get_tail_number(tempInt, value, "normal"); - - offense_apply_setup_to_property( - filename, - command, - &target_offense[tempInt + STA_ATKS - 1], - arglist, - target_parameter - ); - } - /* - * Handle "ALL" case - apply to all non-special attack types. - */ - else if (stricmp(value, "ALL") == 0) - { - for (i = 0; i < max_attack_types; i++) - { - if (is_attack_type_special(i)) - { - continue; - } - - offense_apply_setup_to_property( - filename, - command, - &target_offense[i], - arglist, - target_parameter - ); - } - } -} - -/* -* Caskey, Damon V. -* 2023-02-07 -* -* Applies value to an attack type element -* of offense. -*/ -void offense_apply_setup_to_property(char* filename, char* command, s_offense* offense, ArgList* arglist, e_offense_parameters target_parameter) -{ - /* - * If a NULL pointer gets through, lets - * get out before we cause a NULL pointer - * error - */ - if (!offense) { - return; - } - - /* - * As of 2021-08-30, the up to date method - * sets one parameter at a time. This is more - * readable in the model text files. It also - * allows easier debug and expansion in the future. - * - * Offense is a bit clunky since we have to send - * a constant to tell us which parameter to update - * but it still beats the legacy method. - */ - - switch (target_parameter) { - case OFFENSE_PARAMETER_DAMAGE_ADJUST: - offense->damage_adjust = GET_INT_ARGP(2); - break; - - case OFFENSE_PARAMETER_DAMAGE_MAX: - offense->damage_max = GET_INT_ARGP(2); - break; - - case OFFENSE_PARAMETER_DAMAGE_MIN: - offense->damage_min = GET_INT_ARGP(2); - break; - - case OFFENSE_PARAMETER_FACTOR: - case OFFENSE_PARAMETER_LEGACY: - offense->factor = GET_FLOAT_ARGP(2); - break; - } -} - -int calculate_force_damage(entity *target, entity *attacker, s_attack *attack_object, const s_defense* defense_object, const bool blocked) { - //printf("\n\n calculate_force_damage(%p, %p, %p, %p, %d)", target, attacker, attack_object, defense_object, blocked); - - int force = attack_object->attack_force; - int type = attack_object->attack_type; - - /* - * If touch of death cheat is active, boost player damage - * to equal the target's hp. - * - * This is upstream of damage mitigation by design. Some - * games use defense to make entities immortal for special - * uses and we don't want to break that. - */ - if (global_config.cheats & CHEAT_OPTIONS_TOD_ACTIVE && attacker->modeldata.type & TYPE_PLAYER) { - if (force < target->energy_state.health_current) { - force = target->energy_state.health_current; - } - } - - /* - * Guard-break damage paths do not deal damage. This - * matches typical fighting game behavior where guard-breaks - * are meant to open up the opponent for follow-up attacks, - * not to inflict damage directly. - */ - if(!blocked && target->modeldata.guardpoints > 0 && target->guardpoints <= 0){ - return 0; - } - - //printf("\n\t force: %d", force); - - /* - * Apply the attacker's offense first. - */ - if(type >= 0 && type < max_attack_types && attacker->offense) { - force = offense_result_damage(&attacker->offense[type], force); - } - - //printf("\n\t force: %d", force); - //printf("\n\t defense_object: %p", defense_object); - //printf("\n\t defense_object->factor: %f", defense_object->factor); - - /* - * If we are not supplied a defense object, then we will - * use the target's defense property. This allows us to - * use defense from a body object if we have one, or fall - * back to model level defense if we don't. - */ - - if (!defense_object) { - defense_object = defense_find_current_object( - target, - NULL, - attack_object->attack_type - ); - } - - force = defense_result_damage(defense_object, force, blocked); - - //printf("\n\t force: %d", force); - - return force; -} - -void checkdamageonlanding(entity* acting_entity) { - - //printf("\n\n checkdamageonlanding(%p)", acting_entity); - - s_attack attack = emptyattack; - entity* other = NULL; - int didhit = 0; - - if (acting_entity->energy_state.health_current <= 0) { - return; - } - - if((acting_entity->damage_on_landing.attack_force > 0 && !(acting_entity->death_state & DEATH_STATE_DEAD))) { - - //################## - attack.attack_force = acting_entity->damage_on_landing.attack_force; - - /* - * Apply user defined type for damage on landing - * if populated. Usually there won't be one and we - * fall back to ATK_LAND. - */ - - if (attack.damage_on_landing.attack_type >= 0) { - attack.attack_type = acting_entity->damage_on_landing.attack_type; - - } else { - attack.attack_type = ATK_LAND; - } - - /* - * If we have a valid living opponent, that is - * the entity we take consider the attacker. If - * not, we use ourselves. - */ - - if (acting_entity->opponent && acting_entity->opponent->exists && !(acting_entity->opponent->death_state & DEATH_STATE_DEAD) && acting_entity->opponent->energy_state.health_current > 0) { - other = acting_entity->opponent; - - } else { - other = acting_entity; - } - - lasthit.confirm = 1; - lasthit.attack = &attack; - lasthit.position.x = acting_entity->position.x; - lasthit.position.y = acting_entity->position.y; - lasthit.position.z = acting_entity->position.z; - - const s_defense* defense_object = defense_find_current_object(acting_entity, NULL, attack.attack_type); - - //defense_dump_object(defense_object); - - // Execute the doattack functions before damage is - // processed. - execute_ondoattack_script(acting_entity, other, &attack, EXCHANGE_RECIPIANT, other->attack_id_outgoing); - execute_ondoattack_script(other, acting_entity, &attack, EXCHANGE_CONFERRER, other->attack_id_outgoing); - - //printf("\n\tother: %p", other); - //printf("\n\tattack.attack_type: %d", attack.attack_type); - //printf("\n\tattack.attack_force: %d", attack.attack_force); - - if(lasthit.confirm) { - didhit = 1; - } - - /* - * Can't take damage if we're dead. - */ - - if(acting_entity->death_state & DEATH_STATE_DEAD) { - return; - } - - /* - * Bombs detonante with their own logic when - * landing. We don't want them to take damage. - */ - - if(acting_entity->toexplode & (EXPLODE_DETONATE_HIT | EXPLODE_DETONATE_DAMAGED)) { - return; - } - - // fake 'grab', if failed, return as the attack hit nothing - if(!checkgrab(acting_entity, other, &attack)) { - return; // try to grab but failed, so return 0 means attack missed - } - - if(acting_entity != other) { - set_opponent(acting_entity, other); - } - - //################## - - if (didhit) { - - // pre-check drop - checkdamagedrop(acting_entity, &attack, defense_object); - - // Drop Weapon due to being hit. - if(acting_entity->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_LAND_DAMAGE) { - dropweapon(acting_entity, 1); - } - - // check effects, e.g., frozen, blast, steal - if(!(acting_entity->modeldata.guardpoints > 0 && acting_entity->guardpoints <= 0)) { - checkdamageeffects(acting_entity, &attack); - } - - // mprate can also control the MP recovered per hit. - checkmpadd(acting_entity); - //damage score - checkhitscore(acting_entity, other, &attack); - - /* - * Applies the damage. Send NULL as body object so - * we always use model defense or global default - * when calculating final damage. - */ - checkdamage(acting_entity, other, &attack, defense_object); - - // is it dead now? - checkdeath(acting_entity); - - execute_didhit_script(other, acting_entity, &attack, 0); - } - - if (acting_entity->energy_state.health_current <= 0) { - acting_entity->die_on_landing = 1; - } - - acting_entity->damage_on_landing.attack_force = 0; - } - - // takedamage if thrown or basted - //if( (acting_entity->damage_on_landing.attack_force > 0 && !acting_entity->death_state) && - if( (acting_entity->die_on_landing && !(acting_entity->death_state & DEATH_STATE_DEAD)) && - ((!tobounce(acting_entity) && acting_entity->modeldata.bounce) || !acting_entity->modeldata.bounce) && - (acting_entity->velocity.x == 0 && acting_entity->velocity.z == 0 && acting_entity->velocity.y == 0) - ) { - - if(acting_entity->takedamage) { - - //################## - s_attack attack = emptyattack; - entity *other; - - attack.attack_force = acting_entity->damage_on_landing.attack_force; - if (attack.damage_on_landing.attack_type >= 0) { - attack.attack_type = acting_entity->damage_on_landing.attack_type; - - } else { - attack.attack_type = ATK_LAND; - } - - if (acting_entity->opponent && acting_entity->opponent->exists && !(acting_entity->opponent->death_state & DEATH_STATE_DEAD) && acting_entity->opponent->energy_state.health_current > 0) { - other = acting_entity->opponent; - - } else { - other = acting_entity; - } - //################## - - const s_defense* other_defense_object = defense_find_current_object(other, NULL, attack.attack_type); - - acting_entity->takedamage(acting_entity, other, &attack, 1, other_defense_object); - - } else { - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_DAMAGE_ON_LANDING); - } - - if (acting_entity) { - acting_entity->damage_on_landing.attack_force = 0; - acting_entity->damage_on_landing.attack_type = ATK_NONE; - acting_entity->die_on_landing = 0; - } - } - - return; -} - -/* -* Caskey, Damon V. -* 2025-05-09 -* -* LUT of "special" attack types, as -* in, types normally for internal engine -* use only. -*/ -static const int special_attack_table[MAX_ATKS] = { - [ATK_BOSS_DEATH] = 1, - [ATK_ITEM] = 1, - [ATK_LIFESPAN] = 1, - [ATK_LOSE] = 1, - [ATK_SUB_ENTITY_PARENT_KILL] = 1, - [ATK_SUB_ENTITY_UNSUMMON] = 1, - [ATK_TIMEOVER] = 1, - [ATK_PIT] = 1, -}; - -/* -* Caskey, Damon V. -* 2019-12-26 -* -* Return true if attack type is one of the -* types not included in normal use by creators. -*/ -int is_attack_type_special(attack_type_t type) -{ - /* - * Anything outside of bounds is - * user defined and not special. - */ - if (type >= MAX_ATKS) { - return 0; - } - - /* - * Check vs. LUT of special types. - */ - return special_attack_table[type]; -} - -/* -* Original by unknown author, unknown date. -* -* Applies HP damage to target entity. Executes -* appropriate damage and death scripts as needed. -* -* Caskey, Damon V. -* 2021-09-07 -* -* Slightly reworked to accept the target entity -* as parameter rather than referencing the -* global "self" variable. -* -* Accepts defense object to pass on into -* total damage calculation functions. -*/ -void checkdamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, const s_defense* defense_object) -{ - //printf("\n\n checkdamage(%p, %p, %p, %p)", target_entity, attacking_entity, attack_object, defense_object); - - int64_t force = 0; - - /* Get attack damage force after defense is applied. */ - force = calculate_force_damage(target_entity, attacking_entity, attack_object, defense_object, false); - - /* - * Damage does not return HP and comes from - * a normal source? - */ - const bool normal_damage = (!is_attack_type_special(attack_object->attack_type) && force >= 0) ? true : false; - - /* - * If we're invincible to normal damage - * sources, laugh it off. - */ - if (target_entity->invincible & INVINCIBLE_HP_NULLIFY && normal_damage) { - force = 0; - } - - /* - * Apply the damage. In the case of negative - * damage (IOW, giving back HP), cap at - * maximum health. - * - * If attack has no kill flag enable, don't - * fall below 1 hit point. - */ - - target_entity->energy_state.health_current -= force; - - if (target_entity->energy_state.health_current > target_entity->modeldata.health) { - target_entity->energy_state.health_current = target_entity->modeldata.health; - } - - if(attack_object->no_kill && target_entity->energy_state.health_current <= 0) { - target_entity->energy_state.health_current = 1; - } - - /* Execute the take damage script. */ - execute_takedamage_script(target_entity, attacking_entity, attack_object); - - /* - * Attack meant to put health at 0? We execute - * death script, but may reset HP according - * to invincibility flags. - */ - if (target_entity->energy_state.health_current <= 0) { - - if(normal_damage) { - if (target_entity->invincible & INVINCIBLE_HP_MINIMUM) { - target_entity->energy_state.health_current = 1; - } - - if(target_entity->invincible & INVINCIBLE_HP_RESET) { - target_entity->energy_state.health_current = target_entity->modeldata.health; - } - } - - execute_ondeath_script(target_entity, attacking_entity, attack_object); - } -} - -int checkgrab(entity* target_entity, entity* attacking_entity, s_attack* attack_object) -{ - //if(attack->no_pain) return 0; //no effect, let modders to deside, don't bother check it here - if(target_entity != attacking_entity && attack_object->grab && check_cangrab(attacking_entity, target_entity)) - { - if(adjust_grabposition(attacking_entity, target_entity, attack_object->grab_distance, attack_object->grab)) - { - ents_link(attacking_entity, target_entity); - target_entity->position.y = attacking_entity->position.y; - } - else - { - return 0; - } - } - return 1; -} - -int arrow_takedamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, int fall_flag, const s_defense* defense_object) -{ - target_entity->modeldata.move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - target_entity->modeldata.move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL); - - if(common_takedamage(target_entity, attacking_entity, attack_object, 0, defense_object) - && target_entity->death_state & DEATH_STATE_DEAD) - { - return 1; - } - return 0; -} - -int common_takedamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, int fall_flag, const s_defense* defense_object) -{ - int pain_check = 0; // React with pain animations (1) or ignore (0); - e_death_config_flags death_config; - - /* - * Resolve callers that do not supply a body-specific - * defense object through the target's current defense. - */ - if (!defense_object) { - defense_object = defense_find_current_object( - target_entity, - NULL, - attack_object->attack_type - ); - } - - if(target_entity->death_state & DEATH_STATE_DEAD) - { - return 0; - } - - if(target_entity->toexplode & (EXPLODE_DETONATE_HIT | EXPLODE_DETONATE_DAMAGED)) - { - return 0; - } - - // fake 'grab', if failed, return as the attack hit nothing - if(!checkgrab(target_entity, attacking_entity, attack_object)) - { - return 0; // try to grab but failed, so return 0 means attack missed - } - - // set oppoent - if(target_entity != attacking_entity) - { - set_opponent(target_entity, attacking_entity); - } - - // adjust type - if(attack_object->attack_type >= 0 && attack_object->attack_type < max_attack_types) - { - target_entity->last_damage_type = attack_object->attack_type; - } - else - { - target_entity->last_damage_type = ATK_NORMAL; - } - - if (!target_entity->die_on_landing) - { - // pre-check drop - checkdamagedrop(target_entity, attack_object, defense_object); - - // Drop Weapon due to being hit. - if(target_entity->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_DAMAGE) - { - dropweapon(target_entity, 1); - } - // check effects, e.g., frozen, blast, steal - if(!(target_entity->modeldata.guardpoints > 0 && target_entity->guardpoints <= 0)) - { - checkdamageeffects(target_entity, attack_object); - } - } - - // check backpain - check_backpain(attacking_entity, target_entity); - - /* Check and apply direction flip. */ - checkdamageflip(target_entity, attacking_entity, attack_object, defense_object); - - if (!target_entity->die_on_landing) - { - // mprate can also control the MP recovered per hit. - checkmpadd(target_entity); - //damage score - checkhitscore(target_entity, attacking_entity, attack_object); - - // check damage, cost hp. - checkdamage(target_entity, attacking_entity, attack_object, defense_object); - - // is it dead now? - checkdeath(target_entity); - } - - if(target_entity->modeldata.type & TYPE_PLAYER) - { - if (savedata.joyrumble[target_entity->playerindex]) control_rumble(target_entity->playerindex, 1, attack_object->attack_force * 3); - } - if(target_entity->position.y <= PIT_DEPTH && target_entity->death_state & DEATH_STATE_DEAD) - { - if(target_entity->modeldata.type & TYPE_PLAYER) - { - player_die_entity(target_entity); - } - else - { - kill_entity(target_entity, KILL_ENTITY_TRIGGER_TAKE_DAMAGE_COMMON_PIT); - } - return 1; - } - - // fall to the ground so don't fall again - /*if(acting_entity->damage_on_landing.attack_force) - { - acting_entity->damage_on_landing.attack_force = 0; - return 1; - }*/ - // reset damageonlanding - target_entity->damage_on_landing.attack_force = 0; - target_entity->damage_on_landing.attack_type = ATK_NONE; - - // White Dragon: fix damage_on_landing bug - if(target_entity->die_on_landing && target_entity->energy_state.health_current <= 0) - { - target_entity->modeldata.death_config_flags |= DEATH_CONFIG_MACRO_DEATH_FALL_LAND; - } - - // unlink due to being hit - if((target_entity->opponent && target_entity->opponent->grabbing != target_entity) // Have an opponent, but opponent is not grabbing me. - || target_entity->death_state & DEATH_STATE_DEAD // Dead. - || target_entity->frozen // Frozen. - || target_entity->drop) // Knocked down. - { - ent_unlink(target_entity); - } - // Enemies can now use SPECIAL2 to escape cheap attack strings! - if(target_entity->modeldata.escapehits) - { - if(target_entity->drop) - { - target_entity->escapecount = 0; - } - else - { - target_entity->escapecount++; - } - } - - /* - * Handle Pain, fall, and death animations. - * May also not react at all if attack doesn't - * cause pain or defense is enough to ignore it. - */ - pain_check = defense_result_pain(attack_object, defense_object); - - if(target_entity->drop || target_entity->energy_state.health_current <= 0) - { - target_entity->takeaction = common_fall; - - // Drop Weapon due to death. - if(target_entity->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_DEATH && target_entity->energy_state.health_current <= 0) - { - dropweapon(target_entity, 1); - } - else if(target_entity->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_FALL) - { - dropweapon(target_entity, 1); - } - - death_config = defense_object->death_config_flags; - - if (death_config & DEATH_CONFIG_SOURCE_MODEL) - { - death_config = target_entity->modeldata.death_config_flags; - } - - /* We're alive, or death sequence wants us to handle falling. */ - if(target_entity->energy_state.health_current > 0 || !death_try_sequence_damage(target_entity, death_config, DEATH_TRY_SEQUENCE_ACTING_EVENT_DAMAGE)) - { - if (fall_flag >= 1) return 1; - target_entity->velocity.x = attack_object->dropv.x; - target_entity->velocity.z = attack_object->dropv.z; - if(target_entity->direction == DIRECTION_RIGHT) - { - target_entity->velocity.x = -target_entity->velocity.x; - } - if(target_entity->inbackpain) target_entity->velocity.x *= -1; - toss(target_entity, attack_object->dropv.y); - target_entity->damage_on_landing.attack_force = attack_object->damage_on_landing.attack_force; - target_entity->damage_on_landing.attack_type = attack_object->damage_on_landing.attack_type; - target_entity->knockdowncount = target_entity->modeldata.knockdowncount; // reset the knockdowncount - target_entity->knockdowntime = 0; - - // If no fall/die animations exist, entity simply disappears. - if(!set_fall(target_entity, attacking_entity, attack_object, 1)) - { - if(target_entity->modeldata.type & TYPE_PLAYER) - { - player_die_entity(target_entity); - } - else - { - kill_entity(target_entity, KILL_ENTITY_TRIGGER_TAKE_DAMAGE_COMMON_FALL); - } - return 1; - } - } - - if(target_entity->modeldata.type & TYPE_PLAYER) - { - if (savedata.joyrumble[target_entity->playerindex]) control_rumble(target_entity->playerindex, 1, attack_object->attack_force * 3); - } - } - else if(attack_object->grab && !attack_object->no_pain) - { - target_entity->takeaction = common_pain; - attacking_entity->takeaction = common_grabattack; - attacking_entity->stalltime = _time + global_config.grab_stall; - target_entity->releasetime = _time + (global_config.game_speed / 2); - set_pain(target_entity, target_entity->last_damage_type, 0); - } - // Don't change to pain animation if frozen - else if(!target_entity->frozen && !(target_entity->modeldata.pain_config_flags & PAIN_CONFIG_PAIN_DISABLE) && !attack_object->no_pain && pain_check) - { - target_entity->takeaction = common_pain; - set_pain(target_entity, target_entity->last_damage_type, 1); - } - - return 1; -} - -int common_try_runattack(entity *target) -{ - if(!self->running || !validanim(self, ANI_RUNATTACK)) - { - return 0; - } - - - if(!target) - { - target = normal_find_target(ANI_RUNATTACK, 0); - } - - if(target) - { - if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking != ATTACKING_NONE)) - { - return 0; - } - self->takeaction = common_attack_proc; - self->velocity.z = self->velocity.x = 0; - set_attacking(self); - ent_set_anim(self, ANI_RUNATTACK, 0); - return 1; - } - return 0; -} - -// Active blocking enabled. -// -// AI can behave more like players when blocking. Normally AI -// blocking is passive. IOW, it can only choose to block attacks -// as they hit. This function allows the AI to initiate blocking -// preemptively the way players have to. -// -// AI blocks if following conditions are met: -// -// 1. Entity has active block enabled. -// 2. Target is within range of BLOCK animation. -// 3. Target is actively attacking. -// 4. Blocking chance passes (same rules as active blocking). -static bool common_try_block(entity *target) { - - /* Only active AI may initiate blocking before impact. */ - if (!(self->modeldata.block_config_flags & BLOCK_CONFIG_ACTIVE) - || (self->modeldata.block_config_flags & BLOCK_CONFIG_DISABLED)) { - return false; - } - - // Must have block animation. - if (!validanim(self, ANI_BLOCK)) { - return false; - } - - // Active blocking is enabled. Exit if the chance roll fails. - if (!check_blocking_decision(self)) { - return false; - } - - // If no current target, use block range. - if(!target) { - target = block_find_target(ANI_BLOCK, 0); - } - - // Still no target? Nothing to do, so exit. - if (!target) { - return false; - } - - // If target is attacking, let's block and return true. - if(target->attacking != ATTACKING_NONE) { - // Set up flags, action, and blocking animations. - do_active_block(self); - - return true; - } - - return false; -} - -// this logic could be used for multiple times, so make a function -// pick a random attack or return the first attacks if testonly is set -// when testonly is set, the function will not check special attacks (upper, jumpattack) -// if target is NULL, ranges are not checked -int pick_random_attack(entity *target, int testonly) -{ - int found = 0, i, j; - - for(i = 0; i < max_attacks; i++) // TODO: recheck range for attacks chains - { - if(validanim(self, animattacks[i]) && - (!target || check_range_target_all(self, target, animattacks[i], 0, 0))) - { - for(j = ((5 - i) >= 0 ? (5 - i) : 0) * 3; j >= 0; j--) - { - ai_attack_choice_append(&found, animattacks[i]); - } - } - } - for(i = 0; i < max_freespecials; i++) - { - if(validanim(self, animspecials[i]) && - (check_energy(ENERGY_TYPE_MP, animspecials[i]) || - check_energy(ENERGY_TYPE_HP, animspecials[i])) && - (!target || check_range_target_all(self, target, animspecials[i], 0, 0))) - { - ai_attack_choice_append(&found, animspecials[i]); - } - } - if( validanim(self, ANI_THROWATTACK) && - self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && - (!target || check_range_target_all(self, target, ANI_THROWATTACK, 0, 0) )) - { - ai_attack_choice_append(&found, ANI_THROWATTACK); - } - - if(testonly) - { - if(found) - { - return ai_attack_choices[(rand32() & 0xffff) % found]; - } - return -1; - } - - if( validanim(self, ANI_JUMPATTACK) && - (!target || check_range_target_all(self, target, ANI_JUMPATTACK, 0, 0)) ) - { - if(testonly) - { - return ANI_JUMPATTACK; - } - ai_attack_choice_append(&found, ANI_JUMPATTACK); - } - if( validanim(self, ANI_UPPER) && - (!target || check_range_target_all(self, target, ANI_UPPER, 0, 0)) ) - { - if(testonly) - { - return ANI_UPPER; - } - ai_attack_choice_append(&found, ANI_UPPER); - } - - if(found) - { - return ai_attack_choices[(rand32() & 0xffff) % found]; - } - - return -1; -} - - -// code to lower the chance of attacks, may change while testing old mods -// min - min attack chance -// max - max attack chance -int check_attack_chance(entity *target, float min, float max) -{ - - float chance, chance1, chance2;//, aggfix; - - if(self->modeldata.aiattack & AIATTACK1_ALWAYS) - { - return 1; - } - - chance1 = MIN(1.0f, (diff(self->position.x, self->destx) + diff(self->position.z, self->destz)) / (videomodes.hRes + videomodes.vRes) * move_noatk_factor); - chance2 = MIN(1.0f, (count_ents(self->modeldata.type) - 1) * group_noatk_factor); - - chance = (1.0f - chance1) * (1.0f - chance2); - - if(chance > max) - { - chance = max; - } - else if(chance < min) - { - chance = min; - } - - chance *= (1.0 - self->modeldata.attackthrottle); - - if(self->position.x < screenx - 10 || self->position.x > screenx + videomodes.hRes + 10) - { - if (self->modeldata.offscreen_noatk_factor != 0) chance *= (1.0 - self->modeldata.offscreen_noatk_factor); - else chance *= (1.0 - offscreen_noatk_factor); - } - - return (randf(1) <= chance); -} - -//make a function, mostly for debug purpose -//give it a chance to reset current noattack timer -u32 recheck_nextattack(entity *target) -{ - if(target->blocking & BLOCK_STATE_ACTIVE) - { - self->nextattack = 0; - } - else if(target->attacking != ATTACKING_NONE && self->nextattack > 4) - { - self->nextattack -= 4; - } - else if(target->jumping && self->nextattack > 16) - { - self->nextattack -= 16; - } - - return self->nextattack; -} - -int common_try_normalattack(entity *target) -{ - target = normal_find_target(-1, 0); - - if(!target) - { - return 0; - } - - recheck_nextattack(target); - - if(recheck_nextattack(target) > _time) - { - return 0; - } - - if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking != ATTACKING_NONE || target->takeaction == common_rise)) - { - return 0; - } - - if(pick_random_attack(target, 1) >= 0) - { - if(self->combostep[0] && self->combotime > _time) - { - self->stalltime = _time + 1; - } - else - { - if(!check_attack_chance(target, 1.0f - min_noatk_chance, 1.0f - min_noatk_chance)) - { - self->nextattack = _time + randf(self->modeldata.attackthrottletime); - return 0; - } - else - { - self->stalltime = _time + (int)randf((float)MAX(1, global_config.game_speed * 3 / 4 - self->modeldata.aggression)); - } - } - - self->takeaction = normal_prepare; - self->velocity.z = self->velocity.x = 0; - set_idle(self); - self->idling = IDLING_NONE; // not really idle, in fact it is thinking - self->attacking = ATTACKING_PREPARED; // pre-attack, for AI-block check - return 1; - } - - return 0; -} - -int common_try_jumpattack(entity *target) -{ - entity *dust; - int rnum, ani = 0; - if((validanim(self, ANI_JUMPATTACK) || validanim(self, ANI_JUMPATTACK2))) - { - if(!validanim(self, ANI_JUMPATTACK)) - { - rnum = 1; - } - else if(validanim(self, ANI_JUMPATTACK2) && (rand32() & 1)) - { - rnum = 1; - } - else - { - rnum = 0; - } - - if(rnum == 0 && - // do a jumpattack - (target || (target = normal_find_target(ANI_JUMPATTACK, 0))) ) - { - if(recheck_nextattack(target) > _time) - { - return 0; - } - - if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking != ATTACKING_NONE)) - { - rnum = -1; - } - else - { - if(!check_attack_chance(target, 0.05f, 0.4f)) - { - self->nextattack = _time + randf(self->modeldata.attackthrottletime); - return 0; - } - //ent_set_anim(self, ANI_JUMPATTACK, 0); - ani = ANI_JUMPATTACK; - if(self->direction == DIRECTION_RIGHT) - { - self->velocity.x = (float)1.3; - } - else - { - self->velocity.x = (float) - 1.3; - } - self->velocity.z = 0; - } - } - else if(rnum == 1 && - // do a jumpattack2 - (target || (target = normal_find_target(ANI_JUMPATTACK2, 0))) ) - { - if(recheck_nextattack(target) > _time) - { - return 0; - } - - if(!target->animation->vulnerable[target->animpos] && (target->drop || target->attacking != ATTACKING_NONE)) - { - rnum = -1; - } - else - { - if(!check_attack_chance(target, 0.05f, 0.5f)) - { - self->nextattack = _time + randf(self->modeldata.attackthrottletime); - return 0; - } - //ent_set_anim(self, ANI_JUMPATTACK2, 0); - ani = ANI_JUMPATTACK2; - self->velocity.x = self->velocity.z = 0; - } - } - else - { - rnum = -1; - } - - if(rnum >= 0) - { - - self->takeaction = common_jump; - set_attacking(self); - self->jumping = 1; - toss(self, self->modeldata.jumpheight); - - if(self->modeldata.dust.jump_start >= 0) - { - dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.jump_start, NULL); - if(dust) - { - dust->spawntype = SPAWN_TYPE_DUST_JUMP; - dust->base = self->position.y; - dust->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(dust); - } - } - - ent_set_anim(self, ani, 0); - - return 1; - } - } - - return 0; -} - -int common_try_grab(entity *other) -{ - //printf("\n\t common_try_grab(%p)", other); - - int trygrab(entity * t); - - /* - * Note order does matter in the - * checks below. usually we don't - * have an "other" until it is - * populated by find_ent_here. - */ - - // old rand() - if( (rand32() & 7) == 0 && - (validanim(self, ANI_THROW) || validanim(self, ANI_GRAB)) && - self->idling && - (other || (other = find_ent_here(self, self->position.x, self->position.z, TYPE_ANY, NULL))) && - faction_check_is_hostile(self, other) && - trygrab(other)) - { - return 1; - } - - return 0; -} - -// A.I. try upper cut -int common_try_upper(entity *target) -{ - if(!validanim(self, ANI_UPPER)) - { - return 0; - } - - if(!target) - { - target = normal_find_target(ANI_UPPER, 0); - } - - // Target jumping? Try uppercut! - if(target && target->jumping) - { - /*self->takeaction = common_attack_proc; - set_attacking(self); - self->velocity.z = self->velocity.x = 0; - // Don't waste any time! - ent_set_anim(self, ANI_UPPER, 0);*/ - - if(!check_attack_chance(target, 1.0f - min_noatk_chance, 1.0f - min_noatk_chance)) - { - self->nextattack = _time + randf(self->modeldata.attackthrottletime); - return 0; - } - else - { - self->stalltime = _time + (int)randf((float)MAX(1, global_config.game_speed * 3 / 4 - self->modeldata.aggression)); - } - - self->takeaction = upper_prepare; - self->velocity.z = self->velocity.x = 0; - set_idle(self); - self->idling = IDLING_NONE; // not really idle, in fact it is thinking - self->attacking = ATTACKING_PREPARED; // pre-attack, for AI-block check - return 1; - } - - return 0; -} - -int common_try_duckattack(entity *other) -{ - int indirect; - entity *target = NULL; - - if(!validanim(self, ANI_DUCKATTACK) || !(self->ducking & DUCK_ACTIVE)) - { - return 0; - } - - if(_time / THINK_SPEED % 4 == 0) - { - return 0; - } - - if(self->projectile != BLAST_NONE) - { - indirect = 1; - } - - if(self->custom_target == NULL || !self->custom_target->exists ) target = normal_find_target(-1, 0); - else target = self->custom_target; - - if(target && !(faction_check_can_damage(self, target, indirect))) - { - return 0; - } - - if(recheck_nextattack(target) > _time) - { - return 0; - } - - if(!target || !(target->ducking & DUCK_ACTIVE)) - { - return 0; - } - - if(!check_attack_chance(target, 1.0f - min_noatk_chance, 1.0f - min_noatk_chance)) - { - self->nextattack = _time + randf(self->modeldata.attackthrottletime); - return 0; - } - else - { - self->stalltime = _time + (int)randf((float)MAX(1, global_config.game_speed * 3 / 4 - self->modeldata.aggression)); - } - - // finally attack! - self->takeaction = common_attack_proc; - set_attacking(self); - self->velocity.z = self->velocity.x = 0; - // Don't waste any time! - ent_set_anim(self, ANI_DUCKATTACK, 0); - - return 1; -} - -// Normal attack style -// Used by root A.I., what to do if a target is found. -// return 0 if no action is token -// return 1 if an action is token -int normal_attack() -{ - //int rnum; - - //rnum = rand32()&7; - if( common_try_duckattack(NULL) || - common_try_grab(NULL) || - common_try_upper(NULL) || - common_try_block(NULL) || - common_try_runattack(NULL) || - //(rnum < 2 && common_try_freespecial(NULL)) || - common_try_normalattack(NULL) || - common_try_jumpattack(NULL) ) - { - self->running = RUN_STATE_NONE; - return 1; - } - - return 0;// nothing to do? so go to next think step -} - -// A.I. characters do a throw -void common_throw() -{ - if(self->animating) - { - return; // just play the throw animation - } - - // we have done the throw, return to A.I. root - self->takeaction = NULL; - - set_idle(self); -} - -// toss the grabbed one -void dothrow() -{ - s_attack attack = emptyattack; - entity *other; - self->velocity.x = self->velocity.z = 0; - other = self->link; - if(other == NULL) //change back to idle, or we will get stuck here - { - self->takeaction = NULL;// A.I. root again - set_idle(self); - return; - } - - if(other->modeldata.throwheight) - { - toss(other, other->modeldata.throwheight); - } - else - { - toss(other, other->modeldata.jumpheight); - } - - other->direction = self->direction; - other->projectile |= BLAST_TOSS; - other->projectile |= BLAST_ATTACK; - other->velocity.x = (other->direction == DIRECTION_RIGHT) ? (-other->modeldata.throwdist) : (other->modeldata.throwdist); - - if(autoland == 1 && validanim(other, ANI_LAND)) - { - other->damage_on_landing.attack_force = ATTACK_FORCE_LAND_AUTO; - } - else - { - other->damage_on_landing.attack_force = self->modeldata.throwdamage; - } - - ent_unlink(other); - - other->takeaction = common_fall; - self->takeaction = common_throw; - - // Use default attack values. - set_fall(other, self, &attack, 0); - ent_set_anim(self, ANI_THROW, 0); -} - - -// Waiting until throw frame reached -void common_throw_wait() -{ - if(!self->link) - { - self->takeaction = NULL;// A.I. root again - set_idle(self); - return; - } - - self->releasetime += THINK_SPEED; //extend release time - - if(self->animpos != self->modeldata.throwframewait) - { - return; - } - - dothrow(); -} - - -void common_prethrow() -{ - self->running = RUN_STATE_NONE; // Quits running if grabbed by opponent - - // Just check if we're still grabbed... - if(self->link) - { - return; - } - - self->takeaction = NULL;// A.I. root again - - set_idle(self); -} - -/* -* Caskey, Damon V. -* 2023-05-24 (rewrite of orginal function by Utunnels, unknown date) -* -* Reposition entity to its parent's location -* and play appropriate animation. -*/ -void npc_recall() -{ - entity* const acting_entity = self; - - const s_child_follow* const child_follow = acting_entity->modeldata.child_follow; - - if(!child_follow || !acting_entity->parent) - { - return; - } - - acting_entity->base = acting_entity->parent->base; - acting_entity->position.x = acting_entity->parent->position.x + (acting_entity->parent->direction == DIRECTION_RIGHT ? child_follow->follow_offset.x : -child_follow->follow_offset.x); - acting_entity->position.y = acting_entity->parent->position.y + child_follow->recall_offset.y; - acting_entity->position.z = acting_entity->parent->position.z + child_follow->recall_offset.z; - - acting_entity->velocity.x = 0; - acting_entity->velocity.y = 0; - acting_entity->velocity.z = 0; - - if (child_follow->recall_animation != ANI_NONE) - { - if (validanim(acting_entity, child_follow->recall_animation)) - { - acting_entity->takeaction = common_spawn; - ent_set_anim(acting_entity, child_follow->recall_animation, 0); - } - else if (validanim(acting_entity, ANI_SPAWN)) - { - acting_entity->takeaction = common_spawn; - ent_set_anim(acting_entity, ANI_SPAWN, 0); - } - } -} - -int adjust_grabposition(entity *ent, entity *other, float dist, int grabin) -{ - float x1; - float z1; - float x2; - float z2; - float x; - - if(diff(ent->position.y,other->position.y) > T_WALKOFF) - { - return 0; - } - - if(diff(ent->base,other->base) > T_WALKOFF) - { - return 0; - } - - if(grabin == 1) - { - x1 = ent->position.x; - z1 = z2 = ent->position.z; - x2 = ent->position.x + ((other->position.x > ent->position.x) ? dist : -dist); - } - else - { - x = (ent->position.x + other->position.x) / 2; - x1 = x + ((ent->position.x >= other->position.x) ? (dist / 2) : (-dist / 2)); - x2 = x + ((other->position.x > ent->position.x) ? (dist / 2) : (-dist / 2)); - z1 = z2 = (ent->position.z + other->position.z) / 2; - } - - if(0 >= testmove(ent, ent->position.x, ent->position.z, x1, z1) || 0 >= testmove(other, other->position.x, other->position.z, x2, z2)) - { - return 0; - } - - ent->position.x = x1; - ent->position.z = z1; - other->position.x = x2; - other->position.z = z2; - //other->position.y = ent->position.y; - //other->base = ent->base; - - // Sort order control. - // - // If grabback is set (grabback = 1) the grabbed entity's - // sort order is forced 1 greater than grappler so grappler - // appears behind. Otherwise grabbed is moved one lower, - // forcing grappler to appear in front. - if (ent->modeldata.grabback) - { - other->sortid = ent->sortid + 1; - } - else if (!ent->modeldata.grabback) - { - other->sortid = ent->sortid - 1; - } - - - return 1; -} - -int dograb(entity *attacker, entity *target, e_dograb_adjustcheck adjustcheck) -{ - /* - Execute grab action. Added by splitting off trygrab - so entities can be forced to perform grab by script. - Damon V. Caskey - 2013-12-30 - - Attacker: Entity performing grab. - target, entity being grabbed. - */ - - int result = 0; //Output value. - int pass = 1; //Adjust pass/fail. - - /* If an adjust check is needed, make sure adjusting did not fail. */ - if(adjustcheck == DOGRAB_ADJUSTCHECK_TRUE) - { - pass = adjust_grabposition(attacker, target, attacker->modeldata.grabdistance, 0); - } - - /* If adjust_grabposition passed (or wasn't needed) perform grab actions. */ - if(pass) - { - if(attacker->modeldata.grabflip & 1) // Kratus (10-2021) Make grabflip property accessible by script - { - attacker->direction = (attacker->position.x < target->position.x); - } - - /* Set flags. */ - set_opponent(target, attacker); - ents_link(attacker, target); - target->attacking = ATTACKING_NONE; - attacker->idling = IDLING_NONE; - attacker->running = RUN_STATE_NONE; - attacker->ducking = DUCK_NONE; - attacker->inbackpain = 0; - - /* Stop all movement. */ - attacker->velocity.x = 0; - attacker->velocity.z = 0; - target->velocity.x = 0; - target->velocity.z = 0; - - /* Check for grab animation, otherwise use original throwing system. */ - if(validanim(self, ANI_GRAB)) - { - if(attacker->modeldata.grabflip & 2) // Kratus (10-2021) Make grabflip property accessible by script - { - target->direction = !attacker->direction; - } - attacker->attacking = ATTACKING_NONE; - memset(attacker->combostep, 0, 5 * sizeof(*attacker->combostep)); - target->stalltime = _time + global_config.grab_stall; - attacker->releasetime = _time + (global_config.game_speed / 2); - target->takeaction = common_grabbed; - attacker->takeaction = common_grab; - ent_set_anim(attacker, ANI_GRAB, 0); - set_pain(target, -1, 0); //set grabbed animation - } - else - { - /* - If no throwframewait use original throw code immediately. - Otherwise use throwframewait. - */ - if(attacker->modeldata.throwframewait == -1) - { - dothrow(); - } - else - { - if(attacker->modeldata.grabflip & 2) // Kratus (10-2021) Make grabflip property accessible by script - { - target->direction = !attacker->direction; - } - - target->takeaction = common_prethrow; - attacker->takeaction = common_throw_wait; - ent_set_anim(attacker, ANI_THROW, 0); - set_pain(target, -1, 0); // set grabbed animation - } - } - - result = 1; - } - - return result; -} - -int trygrab(entity *other) -{ - /* - Actions after grab possibility check moved to dograb. - Damon V. Caskey - 2013-12-30 - - other: Grab target. - */ - - int result = 0; //return value. - - if(check_cangrab(self, other)) - { - result = dograb(self, other, DOGRAB_ADJUSTCHECK_TRUE); - } - - return result; -} - -int common_trymove(float xdir, float zdir) -{ - entity *other = NULL, *te = NULL; - int wall, heightvar, t, needcheckhole = 0; - float x, z, oxdir, ozdir; - - if(!xdir && !zdir) - { - return 0; - } - - // UT: move player grab logic here to bypass some extra checks - // it used to be at the very end of this function - //------------------ grab/throw checking ------------------ - - //printf("rand(): %d rand32(): %d\n",rand(),rand32()); - // old rand() - if((self->modeldata.type & TYPE_PLAYER) && - (rand32() & 7) == 0 && - (validanim(self, ANI_THROW) || - validanim(self, ANI_GRAB)) && self->idling && - (other = find_ent_here(self, self->position.x, self->position.z, self->faction.type_hostile, NULL))) - { - if(trygrab(other)) - { - return 0; - } - } - // --------------- end of grab/throw checking ------------------------ - - - oxdir = xdir; - ozdir = zdir; - /* - // entity is grabbed by other - if(self->link && self->link->grabbing==self && self->link->grabwalking) - { - return 1; // just return so we don't have to check twice - }*/ - - x = self->position.x + xdir; - z = self->position.z + zdir; - // -----------bounds checking--------------- - // Subjec to Z and out of bounds? Return to level! - if (self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MIN_Z) - { - if(z < PLAYER_MIN_Z) - { - zdir = PLAYER_MIN_Z - self->position.z; - execute_onblockz_script(self); - } - } - - if (self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MAX_Z) - { - if(z > PLAYER_MAX_Z) - { - zdir = PLAYER_MAX_Z - self->position.z; - execute_onblockz_script(self); - } - } - - // screen checking - if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_SCREEN) - { - if(x < advancex + 10) - { - xdir = advancex + 10 - self->position.x; - execute_onblocks_script(self); //Screen block event. - } - else if(x > advancex + (videomodes.hRes - 10)) - { - xdir = advancex + (videomodes.hRes - 10) - self->position.x; - execute_onblocks_script(self); //Screen block event. - } - } - - if(!xdir && !zdir) - { - return 0; - } - x = self->position.x + xdir; - z = self->position.z + zdir; - - //-----------end of bounds checking----------- - - //-------------hole checking --------------------- - // Don't walk into a hole or walk off platforms into holes - if( self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_HOLE && !inair(self) && !(self->modeldata.type & TYPE_PLAYER) && self->idling && - (!self->animation->move[self->animpos]->base || self->animation->move[self->animpos]->base < 0) && - !(self->modeldata.aimove & AIMOVE2_IGNOREHOLES)) - { - - needcheckhole = 1; - if(zdir && checkhole(self->position.x, z) && checkwall_index(self->position.x, z) < 0 && !check_platform_below(self->position.x, z, self->position.y, self)) - { - //int holeind = checkholeindex_in(self->position.x, z, self->position.y); - - zdir = 0; - //execute_inhole_script(self, 2, (double)level->holes[holeind].height, holeind); - } - if(xdir && checkhole(x, self->position.z) && checkwall_index(x, self->position.z) < 0 && !check_platform_below(x, self->position.z, self->position.y, self)) - { - //int holeind = checkholeindex_in(x, self->position.z, self->position.y); - - xdir = 0; - //execute_inhole_script(self, 1, (double)level->holes[holeind].height, holeind); - } - } - - if(!xdir && !zdir) - { - return 0; - } - x = self->position.x + xdir; - z = self->position.z + zdir; - //-----------end of hole checking--------------- - - //--------------obstacle checking ------------------ - if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_OBSTACLE /*&& !inair(self)*/) - { - int hit = 0; - - //TODO, check once instead of twice - if((other = find_ent_here(self, x, self->position.z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) && - (xdir > 0 ? other->position.x >= self->position.x : other->position.x <= self->position.x) && - (!other->animation->platform || !other->animation->platform[other->animpos][PLATFORM_HEIGHT])) - { - xdir = 0; - if ( self->falling ) hit |= 1; - te = other; - execute_onblocko_script(self, PLANE_X, other); - } - if((other = find_ent_here(self, self->position.x, z, (TYPE_OBSTACLE | TYPE_TRAP), NULL)) && - (zdir > 0 ? other->position.z >= self->position.z : other->position.z <= self->position.z) && - (!other->animation->platform || !other->animation->platform[other->animpos][PLATFORM_HEIGHT])) - { - zdir = 0; - if ( self->falling ) hit |= 1; - if(te != other) //just in case they are the same obstacle - { - execute_onblocko_script(self, PLANE_Z, other); - } - } - - if ( hit && !self->hitwall && validanim(self, ANI_HITOBSTACLE) ) ent_set_anim(self, ANI_HITOBSTACLE, 0); - if ( hit && !self->hitwall ) self->hitwall = 1; - } - - if(!xdir && !zdir) - { - return 0; - } - x = self->position.x + xdir; - z = self->position.z + zdir; - - //-----------end of obstacle checking-------------- - - // ---------------- platform checking---------------- - - if(self->animation->size.y) - { - heightvar = self->animation->size.y; - } - else - { - heightvar = self->modeldata.size.y; - } - - // Check for obstacles with platform code and adjust base accordingly - if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM) - { - int hit = 0; - - //if(xdir>0 ? other->position.x>self->position.x : other->position.xposition.x) {xdir = 0; } - //if(zdir>0 ? other->position.z>self->position.z : other->position.zposition.z) {zdir = 0; } - //temporary fix for thin platforms (i.e, offset is not between left and right side) - // TODO: find the collision position, merge with wall code - if(xdir && (other = check_platform_between(x, self->position.z, self->position.y, self->position.y + heightvar, self)) ) - { - xdir = 0; - if ( self->falling ) hit |= 1; - execute_onblockp_script(self, PLANE_X, other); - } - if(zdir && (other = check_platform_between(self->position.x, z, self->position.y, self->position.y + heightvar, self)) ) - { - zdir = 0; - if ( self->falling ) hit |= 1; - execute_onblockp_script(self, PLANE_Z, other); - } - - if ( hit && !self->hitwall && validanim(self, ANI_HITPLATFORM) ) ent_set_anim(self, ANI_HITPLATFORM, 0); - if ( hit && !self->hitwall ) self->hitwall = 1; - } - - if(!xdir && !zdir) - { - return 0; - } - x = self->position.x + xdir; - z = self->position.z + zdir; - - //-----------end of platform checking------------------ - - // ------------------ wall checking --------------------- - if(self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL) - { - int hit = 0; - - if(xdir && (wall = checkwall_below(x, self->position.z, T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[wall].height > self->position.y) - { - xdir = 0; - if ( self->falling && (self->modeldata.hitwalltype < 0 || (self->modeldata.hitwalltype >= 0 && level->walls[wall].type == self->modeldata.hitwalltype)) ) hit |= 1; - execute_onblockw_script(self, &level->walls[wall], wall, PLANE_X); - } - if(zdir && (wall = checkwall_below(self->position.x, z, T_MAX_CHECK_ALTITUDE)) >= 0 && level->walls[wall].height > self->position.y) - { - zdir = 0; - if ( self->falling && (self->modeldata.hitwalltype < 0 || (self->modeldata.hitwalltype >= 0 && level->walls[wall].type == self->modeldata.hitwalltype)) ) hit |= 1; - execute_onblockw_script(self, &level->walls[wall], wall, PLANE_Z); - } - - if ( hit && !self->hitwall && validanim(self, ANI_HITWALL) ) ent_set_anim(self, ANI_HITWALL, 0); - if ( hit && !self->hitwall ) self->hitwall = 1; - } - - if(!xdir && !zdir) - { - return 0; - } - x = self->position.x + xdir; - z = self->position.z + zdir; - //----------------end of wall checking-------------- - - /* - // Final check to ensure we don't move into other obstacles. - // The old logic allows xdir if zdir is block and vice versa, - // but has a risk that the new destination is actually blocked - // because of multiple obstacle types. - // - // block old - // | / - // | / - // |/__ new - */ - //xdir = zdir = 0; - // TODO: should we add some checks in testmove to execute those onblockwhatever scripts? - t = testmove(self, self->position.x, self->position.z, x, z); - // extra hole check, only avoid hole while idling - if(t <= 0 && (t != -2 || needcheckhole)) - { - return 0; - } - - // do move and return - self->position.x += xdir; - self->position.z += zdir; - - if(xdir) - { - execute_onmovex_script(self); //X move event. - } - if(zdir) - { - execute_onmovez_script(self); //Z move event. - } - return 2 - (xdir == oxdir && zdir == ozdir); // return 2 for some checks -} - -// enemies run off after attack -void common_runoff() -{ - entity *target = normal_find_target(-1, 0); - - if(target == NULL) //sealth checking - { - self->velocity.z = self->velocity.x = 0; - self->takeaction = NULL; // OK, back to A.I. root - set_idle(self); - return; - } - - if(!(self->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP)) - { - self->direction = (self->position.x < target->position.x); - } - if(self->direction == DIRECTION_RIGHT) - { - self->velocity.x = -self->modeldata.speed.x / 2; - } - else - { - self->velocity.x = self->modeldata.speed.x / 2; - } - - self->velocity.z = 0; - - if(_time > self->stalltime) - { - self->takeaction = NULL; // OK, back to A.I. root - } - - adjust_walk_animation(target); -} - - -/*void common_stuck_underneath() -{ - int heightvar = self->animation->size.y ? self->animation->size.y : self->modeldata.size.y; - if(!check_platform_between(self->position.x, self->position.z, self->position.y, self->position.y + heightvar, self) ) - { - self->takeaction = NULL; - set_idle(self); - return; - } - if(player[self->playerindex].keys & FLAG_MOVELEFT) - { - self->direction = DIRECTION_LEFT; - } - else if(player[self->playerindex].keys & FLAG_MOVERIGHT) - { - self->direction = DIRECTION_RIGHT; - } - if(player[self->playerindex].playkeys & FLAG_ATTACK && validanim(self, ANI_DUCKATTACK)) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - self->takeaction = common_attack_proc; - set_attacking(self); - self->velocity.x = self->velocity.z = 0; - self->combostep[0] = 0; - self->running = RUN_STATE_NONE; - ent_set_anim(self, ANI_DUCKATTACK, 0); - return; - } - if((player[self->playerindex].keys & FLAG_MOVEDOWN) && (player[self->playerindex].playkeys & FLAG_JUMP) && validanim(self, ANI_SLIDE)) - { - player[self->playerindex].playkeys &= ~FLAG_JUMP; - self->takeaction = common_attack_proc; - set_attacking(self); - self->velocity.x = self->velocity.z = 0; - self->combostep[0] = 0; - self->running = RUN_STATE_NONE; - ent_set_anim(self, ANI_SLIDE, 0); - return; - } -}*/ - - -// finish attacking, do something -void common_attack_finish() -{ - entity *target; - int stall; - - self->velocity.x = self->velocity.z = 0; - - if(self->modeldata.type & TYPE_PLAYER) - { - if (self->ducking & DUCK_ACTIVE) - { - doduck(self); - } - else - { - self->takeaction = NULL; - set_idle(self); - } - return; - } - - target = self->opponent; - - if(target && !(self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) && self->ducking == DUCK_NONE && diff(self->position.x, target->position.x) < 80 && (rand32() & 3)) - { - self->takeaction = NULL;//common_runoff; - self->destx = self->position.x > target->position.x ? MIN(self->position.x + 40, target->position.x + 80) : MAX(self->position.x - 40, target->position.x - 80); - self->destz = self->position.z; - self->velocity.x = self->position.x > target->position.x ? self->modeldata.speed.x : -self->modeldata.speed.x; - self->velocity.z = 0; - adjust_walk_animation(target); - self->idling = IDLING_PREPARED; - } - else - { - if (self->ducking & DUCK_ACTIVE) - { - doduck(self); - } - else - { - self->takeaction = NULL; - set_idle(self); - } - } - - stall = global_config.game_speed - self->modeldata.aggression; - if (stall < global_config.game_speed / 2) - { - stall = global_config.game_speed / 2; - } - self->stalltime = _time + MAX(0, stall); -} - -//while playing any simple animation -void common_animation_normal() -{ - if(self->animating) - { - return; - } - - self->takeaction = NULL; - set_idle(self); - - return; -} - -//while playing attack animation -void common_attack_proc() -{ - if(self->animating || diff(self->position.y, self->base) >= 4) - { - return; - } - - if(self->tocost) - { - - // Enemy was hit with a special so go ahead and subtract life - if(check_energy(ENERGY_TYPE_MP, self->animnum)) - { - self->energy_state.mp_current -= self->animation->energy_cost.cost; - } - else - { - self->energy_state.health_current -= self->animation->energy_cost.cost; - } - - self->tocost = 0; // Life is subtracted, so go ahead and reset the flag - } - - if(self == smartbomber) - { - // Player is done with the special animation, so unfreeze and execute a smart bomb - smart_bomb(self, self->modeldata.smartbomb); - smartbomber = NULL; - } - if(self->weapon_state & WEAPON_STATE_DEDUCT_USE) - { - subtract_shot(); - self->weapon_state &= ~WEAPON_STATE_DEDUCT_USE; - } - self->attacking = ATTACKING_NONE; - // end of attack proc - common_attack_finish(); -} - - -// dispatch A.I. attack -int common_attack() -{ - int aiattack; - - //if(stalker==self) return 0; - - if(_time / THINK_SPEED % 4 == 0) - { - return 0; - } - - if(self->modeldata.aiattack == -1) - { - return 0; - } - - aiattack = self->modeldata.aiattack & MASK_AIATTACK1; - - switch(aiattack) - { - case AIATTACK1_LONG: - case AIATTACK1_MELEE: - case AIATTACK1_NOATTACK: - return 0; - default: // this is the only available attack style by now - return inair(self) ? 0 : normal_attack(); - } -} - -//maybe used many times, so make a function -// A.I. characters will check if there's a wall infront, and jump onto it if possible -// return 1 if jump -int common_try_jump() -{ - const int COMMON_TRY_JUMP_DEFAULT = 1; - const int COMMON_TRY_JUMP_RUN = 2; - - float xdir = 0.0; - float zdir = 0.0; - int wall = 0; - int to_jump = 0; - float rmin = 0.0; - float rmax = 0.0; - float initial_z_velocity = 0.0; - - animation_id_t jump_animation = ANI_JUMP; - - /* - * If we can't jump at all, return false now. - */ - - if (self->modeldata.air_control & AIR_CONTROL_JUMP_DISABLE) - { - return 0; - } - - if(validanim(self, ANI_JUMP)) - { - xdir = 0; - wall = -1; - rmin = (float)self->modeldata.animation[ANI_JUMP]->range.x.min; - rmax = (float)self->modeldata.animation[ANI_JUMP]->range.x.max; - - if(self->direction == DIRECTION_RIGHT) - { - xdir = self->position.x + rmin; - } - else - { - xdir = self->position.x - rmin; - } - - /* - * If we can Z jump, apply velocity to ZDir. - * This means our checks below will have a - * bit of lateral (z) range. - */ - - if(self->modeldata.air_control & AIR_CONTROL_JUMP_Z_INITIAL) - { - zdir = self->position.z + self->velocity.z; - } - else - { - zdir = self->position.z; - } - - /* Check for obstruction in range of JUMP. */ - - if( (wall = checkwall_below(xdir, zdir, T_MAX_CHECK_ALTITUDE)) >= 0 && - level->walls[wall].height <= self->position.y + rmax && - !inair(self) && self->position.y < level->walls[wall].height ) - { - to_jump = COMMON_TRY_JUMP_DEFAULT; - } - else if(checkhole(self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir) && - checkwall_index(self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir) < 0 && - check_platform (self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir, self) == NULL && - !checkhole(self->position.x + (self->direction == DIRECTION_RIGHT ? rmax : -rmax), zdir)) - { - to_jump = COMMON_TRY_JUMP_DEFAULT; - } - } - - /* - * Caskey, Damon V. - * 2010-03-29 - * - * AI will check its RUNJUMP range if JUMP - * check failed. Code is pretty redundant, - * should probably move to a function later. - */ - - if(!to_jump && validanim(self, ANI_RUNJUMP)) - { - xdir = 0; - wall = -1; - rmin = (float)self->modeldata.animation[ANI_RUNJUMP]->range.x.min; - rmax = (float)self->modeldata.animation[ANI_RUNJUMP]->range.x.max; - - if(self->direction == DIRECTION_RIGHT) - { - xdir = self->position.x + rmin; - } - else - { - xdir = self->position.x - rmin; - } - - /* - * If we can Z jump, apply velocity to ZDir. - * This means our checks below will have a - * bit of lateral (z) range. - */ - - if(self->modeldata.air_control & AIR_CONTROL_JUMP_Z_INITIAL) - { - zdir = self->position.z + self->velocity.z; - } - else - { - zdir = self->position.z; - } - - /* Check for obstruction in range of RUNJUMP. */ - if( (wall = checkwall_below(xdir, zdir, T_MAX_CHECK_ALTITUDE)) >= 0 && - level->walls[wall].height <= self->position.y + rmax && - !inair(self) && self->position.y < level->walls[wall].height ) - { - to_jump = COMMON_TRY_JUMP_RUN; - } - else if(checkhole(self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir) && - checkwall_index(self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir) < 0 && - check_platform (self->position.x + (self->direction == DIRECTION_RIGHT ? 2 : -2), zdir, self) == NULL && - !checkhole(self->position.x + (self->direction == DIRECTION_RIGHT ? rmax : -rmax), zdir)) - { - to_jump = COMMON_TRY_JUMP_RUN; - } - } - - /* - * Now select the appropriate animation - * and send data to tryjump. - */ - - if(to_jump) - { - if(self->running || to_jump == COMMON_TRY_JUMP_RUN) - { - if(validanim(self, ANI_RUNJUMP)) - { - jump_animation = ANI_RUNJUMP; - } - else if(validanim(self, ANI_FORWARDJUMP)) - { - jump_animation = ANI_FORWARDJUMP; - } - else - { - jump_animation = ANI_JUMP; - } - } - else - { - if(validanim(self, ANI_FORWARDJUMP)) - { - jump_animation = ANI_FORWARDJUMP; - } - else - { - jump_animation = ANI_JUMP; - } - } - - if (self->modeldata.air_control & AIR_CONTROL_JUMP_Z_INITIAL) - { - initial_z_velocity = self->velocity.z; - } - else - { - initial_z_velocity = 0.0; - } - - tryjump(self->modeldata.runjumpheight, self->modeldata.jumpspeed* self->modeldata.runjumpdist, initial_z_velocity, jump_animation); - - return 1; - } - return 0; -} - -//test if direction is available for anim_up -static int testup(float xd, float zd) -{ - float f; - if(zd < 0) - { - if(!xd) - { - return 1; - } - f = zd / xd; - return (f > 0.5 || f < -0.5); - } - return 0; -} - -//test if direction is available for anim_down -static int testdown(float xd, float zd) -{ - float f; - if(zd > 0) - { - if(!xd) - { - return 1; - } - f = zd / xd; - return (f > 0.5 || f < -0.5); - } - return 0; -} - -void adjust_walk_animation(entity *other) -{ - int dir = 0; - if(self->running) - { - if (validanim(self, ANI_BACKRUN)) - { - if(is_in_backrun(self)) ent_set_anim(self, ANI_BACKRUN, 0); - else ent_set_anim(self, ANI_RUN, 0); - } - else ent_set_anim(self, ANI_RUN, 0); // Set to run animation if exists - return; - } - - //reset the walk animation - if(validanim(self, ANI_UP) && ((!other && testup(self->velocity.x, self->velocity.z)) || (other && testup(other->position.x - self->position.x, other->position.z - self->position.z)))) - { - common_up_anim(self); //ent_set_anim(self, ANI_UP, 0); - dir = 2; - } - else if(validanim(self, ANI_DOWN) && ((!other && testdown(self->velocity.x, self->velocity.z)) || (other && testdown(other->position.x - self->position.x, other->position.z - self->position.z)))) - { - common_down_anim(self); //ent_set_anim(self, ANI_DOWN, 0); - dir = 3; - } - else if((self->direction == DIRECTION_RIGHT ? self->velocity.x < 0 : self->velocity.x > 0) && validanim(self, ANI_BACKWALK)) - { - common_backwalk_anim(self); //ent_set_anim(self, ANI_BACKWALK, 0); - } - else - { - common_walk_anim(self); //ent_set_anim(self, ANI_WALK, 0); - dir = 1; - } - - if(((self->direction == DIRECTION_RIGHT ? self->velocity.x < 0 : self->velocity.x > 0) && dir == 1) || - (dir == 2 && self->velocity.z > 0) || (dir == 3 && self->velocity.z < 0) ) - { - self->animating = ANIMATING_REVERSE; - } - else - { - self->animating = ANIMATING_FORWARD; - } -} - - -// ai character try to move towards the item -// TODO, check path or entity might get stuck under a wall -int common_try_pick(entity *other) -{ - // if there's an item to pick up, move towards it. - float maxspeed = self->modeldata.speed.x * 1.5; - float dx = diff(self->position.x, other->position.x); - float dz = diff(self->position.z, other->position.z); - - if(other == NULL || self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - - if(!dz && !dx) - { - self->velocity.x = self->velocity.z = 0; - self->destz = self->position.z; - self->destx = self->position.x; - } - else - { - self->velocity.x = maxspeed * dx / (dx + dz); - self->velocity.z = maxspeed * dz / (dx + dz); - self->destx = other->position.x; - self->destz = other->position.z; - } - if(self->position.x > other->position.x) - { - self->velocity.x = -self->velocity.x; - } - if(self->position.z > other->position.z) - { - self->velocity.z = -self->velocity.z; - } - - self->running = RUN_STATE_NONE; - - adjust_walk_animation(other); - - return 1; -} - -#define astarw 640 -#define astarh 360 -#define starts (astarw*astarh) - -// not so completed pathfinding logic based on a* -// it should be fairly slow due to the complicacy of terrain checking -// and it doesn't always work since walking from wall to wall -// requires jump. -int astar(entity *ent, float destx, float destz, float step, s_axis_plane_lateral_float **wp) -{ - int (*came_from)[astarw][astarh][2] = malloc(sizeof(*came_from)); - unsigned char (*closed)[astarw][astarh] = malloc(sizeof(*closed)); - int (*openset)[starts][2] = malloc(sizeof(*openset)); - float (*gscore)[astarw][astarh] = malloc(sizeof(*gscore)); - float (*hscore)[astarw][astarh] = malloc(sizeof(*hscore)); - float (*fscore)[astarw][astarh] = malloc(sizeof(*fscore)); - int opensize = 0; - int result = 0, mi = 0; - float tg, minf; - int x, z, i, j, tx, tz, better; - static int vx[8] = {0, 1, 1, 1, 0, -1, -1, -1}, vz[8] = { -1, -1, 0, 1, 1, 1, 0, -1}; - static float score[8] = {1.0, 1.4, 1.0, 1.4, 1.0, 1.4, 1.0, 1.4}; - - int sx = astarw / 2, sz = astarh / 2; - int dx = sx + (destx - ent->position.x) / step, dz = sz + (destz - ent->position.z) / step; - - *wp = NULL; - if(dx < 0 || dx >= astarw || dz < 0 || dz >= astarh) - { - goto pfclearup; - } - memset(closed, 0, sizeof(*closed)); - (*openset)[opensize][0] = sx; - (*openset)[opensize][1] = sz; - opensize++; - memset(came_from, 0, sizeof(*came_from)); - - (*gscore)[sx][sz] = 0; - (*hscore)[sx][sz] = diff(dx, sx) + diff(dz, sz); - (*fscore)[sx][sz] = (*gscore)[sx][sz] + (*hscore)[sx][sz]; - (*came_from)[sx][sz][0] = -1; - - while(opensize > 0) - { - minf = 9999999; - for(j = 0; j < opensize; j++) - { - x = (*openset)[j][0]; - z = (*openset)[j][1]; - if((*fscore)[x][z] < minf) - { - minf = (*fscore)[x][z]; - mi = j; - } - } - - x = (*openset)[mi][0]; - z = (*openset)[mi][1]; - if(x == dx && z == dz) - { - do - { - tx = (*came_from)[x][z][0]; - tz = (*came_from)[x][z][1]; - result++; - x = tx; - z = tz; - } - while(x >= 0); - *wp = malloc(sizeof(*wp) * result); - tx = (*came_from)[dx][dz][0]; - tz = (*came_from)[dx][dz][1]; - j = 0; - while(tx >= 0) - { - (*wp)[j].x = (tx - sx) * step + ent->position.x; - (*wp)[j].z = (tz - sz) * step + ent->position.z; - x = (*came_from)[tx][tz][0]; - z = (*came_from)[tx][tz][1]; - tx = x; - tz = z; - j++; - } - goto pfclearup; - } - - (*openset)[mi][0] = (*openset)[opensize - 1][0]; - (*openset)[mi][1] = (*openset)[opensize - 1][1]; - - opensize--; - (*closed)[x][z] = 1; - - for(i = 0; i < 8; i++) - { - tx = x + vx[i]; - tz = z + vz[i]; - - if(tx < 0 || tx >= astarw || tz < 0 || tz >= astarh) - { - continue; - } - if((*closed)[tx][tz]) - { - continue; - } - - if(!testmove(ent, (x - sx)*step + ent->position.x, (z - sz)*step + ent->position.z, (tx - sx)*step + ent->position.x, (tz - sz)*step + ent->position.z)) - { - // (*closed)[tx][tz] = 1; // don't add that to close list just in case the entity can jump - continue; - } - - tg = (*gscore)[x][z] + score[i]; - - for(j = 0; j < opensize; j++) - { - if((*openset)[j][0] == tx && (*openset)[j][1] == tz) - { - break; - } - } - - if(j == opensize) - { - (*openset)[opensize][0] = tx; - (*openset)[opensize][1] = tz; - opensize++; - better = 1; - } - else if (tg < (*gscore)[tx][tz]) - { - better = 1; - } - else - { - better = 0; - } - - if(better) - { - (*came_from)[tx][tz][0] = x; - (*came_from)[tx][tz][1] = z; - (*gscore)[tx][tz] = tg; - (*hscore)[tx][tz] = diff(tx, dx) + diff(tz, dz); - (*fscore)[tx][tz] = (*gscore)[tx][tz] + (*hscore)[tx][tz]; - } - } - } - -pfclearup: - if(came_from) - { - free(came_from); - } - came_from = NULL; - if(closed) - { - free(closed); - } - closed = NULL; - if(openset) - { - free(openset); - } - openset = NULL; - if(gscore) - { - free(gscore); - } - gscore = NULL; - if(hscore) - { - free(hscore); - } - hscore = NULL; - if(fscore) - { - free(fscore); - } - fscore = NULL; - - return result; -} - - -// use this after a wall checking meets -// wall sliding code -// whichside: -// 0 -// 1 3 -// 2 -int adjustdirection(float coords[], float offx, float offz, float ox, float oz, float xdir, float zdir, float *cxdir, float *czdir) -{ - float x[4], z[4]; - int whichside, i; - float a; - - for(i = 0; i < 4; i++) - { - x[i] = coords[2 + i] + coords[0] + offx; - } - z[1] = z[3] = coords[1] + offz; - z[0] = z[2] = z[1] - coords[6]; - - if(oz <= z[0]) - { - whichside = 0; - } - else if(oz >= z[1]) - { - whichside = 2; - } - else if(ox < x[2]) - { - whichside = 1; - } - else - { - whichside = 3; - } - - if(whichside == 0 || whichside == 2) - { - *cxdir = xdir; - *czdir = 0; - } - else - { - if((x[0] == x[1] && whichside == 1) || (x[2] == x[3] && whichside == 3)) - { - *cxdir = 0; - *czdir = zdir; - } - else - { - if(whichside == 1) - { - a = (z[1] - z[0]) / (x[1] - x[0]); - } - else - { - a = (z[3] - z[2]) / (x[3] - x[2]); - } - - *cxdir = xdir + zdir / a; - *czdir = a * xdir + zdir; - - a = (ABS(xdir) + ABS(zdir)) / (ABS(*cxdir) + ABS(*czdir)) ; - *cxdir *= a; - *czdir *= a; - } - } - //printf("%f, %f, %f, %f, %d\n", xdir, zdir, *cxdir, *czdir, whichside); - return whichside; -} - -// adjust walk speed for entity assuming it walks straight forward -// x, z - current position -// tx, tz - target position -// speed - max speed -// xdir, zdir - return values -void adjustspeed(float speed, float x, float z, float tx, float tz, float *xdir, float *zdir) -{ - float xd, zd; - float dx = diff(tx, x); - float dz = diff(tz, z) * 2; - - if(dx > dz) - { - xd = speed; - zd = xd / dx * dz; - } - else if(dz > dx) - { - zd = speed; - xd = zd / dz * dx; - } - else if(dx) - { - xd = zd = speed; - } - else - { - xd = zd = 0; - } - - if(tx < x) - { - xd = -xd; - } - if(tz < z) - { - zd = -zd; - } - - zd /= 2; - - *xdir = xd; - *zdir = zd; - -} - -int checkpathblocked() -{ - float x, z, r; - int aitype, wpc; - entity *target; - s_axis_plane_lateral_float *wp; - if(self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - if(self->stalltime >= _time) - { - aitype = self->modeldata.aimove; - if(self->modeldata.subtype == SUBTYPE_CHASE) - { - aitype |= AIMOVE1_CHASE; - } - - //be moo tolerable to PLAYER_MAX_Z and PLAYER_MIN_Z - if((self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MAX_Z && self->velocity.z > 0 && !self->velocity.x && self->velocity.z + self->position.z > PLAYER_MAX_Z) || - (self->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MIN_Z && self->velocity.z < 0 && !self->velocity.x && self->velocity.z + self->position.z < PLAYER_MIN_Z) ) - { - self->velocity.z = -self->velocity.z; - self->pathblocked = 0; - self->destz = self->velocity.z > 0 ? (PLAYER_MIN_Z + videomodes.vRes / 10) : (PLAYER_MAX_Z - videomodes.vRes / 10); - adjust_walk_animation(NULL); - return 1; - } - - if(self->pathblocked > 40 || (self->pathblocked > 20 && (aitype & (AIMOVE1_CHASEX | AIMOVE1_CHASEZ | AIMOVE1_CHASE)))) - { - if(self->modeldata.pathfindstep > 0) - { - target = normal_find_target(-1, 0); - - if(target) - { - //printf("pathfind: (%f %f)-(%f %f) %d steps\n", self->position.x, self->position.z, self->destx, self->destz, pathfind(self, self->destx, self->destz)); - if((wpc = astar(self, target->position.x, target->position.z, self->modeldata.pathfindstep, &wp)) > 0) - { - //printf("wp %d\n", wp); - self->numwaypoints = wpc; - if(self->waypoints) - { - free(self->waypoints); - } - self->waypoints = wp; - self->destx = self->waypoints[self->numwaypoints - 1].x; - self->destz = self->waypoints[self->numwaypoints - 1].z; - self->numwaypoints--; - self->pathblocked = 0; - return 1; - } - } - } - - x = self->velocity.x; - z = self->velocity.z; - if(x > 0) - { - x = self->modeldata.speed.x; - } - else if(x < 0) - { - x = -self->modeldata.speed.x; - } - if(z > 0) - { - z = self->modeldata.speed.x / 2; - } - else if(z < 0) - { - z = -self->modeldata.speed.x / 2; - } - r = randf(1); - if(r > 0.6f) - { - self->velocity.z = x; - self->velocity.x = -z; - } - else if(r > 0.2f) - { - self->velocity.z = -x; - self->velocity.x = z; - } - else - { - self->velocity.z = (1.0f - randf(2)) * self->modeldata.speed.x / 2; - self->velocity.x = (1.0f - randf(2)) * self->modeldata.speed.x; - } - self->running = RUN_STATE_NONE; // TODO: re-adjust walk speed - self->stalltime = _time + global_config.game_speed / 2; - adjust_walk_animation(NULL); - self->pathblocked = 0; - - if(self->velocity.z > 0) - { - self->destz = self->position.z + 40; - } - else if(self->velocity.z < 0) - { - self->destz = self->position.z - 40; - } - else - { - self->destz = self->position.z; - } - if(self->velocity.x > 0) - { - self->destx = self->position.x + 40; - } - else if(self->velocity.x < 0) - { - self->destx = self->position.x - 40; - } - else - { - self->destx = self->position.x; - } - - return 1; - - } - } - return 0; -} - - -// this is the most aggressive aimove pattern -// the entity will try get in and attack at anytime -// though the range depends on what attack you setup -int common_try_chase(entity* acting_entity, const entity *target, const bool axis_x, const bool axis_z) -{ - // start chasing the target - float dx, dz, range; - int randomatk; - - acting_entity->running = RUN_STATE_NONE; - - //adjustspeed(acting_entity->modeldata.speed.x, acting_entity->position.x, acting_entity->position.z, acting_entity->position.x + acting_entity->velocity.x, acting_entity->position.z + acting_entity->velocity.z, &acting_entity->velocity.x, &acting_entity->velocity.z); - - if(target == NULL || acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - - randomatk = pick_random_attack(NULL, 0); - - if(randomatk >= 0) - { - range = (acting_entity->modeldata.animation[randomatk]->range.x.min + acting_entity->modeldata.animation[randomatk]->range.x.max) / 2; - //printf("range picked: ani %d, range %f\n", randomatk, range); - if(range < 0) - { - range = acting_entity->modeldata.grabdistance; - } - else if(range > videomodes.hRes / 4) - { - range = videomodes.hRes / 4; - } - } - else - { - range = acting_entity->modeldata.grabdistance; - } - - if(axis_x) - { - if(acting_entity->position.x > target->position.x) - { - acting_entity->destx = target->position.x + range - 1; - } - else - { - acting_entity->destx = target->position.x - range + 1; - } - dx = diff(acting_entity->position.x, acting_entity->destx); - - if(dx > 150 && validanim(acting_entity, ANI_RUN)) - { - acting_entity->velocity.x = acting_entity->modeldata.runspeed; - acting_entity->running &= ~RUN_STATE_START_Z; - acting_entity->running |= RUN_STATE_START_X; - } - else - { - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - if(acting_entity->destx < acting_entity->position.x) - { - acting_entity->velocity.x = -acting_entity->velocity.x; - } - - //////////// - } - - if (axis_z) - { - acting_entity->destz = target->position.z; - dz = diff(acting_entity->position.z, acting_entity->destz); - - int going_up = (acting_entity->destz < acting_entity->position.z); - int run_flag_check = 0; - - if (going_up) - { - run_flag_check = - (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_ENABLED) && - (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_INITIAL); - } - else - { - run_flag_check = - (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_ENABLED) && - (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_INITIAL); - } - - if (dz > 100 && run_flag_check && validanim(acting_entity, ANI_RUN)) - { - acting_entity->velocity.z = acting_entity->modeldata.runspeed / 2; - acting_entity->running &= ~RUN_STATE_START_X; - acting_entity->running |= RUN_STATE_START_Z; - } - else - { - acting_entity->velocity.z = acting_entity->modeldata.speed.x / 2; - } - - if (going_up) - { - acting_entity->velocity.z = -acting_entity->velocity.z; - } - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2023-05-24 - Rewrite of orginal function by uTunnels, unknown date. -* -* Acting entity attempts to follow -* target entity allong allowed axis. -*/ -int common_try_follow(entity* const acting_entity, const entity *target, const bool axis_x, const bool axis_z) -{ - //printf("\n\n common_try_follow(%p, %p, %d, %d)", acting_entity, target, axis_x, axis_z); - - const s_child_follow* const child_follow = acting_entity->modeldata.child_follow; - - if(acting_entity == NULL || target == NULL || !child_follow || acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - - enum e_follow_state - { - FOLLOW_STATE_NONE = 0, - FOLLOW_STATE_RUN_X = (1 << 0), - FOLLOW_STATE_RUN_Z = (1 << 1), - FOLLOW_STATE_X = (1 << 2), - FOLLOW_STATE_Z = (1 << 3) - } follow_state = FOLLOW_STATE_NONE; - - float follow_speed = 0; - e_run_state run_state = RUN_STATE_NONE; - - /* - * Target positon, distance to target - * entity, and if acting entity is - * facing the target. - */ - - const s_axis_principal_float target_pos = { - .x = target->position.x + (target->direction == DIRECTION_RIGHT ? child_follow->follow_offset.x : -child_follow->follow_offset.x), - .y = target->position.y + child_follow->follow_offset.y, - .z = target->position.z + child_follow->follow_offset.z - }; - - const float distance_x = diff(acting_entity->position.x, target_pos.x); - const float distance_z = diff(acting_entity->position.z, target_pos.z); - - const int facing_target = (acting_entity->direction == DIRECTION_RIGHT ? acting_entity->position.x < target_pos.x : acting_entity->position.x > target_pos.x); - - /* - * Set up follow/run ranges. The use of - * idle range min value for min/max range - * defaults is for legacy compatability. - */ - - const int valid_idle = validanim(acting_entity, ANI_IDLE); - const int follow_range_default_x = (valid_idle) ? acting_entity->modeldata.animation[ANI_IDLE]->range.x.min : 100; - const int follow_range_default_z = (int)follow_range_default_x * 0.5; - const int follow_range_default_run = follow_range_default_x + 100; - - const s_range follow_range = { - .x = { - .max = (child_follow->follow_range.x.max == MAX_INT && valid_idle) ? follow_range_default_x : child_follow->follow_range.x.max, - .min = (child_follow->follow_range.x.min == MIN_INT && valid_idle) ? -follow_range_default_x : child_follow->follow_range.x.min - }, - .z = { - .max = (child_follow->follow_range.z.max == MAX_INT && valid_idle) ? follow_range_default_z : child_follow->follow_range.z.max, - .min = (child_follow->follow_range.z.min == MIN_INT && valid_idle) ? -follow_range_default_z : child_follow->follow_range.z.min - } - }; - - const s_range follow_run_range = { - .x = { - .max = child_follow->follow_run_range.x.max == MAX_INT ? follow_range_default_run : child_follow->follow_run_range.x.max, - .min = child_follow->follow_run_range.x.min == MIN_INT ? -follow_range_default_run : child_follow->follow_run_range.x.min - }, - - //.y = - // .max = child_follow->follow_run_range.y.max == MAX_INT ? (int)videomodes.vRes * 0.90 : child_follow->follow_run_range.y.max, - // .min = child_follow->follow_run_range.y.min == MIN_INT ? (int)videomodes.vRes * -0.90 : child_follow->follow_run_range.y.min - //}, - - .z = { - .max = child_follow->follow_run_range.z.max == MAX_INT ? follow_range_default_run : child_follow->follow_run_range.z.max, - .min = child_follow->follow_run_range.z.min == MIN_INT ? -follow_range_default_run : child_follow->follow_run_range.z.min - } - }; - - //printf("\n\t follow_range.x.min: %d", follow_range.x.min); - //printf("\n\t follow_range.x.max: %d", follow_range.x.max); - //printf("\n\t follow_range.z.min: %d", follow_range.z.min); - //printf("\n\t follow_range.z.max: %d", follow_range.z.max); - - - /* - * Let's try to follow on each axis. If ranges - * are not reversed, then we check to see if - * target is OUTSIDE the range, and if so, then - * set a flag to run downstream movement logic - * to pursue target. We do this for both walking - * and running. - */ - - if (axis_x) - { - if ((follow_range.x.min <= follow_range.x.max) - && !check_range_target_x(acting_entity, target, NULL, follow_range.x.min, follow_range.x.max)) { - - follow_state |= FOLLOW_STATE_X; - } - - /* Following and able to run? */ - if (follow_state & FOLLOW_STATE_X && validanim(acting_entity, ANI_RUN) - && facing_target - && (follow_run_range.x.min <= follow_run_range.x.max) - && !check_range_target_x(acting_entity, target, NULL, follow_run_range.x.min, follow_run_range.x.max)) { - - follow_state |= FOLLOW_STATE_RUN_X; - } - } - - if (axis_z) - { - if ((follow_range.z.min <= follow_range.z.max) - && !check_range_target_z(acting_entity, target, NULL, follow_range.z.min, follow_range.z.max)) { - - follow_state |= FOLLOW_STATE_Z; - } - - /* Following and able to run? */ - if (follow_state & FOLLOW_STATE_Z && validanim(acting_entity, ANI_RUN) - && facing_target - && (follow_run_range.z.min <= follow_run_range.z.max) - && !check_range_target_z(acting_entity, target, NULL, follow_run_range.z.min, follow_run_range.z.max)) { - - follow_state |= FOLLOW_STATE_RUN_Z; - } - } - - //printf("\n\n acting_entity: %p", acting_entity); - //printf("\n target_pos.x: %f", target_pos.x); - //printf("\n target_pos.z: %f", target_pos.z); - //printf("\n distance_x: %f", distance_x); - //printf("\n distance_max: %f", distance_max); - //printf("\n distance_x: %f", distance_x); - //printf("\n distance_z: %f", distance_z); - - //printf("\n\t follow_state: %d", follow_state); - //printf("\n\t axis_x: %d", axis_x); - //printf("\n\t axis_z: %d", axis_z); - - /* - * If we are farther from target on the - * X axis than the Z axis, we will try - * to initialize running toward target - * on X and veer toward target on Z. If - * we are farther on Z axis, then we'll - * do the opposite. - */ - - if (distance_x > distance_z) { - - if (follow_state & FOLLOW_STATE_X) { - - if (follow_state & FOLLOW_STATE_RUN_X) { - - if (acting_entity->direction == DIRECTION_LEFT - && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_X_LEFT_INITIAL | RUN_CONFIG_X_LEFT_ENABLED)) == (RUN_CONFIG_X_LEFT_INITIAL | RUN_CONFIG_X_LEFT_ENABLED)) { - follow_speed = -acting_entity->modeldata.runspeed; - run_state |= RUN_STATE_START_X; - } - else if (acting_entity->direction == DIRECTION_RIGHT - && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_X_RIGHT_INITIAL | RUN_CONFIG_X_RIGHT_ENABLED)) == (RUN_CONFIG_X_RIGHT_INITIAL | RUN_CONFIG_X_RIGHT_ENABLED)) { - follow_speed = acting_entity->modeldata.runspeed; - run_state |= RUN_STATE_START_X; - } - } - else { - follow_speed = acting_entity->modeldata.speed.x; - } - - /* Reverse speed if target is to our left. */ - if (acting_entity->position.x > target_pos.x) - { - follow_speed = -follow_speed; - } - - acting_entity->velocity.x = follow_speed; - acting_entity->running = run_state; - acting_entity->destx = target_pos.x; - } - - follow_speed = 0; - - if (follow_state & FOLLOW_STATE_Z) { - /* - * If we're running and have Z running enabled, let's - * veer ourselves toward the target. - */ - - if (follow_state & FOLLOW_STATE_RUN_Z) { - - if (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_ENABLED) { - follow_speed = acting_entity->modeldata.runspeed / 2; - } - else if (acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_ENABLED) { - follow_speed = -acting_entity->modeldata.runspeed / 2; - } - } - else { - follow_speed = acting_entity->modeldata.speed.x / 2; - } - - /* Reverse speed if target is behind our Z position. */ - if (acting_entity->position.z > target_pos.z) { - follow_speed = -follow_speed; - } - - acting_entity->velocity.z = follow_speed; - acting_entity->running = run_state; - acting_entity->destz = target_pos.z; - } - } - else { - - if (follow_state & FOLLOW_STATE_Z) - { - if (follow_state & FOLLOW_STATE_RUN_Z) - { - if (acting_entity->position.z < target_pos.z - && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_Z_DOWN_INITIAL | RUN_CONFIG_Z_DOWN_ENABLED)) == (RUN_CONFIG_Z_DOWN_INITIAL | RUN_CONFIG_Z_DOWN_ENABLED)) { - - follow_speed = acting_entity->modeldata.runspeed; - run_state = RUN_STATE_START_Z; - } - else if (acting_entity->position.z > target_pos.z - && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_Z_UP_INITIAL | RUN_CONFIG_Z_UP_ENABLED)) == (RUN_CONFIG_Z_UP_INITIAL | RUN_CONFIG_Z_UP_ENABLED)) { - - follow_speed = -acting_entity->modeldata.runspeed; - run_state = RUN_STATE_START_Z; - } - } - else { - follow_speed = acting_entity->modeldata.speed.x; - } - - acting_entity->velocity.z = follow_speed; - acting_entity->running = run_state; - acting_entity->destz = target_pos.z; - } - - follow_speed = 0; - - if (follow_state & FOLLOW_STATE_X) { - /* - * If we're running and have Z running enabled, let's - * veer ourselves toward the target. - */ - - if (follow_state & FOLLOW_STATE_RUN_X) { - - if (acting_entity->direction == DIRECTION_LEFT - && acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_LEFT_ENABLED) { - follow_speed = -acting_entity->modeldata.runspeed / 2; - } - else if (acting_entity->direction == DIRECTION_RIGHT - && acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_RIGHT_ENABLED) { - follow_speed = acting_entity->modeldata.runspeed / 2; - } - } - else { - follow_speed = acting_entity->modeldata.speed.x / 2; - } - - /* Reverse speed if target is behind our Z position. */ - if (acting_entity->position.z > target_pos.z) { - follow_speed = -follow_speed; - } - - acting_entity->velocity.z = follow_speed; - acting_entity->running = run_state; - acting_entity->destz = target_pos.z; - } - } - - //printf("\n\t acting_entity->running : %d", acting_entity->running); - //printf("\n\t acting_entity->destx: %f", acting_entity->destx); - //printf("\n\t acting_entity->destz: %f", acting_entity->destz); - //printf("\n\t acting_entity->velocity.x: %f", acting_entity->velocity.x); - //printf("\n\t acting_entity->velocity.z: %f", acting_entity->velocity.z); - - return 1; -} - -// try to avoid the target -// used by 'avoid avoidz avoidx -// Basic logic: the entity walk within a min distance and a max distance from the target -int common_try_avoid(entity *target, int dox, int doz) -{ - float dx, dz; - float maxdz, mindz, maxdx, mindx; - int randomatk; - - if(target == NULL || self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - - dx = diff(self->position.x, target->position.x); - dz = diff(self->position.z, target->position.z); - - randomatk = pick_random_attack(NULL, 0); - - if((rand32() & 15) < 8 && randomatk >= 0) - { - maxdx = self->modeldata.animation[randomatk]->range.x.max - self->modeldata.speed.x; - if(maxdx < videomodes.hRes / 5) - { - maxdx = videomodes.hRes / 5; - } - mindx = maxdx - 10; - maxdz = self->modeldata.animation[randomatk]->range.z.max - self->modeldata.speed.x; - if(maxdz < videomodes.vRes / 5) - { - maxdz = videomodes.vRes / 5; - } - mindz = maxdz - 10; - } - else - { - mindx = videomodes.hRes / 3; - maxdx = videomodes.hRes / 2; - mindz = videomodes.vRes / 3; - maxdz = videomodes.vRes / 2; - } - - if(dox) - { - if(self->position.x < screenx) - { - self->velocity.x = self->modeldata.speed.x; - self->destx = screenx + videomodes.hRes / 12.0; - } - else if(self->position.x > screenx + videomodes.hRes) - { - self->velocity.x = -self->modeldata.speed.x; - self->destx = screenx + videomodes.hRes * 11.0 / 12.0; - } - else if(dx < mindx) - { - self->velocity.x = (self->position.x < target->position.x) ? (-self->modeldata.speed.x) : self->modeldata.speed.x; - self->destx = (self->position.x < target->position.x) ? (target->position.x - maxdx) : (target->position.x + maxdx); - } - else if (dx > maxdx) - { - self->velocity.x = (self->position.x < target->position.x) ? self->modeldata.speed.x : (-self->modeldata.speed.x); - self->destx = (self->position.x < target->position.x) ? (target->position.x - mindx) : (target->position.x + mindx); - } - else - { - self->velocity.x = 0; - self->destx = self->position.x; - } - } - - if(doz) - { - if(self->position.z < screeny) - { - self->velocity.z = self->modeldata.speed.x / 2; - self->destz = screeny + videomodes.vRes / 12.0; - } - else if(self->position.z > screeny + videomodes.vRes) - { - self->velocity.z = -self->modeldata.speed.x / 2; - self->destz = screeny + videomodes.vRes * 11.0 / 12.0; - } - else if(dz < mindz) - { - self->velocity.z = (self->position.z < target->position.z) ? (-self->modeldata.speed.x / 2) : (self->modeldata.speed.x / 2); - self->destz = (self->position.z < target->position.z) ? (target->position.z - maxdz) : (target->position.z + maxdz); - } - else if(dz > maxdz) - { - self->velocity.z = (self->position.z < target->position.z) ? (self->modeldata.speed.x / 2) : (-self->modeldata.speed.x / 2); - self->destz = (self->position.z < target->position.z) ? (target->position.z - mindz) : (target->position.z + mindz); - } - else - { - self->velocity.z = 0; - self->destz = self->position.z; - } - } - - return 1; -} - -// wander completely and ignore the target -// this ai pattern only works when you use aimove wander, -// if you mix wander with other patterns like chase or avoid -// this pattern is not triggered -int common_try_wandercompletely(int dox, int doz) -{ - int rnum; - - if(self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - return 0; - } - - if(dox) - { - rnum = rand32() & 15; - if(rnum < 4) - { - self->velocity.x = -self->modeldata.speed.x; - } - else if(rnum > 11) - { - self->velocity.x = self->modeldata.speed.x; - } - else - { - self->velocity.x = 0; - } - if( self->position.x < screenx - 10) - { - self->velocity.x = self->modeldata.speed.x; - } - else if(self->position.x > screenx + videomodes.hRes + 10) - { - self->velocity.x = -self->modeldata.speed.x; - } - - if(self->velocity.x > 0) - { - self->destx = self->position.x + videomodes.hRes / 5; - } - else if(self->velocity.x < 0) - { - self->destx = self->position.x - videomodes.hRes / 5; - } - else - { - self->destx = self->position.x; - } - - } - if(doz) - { - rnum = rand32() & 15; - if(rnum < 4) - { - self->velocity.z = -self->modeldata.speed.x / 2; - } - else if(rnum > 11) - { - self->velocity.z = self->modeldata.speed.x / 2; - } - else - { - self->velocity.z = 0; - } - if(self->position.z < screeny - 10) - { - self->velocity.z = self->modeldata.speed.x / 2; - } - else if(self->position.z > screeny + videomodes.vRes + 10) - { - self->velocity.z = -self->modeldata.speed.x / 2; - } - - if(self->velocity.z > 0) - { - self->destz = self->position.z + videomodes.vRes / 5; - } - else if(self->velocity.z < 0) - { - self->destz = self->position.z - videomodes.vRes / 5; - } - else - { - self->destz = self->position.z; - } - - } - - return 1; - -} -/* -int assume_safe_distance(entity* target, int ani, int* minx, int* maxx, int* minz, int* maxz) -{ - int f, set = 0; - short tminx, tmaxx, tminz, tmaxz; - s_anim* ta; - short* coords; - if(validanim(target, ani)){ - ta = target->modeldata.animation[ani]; - *minx = *minz = 9999; - *maxx = *maxz = -9999; - if(ta->collision_attack){ - for(f=0; fnumframes; f++){ - if(!ta->collision_attack[f]) continue; - coords = ta->collision_attack[f]->coords; - if(target->direction == DIRECTION_RIGHT) { - tminx = coords[0]; - tmaxx = coords[2]; - }else{ - tminx = -coords[2]; - tmaxx = -coords[0]; - } - tminz = -coords[4]; - tmaxz = coords[4]; - if(tminx<*minx) - *minx = tminx; - if(tminz<*minz) - *minz = tminz; - if(tmaxx>*maxx) - *maxx = tmaxx; - if(tmaxz>*maxz) - *maxz = tmaxz; - - set = 1; - } - - if(set && self->animation->collision_body_legacy->coords && self->animation->collision_body_legacy[self->animpos]->coords){ - coords = self->animation->collision_body_legacy[self->animpos]->coords; - *minx -= coords[2] - coords[0]; - *minz -= coords[4]; - *maxx += coords[2] - coords[0]; - *maxz += coords[4]; - } - - return set; - } - } - - return 0; - -} -*/ -// for normal and default ai patttern -// the entity is not actually wandering -// they just go around the target and get close -// occasionally to attack -int common_try_wander(entity *target, int dox, int doz) -{ - int walk = 0, behind, grabd, mod; - - float diffx, diffz, //distance from target - returndx, returndz, //how far should keep from target - borderdx, borderdz, //how far should keep offscreen - mindx, mindz;// don't walk into the target - int rnum = rand32() & 15, t, randomatk; - - if(!target || (self->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE)) - { - return 0; - } - - diffx = diff(self->position.x, target->position.x); - diffz = diff(self->position.z, target->position.z); - behind = ((self->position.x < target->position.x) == target->direction); - grabd = self->modeldata.grabdistance; - //when entity is behind the target, it has a greater chance to go after the target - if(behind && diffx < grabd * 4 && diffz < grabd) //right behind, go for it - { - t = 13; - } - else if(behind) // only behind, half chance - { - t = 7; - } - else // otherwise, 1/8 chance - { - t = 2; - } - - if(behind && target->attacking != ATTACKING_NONE) - { - t += 5; - } - - // could use this to replace the completely wander ai - if(dox != doz) - { - t = 0; - } - - if(rnum < t) //chase target - { - returndx = videomodes.hRes / 4; - returndz = videomodes.vRes / 8; - } - else // only chase when too far away - { - returndx = videomodes.hRes * 0.6; - returndz = videomodes.vRes * 0.4; - } - if(rnum > 7) - { - borderdx = videomodes.hRes / 8; - borderdz = videomodes.vRes / 8; - } - else - { - borderdx = borderdz = 0; - } - - randomatk = pick_random_attack(NULL, 0); - - if(randomatk >= 0) - { - mindx = self->modeldata.animation[randomatk]->range.x.max - (self->modeldata.animation[randomatk]->range.x.max - self->modeldata.animation[randomatk]->range.x.min) / 4 - 1; - } - else - { - mindx = (!behind && target->attacking != ATTACKING_NONE) ? grabd * 3 : grabd * 1.2; - } - mindz = grabd / 4; - - mod = ((int)(_time / (videomodes.hRes / self->modeldata.speed.x)) + 1000 + self->energy_state.health_current / 3 + self->pathblocked + self->modeldata.aggression / 10) % 4; - if(mod < 0) - { - mod = -mod; - } - //if ((self->sortid / 100) % 2) - if (rand32() % 2) - { - mod = 3 - mod; - } - - if(dox) - { - if(self->position.x < screenx - borderdx) - { - self->velocity.x = self->modeldata.speed.x; - self->destx = screenx + videomodes.hRes / 8.0; - walk = 1; - } - else if (self->position.x > screenx + videomodes.hRes + borderdx) - { - self->velocity.x = -self->modeldata.speed.x; - self->destx = screenx + videomodes.hRes * 7.0 / 8.0; - walk = 1; - } - else if(diffx > returndx) - { - self->velocity.x = (self->position.x > target->position.x) ? -self->modeldata.speed.x : self->modeldata.speed.x; - self->destx = (self->position.x > target->position.x) ? (target->position.x + mindx) : (target->position.x - mindx); - walk = 1; - } - else - { - switch(mod) - { - case 0: - self->destx = target->position.x + grabd; - break; - case 2: - self->destx = target->position.x - grabd; - break; - case 1: - self->destx = target->position.x + videomodes.hRes * 0.4 + (self->energy_state.health_current / 3 % 20); - break; - case 3: - self->destx = target->position.x - videomodes.hRes * 0.4 - (self->energy_state.health_current / 3 % 20); - break; - } - self->velocity.x = self->position.x > self->destx ? -self->modeldata.speed.x : self->modeldata.speed.x; - walk = 1; - //printf("mod x %d\n", mod); - } - } - - if(doz) - { - if(self->position.z < screeny - borderdz) - { - self->velocity.z = self->modeldata.speed.x / 2; - self->destz = screeny + videomodes.vRes / 12.0; - walk |= 1; - } - else if (self->position.z > screeny + videomodes.vRes + borderdz) - { - self->velocity.z = -self->modeldata.speed.x / 2; - self->destz = screeny + videomodes.vRes * 11.0 / 12.0; - walk |= 1; - } - else if(diffz > returndz) - { - self->velocity.z = (self->position.z > target->position.z) ? -self->modeldata.speed.x / 2 : self->modeldata.speed.x / 2; - self->destz = (self->position.z > target->position.z) ? (target->position.z + mindz) : (target->position.z - mindz); - walk |= 1; - } - else - { - switch(mod) - { - case 1: - self->destz = target->position.z + grabd / 2; - break; - case 3: - self->destz = target->position.z - grabd / 2; - break; - case 2: - self->destz = target->position.z + MIN((PLAYER_MAX_Z - PLAYER_MIN_Z), videomodes.vRes) * 0.25 + (self->energy_state.health_current / 3 % 5); - break; - case 0: - self->destz = target->position.z - MIN((PLAYER_MAX_Z - PLAYER_MIN_Z), videomodes.vRes) * 0.25 - (self->energy_state.health_current / 3 % 5); - break; - } - self->velocity.z = self->position.z > self->destz ? -self->modeldata.speed.x / 2 : self->modeldata.speed.x / 2; - walk |= 1; - //printf("mod z %d\n", mod); - } - } - - return walk; -} - -// Caskey, Damon V. -// 208-04-09 -// -// Set up attack by item and execute didhit script as if item "hit" collector -// to allow easy item scripting. -void do_item_script(entity *ent, entity *item) -{ - s_attack attack = emptyattack; - attack.attack_type = ATK_ITEM; - - execute_didhit_script(item, ent, &attack, 0); -} - -//A.I chracter pickup an item -void common_pickupitem(entity *other) -{ - int pickup = 0; - //weapons - if(self->weapent == NULL && isSubtypeWeapon(other) && validanim(self, ANI_GET)) - { - self->takeaction = common_get; - dropweapon(self, 0); //don't bother dropping the previous one though, scine it won't pickup another - self->weapent = other; - - set_weapon(self, other->modeldata.weapon_properties.weapon_index, 0); - - set_getting(self); - self->velocity.x = self->velocity.z = 0; //stop moving - - /* Move to weapon location if it's an "animal". */ - if(self->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - self->direction = other->direction; - self->position.x = other->position.x; - self->position.z = other->position.z; - } - - if(!(other->nextanim & DELAY_FLAG_INFINITE)) - { - other->nextanim = animation_timestamp_add_bounded( - _time, - delay_multiply_bounded( - global_config.game_speed, - UINT64_C(999999) - ) - ); - } - - other->nextthink = _time + global_config.game_speed * 999999; - ent_set_anim(self, ANI_GET, 0); - pickup = 1; - } - // projectiles - else if(self->weapent == NULL && isSubtypeProjectile(other) && validanim(self, ANI_GET)) - { - self->takeaction = common_get; - dropweapon(self, 0); - self->weapent = other; - set_getting(self); - self->velocity.x = self->velocity.z = 0; //stop moving - if(!(other->nextanim & DELAY_FLAG_INFINITE)) { - other->nextanim = animation_timestamp_add_bounded( - _time, - delay_multiply_bounded( - global_config.game_speed, - UINT64_C(999999) - ) - ); - } - - - other->nextthink = _time + global_config.game_speed * 999999; - ent_set_anim(self, ANI_GET, 0); - pickup = 1; - } - // other items - else if(! isSubtypeWeapon(other) && ! isSubtypeProjectile(other) ) - { - if(validanim(self, ANI_GET) && !isSubtypeTouch(other)) - { - self->takeaction = common_get; - set_getting(self); - self->velocity.x = self->velocity.z = 0; //stop moving - ent_set_anim(self, ANI_GET, 0); - } - if(other->energy_state.health_current) - { - self->energy_state.health_current += other->energy_state.health_current; - if(self->energy_state.health_current > self->modeldata.health) - { - self->energy_state.health_current = self->modeldata.health; - } - other->energy_state.health_current = 0; - //if(global_sample_list.get >= 0) sound_play_sample(global_sample_list.get, 0, savedata.effectvol,savedata.effectvol, 100); - } - // else if, TODO: other effects - // kill that item - other->takeaction = suicide; - other->nextthink = _time + global_config.game_speed * 3; - pickup = 1; - } - // hide it - if(pickup) - { - do_item_script(self, other); - - other->position.z = ITEM_HIDE_POSITION_Z; - } -} - -// for old bikers -int biker_move() -{ - - if((self->direction == DIRECTION_RIGHT) ? (self->position.x > advancex + (videomodes.hRes + 200)) : (self->position.x < advancex - 200)) - { - self->direction = !self->direction; - self->attack_id_outgoing = 0; - self->position.z = (float)(PLAYER_MIN_Z + randf((float)(PLAYER_MAX_Z - PLAYER_MIN_Z))); - - if(global_sample_list.bike >= 0) - { - sound_play_sample(global_sample_list.bike, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(self->modeldata.speed.x) - { - self->velocity.x = (self->direction == DIRECTION_RIGHT) ? (self->modeldata.speed.x) : (-self->modeldata.speed.x); - } - else - { - self->velocity.x = (self->direction == DIRECTION_RIGHT) ? ((float)1.7 + randf((float)0.6)) : (-((float)1.7 + randf((float)0.6))); - } - } - - return 1; -} - -// for common arrow types -int arrow_move(entity* acting_entity) -{ - float dx; - float dz; - float maxspeed; - entity *target = NULL; - - // new subtype chase - if(acting_entity->modeldata.subtype == SUBTYPE_CHASE || acting_entity->modeldata.aimove & AIMOVE1_CHASE) - { - target = homing_find_target(acting_entity); - - if(target) - { - if(!(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP)) - { - acting_entity->direction = (target->position.x > acting_entity->position.x); - } - // start chasing the target - dx = diff(acting_entity->position.x, target->position.x); - dz = diff(acting_entity->position.z, target->position.z); - maxspeed = acting_entity->modeldata.speed.x * 1.5; - - if(!dz && !dx) - { - acting_entity->velocity.x = acting_entity->velocity.z = 0; - } - else - { - acting_entity->velocity.x = maxspeed * dx / (dx + dz); - acting_entity->velocity.z = maxspeed * dz / (dx + dz); - } - if(acting_entity->direction == DIRECTION_LEFT) - { - acting_entity->velocity.x = -acting_entity->velocity.x; - } - if(acting_entity->position.z > target->position.z) - { - acting_entity->velocity.z = -acting_entity->velocity.z; - } - } - else - { - if(!acting_entity->velocity.x && !acting_entity->velocity.z) - { - if(acting_entity->direction == DIRECTION_LEFT) - { - acting_entity->velocity.x = -acting_entity->modeldata.speed.x; - } - else if(acting_entity->direction == DIRECTION_RIGHT) - { - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - } - } - - if(!(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE)) - { - if(target && acting_entity->position.z > target->position.z && validanim(acting_entity, ANI_UP)) - { - common_up_anim(acting_entity); //ent_set_anim(self, ANI_UP, 0); - } - else if(target && target->position.z > acting_entity->position.z && validanim(acting_entity, ANI_DOWN)) - { - common_down_anim(acting_entity); //ent_set_anim(self, ANI_DOWN, 0); - } - else if(validanim(acting_entity, ANI_WALK)) - { - common_walk_anim(acting_entity); //ent_set_anim(self, ANI_WALK, 0); - } - else - { - if(validanim(acting_entity, ANI_IDLE)) ent_set_anim(acting_entity, ANI_IDLE, 0); - } - } - } - else - { - /* - * Apply speed to velocity. If spawned by legacy - * functions, only apply X axis for backward - * compatability. - */ - - if(acting_entity->direction == DIRECTION_LEFT) - { - acting_entity->velocity.x = -acting_entity->modeldata.speed.x; - } - else if(acting_entity->direction == DIRECTION_RIGHT) - { - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - - - if (!(acting_entity->projectile_prime & PROJECTILE_PRIME_INITIALIZE_LEGACY_PROJECTILE_FUNCTION)) - { - acting_entity->velocity.y = acting_entity->modeldata.speed.y; - acting_entity->velocity.z = acting_entity->modeldata.speed.z; - } - } - - if(level) - { - // Bounce off walls or platforms. - projectile_wall_deflect(acting_entity); - - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_PROJECTILE_BASE_DIE) - { - if (acting_entity->landed_on_platform || acting_entity->position.y <= acting_entity->base) - { - acting_entity->takeaction = common_fall; - acting_entity->attacking = ATTACKING_NONE; - acting_entity->energy_state.health_current = 0; - acting_entity->projectile = BLAST_NONE; - acting_entity->damage_on_landing.attack_force = 0; - acting_entity->damage_on_landing.attack_type = ATK_NONE; - - /* Use default attack values. */ - s_attack attack = emptyattack; - attack.attack_drop = 10000; - set_fall(acting_entity, acting_entity, &attack, 0); - } - } - } - - if(acting_entity->projectile_prime & PROJECTILE_PRIME_LAUNCH_STATIONARY)// PROJECTILE_PRIME_BASE_FLOOR) - { - acting_entity->autokill |= AUTOKILL_ANIMATION_COMPLETE; - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2022-06-28 -* -* Explode (play attack animation and stop) if detonate -* flag is set and entity meets conditions. -* -* Return 0 if conditions fail. Return 1 if conditions -* pass or detonation in progress. -*/ -int bomb_try_detonate(entity* acting_entity) -{ - //printf("\n %s:", "bomb_try_detonate"); - - /* - * If not already set to detonate, check if - * we are preared for detonation and in air. - */ - - //printf("\n\t %s: %d", "acting_entity->toexplode", acting_entity->toexplode); - - if (!(acting_entity->toexplode & (EXPLODE_DETONATE_HIT | EXPLODE_DETONATE_DAMAGED))) - { - if (!(acting_entity->toexplode & (EXPLODE_PREPARE_TOUCH | EXPLODE_PREPARE_GROUND))) - { - return 0; - } - - //printf("\n\t %s: %d", "inair(acting_entity)", inair(acting_entity)); - - /* - * - Touches a wall. - * - Touches a platform. - * - Touches base 0 and isn't in a hole. - */ - - //printf("\n\t %s: %d", "check_block_wall(acting_entity)", check_block_wall(acting_entity)); - - if (check_block_wall(acting_entity) == WALL_INDEX_NONE && - !check_block_obstacle(acting_entity) - && inair(acting_entity)) - { - return 0; - } - } - - //printf("\n\t %s: %p", "acting_entity->takeaction", acting_entity->takeaction); - //printf("\n\t %s: %p", "bomb_explode", bomb_explode); - //printf("\n\t %s: %f, %f, %f, %f", "Position (x,y,z,b):", acting_entity->position.x, acting_entity->position.y, acting_entity->position.z, acting_entity->base); - - /* Already detonated? */ - if (acting_entity->takeaction == bomb_explode) - { - return 1; - } - - /* - * Set explode action. Entity stays on screen - * until explode animation finishes, then kills - * itself. - */ - acting_entity->takeaction = bomb_explode; - - /* - * Stop movement. - */ - if (!checkhole(acting_entity->position.x, acting_entity->position.z)) - { - acting_entity->base = acting_entity->position.y; - acting_entity->velocity.y = 0; - acting_entity->velocity.x = 0; - acting_entity->velocity.z = 0; - } - - /* - * Play die sound if we have it. This can act as - * the explosion sound. - */ - if (acting_entity->modeldata.diesound >= 0) - { - sound_play_sample(acting_entity->modeldata.diesound, 0, savedata.effectvol, savedata.effectvol, 100); - } - - /* - * If we hit or got hit, then play ATTACK2. - * If we landed first, play ATTACK1. - */ - if (acting_entity->toexplode & (EXPLODE_DETONATE_HIT | EXPLODE_DETONATE_DAMAGED)) - { - /* - * Play explode animation if we have it. - * - * If we do not have explode animation and - * the explode was triggered by hitting, then - * let's behave like a typical projectile and - * check the remove flag. - */ - - if (validanim(acting_entity, ANI_ATTACK2)) - { - ent_set_anim(acting_entity, ANI_ATTACK2, 0); - //acting_entity->animation->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - else if(acting_entity->modeldata.remove_config & REMOVE_CONFIG_HIT && acting_entity->toexplode & EXPLODE_DETONATE_HIT) - { - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_BOMB_EXPLODE_ANIMATION_UNAVAILABLE); - } - } - else if (validanim(acting_entity, ANI_ATTACK1)) - { - ent_set_anim(acting_entity, ANI_ATTACK1, 0); - //acting_entity->animation->move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2019-12-22 -* -* Original author unknown. Refactored to stop using global self, -* and fix bomb falling after detonation. -*/ -int bomb_move(entity* acting_entity) -{ - /* - * If in air, and prepared to explode (meaning will detonate on contact), - * but NOT yet set to detonate, then we move using velocity (presumably - * we've been tossed and so any Z and Y momentum is already handled). - * - * EXPLODE_DETONATE_HIT status is applied by do_attack() if we touch - * ground or hit another entity. - * - * EXPLODE_DETONATE_DAMAGE set when hit by another entity attack. - * - * In either case case, we "explode" by playing an appropriate animation. - */ - - /* - * Bounce off walls or platforms if there - * is a fall animation. - */ - - if (projectile_wall_deflect(acting_entity)) - { - return 1; - } - - /* - * Check detonation conditions and - * apply accordingly. - */ - - if (bomb_try_detonate(acting_entity)) - { - return 1; - } - - if (acting_entity->direction == DIRECTION_LEFT) - { - acting_entity->velocity.x = -acting_entity->modeldata.speed.x; - } - else if (acting_entity->direction == DIRECTION_RIGHT) - { - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - - return 1; -} - -/* -* Caskey, Damon V. -* 2018-04-07 -* -* Find out if there is a wall blocking target entity, and -* if so return its array key. Returns WALL_INDEX_NONE if -* no blocking wall found. -*/ -int check_block_wall(entity *entity) -{ - //printf("\n\n check_block_wall(%p)", entity); - //printf("\n entity->modeldata.move_config_flags: %d", entity->modeldata.move_config_flags); - - int wall = WALL_INDEX_NONE; - - /* Target entity affected by walls? */ - if(entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_WALL) - { - //printf("\n\t Has constraint."); - - /* Get wall number at our Xand Z axis(if any). */ - wall = checkwall_index(entity->position.x, entity->position.z); - - //printf("\n\t wall: %d", wall); - - /* Did we find a wall? */ - if (wall >= 0) - { - /* - * Compare wall height to our current - * Y axis position. If the wall is - * higher, then it's blocking our way. - * We can return the wall number. - */ - - if(entity->position.y < level->walls[wall].height) - { - return wall; - } - } - } - - /* - * Got this far? Then there's no wall blocking our way. - */ - return WALL_INDEX_NONE; -} - -// Caskey, Damon V. -// 2018-04-07 -// -// Return obstacle entity that is blocking target -// entity (if any). Returns NULL if not blocking -// obstacle found. -entity *check_block_obstacle(entity *ent) -{ - entity *obstacle = NULL; - int height; - - // Target entity affected by obstacles? - if(ent->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM) - { - // Get the height. if entity does not have an - // animation height defined, then use its - // the entity height instead. - if(ent->animation->size.y) - { - height = ent->animation->size.y; - } - else - { - height = ent->modeldata.size.y; - } - - // Add Y position to get the exact Y axis - // height of the entity's top edge. - height += ent->position.y; - - // Find obstacle at entitiy's position (if any). - obstacle = check_platform_between(ent->position.x, ent->position.z, ent->position.y, height, ent); - } - - return obstacle; -} - -/* -* Caskey, Damon V -* 2018-04-06 -* -* Ricochet a projectile off of walls and platforms. -* Returns 1 on successful ricochet. 0 otherwise. -*/ -int projectile_wall_deflect(entity *acting_entity) -{ - const int RICHOCHET_FALL_FORCE = 10000; - const float RICHOCHET_VELOCITY_X_FACTOR = 0.25; // This value is multiplied by current velocity to get an X velocity value to bounce off wall.. - const float RICHOCHET_VELOCITY_Y = 2.5; // Base Y velocity applied when projectile bounces off wall. - const int RICHOCHET_VELOCITY_Y_RAND = 1; // Random seed for Y variance added to base Y velocity when bouncing off wall. - - float richochet_velocity_x; - s_attack attack = emptyattack; - - //printf("\n\n projectile_wall_deflect(%p)", acting_entity); - //printf("\n\t model(%s)", acting_entity->model->name); - //printf("\n\t acting_entity->drop: ", acting_entity->drop); - - if(validanim(acting_entity, ANI_FALL) && acting_entity->modeldata.move_config_flags & MOVE_CONFIG_PROJECTILE_WALL_BOUNCE) - { - //printf("\n\t Has Fall"); - //printf("\n\t position: %f, %f, %f", acting_entity->position.x, acting_entity->position.y, acting_entity->position.z); - //printf("\n\t velocity: %f, %f, %f", acting_entity->velocity.x, acting_entity->velocity.y, acting_entity->velocity.z); - - int blocking_wall; - entity *blocking_obstacle = NULL; - - /* - * Blocked by wall or obstacle? Note these - * functions return false if the entity - * is not subject to wall/obstacle. - */ - - blocking_wall = check_block_wall(acting_entity); - blocking_obstacle = check_block_obstacle(acting_entity); - - //printf("\n\t wall(%d), obstacle(%p)", blocking_wall, blocking_obstacle); - - if(blocking_wall >= 0 || blocking_obstacle) - { - //printf("\n\t Is blocked."); - - /* - * Use the projectile's speed and our factor to see - * how hard it will bounce off wall. - */ - richochet_velocity_x = -acting_entity->velocity.x * RICHOCHET_VELOCITY_X_FACTOR; - - //printf("\n\t richochet_velocity_x: %f", richochet_velocity_x); - - acting_entity->takeaction = common_fall; - acting_entity->attacking = ATTACKING_NONE; - acting_entity->energy_state.health_current = 0; - acting_entity->projectile = BLAST_NONE; - - acting_entity->velocity.x = richochet_velocity_x; - - acting_entity->velocity.z = 0.0; - acting_entity->damage_on_landing.attack_force = 0; - acting_entity->damage_on_landing.attack_type = ATK_NONE; - toss(acting_entity, RICHOCHET_VELOCITY_Y + randf(RICHOCHET_VELOCITY_Y_RAND)); - - /* Reset base detection */ - acting_entity->modeldata.move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL); - acting_entity->modeldata.move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - - acting_entity->base = 0; - - /* Use default attack values. */ - attack.attack_drop = RICHOCHET_FALL_FORCE; - set_fall(acting_entity, acting_entity, &attack, 0); - - //printf("\n\t velocity: %f, %f, %f", acting_entity->velocity.x, acting_entity->velocity.y, acting_entity->velocity.z); - - return 1; - } - - //printf("\n\t Not blocked."); - } - - /* Did not ricochet, so return false. */ - return 0; -} - -// Caskey, Damon V. -// 2018-04-06 -// -// Invert current sorting position vs. parent. -void sort_invert_by_parent(entity *ent, entity *parent) -{ - if(ent->sortid <= parent->sortid) - { - ent->sortid = parent->sortid + 1; - } - else - { - ent->sortid = parent->sortid - 1; - } -} - -int star_move() -{ - if(self->position.x < advancex - 80 || self->position.x > advancex + (videomodes.hRes + 80) || (self->position.y <= self->base && (self->modeldata.death_config_flags & DEATH_CONFIG_MACRO_DEATH))) - { - kill_entity(self, KILL_ENTITY_TRIGGER_STAR_OUT_OF_BOUNDS); - return 0; - } - - //self->base -= 4; - //self->position.y = self->base; - - // Bounce off walls or platforms. - projectile_wall_deflect(self); - - if(self->landed_on_platform || self->position.y <= self->base) - { - self->takeaction = common_lie; - self->death_state |= DEATH_STATE_DEAD; - self->energy_state.health_current = 0; - if((self->modeldata.death_config_flags & (DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) == (DEATH_CONFIG_FALL_LAND_AIR | DEATH_CONFIG_FALL_LAND_GROUND | DEATH_CONFIG_REMOVE_VANISH_AIR | DEATH_CONFIG_REMOVE_VANISH_GROUND)) - { - self->animating = ANIMATING_NONE; - } - } - - return 1; -} - - -//dispatch move patterns -//root function for aimove -int common_move() -{ - entity* acting_entity = self; - e_aimove aimove; - int makestop = 0; - int reachx; - int reachz; - int air = inair(acting_entity); - entity *other = NULL; //item - entity *target = NULL;//hostile target - entity *owner = NULL; - entity *ent = NULL; - e_direction predir; - long stall; - int patx[5]; - int pxc; - int px; - int patz[5]; - int pzc; - int pz; - int fz; - - if(acting_entity->modeldata.aimove == -1) - { - return 0; // invalid value - } - - // get move pattern - aimove = acting_entity->modeldata.aimove & MASK_AIMOVE1; - -//if(stricmp(acting_entity->name, "os")==0) printf("%d\n", aimove); - // old and outdated patterns, but MUST be kept anyway - if(aimove & AIMOVE1_BIKER) - { - // for biker subtype - return biker_move(); - } - else if(aimove & AIMOVE1_ARROW) - { - // for common straight-flying arrow - return arrow_move(acting_entity); - } - else if(aimove & AIMOVE1_STAR) - { - // for a star, disappear when hit ground - return star_move(); - } - else if(aimove & AIMOVE1_BOMB) - { - // for a bomb, travel in a arc - return bomb_move(acting_entity); - } - else if(aimove & AIMOVE1_NOMOVE) - { - // no move, just return - return 0; - } - else - { - // all above are special move patterns, real AI goes here: - - // skip if the entity is in air, - // removing this and entity might be spawned walking in air - if (air) - { - return 0; - } - - // store this for turning checking - predir = acting_entity->direction; - - // find all possible entities for target - // bad for optimization, but makes better sense - if (acting_entity->custom_target == NULL || !acting_entity->custom_target->exists) target = normal_find_target(-1, 0); // confirm the target again - else target = acting_entity->custom_target; - - other = ((_time / global_config.game_speed + acting_entity->energy_state.health_current / 3 + 1000) % 15 < 10) ? normal_find_item() : NULL; // find an item - owner = acting_entity->parent; - - // temporary solution to turn off running if xdir is not set - // unless one day vertical running logic is written - if (!acting_entity->velocity.x) - { - acting_entity->running = RUN_STATE_NONE; - } - - // change direction unless the ai pattern ignores target or model has noflip - if (!(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_FLIP) && !acting_entity->running && aimove != AIMOVE1_WANDER) - { - if (other) //try to pick up an item, if possible - { - acting_entity->direction = (acting_entity->position.x < other->position.x) ? DIRECTION_RIGHT : DIRECTION_LEFT; - } - else if (target) - { - acting_entity->direction = (acting_entity->position.x < target->position.x) ? DIRECTION_RIGHT : DIRECTION_LEFT;; - } - else if (owner) - { - /* - * If we're following a parent, then check to see - * if we are in direction adjust range and if so - * we'll apply the direction adjustment. Otherwise - * we just face parent. - * - * Any range with min > max is true. - */ - - const s_child_follow* const child_follow = acting_entity->modeldata.child_follow; - - if (child_follow - && (child_follow->direction_adjust_range.x.min <= child_follow->direction_adjust_range.x.max && check_range_target_x(acting_entity, owner, NULL, child_follow->direction_adjust_range.x.min, child_follow->direction_adjust_range.x.max)) - && (child_follow->direction_adjust_range.z.min <= child_follow->direction_adjust_range.z.max && check_range_target_z(acting_entity, owner, NULL, child_follow->direction_adjust_range.z.min, child_follow->direction_adjust_range.z.max)) - && (child_follow->direction_adjust_range.y.min <= child_follow->direction_adjust_range.y.max && check_range_target_y(acting_entity, owner, NULL, child_follow->direction_adjust_range.y.min, child_follow->direction_adjust_range.y.max))) { - - acting_entity->direction = direction_get_adjustment_result(acting_entity, owner, child_follow->direction_adjust_config); - } - } - } - else if (aimove == AIMOVE1_WANDER) - { - if (acting_entity->velocity.x) - { - acting_entity->direction = (acting_entity->velocity.x > 0) ? DIRECTION_RIGHT : DIRECTION_LEFT; - } - } - - //turn back if we have a turn animation - // TODO, make a function for ai script - if (acting_entity->direction != predir && validanim(acting_entity, ANI_TURN) && acting_entity->ducking == DUCK_NONE) - { - acting_entity->takeaction = common_turn; - acting_entity->direction = (acting_entity->direction == DIRECTION_RIGHT) ? DIRECTION_LEFT : DIRECTION_RIGHT; - acting_entity->velocity.x = 0; - acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_TURN, 0); - return 1; - } - - //pick up the item if possible - if (other && diff(other->position.x, acting_entity->position.x) < (acting_entity->modeldata.grabdistance * 0.83333) - && diff(other->position.z, acting_entity->position.z) < (acting_entity->modeldata.grabdistance / 3) && - other->animation->vulnerable[other->animpos])//won't pickup an item that is not previous one - { - if (diff(acting_entity->base, other->position.y) < 0.1) - { - common_pickupitem(other); - return 1; - } - } - - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - acting_entity->idling = IDLING_PREPARED; - return 1; - } - - if (common_try_jump()) - { - acting_entity->numwaypoints = 0; - return 1; //need to jump? so quit - } - - if (checkpathblocked()) - { - return 1; // handle path blocked logic - } - - // judge next move if stalltime is expired - // skip if waypoints presents (passive move) - if (acting_entity->stalltime < _time && !acting_entity->waypoints) - { - if (other) - { - // try walking to the item - common_try_pick(other); - ent = other; - } - else - { - if (target && (acting_entity->modeldata.subtype == SUBTYPE_CHASE || - ((acting_entity->modeldata.type & TYPE_NPC) && acting_entity->parent))) - // try chase a target - { - aimove |= AIMOVE1_CHASE; - } - - if (aimove & AIMOVE1_CHASE) - { - aimove |= AIMOVE1_CHASEX | AIMOVE1_CHASEZ; - } - if (aimove & AIMOVE1_AVOID) - { - aimove |= AIMOVE1_AVOIDX | AIMOVE1_AVOIDZ; - } - - if (other != ent) - { - acting_entity->velocity.x = acting_entity->velocity.z = 0; - } - - if (!aimove && target) - { - common_try_wander(target, 1, 1); - ent = target; - } - else if (target && (!(acting_entity->modeldata.aimove & AIMOVE2_NOTARGETIDLE) || ((acting_entity->modeldata.aimove & AIMOVE2_NOTARGETIDLE) && target->animnum != ANI_IDLE))) - { - ent = target; - pxc = pzc = 0; - - if (aimove & AIMOVE1_WANDER) - { - patx[pxc++] = AIMOVE1_WANDER; - patx[pxc++] = AIMOVE1_WANDER; - patz[pzc++] = AIMOVE1_WANDER; - patz[pzc++] = AIMOVE1_WANDER; - } - if (aimove & AIMOVE1_CHASEX) - { - patx[pxc++] = AIMOVE1_CHASEX; - } - if (aimove & AIMOVE1_AVOIDX) - { - patx[pxc++] = AIMOVE1_AVOIDX; - } - if (aimove & AIMOVE1_CHASEZ) - { - patz[pzc++] = AIMOVE1_CHASEZ; - } - if (aimove & AIMOVE1_AVOIDZ) - { - patz[pzc++] = AIMOVE1_AVOIDZ; - } - if (!pxc) - { - patx[pxc++] = AIMOVE1_WANDER; - } - if (!pzc) - { - patz[pzc++] = AIMOVE1_WANDER; - } - px = patx[(rand32() & 0xff) % pxc]; - pz = patz[(rand32() & 0xff) % pzc]; - - fz = 0; - - aimove = (acting_entity->modeldata.aimove & MASK_AIMOVE1); - - //valid types: avoidx, aviodz, chasex, chasez, wander - if (px == AIMOVE1_WANDER) - { - if (pz == AIMOVE1_WANDER && aimove == AIMOVE1_WANDER) - { - common_try_wandercompletely(1, 1); - fz = 1; - } - else - { - common_try_wander(target, 1, 0); - } - - } - else if (px == AIMOVE1_CHASEX) - { - common_try_chase(acting_entity, target, 1, (pz == AIMOVE1_CHASEZ)); - fz = (pz == AIMOVE1_CHASEZ); - } - else if (px == AIMOVE1_AVOIDX) - { - common_try_avoid(target, 1, (pz == AIMOVE1_AVOIDZ)); - fz = (pz == AIMOVE1_AVOIDZ); - } - if (!fz) - { - if (pz == AIMOVE1_WANDER) - { - common_try_wander(target, 0, 1); - } - else if (pz == AIMOVE1_CHASEZ) - { - common_try_chase(acting_entity, target, 0, 1); - } - else if (pz == AIMOVE1_AVOIDZ) - { - common_try_avoid(target, 0, 1); - } - } - - } - else if (!common_try_follow(acting_entity, owner, 1, 1) && !(acting_entity->modeldata.aimove & AIMOVE2_NOTARGETIDLE)) - { - common_try_wandercompletely(1, 1); - ent = NULL; - } - else - { - ent = owner; - } - } - //end of if - - }//if(acting_entity->stalltime < _time ) - else - { - ent = other; - if (!ent) - { - ent = target; - } - if (!ent) - { - ent = owner; - } - } - if (acting_entity->numwaypoints == 0 && acting_entity->waypoints) - { - free(acting_entity->waypoints); - acting_entity->waypoints = NULL; - } - - //fix 2d level panic, or should this be moved to the very beginning? - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MIN_Z && acting_entity->destz < PLAYER_MIN_Z) - { - acting_entity->destz = PLAYER_MIN_Z; - } - if (acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_MAX_Z && acting_entity->destz > PLAYER_MAX_Z) - { - acting_entity->destz = PLAYER_MAX_Z; - } - - // don't run in passive move mode. The path could be complex and running may look bad. - if (acting_entity->waypoints) - { - acting_entity->running = RUN_STATE_NONE; - } - - if (acting_entity->direction == (acting_entity->destx < acting_entity->position.x)) - { - acting_entity->running = RUN_STATE_NONE; - } - - // make the entity walks in a straight path instead of flickering here and there - // acceleration can be added easily based on this logic, if necessary - adjustspeed(acting_entity->running ? acting_entity->modeldata.runspeed : acting_entity->modeldata.speed.x, - acting_entity->position.x, acting_entity->position.z, - acting_entity->destx, acting_entity->destz, - &acting_entity->velocity.x, - &acting_entity->velocity.z); - - /* - * If we can't run on a different axis - * then stay on the rails. - */ - - if (acting_entity->running & RUN_STATE_START_X) { - if ((acting_entity->velocity.z < 0 && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_ENABLED)) - || (acting_entity->velocity.z > 0 && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_ENABLED)) - || (acting_entity->velocity.x < 0 && acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_LEFT_DASH_FIXED) - || (acting_entity->velocity.x > 0 && acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_RIGHT_DASH_FIXED)) { - acting_entity->velocity.z = 0; - acting_entity->destz = acting_entity->position.z; - } - } - else if (acting_entity->running & RUN_STATE_START_Z) { - if ((acting_entity->velocity.x < 0 && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_LEFT_ENABLED)) - || (acting_entity->velocity.x > 0 && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_RIGHT_ENABLED)) - || (acting_entity->velocity.z < 0 && acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_DASH_FIXED) - || (acting_entity->velocity.z > 0 && acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_DASH_FIXED)) { - acting_entity->velocity.x = 0; - acting_entity->destz = acting_entity->position.x; - } - } - - // check destination point to make a stop or pop a waypoint from the stack - reachx = (diff(acting_entity->position.x, acting_entity->destx) < MAX(1, ABS(acting_entity->velocity.x))); - reachz = (diff(acting_entity->position.z, acting_entity->destz) < MAX(1, ABS(acting_entity->velocity.z))); - - // check destination point to make a stop or pop a waypoint from the stack - if(reachx && reachz) - { - if(acting_entity->waypoints && acting_entity->numwaypoints) - { - acting_entity->destx = acting_entity->waypoints[acting_entity->numwaypoints - 1].x; - acting_entity->destz = acting_entity->waypoints[acting_entity->numwaypoints - 1].z; - acting_entity->numwaypoints--; - } - else if(acting_entity->velocity.x || acting_entity->velocity.z) - { - makestop = 1; - } - } - - if(!acting_entity->waypoints || !acting_entity->numwaypoints) - { - if(reachx) - { - acting_entity->velocity.x = 0; - acting_entity->destx = acting_entity->position.x; - } - if(reachz) - { - acting_entity->velocity.z = 0; - acting_entity->destz = acting_entity->position.z; - } - } - - // IMPORTANT: stoped so play idle, preventinng funny stepping bug, but may cause flickering - if(!acting_entity->velocity.x && !acting_entity->velocity.z && !acting_entity->waypoints) - { - set_idle(acting_entity); - if(makestop) - { - stall = (global_config.game_speed - acting_entity->modeldata.aggression) / 2; - if(stall < global_config.game_speed / 5) - { - stall = global_config.game_speed / 5; - } - acting_entity->stalltime = _time + MAX(0, stall); - } - } - else - { - // readjust walk animation - adjust_walk_animation(ent); - // give proper stalltime if destination point is not reached - // if the destination point is not reachable, - // it should be already handled in checkpathblocked - if(_time > acting_entity->stalltime) - { - if(ABS(acting_entity->velocity.x) > ABS(acting_entity->velocity.z)) - { - stall = diff(acting_entity->destx, acting_entity->position.x) / ABS(acting_entity->velocity.x) * 2; - } - else if(acting_entity->velocity.z) - { - stall = diff(acting_entity->destz, acting_entity->position.z) / ABS(acting_entity->velocity.z) * 2; - } - else - { - stall = global_config.game_speed / 2; - } - acting_entity->stalltime = _time + MAX(0, stall); - } - } - - //target is moving? readjust destination sooner - if(aimove != AIMOVE1_WANDER && !acting_entity->waypoints && ent && (acting_entity->velocity.x || acting_entity->velocity.z) && (ent->velocity.x || ent->velocity.z)) - { - if(acting_entity->running && acting_entity->stalltime > _time + global_config.game_speed / 2) - { - acting_entity->stalltime = _time + global_config.game_speed / 2; - } - else if(!acting_entity->running && acting_entity->stalltime > _time + global_config.game_speed / 5) - { - acting_entity->stalltime = _time + global_config.game_speed / 5; - } - } - - return 1; - - } - - return 1; -} - - -void decide_stalker() -{ - entity *ent, *furthest = NULL; - int i; - int l = 0, r = 0; - float maxz = 0.0f, z; - - if(stalker && stalking) - { - return; - } - - firstplayer = NULL; - - for(i = 0; i < MAX_PLAYERS; i++) - { - if(player[i].ent) - { - firstplayer = player[i].ent; - break; - } - } - - if(!firstplayer) - { - return; - } - - for(i = 0; i < ent_max; i++) - { - ent = ent_list[i]; - - if(ent->exists && !(ent->death_state & DEATH_STATE_DEAD) && (ent->modeldata.type & TYPE_ENEMY)) - { - if(ent->position.x > firstplayer->position.x) - { - r++; - } - else - { - l++; - } - - if((z = diff(ent->position.z, firstplayer->position.z)) >= maxz && - (ent->modeldata.aimove == 0 || (ent->modeldata.aimove & AIMOVE1_CHASE))) // 2 mostly used type - { - maxz = z; - furthest = ent; - } - } - } - - if((l > 1 && !r) || (r > 1 && !l)) - { - stalker = furthest; - //printf("** stalker decided: %s @ _time %d\n", stalker->name, _time); - } -} - - -void plan() -{ - decide_stalker(); -} - -void checkstalker() -{ - float maxspeed; - e_run_state running = RUN_STATE_NONE; - - if(self != stalker) - { - return; - } - - if(!firstplayer) - { - stalker = NULL; - return; - } - - if(stalking) - { - if(self->stalltime <= _time) - { - //printf("** stalk _time expired: %s @ _time %d\n", stalker->name, _time); - stalker = NULL; - } - return; - } - - if (validanim(self, ANI_RUN)) - { - running |= RUN_STATE_START_X; - } - - maxspeed = (running & RUN_STATE_START_X) ? self->modeldata.runspeed : self->modeldata.speed.x; - - self->velocity.x = maxspeed; - self->velocity.z = 0; - - if(self->position.x > firstplayer->position.x) - { - self->velocity.x = -self->velocity.x; - } - - self->running = running; - - - self->stalltime = _time + (diff(self->position.x, firstplayer->position.x) + 150) / maxspeed * THINK_SPEED; - - adjust_walk_animation(firstplayer); - - stalking = 1; - //printf("**start stalking: %s @ _time %d till @%d\n", stalker->name, time, self->stalltime); -} - -int checkplanned() -{ - return 0; -} - -/* -* Caskey, Damon V. -* 2023-05-24 (rewrite of orginal function by Utunnels, unknown date) -* -* Check if entity is outside of recall -* location, and if so, trigger the -* recall function. -*/ -int ai_check_recall() -{ - entity* const acting_entity = self; - const s_child_follow* const child_follow = acting_entity->modeldata.child_follow; - - if(!child_follow || acting_entity->link) - { - return 0; - } - - /* - * Set up recall range. X and Z using the - * idle range x max when supplied values - * are MIN/MAX is for legacy compatability. - */ - - const int valid_idle = validanim(acting_entity, ANI_IDLE); - const int default_range = (valid_idle) ? acting_entity->modeldata.animation[ANI_IDLE]->range.x.max : MAX_INT; - - const s_range recall_range = { - .x = { - .max = (child_follow->recall_range.x.max == MAX_INT && valid_idle) ? default_range : child_follow->recall_range.x.max, - .min = (child_follow->recall_range.x.min == MIN_INT && valid_idle) ? -default_range : child_follow->recall_range.x.min - }, - - .y = { - .max = child_follow->recall_range.y.max, - .min = child_follow->recall_range.y.min - }, - - .z = { - .max = (child_follow->recall_range.z.max == MAX_INT && valid_idle) ? default_range : child_follow->recall_range.z.max, - .min = (child_follow->recall_range.z.min == MIN_INT && valid_idle) ? -default_range : child_follow->recall_range.z.min - }, - - .base = { - .max = child_follow->recall_range.base.max, - .min = child_follow->recall_range.base.min - } - }; - - if(acting_entity->modeldata.subtype == SUBTYPE_FOLLOW && acting_entity->parent && - (!check_range_target_x(acting_entity, acting_entity->parent, NULL, recall_range.x.min, recall_range.x.max) || - !check_range_target_z(acting_entity, acting_entity->parent, NULL, recall_range.z.min, recall_range.z.max) || - !check_range_target_y(acting_entity, acting_entity->parent, NULL, recall_range.y.min, recall_range.y.max) || - !check_range_target_base(acting_entity, acting_entity->parent, NULL, recall_range.base.min, recall_range.base.max))) - { - acting_entity->takeaction = npc_recall; - return 1; - } - return 0; -} - -int ai_check_lie() -{ - if(self->drop - && self->position.y == self->base - && !self->velocity.y - && validanim(self, ANI_RISEATTACK) - && ((rand32() % (self->stalltime - _time + 1)) < 3) - && (self->energy_state.health_current > 0 - && _time > self->staydown.riseattack_stall)) - { - common_try_riseattack(); - return 1; - } - return 0; -} - -int ai_check_grabbed() -{ - if (!self->link) - { - return 0; - } - - if (self->grabbing) - { - return 0; - } - - if (self->inpain & ~IN_PAIN_NONE) - { - return 0; - } - - if (self->takeaction == common_prethrow) - { - return 0; - } - - if (inair(self)) - { - return 0; - } - - if (_time < self->stalltime) - { - return 0; - } - - if (!validanim(self, ANI_SPECIAL)) - { - return 0; - } - - check_special(); - - return 1; -} - -int ai_check_grab() -{ - if(self->grabbing && self->attacking == ATTACKING_NONE) - { - common_grab_check(); - return 1; - } - return 0; -} - -int ai_check_escape() -{ - if((self->escapecount > self->modeldata.escapehits) && !inair(self) && validanim(self, ANI_SPECIAL2)) - { - // Counter the player! - check_costmove(ANI_SPECIAL2, 0, 0); - return 1; - } - return 0; -} - -int ai_check_busy() -{ - return self->link || !self->idling; -} - -int ai_check_ducking() -{ - int indirect; - entity *target = NULL; - float t_rangex = 60.0f; - float t_rangez = 30.0f; - - if ((self->ducking & DUCK_PREPARED) || (self->ducking & DUCK_RISE)) - { - return 1; - } - - if(self->link || inair(self)) - { - return 0; - } - - if( !validanim(self, ANI_DUCK) || !validanim(self, ANI_DUCKATTACK) ) - { - return 0; - } - - if(self->projectile & BLAST_ATTACK) - { - indirect = 1; - } - - if(self->custom_target == NULL || !self->custom_target->exists ) target = normal_find_target(-1, 0); - else target = self->custom_target; - - if(target && !(faction_check_can_damage(self, target, indirect))) - { - return 0; - } - - if ((self->ducking & DUCK_ACTIVE) && self->animnum == ANI_DUCK) - { - if ( !target || inair(target) || !(target->ducking & DUCK_ACTIVE) || - (!check_range_target_all(self,target,ANI_DUCK, 0, 0) && - diff(self->position.x, target->position.x) > t_rangex && diff(self->position.z, target->position.z) > t_rangez) ) - { - self->velocity.x = self->velocity.z = 0; - tryduckrise(self); - return 1; - } - } - - if(!target || !(target->ducking & DUCK_ACTIVE)) - { - return 0; - } - else - { - if (self->ducking & DUCK_ACTIVE) - { - return 1; - } - else - { - int range_flag = check_range_target_all(self,target,ANI_DUCK, 0, 0); - if (!range_flag) - { - if ( diff(self->position.x, target->position.x) <= t_rangex && - diff(self->position.z, target->position.z) <= t_rangez) range_flag = 1; - } - if (!range_flag) return 0; - - if(self->ducking == DUCK_NONE) - { - tryduck(self); - } - return 1; - } - } - - return 0; -} - - -// A.I root -void common_think() -{ - - if(self->death_state & DEATH_STATE_DEAD) - { - return; - } - - //if(checkplanned()) return; - - // too far away , do a warp - if(ai_check_recall()) - { - return; - } - - // rise? try rise attack - if(ai_check_lie()) - { - return; - } - - // Escape? - if(ai_check_grabbed()) - { - return; - } - - //grabbing something - if(ai_check_grab()) - { - return; - } - - // Enemies can now escape non-knockdown spammage (What a weird phrase)! - if(ai_check_escape()) - { - return; - } - - // busy right now? - if(ai_check_busy()) - { - return; - } - - // idle, so try to attack or judge next move - // dont move if fall into a hole or off a wall - if(common_attack()) - { - return; - } - - // target is ducking? try to ducking.. - if(ai_check_ducking()) - { - return; - } - - common_move(); -} - -////////////////////////////////////////////////////////////////////////// - -void suicide() -{ - - if(_time < self->stalltime) - { - return; - } - level_completed |= self->boss; - level_completed_defeating_boss |= self->boss; - - kill_entity(self, KILL_ENTITY_TRIGGER_SUICIDE); -} - - - -// Re-enter playfield -// Used by player_fall and player_takedamage -void player_die_entity(entity* acting_entity) -{ - int playerindex = acting_entity->playerindex; - int i = 0; - - if(!(global_config.cheats & CHEAT_OPTIONS_LIVES_ACTIVE)) - { - --player[playerindex].lives; - } - - if(firstplayer == acting_entity) - { - firstplayer = NULL; - } - - execute_pdie_script(playerindex); - - if(nomaxrushreset[4] >= 1) - { - nomaxrushreset[playerindex] = player[playerindex].ent->rush.max; - } - player[playerindex].ent = NULL; - player[playerindex].spawnhealth = acting_entity->modeldata.health; - player[playerindex].spawnmp = acting_entity->modeldata.mp; - - /* - * Handle the body. If any corpse flags - * are set, we leave entity on screen - * and make it inert. Otherwise we can - * just run kill function to remove. - * - * REMOVE_CORPSE_* flags refer to how - * the live entity is removed from the - * game while leaving a corpse behind. - */ - - static const e_death_config_flags leave_corpse = DEATH_CONFIG_REMOVE_CORPSE_AIR | DEATH_CONFIG_REMOVE_CORPSE_GROUND; - - if (acting_entity->modeldata.death_config_flags & leave_corpse) { - acting_entity->think = NULL; - acting_entity->takeaction = NULL; - acting_entity->death_state |= DEATH_STATE_CORPSE; - } else { - kill_entity(acting_entity, KILL_ENTITY_TRIGGER_PLAYER_DEATH); - } - - if(player[playerindex].lives <= 0) - { - int all_p_ko = 0; - - // Count number of KO'd (dead) players, by looping player - // indexes and incrementing when player does not have - // an entity. - for(i = 0; i < MAX_PLAYERS; i++) - { - if (!player[i].ent) - { - ++all_p_ko; - } - } - - // If all players are KO'd, then KO count = 1. - // Otherwise, set it to 0. - all_p_ko = (all_p_ko >= MAX_PLAYERS) ? 1 : 0; - - // All players KO'd? - if(all_p_ko) - { - int all_p_nojoin = 0; - int all_p_nocredits = 0; - - // All players NOT joining? - // Same logic as all player KO. - for(i = 0; i < MAX_PLAYERS; i++) - { - if (!player[i].joining) - { - ++all_p_nojoin; - } - } - - all_p_nojoin = (all_p_nojoin >= MAX_PLAYERS) ? 1 : 0; - - // All players out of credits? - // Same logic as all player KO. - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].credits < 1) - { - ++all_p_nocredits; - } - } - - all_p_nocredits = (all_p_nocredits >= MAX_PLAYERS) ? 1 : 0; - - // Set the timer to a 10 second count down. - timeleft = 10 * global_config.counter_speed; - - // No one joining in? - if(all_p_nojoin) - { - // If the player can't continue, let's set the time over - // to end almost instantly so they won't have to wait. - - // If noshare is enabled, credit shares are not allowed. Verify all - // player individual credit supplies are empty. Otherwise credit - // shares are allowed, so verify pool of credits is empty. - if (noshare) - { - if (all_p_nocredits) - { - timeleft = global_config.counter_speed / 2; - } - } - else - { - if (credits < 1) - { - timeleft = global_config.counter_speed / 2; - } - } - } - } - - if(acting_entity->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_STAGE) - { - player[playerindex].weapnum = level->setweap; - } - - if(nomaxrushreset[4] != 2) - { - nomaxrushreset[playerindex] = 0; - } - - return; - } - else - { - spawnplayer(playerindex); - execute_respawn_script(playerindex); - if(!nodropen) - { - if (savedata.joyrumble[playerindex]) control_rumble(playerindex, 1, 125); - drop_all_enemies(); - } - } - - if(!level->noreset) - { - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - } - -} - -void player_die(void) -{ - player_die_entity(self); -} - - - -int player_trymove(float xdir, float zdir) -{ - return common_trymove(xdir, zdir); -} - -int check_energy(e_cost_check which, int ani) -{ - int result = FALSE; - e_entity_type type; //Entity type. - s_energy_cost energy_cost; - - // Get animation's energy_cost data. - energy_cost.cost = self->modeldata.animation[ani]->energy_cost.cost; - energy_cost.disable = self->modeldata.animation[ani]->energy_cost.disable; - energy_cost.mponly = self->modeldata.animation[ani]->energy_cost.mponly; - - // Get entity type. - type = self->modeldata.type; - - // If we're bind and special is overridden, then - // return false. - if(type & (TYPE_ENEMY | TYPE_NPC)) - { - if(check_bind_override(self, BIND_CONFIG_OVERRIDE_SPECIAL_AI)) - { - return FALSE; - } - } - else if(type & TYPE_PLAYER) - { - if(check_bind_override(self, BIND_CONFIG_OVERRIDE_SPECIAL_PLAYER)) - { - return FALSE; - } - } - - if(validanim(self, ani)) - { - // Caskey, Damon V. - // 2010-05-08 - // - // It is now possible to individually disable specials. In - // many cases (weapons in particular) this can help cut down the need for - // superfluous models when differing abilities are desired for players, - // enemies, or npcs. - // Kratus (10-2021) Fixed the new broken code for "disable" flag check, back to the previous code - if(!(energy_cost.disable == type // Disabled by type? - || (energy_cost.disable == -1) // Disabled for all? - || (energy_cost.disable == -2 && (type & (TYPE_ENEMY | TYPE_NPC))) // Disabled for all AI? - || (energy_cost.disable == -3 && (type & (TYPE_PLAYER | TYPE_NPC))) // Disabled for players & NPCs? - || (energy_cost.disable == -4 && (type & (TYPE_PLAYER | TYPE_ENEMY))))) // Disabled for all AI? - { - // No seal or seal is less/same as energy cost? - if (!self->seal || self->seal >= energy_cost.cost) - { - if((which == ENERGY_TYPE_MP && (energy_cost.mponly != COST_TYPE_HP_ONLY) && (self->energy_state.mp_current >= energy_cost.cost)) - || (which == ENERGY_TYPE_HP && (energy_cost.mponly != COST_TYPE_MP_ONLY) && (self->energy_state.health_current > energy_cost.cost))) - { - result = TRUE; - } - else - { - //DC 2009-01-23 - //Tried putting the CANT animation here to keep code compacted, but won't work. I'll come back to this. - //if (validanim(self,ani)){ - // ent_set_anim(self, ANI_CANT, 0); - // self->takeaction = common_attack_proc; - // player[self->playerindex].playkeys = 0; - //} - } - } - } - } - - return result; -} - -// Caskey Damon V. -// 2018-05-10 -// -// Replaces unreadable check_range() macro. Runs individual -// check range functions for each axis and returns true -// if target is within range of ALL. -bool check_range_target_all(const entity *ent, const entity *target, const animation_id_t animation_id, int64_t range_min, int64_t range_max) -{ - // Must have a valid target entity. - if(!target) - { - return false; - } - - // Get pointer to animation. - const s_anim *animation = ent->modeldata.animation[animation_id]; - - if (!check_range_target_x(ent, target, animation, range_min, range_max)) - { - return false; - } - - if (!check_range_target_y(ent, target, animation, range_min, range_max)) - { - return false; - } - - if (!check_range_target_z(ent, target, animation, range_min, range_max)) - { - return false; - } - - if (!check_range_target_base(ent, target, animation, range_min, range_max)) - { - return false; - } - - return true; -} - -// Caskey, Damon V. -// 2018-05-12 -// -// Return true if target is within Base range -// of entity's animation. -bool check_range_target_base(const entity *acting_entity, const entity *target, const s_anim *animation, int64_t range_min, int64_t range_max) -{ - int ent_base; - int target_base; - - s_metric_range range; - - // Must have a target. - if(!acting_entity || !target) - { - return false; - } - - range.max = range_max; - range.min = range_min; - - if (animation) - { - range.max += animation->range.base.max; - range.min += animation->range.base.min; - } - - // Get positions cast as integers. - ent_base = (int)acting_entity->base; - target_base = (int)target->base; - - // Subtract entity Base position from target position. - target_base -= ent_base; - - // Return true if final target location is - // within range min and max. - return (target_base >= range.min - && target_base <= range.max) ? true : false; -} - -// Caskey, Damon V. -// 2018-05-10 -// -// Return true if target is within X range -// of entity's animation. -bool check_range_target_x(const entity *acting_entity, const entity *target, const s_anim *animation, int64_t range_min, int64_t range_max) -{ - // Must have entities. - if(!acting_entity || !target) - { - return false; - } - - // Get positions cast as integers. - const int ent_x = (int)acting_entity->position.x; - const int target_x = (int)target->position.x; - - s_metric_range range; - - range.max = range_max; - range.min = range_min; - - if (animation) - { - range.max += animation->range.x.max; - range.min += animation->range.x.min; - } - - // Return true if final target location is - // within range X min and max. Range comparison - // is reversed when entity faces left. - if(acting_entity->direction == DIRECTION_RIGHT) - { - // Add range to entity X position - // for final X range coordinates. - range.min = ent_x + range.min; - range.max = ent_x + range.max; - - return (target_x >= range.min - && target_x <= range.max) ? true : false; - } - else - { - // Subtract range from entity X - // position for final X range coordinates. - range.min = ent_x - range.min; - range.max = ent_x - range.max; - - return (target_x <= range.min - && target_x >= range.max) ? true : false; - } -} - -// Caskey, Damon V. -// 2018-05-10 -// -// Return true if target is within Y range -// of entity's animation. -bool check_range_target_y(const entity *acting_entity, const entity *target, const s_anim *animation, int64_t range_min, int64_t range_max) -{ - // Must have a target. - if(!acting_entity || !target) - { - return false; - } - - s_metric_range range; - - range.max = range_max; - range.min = range_min; - - if (animation) - { - range.max += animation->range.y.max; - range.min += animation->range.y.min; - } - - // Get positions cast as integers. - const int ent_y = (int)acting_entity->position.y; - const int target_y = (int)target->position.y - ent_y; - - // Return true if final target location is - // within range min and max. - return (target_y >= range.min - && target_y <= range.max) ? true : false; -} - -// Caskey, Damon V. -// 2018-05-12 -// -// Return true if target is within Z range -// of entity's animation. -bool check_range_target_z(const entity * acting_entity, const entity *target, const s_anim *animation, int64_t range_min, int64_t range_max) -{ - // Must have a target. - if(!acting_entity || !target) - { - return false; - } - - s_metric_range range; - - range.min = range_min; - range.max = range_max; - - if (animation) - { - range.max += animation->range.z.max; - range.min += animation->range.z.min; - } - - // Get positions cast as integers. - const int ent_z = (int)acting_entity->position.z; - const int target_z = (int)target->position.z - ent_z; - - // Return true if final target location is - // within range min and max. - return (target_z >= range.min - && target_z <= range.max) ? true : false; -} - -int check_special() -{ - entity *e; - if((!level->nospecial || level->nospecial == 3) && validanim(self, ANI_SPECIAL) && - (check_energy(ENERGY_TYPE_HP, ANI_SPECIAL) || check_energy(ENERGY_TYPE_MP, ANI_SPECIAL)) - ) - { - self->takeaction = common_attack_proc; - set_attacking(self); - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - - e = self->link; - if(e) - { - e->takeaction = NULL; - ent_unlink(self); - set_idle(e); - } - - if(self->modeldata.smartbomb && !self->modeldata.dofreeze) - { - smart_bomb(self, self->modeldata.smartbomb); // do smartbomb immediately if it doesn't freeze screen - } - - self->running = RUN_STATE_NONE; // If special is executed while running, ceases to run - self->velocity.x = self->velocity.z = 0; - ent_set_anim(self, ANI_SPECIAL, 0); - - if(self->modeldata.dofreeze) - { - smartbomber = self; // Freezes the animations of all enemies/players while special is executed - } - - // Kratus (10-2021) Now the "infinite health cheat" affects players only, not enemies or npc - // And now the "infinite health cheat" will only work when the cost is HEALTH, will not work when the cost is MP anymore - if(self->modeldata.type & TYPE_PLAYER) - { - if(!nocost) - { - if(!(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE)) - { - if(self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, ANI_SPECIAL)) - { - self->energy_state.mp_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - else - { - self->energy_state.health_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - } - } - else - { - if(self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, ANI_SPECIAL)) - { - self->energy_state.mp_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - } - } - } - } - else - { - if(!nocost) - { - if(self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, ANI_SPECIAL)) - { - self->energy_state.mp_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - else - { - self->energy_state.health_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - } - } - } - return 1; - } - return 0; -} - -// Check keys for special move. Used several times, so I func'd it. -// Kratus (10-2021) Added new flags to use with another ATTACK# keys as an new alternative -int player_check_special() -{ - key_mask_t thekey = 0; - key_mask_t player_keys = player[self->playerindex].playkeys; - - switch (global_config.ajspecial) - { - case AJSPECIAL_KEY_SPECIAL: - - if (player_keys & FLAG_SPECIAL) - { - thekey = FLAG_SPECIAL; - } - - break; - - case AJSPECIAL_KEY_DOUBLE: - - if (!validanim(self, ANI_BLOCK) && player_keys & FLAG_SPECIAL) - { - thekey = FLAG_SPECIAL; - } - else if (player_keys & FLAG_JUMP && player_keys & FLAG_ATTACK) - { - thekey = FLAG_JUMP | FLAG_ATTACK; - } - break; - - case AJSPECIAL_KEY_ATTACK2: - - if (player_keys & FLAG_ATTACK2) - { - thekey = FLAG_ATTACK2; - } - break; - - case AJSPECIAL_KEY_ATTACK3: - - if (player_keys & FLAG_ATTACK3) - { - thekey = FLAG_ATTACK3; - } - break; - - case AJSPECIAL_KEY_ATTACK4: - - if (player_keys & FLAG_ATTACK4) - { - thekey = FLAG_ATTACK4; - } - break; - - default: - thekey = 0; - } - - if (!thekey) - { - return 0; - } - - if(check_special()) - { - self->stalltime = 0; - player[self->playerindex].playkeys &= ~thekey; - return 1; - } - else - { - return 0; - } -} - - -void common_land() -{ - self->velocity.x = self->velocity.z = 0; - if(self->animating) - { - return; - } - - self->takeaction = NULL; - set_idle(self); -} - - -//animal run when you lost it 3 times by tails -void runanimal() -{ - common_walk_anim(self); - //ent_set_anim(self, ANI_WALK, 0); - - if(self->position.x < advancex - 80 || self->position.x > advancex + (videomodes.hRes + 80)) - { - kill_entity(self, KILL_ENTITY_TRIGGER_ANIMAL_RUN_OUT_OF_BOUNDS); - return; - } - - if(self->direction == DIRECTION_RIGHT) - { - self->position.x += self->modeldata.speed.x; - } - else - { - self->position.x -= self->modeldata.speed.x; - } -} - - -void player_blink() -{ - self->blink = 1; - if(_time >= self->stalltime) - { - player_die(); - } -} - - -void common_grabattack() -{ - if(self->animating) - { - return; - } - - self->attacking = ATTACKING_NONE; - - if(!(self->combostep[0] || self->combostep[1] || - self->combostep[2] || self->combostep[3] || - self->combostep[4])) - { - ent_unlink(self); - } - - if(self->link) - { - self->takeaction = common_grab; - self->link->takeaction = common_grabbed; - self->attacking = ATTACKING_NONE; - ent_set_anim(self, ANI_GRAB, 0); - set_pain(self->link, -1, 0); - update_frame(self, self->animation->numframes - 1); - update_frame(self->link, self->link->animation->numframes - 1); - } - else - { - self->takeaction = NULL; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - set_idle(self); - } -} - -// Function that causes the player to continue to move up or down until the animation has finished playing -void common_dodge() // New function so players can dodge with up up or down down -{ - if(self->animating) // Continues to move as long as the player is animating - { - return; - } - else // Once done animating, returns to thinking - { - self->takeaction = NULL; - self->velocity.x = self->velocity.z = 0; - set_idle(self); - } -} - - -void common_preduck() -{ - if(self->animating) - { - return; - } - doduck(self); -} - - -void common_idle() -{ - if(self->animating) - { - return; - } - self->takeaction = NULL; - self->attacking = ATTACKING_NONE; - self->idling = IDLING_PREPARED; - common_idle_anim(self); -} - - -void tryduck(entity *ent) -{ - ent->running = RUN_STATE_NONE; - if(validanim(ent, ANI_DUCKING)) - { - ent->takeaction = common_preduck; - ent->velocity.x = ent->velocity.z = 0; - ent->ducking = DUCK_PREPARED; - ent->idling = IDLING_NONE; - ent_set_anim(ent, ANI_DUCKING, 0); - } - else - { - doduck(ent); - } -} - - -void tryduckrise(entity *ent) -{ - ent->running = RUN_STATE_NONE; - if(validanim(ent, ANI_DUCKRISE)) - { - ent->takeaction = common_idle; - ent->velocity.x = ent->velocity.z = 0; - ent->ducking = DUCK_RISE; - ent->idling = IDLING_NONE; - ent_set_anim(ent, ANI_DUCKRISE, 0); - } - else - { - ent->takeaction = NULL; - ent->idling = IDLING_PREPARED; - common_idle_anim(self); - } -} - - -void doduck(entity *ent) -{ - ent->takeaction = NULL; - ent->velocity.x = ent->velocity.z = 0; - ent->ducking = DUCK_ACTIVE; - ent->idling |= IDLING_PREPARED; - ent_set_anim(ent, ANI_DUCK, 0); -} - - -void common_prejump() -{ - if(self->animating) - { - return; - } - dojump(self->jump.velocity.y, self->jump.velocity.x, self->jump.velocity.z, self->jump.animation_id); -} - - -void tryjump(float jumpv, float jumpx, float jumpz, animation_id_t animation_id) -{ - self->jump.velocity.y = jumpv; - self->jump.velocity.x = jumpx; - self->jump.velocity.z = jumpz; - self->jump.animation_id = animation_id; - - self->ducking = DUCK_NONE; - if(validanim(self, ANI_JUMPDELAY)) - { - self->takeaction = common_prejump; - self->velocity.x = self->velocity.z = 0; - - self->idling = IDLING_NONE; - ent_set_anim(self, ANI_JUMPDELAY, 0); - } - else - { - dojump(jumpv, jumpx, jumpz, animation_id); - } -} - - -void dojump(float jumpv, float jumpx, float jumpz, animation_id_t animation_id) -{ - entity *dust; - - self->takeaction = common_jump; - - if(global_sample_list.jump >= 0) - { - sound_play_sample(global_sample_list.jump, 0, savedata.effectvol, savedata.effectvol, 100); - } - - //Spawn jumpstart dust. - if(self->modeldata.dust.jump_start >= 0) - { - dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.jump_start, NULL); - if(dust) - { - dust->spawntype = SPAWN_TYPE_DUST_JUMP; - dust->base = self->position.y; - dust->autokill |= AUTOKILL_ANIMATION_COMPLETE; - execute_onspawn_script(dust); - } - } - - set_jumping(self); - - toss(self, jumpv); - - if(self->direction == DIRECTION_LEFT) - { - self->velocity.x = -jumpx; - } - else - { - self->velocity.x = jumpx; - } - - self->velocity.z = jumpz; - ent_set_anim(self, animation_id, 0); -} - -// Function created to combine the action taken if either picking up an item, or running into an item that is a -// SUBTYPE_TOUCH, executing the appropriate action based on which type of item is picked up -void didfind_item(entity *other) -{ - // Function that takes care of items when picked up - set_opponent(self, other); - - /* - * Legacy limited use replenish. - * - * If item has a use_add value and collecting - * entity has a limited use weapon, we add - * use_add to uses remaining. - */ - - if(other->modeldata.weapon_properties.use_add) - { - if(self->weapent && self->weapent->modeldata.weapon_properties.weapon_state & WEAPON_STATE_LIMITED_USE) - { - self->weapent->modeldata.weapon_properties.use_count += other->modeldata.weapon_properties.use_add; - - if(global_sample_list.get >= 0) - { - sound_play_sample(global_sample_list.get, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else - { - addscore(self->playerindex, other->modeldata.score); - if(global_sample_list.get_2 >= 0) - { - sound_play_sample(global_sample_list.get_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - } - - //end of weapons items section - else if(other->modeldata.score) - { - addscore(self->playerindex, other->modeldata.score); - if(global_sample_list.get_2 >= 0) - { - sound_play_sample(global_sample_list.get_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->energy_state.health_current) - { - self->energy_state.health_current += other->energy_state.health_current; - - if(self->energy_state.health_current > self->modeldata.health) - { - self->energy_state.health_current = self->modeldata.health; - } - - other->energy_state.health_current = 0; - - if(global_sample_list.get >= 0) - { - sound_play_sample(global_sample_list.get, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.mp) - { - self->energy_state.mp_current += other->modeldata.mp; - - if(self->energy_state.mp_current > self->modeldata.mp) - { - self->energy_state.mp_current = self->modeldata.mp; - } - - other->energy_state.mp_current = 0; - sound_play_sample(global_sample_list.get, 0, savedata.effectvol, savedata.effectvol, 100); - } - else if(stricmp(other->modeldata.name, "Time") == 0) - { - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - - if(global_sample_list.get_2 >= 0) - { - sound_play_sample(global_sample_list.get_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.makeinv) - { - // Mar 2, 2005 - New item makes player invincible - self->invincible |= INVINCIBLE_INTANGIBLE; - self->invinctime = _time + ABS(other->modeldata.makeinv); - self->blink = (other->modeldata.makeinv > 0); - - if(global_sample_list.get_2 >= 0) - { - sound_play_sample(global_sample_list.get_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.smartbomb) - { - // Damages everything on the screen - smart_bomb(self, other->modeldata.smartbomb); - - if(global_sample_list.get_2 >= 0) - { - sound_play_sample(global_sample_list.get_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.subtype == SUBTYPE_WEAPON) - { - dropweapon(self, 0); - self->weapent = other; - set_weapon(self, other->modeldata.weapon_properties.weapon_index, 0); - - /* Move to weapon location if it's an "animal". */ - if(self->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL) - { - self->direction = other->direction; - self->position.x = other->position.x; - self->position.z = other->position.z; - } - - if(!(other->modeldata.weapon_properties.weapon_state & WEAPON_STATE_LIMITED_USE) && self->modeldata.weapon_properties.weapon_state & WEAPON_STATE_LIMITED_USE) - { - other->modeldata.weapon_properties.weapon_state |= WEAPON_STATE_LIMITED_USE; - } - - if(global_sample_list.get >= 0) - { - sound_play_sample(global_sample_list.get, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.subtype == SUBTYPE_PROJECTILE) - { - dropweapon(self, 0); - self->weapent = other; - - if(global_sample_list.get >= 0) - { - sound_play_sample(global_sample_list.get, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if(other->modeldata.credit) - { - if(!noshare) - { - credits++; - } - else - { - player[self->playerindex].credits++; - } - - if(global_sample_list.one_up >= 0) - { - sound_play_sample(global_sample_list.one_up, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else - { - // Must be a 1up then. - player[self->playerindex].lives++; - - if(global_sample_list.one_up >= 0) - { - sound_play_sample(global_sample_list.one_up, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - - if(other->modeldata.subtype != SUBTYPE_WEAPON && other->modeldata.subtype != SUBTYPE_PROJECTILE) - { - other->takeaction = suicide; - if(!other->modeldata.instantitemdeath) - { - other->nextthink = _time + global_config.game_speed * 3; - } - } - else - { - if(!(other->nextanim & DELAY_FLAG_INFINITE)) { - other->nextanim = animation_timestamp_add_bounded( - _time, - delay_multiply_bounded( - global_config.game_speed, - UINT64_C(999999) - ) - ); - } - other->nextthink = _time + global_config.game_speed * 999999; - } - other->position.z = ITEM_HIDE_POSITION_Z; -} - -void player_fall_check() -{ - if(autoland != 2 && (player[self->playerindex].keys & (FLAG_MOVEUP | FLAG_JUMP)) == (FLAG_MOVEUP | FLAG_JUMP)) - { - // mark it, so we will play land animation when hit the ground. - self->damage_on_landing.attack_force = ATTACK_FORCE_LAND_COMMAND; - } -} - -void player_grab_check() -{ - entity *other = self->link; - - if(other == NULL || (self->modeldata.grabfinish && self->animating && !self->grabwalking)) - { - return; - } - - if(self->base != other->base) - { - // Change this from ->position.y to ->base - self->takeaction = NULL; - ent_unlink(self); - set_idle(self); - return; - } - - if(player_check_special()) - { - return; - } - - if(!nolost && self->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_GRABBING) - { - dropweapon(self, 1); - } - - // grabturn code - if(self->animation == self->modeldata.animation[ANI_GRABTURN]) - { - // still turning? don't bother with anything else - if(self->animating) - { - return; - } - - // done turning? switch directions and return to grab animation - else - { - if(self->direction == DIRECTION_RIGHT) - { - self->direction = DIRECTION_LEFT; - other->direction = DIRECTION_RIGHT; - } - else - { - self->direction = DIRECTION_RIGHT; - other->direction = DIRECTION_LEFT; - } - other->position.x = self->position.x + (((self->direction * 2) - 1) * self->modeldata.grabdistance); - ent_set_anim(self, ANI_GRAB, 0); - set_pain(other, -1, 0); - update_frame(self, self->animation->numframes - 1); - update_frame(other, other->animation->numframes - 1); - } - } - - self->attacking = ATTACKING_NONE; //for checking - self->grabwalking = 0; - - // Move key opposite vs. dicretion? - if(self->direction == DIRECTION_RIGHT ? (player[self->playerindex].keys & FLAG_MOVELEFT) : (player[self->playerindex].keys & FLAG_MOVERIGHT)) - { - // initiating grabturn - if(self->modeldata.grabturn) - { - // start animation if it exists... - if(validanim(self, ANI_GRABTURN)) - { - ent_set_anim(self, ANI_GRABTURN, 0); - if(validanim(other, ANI_GRABBEDTURN)) - { - ent_set_anim(other, ANI_GRABBEDTURN, 0); - } - else if(validanim(other, ANI_GRABBED)) - { - ent_set_anim(other, ANI_GRABBED, 0); - } - else - { - if ( ((!other->direction && self->position.x > other->position.x) || (other->direction && self->position.x < other->position.x)) && validanim(other, ANI_BACKPAIN) ) ent_set_anim(other, ANI_BACKPAIN, 0); - else ent_set_anim(other, ANI_PAIN, 0); - } - other->velocity.x = other->velocity.z = self->velocity.x = self->velocity.z = 0; - other->position.x = self->position.x; - return; - } - - // otherwise, just turn around - else - { - if(self->direction == DIRECTION_RIGHT) - { - self->direction = DIRECTION_LEFT; - other->direction = DIRECTION_RIGHT; - } - else - { - self->direction = DIRECTION_RIGHT; - other->direction = DIRECTION_LEFT; - } - ent_set_anim(self, ANI_GRAB, 0); - set_pain(other, -1, 0); - update_frame(self, self->animation->numframes - 1); - update_frame(other, other->animation->numframes - 1); - other->position.x = self->position.x + (((self->direction * 2) - 1) * self->modeldata.grabdistance); - } - } - else if(!validanim(self, ANI_GRABWALK) && _time > self->releasetime) - { - // Release - self->takeaction = NULL; - ent_unlink(self); - set_idle(self); - return; - } - } - else - { - self->releasetime = _time + (global_config.game_speed / 2); - } - - if((player[self->playerindex].playkeys & FLAG_ATTACK) && - (self->direction ? - (player[self->playerindex].keys & FLAG_MOVELEFT) : - (player[self->playerindex].keys & FLAG_MOVERIGHT))) - { - player[self->playerindex].playkeys -= FLAG_ATTACK; - if(validanim(self, ANI_GRABBACKWARD)) - { - dograbattack(GRAB_ACTION_SELECT_BACKWARD); - } - else if(validanim(self, ANI_THROW)) - { - if(self->modeldata.throwframewait >= 0) - { - doprethrow(); - } - else - { - dothrow(); - } - } - else - { - dograbattack(GRAB_ACTION_SELECT_ATTACK); - } - } - // grab forward - else if((player[self->playerindex].playkeys & FLAG_ATTACK) && - validanim(self, ANI_GRABFORWARD) && - (!self->direction ? - (player[self->playerindex].keys & FLAG_MOVELEFT) : - (player[self->playerindex].keys & FLAG_MOVERIGHT))) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - dograbattack(GRAB_ACTION_SELECT_FORWARD); - } - // grab up - else if((player[self->playerindex].playkeys & FLAG_ATTACK) && - validanim(self, ANI_GRABUP) && (player[self->playerindex].keys & FLAG_MOVEUP)) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - dograbattack(GRAB_ACTION_SELECT_UP); - } - // grab down - else if((player[self->playerindex].playkeys & FLAG_ATTACK) && - validanim(self, ANI_GRABDOWN) && (player[self->playerindex].keys & FLAG_MOVEDOWN)) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - dograbattack(GRAB_ACTION_SELECT_DOWN); - } - // normal grab attack - else if((player[self->playerindex].playkeys & FLAG_ATTACK) && validanim(self, ANI_GRABATTACK)) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - dograbattack(GRAB_ACTION_SELECT_ATTACK); - } - // Kratus (10-2021) Added the vault animation - else if(player[self->playerindex].playkeys & FLAG_JUMP && validanim(self, ANI_VAULT)) - { - // Kratus (07-2022) Fixed the "3-vaults" loop bug, now will execute once as intended - // Kratus (01-2023) Fixed an issue where grabattack2 animation nullifies vault if both are declared - // Kratus (01-2023) Added some native behaviours - player[self->playerindex].playkeys &= ~FLAG_JUMP; - self->attacking = ATTACKING_ACTIVE; - self->takeaction = common_grabattack; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - ent_set_anim(self, ANI_VAULT, 0); - } - // grab attack finisher - else if(player[self->playerindex].playkeys & (FLAG_ATTACK | FLAG_JUMP)) - { - player[self->playerindex].playkeys &= ~(FLAG_ATTACK | FLAG_JUMP); - - // Perform final blow - if(validanim(self, ANI_GRABATTACK2) || validanim(self, ANI_ATTACK3)) - { - dograbattack(GRAB_ACTION_SELECT_FINISH); - } - else - { - self->attacking = ATTACKING_ACTIVE; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - self->takeaction = common_grabattack; - tryjump(self->modeldata.jumpheight, self->modeldata.jumpspeed, 0, ANI_JUMP); - } - } - - // grab walk code - else if(validanim(self, ANI_GRABWALK) // check if grabwalk animation exists - - // if entity is still animating anything besides a grabwalk variant, don't let them move - && (!self->animating || self->animation == self->modeldata.animation[ANI_GRABWALK] - || self->animation == self->modeldata.animation[ANI_GRABWALKUP] - || self->animation == self->modeldata.animation[ANI_GRABWALKDOWN] - || self->animation == self->modeldata.animation[ANI_GRABBACKWALK])) - { - - // z axis movement - if(PLAYER_MIN_Z != PLAYER_MAX_Z) - { - if(player[self->playerindex].keys & FLAG_MOVEUP) - { - if(self->modeldata.grabwalkspeed) - { - self->velocity.z = -self->modeldata.grabwalkspeed / 2; - } - else - { - self->velocity.z = -self->modeldata.speed.x / 2; - } - } - else if(player[self->playerindex].keys & FLAG_MOVEDOWN) - { - if(self->modeldata.grabwalkspeed) - { - self->velocity.z = self->modeldata.grabwalkspeed / 2; - } - else - { - self->velocity.z = self->modeldata.speed.x / 2; - } - } - else if(!(player[self->playerindex].keys & (FLAG_MOVEUP | FLAG_MOVEDOWN))) - { - self->velocity.z = 0; - } - } - - // x axis movement - if(player[self->playerindex].keys & FLAG_MOVELEFT) - { - if(self->modeldata.grabwalkspeed) - { - self->velocity.x = -self->modeldata.grabwalkspeed; - } - else - { - self->velocity.x = -self->modeldata.speed.x; - } - } - - else if(player[self->playerindex].keys & FLAG_MOVERIGHT) - { - if(self->modeldata.grabwalkspeed) - { - self->velocity.x = self->modeldata.grabwalkspeed; - } - else - { - self->velocity.x = self->modeldata.speed.x; - } - } - else if(!((player[self->playerindex].keys & FLAG_MOVELEFT) || (player[self->playerindex].keys & FLAG_MOVERIGHT)) ) - { - self->velocity.x = 0; - } - - // setting the animations based on the velocity set above - if(self->velocity.x || self->velocity.z) - { - if(((self->velocity.x > 0 && self->direction == DIRECTION_LEFT) || (self->velocity.x < 0 && self->direction == DIRECTION_RIGHT)) && validanim(self, ANI_GRABBACKWALK)) - { - ent_set_anim(self, ANI_GRABBACKWALK, 0); - } - else if(self->velocity.z < 0 && validanim(self, ANI_GRABWALKUP)) - { - ent_set_anim(self, ANI_GRABWALKUP, 0); - } - else if(self->velocity.z > 0 && validanim(self, ANI_GRABWALKDOWN)) - { - ent_set_anim(self, ANI_GRABWALKDOWN, 0); - } - else - { - ent_set_anim(self, ANI_GRABWALK, 0); - } - if(self->animation == self->modeldata.animation[ANI_GRABWALKUP] && validanim(other, ANI_GRABBEDWALKUP)) - { - ent_set_anim(other, ANI_GRABBEDWALKUP, 0); - } - else if(self->animation == self->modeldata.animation[ANI_GRABWALKDOWN] && validanim(other, ANI_GRABBEDWALKDOWN)) - { - ent_set_anim(other, ANI_GRABBEDWALKDOWN, 0); - } - else if(self->animation == self->modeldata.animation[ANI_GRABBACKWALK] && validanim(other, ANI_GRABBEDBACKWALK)) - { - ent_set_anim(other, ANI_GRABBEDBACKWALK, 0); - } - else if(validanim(other, ANI_GRABBEDWALK)) - { - ent_set_anim(other, ANI_GRABBEDWALK, 0); - } - else if (validanim(other, ANI_GRABBED)) - { - ent_set_anim(other, ANI_GRABBED, 0); - } - else - { - ent_set_anim(other, ANI_PAIN, 0); - } - } - else - { - ent_set_anim(self, ANI_GRAB, 0); - if (validanim(other, ANI_GRABBED)) - { - ent_set_anim(other, ANI_GRABBED, 0); - } - else - { - ent_set_anim(other, ANI_PAIN, 0); - } - } - // use check_link_move to set velocity, don't change it here - other->velocity.z = other->velocity.x = 0; - self->grabwalking = 1; - } - - if(self->attacking != ATTACKING_NONE) - { - self->releasetime = _time + (global_config.game_speed / 2); // reset releasetime when do collision - } -} - -void player_walkoff_check() -{ - /* - * Turn. - */ - if(self->modeldata.air_control & AIR_CONTROL_WALKOFF_TURN) - { - if((player[self->playerindex].keys & FLAG_MOVELEFT)) - { - self->direction = DIRECTION_LEFT; - } - else if((player[self->playerindex].keys & FLAG_MOVERIGHT)) - { - self->direction = DIRECTION_RIGHT; - } - } - - /* - * X stop. If not holding a Left or - * Right key, kill horizontal momentum. - */ - if (self->modeldata.air_control & AIR_CONTROL_WALKOFF_X_STOP) - { - if (!(player[self->playerindex].keys & (FLAG_MOVELEFT | FLAG_MOVERIGHT))) - { - if (self->velocity.x != 0) - { - self->velocity.x *= AIR_CONTROL_STOP_FACTOR; - } - } - } - - /* - * Z stop. If not holding an Up or - * Down key, kill lateral momentum. - */ - if (self->modeldata.air_control & AIR_CONTROL_WALKOFF_Z_STOP) - { - if (!(player[self->playerindex].keys & (FLAG_MOVEUP | FLAG_MOVEDOWN))) - { - if (self->velocity.z != 0) - { - self->velocity.z *= AIR_CONTROL_STOP_FACTOR; - } - } - } - - /* Horizontal move control (if already moving). */ - if(self->modeldata.air_control & AIR_CONTROL_WALKOFF_X_ADJUST) //move? - { - if(((player[self->playerindex].keys & FLAG_MOVELEFT) && self->velocity.x > 0) || - ((player[self->playerindex].keys & FLAG_MOVERIGHT) && self->velocity.x < 0)) - { - self->velocity.x = -self->velocity.x; - } - } - - /* Horizontal move control (any walkoff). */ - if(self->modeldata.air_control & AIR_CONTROL_WALKOFF_X_MOVE) - { - if(((player[self->playerindex].keys & FLAG_MOVELEFT) && self->velocity.x > 0) || - ((player[self->playerindex].keys & FLAG_MOVERIGHT) && self->velocity.x < 0)) - { - self->velocity.x = -self->velocity.x; - } - - if((player[self->playerindex].keys & FLAG_MOVELEFT) && (!self->velocity.x)) - { - self->velocity.x -= self->modeldata.speed.x; - } - else if((player[self->playerindex].keys & FLAG_MOVERIGHT) && (!self->velocity.x)) - { - self->velocity.x = self->modeldata.speed.x; - } - } - - /* Z move control (if already moving). */ - if(self->modeldata.air_control & AIR_CONTROL_WALKOFF_Z_ADJUST) - { - if(((player[self->playerindex].keys & FLAG_MOVEUP) && self->velocity.z > 0) || - ((player[self->playerindex].keys & FLAG_MOVEDOWN) && self->velocity.z < 0)) - { - self->velocity.z = -self->velocity.z; - } - } - - /* Z move control (any walkoff). */ - if(self->modeldata.air_control & AIR_CONTROL_WALKOFF_Z_MOVE) - { - if((player[self->playerindex].keys & FLAG_MOVEUP) && (!self->velocity.z)) - { - self->velocity.z -= (0.5 * self->modeldata.speed.x); - } - else if((player[self->playerindex].keys & FLAG_MOVEDOWN) && (!self->velocity.z)) - { - self->velocity.z = (0.5 * self->modeldata.speed.x); - } - } - - return; -} - -void player_jump_check() -{ - int candospecial = 0; - - // Kratus (10-2021) Fixed the noaircancel function - // Now the flag "2" works as intended and completely disables the cancelation between all jumping attacks - // In the previous code, both flags 1 and 2 have the same effect and allow the cancelation after last jumpattack is finished - if((!noaircancel) || (noaircancel&1 && !self->animating) || (noaircancel&3 && (self->animnum == self->jump.animation_id))) - { - //air special, copied and changed from Fugue's code - if((!level->nospecial || level->nospecial == 3) && player[self->playerindex].playkeys & FLAG_SPECIAL) - { - if(validanim(self, ANI_JUMPSPECIAL)) - { - // Kratus (10-2021) For safe, added an new step to check if the entity is not in the "jumpspecial" animation - // Fixes the bug that constantly consumes health or mp if the special button is constantly pressed, even if - // the current "jumpspecial" animation cycle is not finished yet - if(self->animnum != ANI_JUMPSPECIAL) - { - if(self->modeldata.animation[ANI_JUMPSPECIAL]->energy_cost.cost && check_energy(ENERGY_TYPE_MP, ANI_JUMPSPECIAL)) - { - // Kratus (10-2021) Now the "infinite health cheat" will only work when the cost is HEALTH, will not work when the cost is MP anymore - self->energy_state.mp_current -= self->modeldata.animation[ANI_JUMPSPECIAL]->energy_cost.cost; - candospecial = 1; - } - else if(self->modeldata.animation[ANI_JUMPSPECIAL]->energy_cost.cost && check_energy(ENERGY_TYPE_HP, ANI_JUMPSPECIAL)) - { - if(!(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE)) - { - self->energy_state.health_current -= self->modeldata.animation[ANI_JUMPSPECIAL]->energy_cost.cost; - } - candospecial = 1; - } - else if(validanim(self, ANI_JUMPCANT)) - { - ent_set_anim(self, ANI_JUMPCANT, 0); - self->velocity.y = 0; - } - } - - if(candospecial) - { - player[self->playerindex].playkeys &= ~FLAG_SPECIAL; - self->attacking = ATTACKING_ACTIVE; - - // Kratus (10-2021) Add a option to kill or not the xyz movement - // Kratus (04-2022) Minor fix on the jumpspecial code - if(!(self->modeldata.jumpspecial & 1)) - { - self->velocity.x = self->velocity.z = 0; // Kill movement when the special starts - self->velocity.y = 0; - } - - ent_set_anim(self, ANI_JUMPSPECIAL, 0); - } - } - }//end of jumpspecial - - //jumpattacks, up down forward normal....we don't check energy cost - else if(player[self->playerindex].playkeys & FLAG_ATTACK) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - self->attacking = ATTACKING_ACTIVE; - - if((player[self->playerindex].keys & FLAG_MOVEDOWN) && validanim(self, ANI_JUMPATTACK2)) - { - ent_set_anim(self, ANI_JUMPATTACK2, 0); - } - else if((player[self->playerindex].keys & FLAG_MOVEUP) && validanim(self, ANI_JUMPATTACK3)) - { - ent_set_anim(self, ANI_JUMPATTACK3, 0); - } - else if(self->running && validanim(self, ANI_RUNJUMPATTACK)) - { - ent_set_anim(self, ANI_RUNJUMPATTACK, 0); // Added so an extra strong jump attack can be executed - } - else if(self->velocity.x != 0 && validanim(self, ANI_JUMPFORWARD)) - { - ent_set_anim(self, ANI_JUMPFORWARD, 0); // If moving and set, do this attack - } - else if(validanim(self, ANI_JUMPATTACK)) - { - ent_set_anim(self, ANI_JUMPATTACK, 0); - } - }//end of jumpattack - } - - /* - * Jump height control. Stop rising if jump - * key is inactive. - */ - if (self->modeldata.air_control & AIR_CONTROL_JUMP_Y_STOP) - { - if (!(player[self->playerindex].keys & FLAG_JUMP)) - { - if (self->velocity.y > 0) - { - self->velocity.y *= AIR_CONTROL_STOP_FACTOR; - } - } - } - - /* - * Jump X stop. If not holding a Left or - * Right key, kill horizontal momentum. - */ - if (self->modeldata.air_control & AIR_CONTROL_JUMP_X_STOP) - { - if (!(player[self->playerindex].keys & (FLAG_MOVELEFT | FLAG_MOVERIGHT))) - { - if (self->velocity.x != 0) - { - self->velocity.x *= AIR_CONTROL_STOP_FACTOR; - } - } - } - - /* - * Jump Z stop. If not holding an Up or - * Down key, kill lateral momentum. - */ - if (self->modeldata.air_control & AIR_CONTROL_JUMP_Z_STOP) - { - if (!(player[self->playerindex].keys & (FLAG_MOVEUP | FLAG_MOVEDOWN))) - { - if (self->velocity.z != 0) - { - self->velocity.z *= AIR_CONTROL_STOP_FACTOR; - } - } - } - - /* Jump turn control. */ - if(self->modeldata.air_control & AIR_CONTROL_JUMP_TURN) - { - if((player[self->playerindex].keys & FLAG_MOVELEFT)) - { - self->direction = DIRECTION_LEFT; - } - else if((player[self->playerindex].keys & FLAG_MOVERIGHT)) - { - self->direction = DIRECTION_RIGHT; - } - } - - /* Jump horizontal move control (if already moving). */ - if(self->modeldata.air_control & AIR_CONTROL_JUMP_X_ADJUST) - { - if(((player[self->playerindex].keys & FLAG_MOVELEFT) && self->velocity.x > 0 ) || - ((player[self->playerindex].keys & FLAG_MOVERIGHT) && self->velocity.x < 0)) - { - self->velocity.x = -self->velocity.x; - } - } - - /* Jump horizontal move control (any jump). */ - if(self->modeldata.air_control & AIR_CONTROL_JUMP_X_MOVE) - { - if(((player[self->playerindex].keys & FLAG_MOVELEFT) && self->velocity.x > 0) || - ((player[self->playerindex].keys & FLAG_MOVERIGHT) && self->velocity.x < 0)) - { - self->velocity.x = -self->velocity.x; - } - - if((player[self->playerindex].keys & FLAG_MOVELEFT) && (!self->velocity.x)) - { - self->velocity.x -= self->modeldata.speed.x; - } - else if((player[self->playerindex].keys & FLAG_MOVERIGHT) && (!self->velocity.x)) - { - self->velocity.x = self->modeldata.speed.x; - } - } - - /* Jump Z move control (if already moving). */ - if(self->modeldata.air_control & AIR_CONTROL_JUMP_Z_ADJUST) - { - if(((player[self->playerindex].keys & FLAG_MOVEUP) && self->velocity.z > 0) || - ((player[self->playerindex].keys & FLAG_MOVEDOWN) && self->velocity.z < 0)) - { - self->velocity.z = -self->velocity.z; - } - } - - /* Jump Z move control (any jump). */ - if(self->modeldata.air_control & AIR_CONTROL_JUMP_Z_MOVE) - { - if((player[self->playerindex].keys & FLAG_MOVELEFT)) - { - self->direction = DIRECTION_LEFT; - } - else if((player[self->playerindex].keys & FLAG_MOVERIGHT)) - { - self->direction = DIRECTION_RIGHT; - } - - if(((player[self->playerindex].keys & FLAG_MOVEUP) && self->velocity.z > 0) || - ((player[self->playerindex].keys & FLAG_MOVEDOWN) && self->velocity.z < 0)) - { - self->velocity.z = -self->velocity.z; - } - - if((player[self->playerindex].keys & FLAG_MOVEUP) && (!self->velocity.z)) - { - self->velocity.z -= (0.5 * self->modeldata.speed.x); - } - else if((player[self->playerindex].keys & FLAG_MOVEDOWN) && (!self->velocity.z)) - { - self->velocity.z = (0.5 * self->modeldata.speed.x); - } - } - - return; -} - -void player_pain_check() -{ - if(player_check_special()) - { - self->inpain = IN_PAIN_NONE; - self->rising = RISING_NONE; - self->ducking = DUCK_NONE; - self->inbackpain = 0; - } -} - -// check riseattack input up+attack -void player_lie_check() -{ - if(validanim(self, ANI_RISEATTACK) && - (player[self->playerindex].playkeys & FLAG_ATTACK) && - (player[self->playerindex].keys & FLAG_MOVEUP) && - (self->energy_state.health_current > 0 && _time > self->staydown.riseattack_stall)) - { - player[self->playerindex].playkeys &= ~FLAG_ATTACK; - if((player[self->playerindex].keys & FLAG_MOVELEFT)) - { - self->direction = DIRECTION_LEFT; - } - if((player[self->playerindex].keys & FLAG_MOVERIGHT)) - { - self->direction = DIRECTION_RIGHT; - } - self->stalltime = 0; - set_riseattack(self, self->last_damage_type, 0); - } -} - -void player_charge_check() -{ - if(!((player[self->playerindex].keys & FLAG_JUMP) && - (player[self->playerindex].keys & FLAG_SPECIAL))) - { - self->takeaction = NULL; - self->charging = 0; - set_idle(self); - } -} - -// make a function so enemies can use -// UT: jumphack is a temporary fix for jump cancel -int check_costmove(int s, int fs, int jumphack) -{ - if(((fs == 1 && level->nospecial < 2) || (fs == 0 && level->nospecial == 0) || (fs == 0 && level->nospecial == 3)) && - (check_energy(ENERGY_TYPE_HP, s) || - check_energy(ENERGY_TYPE_MP, s)) ) - { - if(!jumphack) - { - self->takeaction = common_attack_proc; - } - // Kratus (10-2021) Now the "infinite health cheat" affects players only, not enemies or npc - // And now the "infinite health cheat" will only work when the cost is HEALTH, will not work when the cost is MP anymore - if(self->modeldata.type & TYPE_PLAYER) - { - if(!nocost) - { - if(!(global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE)) - { - if(self->modeldata.animation[s]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, s)) - { - self->energy_state.mp_current -= self->modeldata.animation[s]->energy_cost.cost; - } - else - { - self->energy_state.health_current -= self->modeldata.animation[s]->energy_cost.cost; - } - } - } - else - { - if(self->modeldata.animation[s]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, s)) - { - self->energy_state.mp_current -= self->modeldata.animation[s]->energy_cost.cost; - } - } - } - } - } - else - { - if(!nocost) - { - if(self->modeldata.animation[s]->energy_cost.cost) - { - if(check_energy(ENERGY_TYPE_MP, s)) - { - self->energy_state.mp_current -= self->modeldata.animation[s]->energy_cost.cost; - } - else - { - self->energy_state.health_current -= self->modeldata.animation[s]->energy_cost.cost; - } - } - } - } - - self->running = RUN_STATE_NONE; - self->velocity.x = self->velocity.z = 0; - set_attacking(self); - self->inpain = IN_PAIN_NONE; - self->rising = RISING_NONE; - self->inbackpain = 0; - memset(self->combostep, 0, sizeof(*self->combostep) * 5); - ent_unlink(self); - ent_set_anim(self, s, 0); - return 1; - } - return 0; -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Record the starting time for every newly pressed -* command input flag. -* -* Physical and direction-relative flags share the same -* 64-bit namespace. Using the flag's bit index provides -* hold timing without a parallel command-history ring. -*/ -static void command_input_hold_start_update( - s_player* acting_player, - const key_mask_t pressed_flags, - const uint64_t event_time -) { - key_mask_t scan_mask = pressed_flags; - - while(scan_mask) { - const uint64_t input_index = - bitmask64_get_lowest_index(scan_mask); - - const key_mask_t input_flag = - bitmask64_from_index(input_index); - - acting_player->command_input_hold_start_time[ - input_index - ] = event_time; - - acting_player->command_input_hold_start_valid |= - input_flag; - - /* - * A new press begins a new continuous hold. Clear - * the automatic-trigger record so time zero can - * trigger again for the new hold. - */ - acting_player->command_input_hold_trigger_valid &= - ~input_flag; - - scan_mask &= ~input_flag; - } -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Collect automatic held-input edges which reach their -* configured threshold on this logical tick. -* -* Thresholds come from the acting entity's configurable -* special commands. A per-input timestamp prevents a -* second input refresh during the same tick from emitting -* the same edge again. Different thresholds for the same -* input remain independent because each is reached on a -* different logical tick during one continuous hold. -*/ -static key_mask_t command_input_hold_trigger_collect( - s_player* acting_player, - const key_mask_t held_flags, - const uint64_t event_time -) { - const entity* acting_entity; - - key_mask_t collected_flags = 0; - - int special_index; - - if(!acting_player || !acting_player->ent) { - return 0; - } - - acting_entity = acting_player->ent; - - for(special_index = 0; - special_index < acting_entity->modeldata.specials_loaded; - special_index++) { - - const s_com* special_command = - &acting_entity->modeldata.special[special_index]; - - int step_index; - - if(special_command->steps <= 0 - || special_command->steps > MAX_SPECIAL_INPUTS) { - continue; - } - - for(step_index = 0; - step_index < special_command->steps; - step_index++) { - - const s_command_input_step* input_step = - &special_command->input[step_index]; - - key_mask_t scan_mask = - input_step->hold_trigger & held_flags; - - while(scan_mask) { - const uint64_t input_index = - bitmask64_get_lowest_index(scan_mask); - - const key_mask_t input_flag = - bitmask64_from_index(input_index); - - const uint64_t hold_start_time = - acting_player->command_input_hold_start_time[ - input_index - ]; - - const bool already_emitted_this_tick = - (acting_player->command_input_hold_trigger_valid - & input_flag) - && acting_player->command_input_hold_trigger_time[ - input_index - ] == event_time; - - if((acting_player->command_input_hold_start_valid - & input_flag) - && hold_start_time <= event_time - && event_time - hold_start_time - == input_step->hold_time - && !already_emitted_this_tick) { - - collected_flags |= input_flag; - } - - scan_mask &= ~input_flag; - } - } - } - - /* - * Record emitted flags only after scanning every - * command. Commands sharing the same input and - * threshold deliberately share one history edge. - */ - { - key_mask_t scan_mask = collected_flags; - - while(scan_mask) { - const uint64_t input_index = - bitmask64_get_lowest_index(scan_mask); - - const key_mask_t input_flag = - bitmask64_from_index(input_index); - - acting_player->command_input_hold_trigger_time[ - input_index - ] = event_time; - - acting_player->command_input_hold_trigger_valid |= - input_flag; - - scan_mask &= ~input_flag; - } - } - - return collected_flags; -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Append one event to a player's command history. -*/ -static void command_input_history_push(s_player* acting_player, const s_command_input_event* input_event) { - - acting_player->command_input_history[acting_player->command_input_index] = *input_event; - - acting_player->command_input_index = (acting_player->command_input_index + 1) & SPECIAL_INPUT_INDEX_MASK; - - if(acting_player->command_input_count < MAX_SPECIAL_INPUTS) { - acting_player->command_input_count++; - } -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Consume the newest press edge from a player's command -* history. -* -* Several hard-coded movement commands consume their -* triggering press. A combined event may also contain a -* release or automatic hold edge, so only remove the -* complete entry when no other edge remains. -*/ -static void command_input_history_consume_latest_press( - s_player* acting_player -) { - s_command_input_event* input_event; - - uint64_t input_index; - - if(!acting_player || !acting_player->command_input_count) { - return; - } - - input_index = - (acting_player->command_input_index - 1) - & SPECIAL_INPUT_INDEX_MASK; - - input_event = - &acting_player->command_input_history[ - input_index - ]; - - input_event->press = 0; - input_event->press_chord = 0; - - if(input_event->hold || input_event->release) { - return; - } - - acting_player->command_input_index = input_index; - - memset(input_event, 0, sizeof(*input_event)); - - acting_player->command_input_count--; -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Consume selected automatic held-input flags from the -* event which triggered a configurable command. -* -* Other flags remain available when the same history -* entry also contains a press, release, or another held -* edge. Empty non-latest entries stay in place so ring -* order and stored event ages do not need compaction. -*/ -static void command_input_history_consume_hold_trigger( - s_player* acting_player, - const uint64_t event_age, - const key_mask_t trigger_flags -) { - s_command_input_event* input_event; - - uint64_t input_index; - - if(!acting_player - || !trigger_flags - || event_age >= acting_player->command_input_count) { - return; - } - - input_index = - (acting_player->command_input_index - event_age - 1) - & SPECIAL_INPUT_INDEX_MASK; - - input_event = - &acting_player->command_input_history[input_index]; - - input_event->hold &= ~trigger_flags; - - if(input_event->press - || input_event->hold - || input_event->release - || event_age) { - return; - } - - acting_player->command_input_index = input_index; - - memset(input_event, 0, sizeof(*input_event)); - - acting_player->command_input_count--; -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Read the preceding valid event from a player's -* command history. -*/ -static const s_command_input_event* command_input_history_previous( - const s_player* acting_player, - uint64_t* history_index, - uint64_t* remaining_events -) { - if(!*remaining_events) { - return NULL; - } - - *history_index = - (*history_index - 1) & SPECIAL_INPUT_INDEX_MASK; - - (*remaining_events)--; - - return &acting_player->command_input_history[ - *history_index - ]; -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Read the preceding press event from a player's -* command history. -* -* Non-press entries are skipped so release and timed -* hold events can be added without changing legacy -* hard-coded command behavior. -*/ -static const s_command_input_event* command_input_history_previous_press( - const s_player* acting_player, - uint64_t* history_index, - uint64_t* remaining_events -) { - const s_command_input_event* input_event; - - while((input_event = command_input_history_previous( - acting_player, - history_index, - remaining_events - ))) { - - if(input_event->press) { - return input_event; - } - } - - return NULL; -} - -/* -* Check whether the player's most recent press -* events satisfy a hard-coded command sequence. -* -* Each sequence entry is a bit mask of required -* inputs. A recorded press may contain additional -* flags and still match. -* -* Release and timed hold events are deliberately -* ignored so existing hard-coded commands retain -* their positive-edge behavior. -*/ -static bool match_combo(const key_mask_t sequence[], const s_player* acting_player, const uint64_t length) { - const s_command_input_event* input_event; - - uint64_t history_index; - uint64_t newer_event_time; - uint64_t remaining_events; - uint64_t sequence_index; - - if(!sequence - || !acting_player - || !length - || length > MAX_SPECIAL_INPUTS) { - return false; - } - - history_index = acting_player->command_input_index; - newer_event_time = _time; - remaining_events = acting_player->command_input_count; - - for(sequence_index = length; - sequence_index > 0; - sequence_index--) { - - const key_mask_t required_press = - sequence[sequence_index - 1]; - - input_event = command_input_history_previous_press( - acting_player, - &history_index, - &remaining_events - ); - - if(!input_event - || (input_event->press & required_press) - != required_press - || newer_event_time - input_event->time - > global_config.command_time) { - return false; - } - - newer_event_time = input_event->time; - } - - return true; -} - -/* -* Return the grace time used by one configurable command -* sequence. Commands without an explicit override inherit -* the engine-wide setting at match time. -*/ -static uint64_t command_sequence_grace_time_get( - const s_com* special_command -) { - assert(special_command); - - return special_command->sequence_grace_time_override - ? special_command->sequence_grace_time - : global_config.command_time; -} - -/* -* Return the longest grace time needed by the acting -* entity's configurable and hard-coded commands. -* -* Input history is shared by every command. Retaining it -* for the longest configured grace prevents a command -* with a longer local override from losing its earlier -* steps to the global history timeout. -*/ -static uint64_t command_input_history_grace_time_get( - const entity* acting_entity -) { - uint64_t history_grace_time = global_config.command_time; - - int special_index; - - if(!acting_entity) { - return history_grace_time; - } - - for(special_index = 0; - special_index < acting_entity->modeldata.specials_loaded; - special_index++) { - - const s_com* special_command = - &acting_entity->modeldata.special[special_index]; - - const uint64_t sequence_grace_time = - command_sequence_grace_time_get(special_command); - - if(sequence_grace_time > history_grace_time) { - history_grace_time = sequence_grace_time; - } - } - - return history_grace_time; -} - -/* -* Return the absolute logical tick when shared command -* history expires. Saturation preserves extremely large -* creator-defined grace values without wrapping the -* expiration time around to the beginning of the clock. -*/ -static uint64_t command_input_history_expiration_time_get( - const entity* acting_entity, - const uint64_t event_time -) { - const uint64_t history_grace_time = - command_input_history_grace_time_get(acting_entity); - - if(history_grace_time > UINT64_MAX - event_time) { - return UINT64_MAX; - } - - return event_time + history_grace_time; -} - -/* -* Return whether an input event satisfies the positive -* edge requirement for one configurable command step. -* -* Single-key steps retain exact legacy behavior and use -* only the physical press edge. Multi-key steps use the -* chord snapshot and their configured chord_time. Zero -* requires every member to begin on the same logical tick. -* At least one required key must be physically pressed in -* the triggering event, preventing an unrelated third key -* from retriggering a chord which merely remains held. -*/ -static bool command_input_event_matches_press( - const s_command_input_step* input_step, - const s_command_input_event* input_event, - const s_player* acting_player -) { - const key_mask_t required_press = input_step->press; - - key_mask_t scan_mask; - - if(!required_press) { - return true; - } - - /* - * A mask with one active bit has no second bit after - * removing its lowest bit. - */ - if(!(required_press & (required_press - 1))) { - return (input_event->press & required_press) - == required_press; - } - - if(!(input_event->press & required_press) - || (input_event->press_chord & required_press) - != required_press) { - return false; - } - - scan_mask = required_press; - - while(scan_mask) { - const uint64_t input_index = - bitmask64_get_lowest_index(scan_mask); - - const key_mask_t input_flag = - bitmask64_from_index(input_index); - - const uint64_t press_time = - acting_player->command_input_hold_start_time[ - input_index - ]; - - if(!(acting_player->command_input_hold_start_valid - & input_flag) - || press_time > input_event->time - || input_event->time - press_time - > input_step->chord_time) { - return false; - } - - scan_mask &= ~input_flag; - } - - return true; -} - -/* -* Return whether an input event satisfies every passive -* and automatic held requirement for one command step. -*/ -static bool command_input_event_matches_hold( - const s_command_input_step* input_step, - const s_command_input_event* input_event, - const s_player* acting_player -) { - const key_mask_t required_hold_flags = - input_step->hold | input_step->hold_trigger; - - key_mask_t scan_mask; - - if(!required_hold_flags) { - return true; - } - - if((input_event->held & required_hold_flags) - != required_hold_flags) { - return false; - } - - scan_mask = required_hold_flags; - - while(scan_mask) { - const uint64_t input_index = - bitmask64_get_lowest_index(scan_mask); - - const key_mask_t input_flag = - bitmask64_from_index(input_index); - - const uint64_t hold_start_time = - acting_player->command_input_hold_start_time[ - input_index - ]; - - if(!(acting_player->command_input_hold_start_valid - & input_flag) - || hold_start_time > input_event->time) { - return false; - } - - { - const uint64_t held_time = - input_event->time - hold_start_time; - - /* - * Passive holds accept the inclusive minimum - * through the optional inclusive maximum. A - * zero maximum leaves the upper bound open. - * Automatic holds match only their exact - * minimum threshold edge, preventing a later - * threshold for the same key from retriggering - * an earlier automatic command. - */ - if(((input_step->hold & input_flag) - && (held_time < input_step->hold_time - || (input_step->hold_time_maximum - && held_time - > input_step->hold_time_maximum))) - || ((input_step->hold_trigger & input_flag) - && held_time != input_step->hold_time)) { - return false; - } - } - - scan_mask &= ~input_flag; - } - - return true; -} - -/* -* Read the preceding event whose edge type is relevant -* to a configurable command step. -* -* Release-only events do not disturb press-only steps, -* and press-only events do not disturb release-only -* steps. An event of a required type with the wrong key -* is returned so it correctly interrupts the sequence. -*/ -static const s_command_input_event* command_input_history_previous_for_step( - const s_player* acting_player, - const s_command_input_step* input_step, - uint64_t* history_index, - uint64_t* remaining_events -) { - const s_command_input_event* input_event; - - while((input_event = command_input_history_previous( - acting_player, - history_index, - remaining_events - ))) { - - if((input_step->press && input_event->press) - || (input_step->release && input_event->release) - || (input_step->hold_trigger && input_event->hold)) { - return input_event; - } - } - - return NULL; -} - -/* -* Check whether the player's most recent input events -* satisfy a configurable special command. -* -* Press, release, and automatic hold masks are edge -* requirements. Passive hold is a state and minimum -* duration requirement evaluated at the triggering event. -*/ -static bool match_special_command( - const s_command_input_step sequence[], - const s_player* acting_player, - const uint64_t length, - const uint64_t sequence_grace_time, - uint64_t* match_time, - uint64_t* match_age -) { - const s_command_input_event* input_event; - - uint64_t history_index; - uint64_t newer_event_time; - uint64_t remaining_events; - uint64_t sequence_index; - - if(!sequence - || !acting_player - || !match_time - || !match_age - || !length - || length > MAX_SPECIAL_INPUTS) { - return false; - } - - *match_time = 0; - *match_age = UINT64_MAX; - - history_index = acting_player->command_input_index; - newer_event_time = _time; - remaining_events = acting_player->command_input_count; - - for(sequence_index = length; - sequence_index > 0; - sequence_index--) { - - const s_command_input_step* input_step = - &sequence[sequence_index - 1]; - - input_event = command_input_history_previous_for_step( - acting_player, - input_step, - &history_index, - &remaining_events - ); - - if(!input_event - || !command_input_event_matches_press( - input_step, - input_event, - acting_player - ) - || (input_event->release & input_step->release) - != input_step->release - || (input_event->hold & input_step->hold_trigger) - != input_step->hold_trigger - || newer_event_time - input_event->time - > sequence_grace_time - || !command_input_event_matches_hold( - input_step, - input_event, - acting_player - )) { - return false; - } - - if(sequence_index == length) { - *match_time = input_event->time; - *match_age = - acting_player->command_input_count - - remaining_events - 1; - } - - newer_event_time = input_event->time; - } - - return true; -} - -bool check_combo(s_player* acting_player) { - - unsigned int i; - int maxstep = -1; - int maxkeys = -1; - int valid = -1; - - uint64_t min_match_age = UINT64_MAX; - uint64_t max_match_time = 0; - key_mask_t selected_hold_trigger_flags = 0; - - bool match_found = false; - - s_com *com; - - for(i = 0; i < self->modeldata.specials_loaded; i++) { - - com = self->modeldata.special + i; - - if(self->animation->cancel != ANIMATION_CANCEL_DISABLED && - (self->animnum != com->cancel || - com->frame.min > self->animpos || - com->frame.max < self->animpos || - self->animation->hit_count < com->hits)) { - - continue; - - } else if(self->animation->cancel == ANIMATION_CANCEL_DISABLED - && (com->cancel || !player_accepts_idle_input(self) || diff(self->position.y, self->base) > 1)) { - - continue; - } - - { - uint64_t command_match_age; - uint64_t command_match_time; - - const uint64_t sequence_grace_time = - command_sequence_grace_time_get(com); - - if(validanim(self, com->anim) - && (check_energy(ENERGY_TYPE_MP, com->anim) || check_energy(ENERGY_TYPE_HP, com->anim)) - && match_special_command( - com->input, - acting_player, - com->steps, - sequence_grace_time, - &command_match_time, - &command_match_age - )) { - - /* - * Prefer the command triggered by the newest - * input event. Ring age resolves events recorded - * during the same logical tick. Commands sharing - * that event retain the existing longest-sequence, - * then greatest-chord-size ranking. - */ - const bool better_match = - !match_found - || command_match_age < min_match_age - || (command_match_age == min_match_age - && (command_match_time > max_match_time - || (command_match_time == max_match_time - && (com->steps > maxstep - || (com->steps == maxstep - && com->numkeys > maxkeys))))); - - if(!better_match) { - continue; - } - - valid = com->anim; - min_match_age = command_match_age; - max_match_time = command_match_time; - maxstep = com->steps; - maxkeys = com->numkeys; - selected_hold_trigger_flags = - com->input[com->steps - 1].hold_trigger; - match_found = true; - } - } - - } - - if(valid >= 0 && check_costmove(valid, 1, self->jumping)) { - /* - * Automatic held edges are one-shot input events. - * Consume the selected final-step flags only after - * the move starts successfully. Press, release, - * and unrelated automatic flags remain available. - */ - command_input_history_consume_hold_trigger( - acting_player, - min_match_age, - selected_hold_trigger_flags - ); - - return true; - } - - return false; -} - -/* -* Caskey, Damon V. -* 2026-07-26 - Originally written by Fugue (unknown date). -* -* Rework evaluates whether a player -* has a pending command sequence to execute. -*/ -bool player_preinput() { - - s_player *acting_player = player + self->playerindex; - - if(check_combo(acting_player)) { - acting_player->playkeys &= ~FLAG_CONTROLKEYS; - - return true; - } - - return false; -} - - -/* -* Caskey, Damon V. -* 2023-12-29 -* -* Stop running if player -* no longer inputs direction -* that started the run. -*/ -void run_try_runstop_check(entity* acting_entity, const e_RunXDirection movex, const e_RunZDirection movez, const e_RunXDirection running_x, const e_RunZDirection running_z, const int runConfigFlags, const int dashCommandFlag, const int dashFixedFlag, const int enabledFlag, const int stopStateFlag) { - if (!(runConfigFlags & enabledFlag) - || (dashFixedFlag && !acting_entity->animating) - || ((dashCommandFlag && !acting_entity->animating) - || (diff(movex, running_x) && (movez == RUN_DIR_Z_NONE || acting_entity->running & RUN_STATE_START_X)) - || (diff(movez, running_z) && (movex == RUN_DIR_X_NONE || acting_entity->running & RUN_STATE_START_Z)))) { - acting_entity->running = stopStateFlag; - } -} - -/* -* Caskey, Damon V. -* 2023-12-29 -* -* Check player input and run stop -* function if needed. -*/ -void run_try_runstop_player(entity* acting_entity, const s_player* acting_player) -{ - const e_run_state run_state = acting_entity->running; - - if (run_state == RUN_STATE_NONE) - { - return; - } - - /* - * Get player directional input - * from key status. - */ - - const e_RunZDirection movez = (acting_player->keys & FLAG_MOVEUP) ? RUN_DIR_Z_UP : (acting_player->keys & FLAG_MOVEDOWN) ? RUN_DIR_Z_DOWN : RUN_DIR_Z_NONE; - const e_RunXDirection movex = (acting_player->keys & FLAG_MOVELEFT) ? RUN_DIR_X_LEFT : (acting_player->keys & FLAG_MOVERIGHT) ? RUN_DIR_X_RIGHT : RUN_DIR_X_NONE; - - /* - * Get a running direction from - * velocity. - */ - - const e_RunZDirection running_z = run_state ? ((acting_entity->velocity.z < 0) ? RUN_DIR_Z_UP : (acting_entity->velocity.z > 0) ? RUN_DIR_Z_DOWN : RUN_DIR_Z_NONE) : RUN_DIR_Z_NONE; - const e_RunXDirection running_x = run_state ? ((acting_entity->velocity.x < 0) ? RUN_DIR_X_LEFT : (acting_entity->velocity.x > 0) ? RUN_DIR_X_RIGHT : RUN_DIR_X_NONE) : RUN_DIR_X_NONE; - - /* Just for readability below. */ - const e_run_config_flags acting_run_config_flags = acting_entity->modeldata.run_config_flags; - - /* - * Stop running? - * - * 1. X axis direction. - * 2. Able to run in X direction? - * 3. Fixed dash? Fixed dashes stop - * when the animation completes. They - * ignore releasing the key and do not - * stop on a perpendicular axis command - * even if we can't move on the other - * axis. Note the other axis is ignored - * by logic downstream. - * - * 4. Stop on following: - * - No direction command. - * - Direction command opposes current direction. - * - Perpendicular axis command when we don't have the flag enabled. - * - * Repeat check for opposite direction - * and for Z axis. - */ - - switch (running_x) { - case RUN_DIR_X_LEFT: - run_try_runstop_check(acting_entity, movex, movez, running_x, running_z, acting_run_config_flags, RUN_CONFIG_X_LEFT_DASH_COMMAND, RUN_CONFIG_X_LEFT_DASH_FIXED, RUN_CONFIG_X_LEFT_ENABLED, RUN_STATE_NONE); - break; - - case RUN_DIR_X_RIGHT: - run_try_runstop_check(acting_entity, movex, movez, running_x, running_z, acting_run_config_flags, RUN_CONFIG_X_RIGHT_DASH_COMMAND, RUN_CONFIG_X_RIGHT_DASH_FIXED, RUN_CONFIG_X_RIGHT_ENABLED, RUN_STATE_NONE); - break; - - case RUN_DIR_X_NONE: - break; - } - - switch (running_z) { - case RUN_DIR_Z_UP: - run_try_runstop_check(acting_entity, movex, movez, running_x, running_z, acting_run_config_flags, RUN_CONFIG_Z_UP_DASH_COMMAND, RUN_CONFIG_Z_UP_DASH_FIXED, RUN_CONFIG_Z_UP_ENABLED, RUN_STATE_NONE); - break; - - case RUN_DIR_Z_DOWN: - run_try_runstop_check(acting_entity, movex, movez, running_x, running_z, acting_run_config_flags, RUN_CONFIG_Z_DOWN_DASH_COMMAND, RUN_CONFIG_Z_DOWN_DASH_FIXED, RUN_CONFIG_Z_DOWN_ENABLED, RUN_STATE_NONE); - break; - - case RUN_DIR_Z_NONE: - break; - } -} - -/* -* Caskey, Damon V. -* 2026-07-16 -* -* Return true when the entity may -* process ordinary idle-state player -* input. -*/ -bool player_accepts_idle_input(const entity *acting_entity) { - - const s_anim *animation = acting_entity->animation; - - if(acting_entity->idling) { - return true; - } - - if(!animation - || !animation->idle - || animation->numframes <= 0 - || acting_entity->animpos - >= (uint64_t)animation->numframes) { - return false; - } - - return animation->idle[acting_entity->animpos] ? true : false; -} - -void player_think() -{ - typedef enum e_local_action_flags - { - ACTION_NONE, - ACTION_WALK, - ACTION_UP, - ACTION_DOWN, - ACTION_RUN - } e_local_action_flags; - - e_local_action_flags action = 0; - bool back_walk = false; //backwalk - - entity *other = NULL; - float initial_jump_velocity_z = 0.0; - - entity* acting_entity = self; - - const key_mask_t sequence_left_left[] = {FLAG_MOVELEFT, FLAG_MOVELEFT}; - const key_mask_t sequence_right_right[] = {FLAG_MOVERIGHT, FLAG_MOVERIGHT}; - const key_mask_t sequence_up_up[] = {FLAG_MOVEUP, FLAG_MOVEUP}; - const key_mask_t sequence_down_down[] = {FLAG_MOVEDOWN, FLAG_MOVEDOWN}; - - int pli = acting_entity->playerindex; - s_player *acting_player = player + pli; - - if(acting_player->ent != acting_entity || acting_entity->death_state & DEATH_STATE_DEAD) - { - return; - } - - /* - * Are we touching the end level entity? - */ - if((other = find_ent_here(acting_entity, acting_entity->position.x, acting_entity->position.z, TYPE_ENDLEVEL, NULL)) - && diff(acting_entity->position.y, other->position.y) <= 0.1) { - - bool no_player_reached = false; - uint64_t sum_not_reached = 0; - uint64_t sum_reached = 0; - uint64_t i; - - for (i = 0; i < MAX_PLAYERS; i++) { - if (!reached[i]){ - sum_not_reached++; - } - } - no_player_reached = (sum_not_reached >= MAX_PLAYERS) ? true : false; - - if(no_player_reached) { - addscore(pli, other->modeldata.score); - } - reached[pli] = true; - - for (i = 0; i < MAX_PLAYERS; i++) { - sum_reached += reached[i]; - } - - if (!other->modeldata.subtype || (other->modeldata.subtype == SUBTYPE_BOTH && sum_reached >= (count_ents(TYPE_PLAYER)))) { - level_completed = 1; - - if(other->modeldata.branch) { - strncpy( branch_name, other->modeldata.branch, MAX_NAME_LEN); //now, you can branch to another level - } - return; - } - } - - /* - * Reset combo count if time has expired. - */ - if(_time > acting_entity->rush.time) { - acting_entity->rush.count = 0; - acting_entity->rush.time = 0; - } - - if(player_preinput()) { - goto endthinkcheck; - } - - if(acting_entity->charging) { - player_charge_check(); - goto endthinkcheck; - } - - if(acting_entity->inpain & ~IN_PAIN_NONE || (acting_entity->link && !acting_entity->grabbing)) { - player_pain_check(); - goto endthinkcheck; - } - - // falling? check for landing - if(acting_entity->projectile & BLAST_TOSS) { - player_fall_check(); - goto endthinkcheck; - } - - // grab section, dont move if still animating - if(acting_entity->grabbing && acting_entity->attacking == ATTACKING_NONE && acting_entity->takeaction != common_throw_wait) { - player_grab_check(); - goto endthinkcheck; - } - - // jump section - if(acting_entity->jumping) { - player_jump_check(); - goto endthinkcheck; - } - - if(acting_entity->animnum == ANI_WALKOFF) { - player_walkoff_check(); - goto endthinkcheck; - } - - if(acting_entity->drop && acting_entity->position.y == acting_entity->base && !acting_entity->velocity.y) { - player_lie_check(); - goto endthinkcheck; - } - - /* - * Check if player is in a state that allows - * ordinary idle-state input processing. If not, - * skip the rest of the input checks. - */ - if(!player_accepts_idle_input(acting_entity)) { - goto endthinkcheck; - } - - // Check if entity is under a platform - /*if(acting_entity->modeldata.move_config_flags & MOVE_CONFIG_SUBJECT_TO_PLATFORM && (heightvar = acting_entity->animation->size.y ? acting_entity->animation->size.y : acting_entity->modeldata.size.y) && - validanim(acting_entity, ANI_DUCK) && check_platform_between(acting_entity->position.x, acting_entity->position.z, acting_entity->position.y, acting_entity->position.y + heightvar, acting_entity)) - { - acting_entity->idling = IDLING_NONE; - acting_entity->ducking = DUCK_ACTIVE; - acting_entity->takeaction = common_stuck_underneath; - ent_set_anim(acting_entity, ANI_DUCK, 0); - goto endthinkcheck; - }*/ - - const float altdiff = diff(acting_entity->position.y, acting_entity->base); - const bool notinair = (acting_entity->landed_on_platform ? altdiff < 5 : altdiff < 2); - - if(acting_player->playkeys & FLAG_MOVEUP) { - - const bool command_match = (notinair && match_combo(sequence_up_up, acting_player, 2)); - - if(command_match && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_Z_UP_ENABLED | RUN_CONFIG_Z_UP_INITIAL)) == (RUN_CONFIG_Z_UP_ENABLED | RUN_CONFIG_Z_UP_INITIAL) && validanim(acting_entity, ANI_RUN)) { - acting_player->playkeys &= ~FLAG_MOVEUP; - command_input_history_consume_latest_press(acting_player); - acting_entity->running |= RUN_STATE_START_X; // Player begins to run - - } else if(command_match && validanim(acting_entity, ANI_ATTACKUP)) { - - // New u u combo attack - acting_player->playkeys &= ~FLAG_MOVEUP; - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->combostep[0] = 0; - acting_entity->velocity.x = acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_ATTACKUP, 0); - command_input_history_consume_latest_press(acting_player); // this workaround deals default freespecial2 - goto endthinkcheck; - - } else if(command_match && validanim(acting_entity, ANI_DODGE)) { - // New dodge move like on SOR3 - acting_player->playkeys &= ~FLAG_MOVEUP; - acting_entity->takeaction = common_dodge; - acting_entity->combostep[0] = 0; - acting_entity->idling = IDLING_NONE; - acting_entity->velocity.z = -acting_entity->modeldata.speed.x * 1.75; - acting_entity->velocity.x = 0;// OK you can use jumpframe to modify this anyway - ent_set_anim(acting_entity, ANI_DODGE, 0); - command_input_history_consume_latest_press(acting_player); - goto endthinkcheck; - } - } - - if(acting_player->playkeys & FLAG_MOVEDOWN) { - const bool command_match = (notinair && match_combo(sequence_down_down, acting_player, 2)); - - if(command_match && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_DOWN_INITIAL)) == (RUN_CONFIG_Z_DOWN_ENABLED | RUN_CONFIG_Z_DOWN_INITIAL) && validanim(acting_entity, ANI_RUN)) { - acting_player->playkeys &= ~FLAG_MOVEDOWN; - command_input_history_consume_latest_press(acting_player); - acting_entity->running |= RUN_STATE_START_Z; // Player begins to run - - } else if(command_match && validanim(acting_entity, ANI_ATTACKDOWN)) { - // New d d combo attack - acting_player->playkeys &= ~FLAG_MOVEDOWN; - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - ent_set_anim(acting_entity, ANI_ATTACKDOWN, 0); - command_input_history_consume_latest_press(acting_player); - goto endthinkcheck; - - } else if(command_match && validanim(acting_entity, ANI_DODGE)) { - // New dodge move like on SOR3 - acting_player->playkeys &= ~FLAG_MOVEDOWN; - acting_entity->takeaction = common_dodge; - acting_entity->combostep[0] = 0; - acting_entity->idling = IDLING_NONE; - acting_entity->velocity.z = acting_entity->modeldata.speed.x * 1.75; - acting_entity->velocity.x = 0; - ent_set_anim(acting_entity, ANI_DODGE, 0); - command_input_history_consume_latest_press(acting_player); - goto endthinkcheck; - } - } - - if((acting_player->playkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT))) { - - const bool command_match_left = (notinair && (acting_entity->direction == DIRECTION_LEFT && match_combo(sequence_left_left, acting_player, 2))); - const bool command_match_right = (notinair && (acting_entity->direction == DIRECTION_RIGHT && match_combo(sequence_right_right, acting_player, 2))); - const bool command_match_forward = command_match_left || command_match_right; - const bool command_match_back = notinair - && acting_entity->modeldata.facing - && ((acting_entity->direction == DIRECTION_RIGHT && match_combo(sequence_left_left, acting_player, 2)) - || (acting_entity->direction == DIRECTION_LEFT && match_combo(sequence_right_right, acting_player, 2))); - - if (command_match_left && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_X_LEFT_ENABLED | RUN_CONFIG_X_LEFT_INITIAL)) == (RUN_CONFIG_X_LEFT_ENABLED | RUN_CONFIG_X_LEFT_INITIAL) && validanim(acting_entity, ANI_RUN)) { - - acting_player->playkeys &= ~(FLAG_MOVELEFT | FLAG_MOVERIGHT); // usually left + right is not acceptable, so it is OK to null both - command_input_history_consume_latest_press(acting_player); - acting_entity->running |= RUN_STATE_START_X; // Player begins to run - - } else if(command_match_right && (acting_entity->modeldata.run_config_flags & (RUN_CONFIG_X_RIGHT_ENABLED | RUN_CONFIG_X_RIGHT_INITIAL)) == (RUN_CONFIG_X_RIGHT_ENABLED | RUN_CONFIG_X_RIGHT_INITIAL) && validanim(acting_entity, ANI_RUN)) { - - acting_player->playkeys &= ~(FLAG_MOVELEFT | FLAG_MOVERIGHT); // usually left + right is not acceptable, so it is OK to null both - command_input_history_consume_latest_press(acting_player); - acting_entity->running |= RUN_STATE_START_X; // Player begins to run - - } else if(command_match_back && validanim(acting_entity, ANI_BACKRUN)) { - acting_player->playkeys &= ~(FLAG_MOVELEFT | FLAG_MOVERIGHT); // usually left + right is not acceptable, so it is OK to null both - command_input_history_consume_latest_press(acting_player); - acting_entity->running |= RUN_STATE_START_X; // Player begins to run - - } else if(command_match_forward && validanim(acting_entity, ANI_ATTACKFORWARD)) { - acting_player->playkeys &= ~(FLAG_MOVELEFT | FLAG_MOVERIGHT); - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - ent_set_anim(acting_entity, ANI_ATTACKFORWARD, 0); - command_input_history_consume_latest_press(acting_player); - goto endthinkcheck; - } - } - - /* - * Attack both. Attack + Key mapped - * by ajspecial. - */ - - if( (global_config.ajspecial == AJSPECIAL_KEY_SPECIAL && (acting_player->playkeys & FLAG_JUMP) && validanim(acting_entity, ANI_ATTACKBOTH))|| - (global_config.ajspecial == AJSPECIAL_KEY_ATTACK2 && (acting_player->playkeys & FLAG_JUMP) && validanim(acting_entity, ANI_ATTACKBOTH))|| - (global_config.ajspecial == AJSPECIAL_KEY_ATTACK3 && (acting_player->playkeys & FLAG_JUMP) && validanim(acting_entity, ANI_ATTACKBOTH))|| - (global_config.ajspecial == AJSPECIAL_KEY_ATTACK4 && (acting_player->playkeys & FLAG_JUMP) && validanim(acting_entity, ANI_ATTACKBOTH))) - { - if((acting_player->keys & FLAG_ATTACK) && notinair) - { - acting_player->playkeys &= ~FLAG_JUMP; - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - acting_entity->stalltime = 0; // If attack is pressed, holding down attack to execute attack3 is no longer valid - ent_set_anim(acting_entity, ANI_ATTACKBOTH, 0); - goto endthinkcheck; - } - } - - /* - * Command MP Charge. - */ - - if((acting_player->playkeys & FLAG_JUMP) && validanim(acting_entity, ANI_CHARGE)) - { - if((acting_player->keys & FLAG_SPECIAL) && notinair) - { - acting_player->playkeys &= ~FLAG_JUMP; - acting_entity->takeaction = common_charge; - acting_entity->combostep[0] = 0; - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->stalltime = 0; - set_charging(acting_entity); - ent_set_anim(acting_entity, ANI_CHARGE, 0); - goto endthinkcheck; - } - } - - /* - * Handle special key. Check for part of a - * freespecial command, and then blocking. - */ - - if(acting_player->playkeys & FLAG_SPECIAL) // The special button can now be used for freespecials - { - if( validanim(acting_entity, ANI_SPECIAL2) && notinair && - (acting_entity->direction == DIRECTION_LEFT ? - (acting_player->keys & FLAG_MOVELEFT) : - (acting_player->keys & FLAG_MOVERIGHT)) ) - { - if(check_costmove(ANI_SPECIAL2, 0, 0)) - { - acting_player->playkeys &= ~FLAG_SPECIAL; - goto endthinkcheck; - } - } - - // Blocking. - if(validanim(acting_entity, ANI_BLOCK) && notinair && !(acting_entity->modeldata.block_config_flags & BLOCK_CONFIG_DISABLED)) - { - acting_player->playkeys &= ~FLAG_SPECIAL; - - // Set up flags, action, and block animations. - do_active_block(acting_entity); - - goto endthinkcheck; - } - } - - /* - * Breakout special. - */ - - if(notinair && player_check_special()) - { - goto endthinkcheck; // So you don't perform specials falling off the edge - } - - /* - * Charge attack (hold Attack & release). - */ - - if((acting_player->releasekeys & FLAG_ATTACK)) - { - if(acting_entity->stalltime && notinair && - ((validanim(acting_entity, ANI_CHARGEATTACK) && acting_entity->stalltime + (global_config.game_speed * acting_entity->modeldata.animation[ANI_CHARGEATTACK]->charge_time) < _time) || - (!validanim(acting_entity, ANI_CHARGEATTACK) && validanim(acting_entity, animattacks[acting_entity->modeldata.atchain[acting_entity->modeldata.chainlength - 1] - 1]) - && acting_entity->modeldata.chainlength > 0 && acting_entity->stalltime + (global_config.game_speed * acting_entity->modeldata.animation[animattacks[acting_entity->modeldata.atchain[acting_entity->modeldata.chainlength - 1] - 1]]->charge_time) < _time))) - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - - acting_entity->stalltime = 0; - acting_entity->combostep[0] = 0; - - if(global_sample_list.punch >= 0) - { - sound_play_sample(global_sample_list.punch, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(validanim(acting_entity, ANI_CHARGEATTACK)) - { - ent_set_anim(acting_entity, ANI_CHARGEATTACK, 0); - } - else if(validanim(acting_entity, animattacks[acting_entity->modeldata.atchain[acting_entity->modeldata.chainlength - 1] - 1])) - { - ent_set_anim(acting_entity, animattacks[acting_entity->modeldata.atchain[acting_entity->modeldata.chainlength - 1] - 1], 0); - } - goto endthinkcheck; - } - acting_entity->stalltime = 0; - } - - /* - * Attack button. Handle basic attack - * button actions (attack, get, etc.). - */ - - if((acting_player->playkeys & FLAG_ATTACK) && notinair) - { - acting_player->playkeys &= ~FLAG_ATTACK; - acting_entity->stalltime = 0; // Disable the attack3 stalltime - - if((acting_entity->ducking & DUCK_ACTIVE) && validanim(acting_entity, ANI_DUCKATTACK) && PLAYER_MIN_Z == PLAYER_MAX_Z) //acting_player->keys & FLAG_MOVEDOWN - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - ent_set_anim(acting_entity, ANI_DUCKATTACK, 0); - goto endthinkcheck; - } - - if(acting_entity->running && validanim(acting_entity, ANI_RUNATTACK)) // New run attack code section - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - acting_entity->running = RUN_STATE_NONE; - ent_set_anim(acting_entity, ANI_RUNATTACK, 0); - goto endthinkcheck; - } - - /* - * Back attack. If player's command buffer matches - * the back attack sequence, we'll attempt to do - * a back attack. - */ - const key_mask_t sequence_back_attack[] = {FLAG_BACKWARD, FLAG_ATTACK}; - - if(validanim(acting_entity, ANI_ATTACKBACKWARD) && match_combo(sequence_back_attack, acting_player, 2)) { - const s_command_input_event* attack_input_event; - const s_command_input_event* backward_input_event; - - uint64_t history_index = - acting_player->command_input_index; - - uint64_t remaining_events = - acting_player->command_input_count; - - /* - * Get the last two press events. Reading through - * the compatibility helper prevents future release - * and timed hold events from disturbing back attack. - */ - attack_input_event = command_input_history_previous_press( - acting_player, - &history_index, - &remaining_events - ); - - backward_input_event = command_input_history_previous_press( - acting_player, - &history_index, - &remaining_events - ); - - /* - * Did back attack inputs come within the - * time window? If so, we'll do a back attack. - */ - if(attack_input_event - && backward_input_event - && attack_input_event->time - - backward_input_event->time - < global_config.game_speed / 10) { - - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = 0; - acting_entity->velocity.z = 0; - - if(acting_entity->direction == DIRECTION_LEFT - && (backward_input_event->press & FLAG_MOVELEFT)) { - - acting_entity->direction = DIRECTION_RIGHT; - - } else if(acting_entity->direction == DIRECTION_RIGHT - && (backward_input_event->press & FLAG_MOVERIGHT)) { - acting_entity->direction = DIRECTION_LEFT; - } - - acting_entity->combostep[0] = 0; - ent_set_anim(acting_entity, ANI_ATTACKBACKWARD, 0); - goto endthinkcheck; - } - } - - /* - * Get item. If player is standing on an item - * and the get animation is valid, then - * we'll pick it up and run the get animation. - */ - if(validanim(acting_entity, ANI_GET) - && (other = find_ent_here(acting_entity, acting_entity->position.x, acting_entity->position.z, TYPE_ITEM, player_test_pickable))) { - - acting_entity->velocity.x = acting_entity->velocity.z = 0; - set_getting(acting_entity); - acting_entity->takeaction = common_get; - ent_set_anim(acting_entity, ANI_GET, 0); - - /* - * Item "attacks" collector to make it - * easy to script actions on item pick up. - */ - do_item_script(acting_entity, other); - - didfind_item(other); - goto endthinkcheck; - } - - // Use stalltime to charge end-move - acting_entity->stalltime = _time; - acting_entity->velocity.x = acting_entity->velocity.z = 0; - - if( acting_entity->weapent && - acting_entity->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && - validanim(acting_entity, ANI_THROWATTACK) ) - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - ent_set_anim(acting_entity, ANI_THROWATTACK, 0); - goto endthinkcheck; - } - else if(perform_atchain()) - { - if(global_sample_list.punch >= 0 && acting_entity->attacking != ATTACKING_NONE) - { - sound_play_sample(global_sample_list.punch, 0, savedata.effectvol, savedata.effectvol, 100); - } - goto endthinkcheck; - } - - } - - /* - * Jumping contorl. - */ - - if(acting_player->playkeys & FLAG_JUMP && notinair) - { - // Added !inair(acting_entity) so players can't jump when falling into holes - acting_player->playkeys &= ~FLAG_JUMP; - - /* - * Z axis control. - * - * If player can initialize a Z jump - * and Up or Down keys are active we'll - * get a portion of their jump speed as - * a Z velocity. We'll use this value as - * the Z parameter for all downstream - * jump function calls. - */ - - if (acting_entity->modeldata.air_control & AIR_CONTROL_JUMP_Z_INITIAL) - { - if (acting_player->keys & FLAG_MOVEUP) - { - initial_jump_velocity_z = -acting_entity->modeldata.jumpspeed * 0.5; - } - else if (acting_player->keys & FLAG_MOVEDOWN) - { - initial_jump_velocity_z = acting_entity->modeldata.jumpspeed * 0.5; - } - } - else - { - initial_jump_velocity_z = 0.0; - } - - if(acting_entity->running) - { - //Slide - if((acting_player->keys & FLAG_MOVEDOWN) && validanim(acting_entity, ANI_RUNSLIDE)) - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - acting_entity->running = RUN_STATE_NONE; - ent_set_anim(acting_entity, ANI_RUNSLIDE, 0); - goto endthinkcheck; - } - - /* Jumping allowed? */ - if (!(acting_entity->modeldata.air_control & AIR_CONTROL_JUMP_DISABLE)) - { - if (validanim(acting_entity, ANI_RUNJUMP)) - { - tryjump(acting_entity->modeldata.runjumpheight, acting_entity->modeldata.jumpspeed * acting_entity->modeldata.runjumpdist, initial_jump_velocity_z, ANI_RUNJUMP); - } - else if (validanim(acting_entity, ANI_FORWARDJUMP)) - { - tryjump(acting_entity->modeldata.runjumpheight, acting_entity->modeldata.jumpspeed * acting_entity->modeldata.runjumpdist, initial_jump_velocity_z, ANI_FORWARDJUMP); - } - else if (validanim(acting_entity, ANI_JUMP)) - { - tryjump(acting_entity->modeldata.runjumpheight, acting_entity->modeldata.jumpspeed * acting_entity->modeldata.runjumpdist, initial_jump_velocity_z, ANI_JUMP); - } - } - } - else - { - //Slide - if((acting_player->keys & FLAG_MOVEDOWN) && validanim(acting_entity, ANI_SLIDE)) - { - acting_entity->takeaction = common_attack_proc; - set_attacking(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - acting_entity->combostep[0] = 0; - acting_entity->running = RUN_STATE_NONE; - ent_set_anim(acting_entity, ANI_SLIDE, 0); - goto endthinkcheck; - } - - /* Jumping allowed? */ - if (!(acting_entity->modeldata.air_control & AIR_CONTROL_JUMP_DISABLE)) - { - - /* - * Handle left/right direction command. - * - * If left or right key is active, - * then switch facing accordingly and - * continue on to moving jump logic. - * - * Otherwise perform a jump with no - * horizontal velocity. - */ - - if (!(acting_player->keys & (FLAG_MOVELEFT | FLAG_MOVERIGHT)) && validanim(acting_entity, ANI_JUMP)) - { - tryjump(acting_entity->modeldata.jumpheight, 0, initial_jump_velocity_z, ANI_JUMP); - goto endthinkcheck; - } - else if ((acting_player->keys & FLAG_MOVELEFT)) - { - acting_entity->direction = DIRECTION_LEFT; - } - else if ((acting_player->keys & FLAG_MOVERIGHT)) - { - acting_entity->direction = DIRECTION_RIGHT; - } - - /* - * Horizontal moving jump. - */ - - if (validanim(acting_entity, ANI_FORWARDJUMP)) - { - tryjump(acting_entity->modeldata.jumpheight, acting_entity->modeldata.jumpspeed, initial_jump_velocity_z, ANI_FORWARDJUMP); - } - else if (validanim(acting_entity, ANI_JUMP)) - { - tryjump(acting_entity->modeldata.jumpheight, acting_entity->modeldata.jumpspeed, initial_jump_velocity_z, ANI_JUMP); - } - } - } - return; - } - - /* - * Run stop. - */ - run_try_runstop_player(acting_entity, acting_player); - - /* - */ - - if(PLAYER_MIN_Z != PLAYER_MAX_Z && acting_entity->ducking == DUCK_NONE) - { - // More of a platform feel - if(acting_player->keys & FLAG_MOVEUP) - { - if(validanim(acting_entity, ANI_UP) && acting_entity->running == RUN_STATE_NONE) - { - action = ACTION_UP; - acting_entity->velocity.z = -acting_entity->modeldata.speed.x / 2; // Used for up animation - } - else if(acting_entity->running & RUN_STATE_START_X) - { - action = ACTION_RUN; - - if (acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_RIGHT_DASH_FIXED - && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_UP_ENABLED)) { - acting_entity->velocity.z = 0.0; - } - else - { - acting_entity->velocity.z = -acting_entity->modeldata.runspeed / 2; // Moves up at a faster rate running - } - } - else - { - action = ACTION_WALK; - acting_entity->velocity.z = -acting_entity->modeldata.speed.x / 2; - } - } - else if(acting_player->keys & FLAG_MOVEDOWN) - { - if(validanim(acting_entity, ANI_DOWN) && acting_entity->running == RUN_STATE_NONE) - { - action = ACTION_DOWN; - acting_entity->velocity.z = acting_entity->modeldata.speed.x / 2; // Used for down animation - } - else if(acting_entity->running & RUN_STATE_START_X) - { - action = ACTION_RUN; - - if (acting_entity->modeldata.run_config_flags & RUN_CONFIG_X_RIGHT_DASH_FIXED - && !(acting_entity->modeldata.run_config_flags & RUN_CONFIG_Z_DOWN_ENABLED)) { - acting_entity->velocity.z = 0.0; - } - else - { - acting_entity->velocity.z = acting_entity->modeldata.runspeed / 2; // Moves up at a faster rate running - } - } - else - { - action = ACTION_WALK; - acting_entity->velocity.z = acting_entity->modeldata.speed.x / 2; - } - } - else if(!(acting_player->keys & (FLAG_MOVEUP | FLAG_MOVEDOWN))) - { - acting_entity->velocity.z = 0; - } - } - else if(acting_entity->ducking == DUCK_NONE && validanim(acting_entity, ANI_DUCK) && acting_player->keys & FLAG_MOVEDOWN && notinair) - { - tryduck(acting_entity); - goto endthinkcheck; - } - - if(acting_player->keys & FLAG_MOVELEFT && acting_entity->ducking == DUCK_NONE) - { - if(acting_entity->direction == DIRECTION_RIGHT) - { - //acting_entity->running = RUN_STATE_NONE; // Quits running if player changes direction - if(acting_entity->modeldata.turndelay && !acting_entity->turntime) - { - acting_entity->turntime = _time + acting_entity->modeldata.turndelay; - } - else if(acting_entity->turntime && _time >= acting_entity->turntime) - { - acting_entity->turntime = 0; - if(validanim(acting_entity, ANI_TURN)) - { - acting_entity->takeaction = common_turn; - set_turning(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_TURN, 0); - goto endthinkcheck; - } - acting_entity->direction = DIRECTION_LEFT; - } - else if(!acting_entity->modeldata.turndelay && validanim(acting_entity, ANI_TURN)) - { - acting_entity->takeaction = common_turn; - set_turning(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_TURN, 0); - goto endthinkcheck; - } - else if(!acting_entity->turntime) - { - acting_entity->direction = DIRECTION_LEFT; - } - } - else - { - acting_entity->turntime = 0; - } - - if(acting_entity->running) - { - action = ACTION_RUN; - acting_entity->velocity.x = -acting_entity->modeldata.runspeed; // If running, player moves at a faster rate - } - else if(action != ACTION_UP && action != ACTION_DOWN) - { - action = ACTION_WALK; - acting_entity->velocity.x = -acting_entity->modeldata.speed.x; - } - else - { - acting_entity->velocity.x = -acting_entity->modeldata.speed.x; - } - } - else if(acting_player->keys & FLAG_MOVERIGHT && acting_entity->ducking == DUCK_NONE) - { - if(acting_entity->direction == DIRECTION_LEFT) - { - //acting_entity->running = RUN_STATE_NONE; // Quits running if player changes direction - if(acting_entity->modeldata.turndelay && !acting_entity->turntime) - { - acting_entity->turntime = _time + acting_entity->modeldata.turndelay; - } - else if(acting_entity->turntime && _time >= acting_entity->turntime) - { - acting_entity->turntime = 0; - if(validanim(acting_entity, ANI_TURN)) - { - acting_entity->takeaction = common_turn; - set_turning(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_TURN, 0); - goto endthinkcheck; - } - acting_entity->direction = DIRECTION_RIGHT; - } - else if(!acting_entity->modeldata.turndelay && validanim(acting_entity, ANI_TURN)) - { - acting_entity->takeaction = common_turn; - set_turning(acting_entity); - acting_entity->velocity.x = acting_entity->velocity.z = 0; - ent_set_anim(acting_entity, ANI_TURN, 0); - goto endthinkcheck; - } - else if(!acting_entity->turntime) - { - acting_entity->direction = DIRECTION_RIGHT; - } - } - else - { - acting_entity->turntime = 0; - } - - if(acting_entity->running) - { - action = ACTION_RUN; - acting_entity->velocity.x = acting_entity->modeldata.runspeed; // If running, player moves at a faster rate - } - else if(action != ACTION_UP && action != ACTION_DOWN) - { - action = ACTION_WALK; - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - else - { - acting_entity->velocity.x = acting_entity->modeldata.speed.x; - } - } - else if(!((acting_player->keys & FLAG_MOVELEFT) || - (acting_player->keys & FLAG_MOVERIGHT)) ) - { - //acting_entity->running = RUN_STATE_NONE; // Player let go of left/right and so quits running - acting_entity->velocity.x = 0; - acting_entity->turntime = 0; - } - - if((other = find_ent_here(acting_entity, acting_entity->position.x, acting_entity->position.z, TYPE_ITEM, player_test_touch)) ) - { - do_item_script(acting_entity, other); - didfind_item(other); // Added function to clean code up a bit - } - - if (acting_entity->ducking & DUCK_ACTIVE) - { - if (!(acting_player->keys & FLAG_MOVEDOWN)) - { - tryduckrise(acting_entity); - goto endthinkcheck; - } - if(acting_player->keys & FLAG_MOVELEFT) - { - if(acting_entity->direction == DIRECTION_RIGHT) - { - acting_entity->direction = DIRECTION_LEFT; - } - } - else if(acting_player->keys & FLAG_MOVERIGHT) - { - if(acting_entity->direction == DIRECTION_LEFT) - { - acting_entity->direction = DIRECTION_RIGHT; - } - } - } - if (acting_entity->ducking) - { - goto endthinkcheck; - } - - - //White Dragon: prepare for idling animations... - if(action) - { - acting_entity->takeaction = NULL; - acting_entity->idling = IDLING_PREPARED; - } - - switch(action) - { - case ACTION_WALK: - // back walk feature - if(level && validanim(acting_entity, ANI_BACKWALK)) { - - if(acting_entity->modeldata.facing == FACING_ADJUST_RIGHT || level->facing == FACING_ADJUST_RIGHT) { - - back_walk = !acting_entity->direction; - - } else if(acting_entity->modeldata.facing == FACING_ADJUST_LEFT || level->facing == FACING_ADJUST_LEFT) { - - back_walk = acting_entity->direction; - - } else if((acting_entity->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_LEFT) && acting_entity->direction == DIRECTION_LEFT) { - - back_walk = true; - - } else if((acting_entity->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_RIGHT) && acting_entity->direction == DIRECTION_RIGHT) { - - back_walk = true; - - } else if(acting_entity->turntime && acting_entity->modeldata.turndelay) { - - back_walk = true; - } - - if(back_walk) { - common_backwalk_anim(acting_entity); - } else { - common_walk_anim(acting_entity); - } - - } else { - common_walk_anim(acting_entity); - } - break; - case ACTION_UP: - common_up_anim(acting_entity); //ent_set_anim(acting_entity, ANI_UP, 0); // Set to up animation if exists - break; - case ACTION_DOWN: - common_down_anim(acting_entity); //ent_set_anim(acting_entity, ANI_DOWN, 0); // Set to down animation if exists - break; - case ACTION_RUN: - if (validanim(acting_entity, ANI_BACKRUN)) - { - if (is_in_backrun(acting_entity)) ent_set_anim(acting_entity, ANI_BACKRUN, 0); - else ent_set_anim(acting_entity, ANI_RUN, 0); - } - else ent_set_anim(acting_entity, ANI_RUN, 0); // Set to run animation if exists - - break; - default: - - if(acting_entity->idling) - { - common_idle_anim(acting_entity); - } - break; - } - - -endthinkcheck: - //insert check here - return; -} - -int is_in_backrun(entity* self) -{ - if ( ((self->modeldata.facing == FACING_ADJUST_RIGHT || level->facing == FACING_ADJUST_RIGHT) && self->velocity.x < 0) || - ((self->modeldata.facing == FACING_ADJUST_LEFT || level->facing == FACING_ADJUST_LEFT) && self->velocity.x > 0) || - (((self->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_RIGHT)) && self->velocity.x > 0) || - (((self->modeldata.facing == FACING_ADJUST_LEVEL || level->facing == FACING_ADJUST_LEVEL) && (level->scrolldir & SCROLL_LEFT)) && self->velocity.x > 0) - ) return 1; - else return 0; -} - -//ammo count goes down -void subtract_shot() -{ - if(self->weapent && self->weapent->modeldata.weapon_properties.use_count) - { - self->weapent->modeldata.weapon_properties.use_count--; - - /* - * Out of uses? Drop the weapon. - */ - - if(!self->weapent->modeldata.weapon_properties.use_count) - { - self->weapent->modeldata.weapon_properties.loss_count = 0; - dropweapon(self, 0); - } - } -} - - -void dropweapon(entity* acting_entity, int flag) -{ - int wall = 0; - entity *other = NULL; - entity* weapon_entity = NULL; - s_weapon* weapon_properties = NULL; - - // If we already have a weapon, we'll need to discard it. - if(acting_entity->weapent) - { - /* - * Dump pointers to self's weapon entity and the - * weapon entity's modeldata weapon properties - * into local variables. This is just for eaiser - * reading downstream. - */ - - weapon_entity = acting_entity->weapent; - weapon_properties = &acting_entity->weapent->modeldata.weapon_properties; - - // 2019-09-29 - Not sure about this logic. It appears that only type shot - // weapons or weapons with shot ammo are dropped. Anything else is simply discarded. - // Need to evaluate all weapon logic to get the workflow. - if(weapon_properties->weapon_state & WEAPON_STATE_LIMITED_USE || (!(weapon_properties->weapon_state & WEAPON_STATE_LIMITED_USE) && weapon_properties->use_count)) - { - // If the flag is 2 or below, we subtract the flag's - // value from weapon counter. - if(flag < 2) - { - weapon_properties->loss_count -= flag; - } - - // We're going to use our own position for the weapon. - weapon_entity->direction = acting_entity->direction; - weapon_entity->position.z = acting_entity->position.z; - weapon_entity->position.x = acting_entity->position.x; - weapon_entity->position.y = acting_entity->position.y; - - // Get any walls and platforms. - other = check_platform(weapon_entity->position.x, weapon_entity->position.z, acting_entity); - wall = checkwall_index(weapon_entity->position.x, weapon_entity->position.z); - - // Place onto wall or platform. - if(other && other != weapon_entity) - { - weapon_entity->base += other->position.y + other->animation->platform[other->animpos][PLATFORM_HEIGHT]; - } - else if(wall >= 0) - { - weapon_entity->base += level->walls[wall].height; - } - - // Use the weapon's RESPAWN or SPAWN animations if available, otherwise - // go right to idle. - if(validanim(weapon_entity, ANI_RESPAWN)) - { - ent_set_anim(weapon_entity, ANI_RESPAWN, 1); - } - else if(validanim(weapon_entity, ANI_SPAWN)) - { - ent_set_anim(weapon_entity, ANI_SPAWN, 1); - } - else - { - if(validanim(weapon_entity, ANI_IDLE)) ent_set_anim(weapon_entity, ANI_IDLE, 1); - } - - // If the weapon's counter is depleted, then weapon is lost for good. - // If it is an "animal", then we apply the animal running away logic. - // Otherwise the weapon blinks out. - if(!weapon_properties->loss_count) - { - if(!(acting_entity->modeldata.weapon_properties.weapon_state & WEAPON_STATE_ANIMAL)) - { - weapon_entity->blink = 1; - weapon_entity->takeaction = common_lie; - } - else - { - weapon_entity->modeldata.type = TYPE_NONE; - weapon_entity->think = runanimal; - } - } - weapon_entity->nextthink = _time + 1; - } - - // Clear our tracking variable that keeps the weapon entity pointer. - acting_entity->weapent = NULL; - } - - // Flag 2 means we're probably setting the weapon directly (ex: setweapon command). - // In that case we don't worry about a weapon entity. Just switch ourselves over - // to the weapon model. - if(flag < 2) - { - if(acting_entity->modeldata.type & TYPE_PLAYER) - { - if(player[acting_entity->playerindex].weapnum) - { - set_weapon(acting_entity, player[acting_entity->playerindex].weapnum, 0); - } - else - { - set_weapon(acting_entity, level->setweap, 0); - } - } - else - { - set_weapon(acting_entity, 0, 0); - } - } - - // Model override. If this is populated, we use its value - // to locate a model by index and revert to that instead - // of the default model when a weapon is lost. - if(acting_entity->modeldata.weapon_properties.loss_index != MODEL_INDEX_NONE) - { - set_weapon(acting_entity, acting_entity->modeldata.weapon_properties.loss_index, 0); - } -} - - -int player_takedamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, int fall_flag, const s_defense* defense_object) -{ - s_attack atk = *attack_object; - //printf("damaged by: '%s' %d\n", other->name, attack->attack_force); - - // Kratus (10-2021) Now the "infinite health cheat" will check the damage source, it will avoid some "special" damage sources - - // Damage comes from a normal source? - const bool normal_damage = (!is_attack_type_special(atk.attack_type)) ? true : false; - - if((global_config.cheats & CHEAT_OPTIONS_HEALTH_ACTIVE && normal_damage) - || (level->nohurt == DAMAGE_FROM_ENEMY_OFF && (attacking_entity->modeldata.type & TYPE_ENEMY))) - { - atk.attack_force = 0; - } - - return common_takedamage(target_entity, attacking_entity, &atk, fall_flag, defense_object); -} - -//////////////////////////////// - -// Called when player re-enters the game. -// Drop all enemies EXCEPT for the linked/frozen ones. -void drop_all_enemies() -{ - int i; - entity *weapself = self; - s_attack attack = emptyattack; - - for(i = 0; i < ent_max; i++) - { - if(ent_list[i]->exists && - ent_list[i]->energy_state.health_current > 0 && - (ent_list[i]->modeldata.type & TYPE_ENEMY) && - !ent_list[i]->owner && // Don't want to knock down a projectile - !ent_list[i]->frozen && // Don't want to unfreeze a frozen enemy - !(ent_list[i]->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) && - !(ent_list[i]->modeldata.pain_config_flags & PAIN_CONFIG_FALL_DISABLE) && - validanim(ent_list[i], ANI_FALL) ) - { - ent_list[i]->attacking = ATTACKING_NONE; - ent_list[i]->projectile = BLAST_NONE; - ent_list[i]->takeaction = common_fall;//enemy_fall; - ent_list[i]->damage_on_landing.attack_force = 0; - ent_list[i]->damage_on_landing.attack_type = ATK_NONE; - self = ent_list[i]; - ent_unlink(self); - ent_list[i]->velocity.x = (self->direction == DIRECTION_RIGHT) ? (-1.2) : 1.2; - - if(ent_list[i]->modeldata.weapon_properties.loss_condition & WEAPON_LOSS_CONDITION_STAGE) - { - dropweapon(self, 1); - } - - toss(ent_list[i], 2.5 + randf(1)); - ent_list[i]->knockdowncount = ent_list[i]->modeldata.knockdowncount; - - ent_list[i]->knockdowntime = 0; - - set_fall(ent_list[i], self, &attack, 1); - } - } - self = weapself; -} - - - -/* Called when boss dies. */ -void kill_all_enemies() -{ - int i; - s_attack attack = emptyattack; - entity *tmpself = NULL; - - attack.attack_type = ATK_BOSS_DEATH; - attack.dropv = default_model_dropv; - - /* - * Downstream damage functions use - * self global, so we populate it with - * entity cursor in each iteration of - * loop below. Keep current value here - * so we can restore when loop is finished. - */ - tmpself = self; - - /* - * Every valid enemy type with a takedamage - * function takes its current health in damage. - */ - for(i = 0; i < ent_max; i++) - { - if( ent_list[i]->exists - && ent_list[i]->energy_state.health_current > 0 - && (ent_list[i]->modeldata.type & TYPE_ENEMY) - && ent_list[i]->takedamage) - { - self = ent_list[i]; - - attack.attack_force = self->energy_state.health_current; - self->takedamage(self, self, &attack, 0, self->defense); - } - } - - self = tmpself; -} - - - -void smart_bomb(entity *e, s_attack *attack) { // New method for smartbombs - - int i, hit = 0; - entity *tmpself = NULL; - - tmpself = self; - for(i = 0; i < ent_max; i++) { - - if( ent_list[i]->exists - && ent_list[i] != e - && ent_list[i]->energy_state.health_current > 0 - && faction_check_is_hostile(e, ent_list[i])) { - - self = ent_list[i]; - hit = 1; // for nocost, if the bomb doesn't hit, it won't cost energy - - lasthit.attack = attack; - lasthit.attacker = e; - lasthit.collision_attack = NULL; - lasthit.confirm = 1; - lasthit.detect_body = NULL; - lasthit.detect_collision_attack = NULL; - lasthit.detect_collision_body = NULL; - lasthit.position.x = self->position.x; - lasthit.position.y = self->position.y; - lasthit.position.z = self->position.z; - lasthit.target = self; - - if(self->takedamage) { - - const s_defense* defense_object = defense_find_current_object(self, NULL, attack->attack_type); - - //attack.attack_drop = self->modeldata.knockdowncount+1; - self->takedamage(self, e, attack, 0, defense_object); - - } else { - self->energy_state.health_current -= attack->attack_force; - - if(self->energy_state.health_current <= 0) { - kill_entity(self, KILL_ENTITY_TRIGGER_SMARTBOMB); - } - } - - spawn_attack_flash(self, attack, attack->flash.model_hit, self->modeldata.flash.model_block); - - } - } - - if(nocost && hit && smartbomber) { // don't use e, because this can be an item-bomb - self = smartbomber; - - if(check_energy(ENERGY_TYPE_MP, ANI_SPECIAL)) { - self->energy_state.mp_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } else { - self->energy_state.health_current -= self->modeldata.animation[ANI_SPECIAL]->energy_cost.cost; - } - - } - - self = tmpself; - -} - - -//////////////////////////////// - -void anything_walk() -{ - if(self->position.x < advancex - 80 || self->position.x > advancex + (videomodes.hRes + 80)) - { - kill_entity(self, KILL_ENTITY_TRIGGER_WALK_OUT_OF_BOUNDS); - return; - } - //self->position.x += self->velocity.x; -} - -// Caskey, Damon V. -// 2019-12-18 -// -// Apply color set adjustment to entity, possibly -// based on a parent/owner depending on color set -// adjustment setting. -void apply_color_set_adjust(entity* ent, entity* parent, e_color_adjust adjustment) -{ - int i = 0; // Loop cursor. - - // Apply color setting. - switch (adjustment) - { - default: - - // Use adjustment value as color set index. - ent_set_colourmap(ent, adjustment); - break; - - case COLORSET_ADJUST_NONE: - - // Do nothing. - break; - - case COLORSET_ADJUST_PARENT_INDEX: - - // Locate parent's current color set index. Then - // set our color set by that index. - - for (i = 0; i < parent->modeldata.maps_loaded; i++) - { - if (parent->colourmap == parent->modeldata.colourmap[i]) - { - ent_set_colourmap(ent, i); - break; - } - } - break; - - case COLORSET_ADJUST_PARENT_TABLE: - - // Use parent's color table. - - ent->colourmap = parent->colourmap; - break; - - } -} - -/* -* Caskey, Damon V. -* -* 2019-12-22 -* Copy the faction settings from a -* source entity. -*/ -void faction_copy_all(entity* dest, entity* source) -{ - faction_copy_data(&dest->modeldata.faction, &source->faction); - faction_copy_data(&dest->faction, &source->faction); -} - -/* -* Caskey, Damon V. -* 2023-02-28 -* -* Copy faction properties if -* conditions pass. -*/ -void faction_copy_data(s_faction* dest, s_faction* source) { - - /* - * The destination is always a faction - * object, regardless of which faction - * properties qualify for copying. - */ - dest->object_type = OBJECT_TYPE_FACTION; - - /* - * Faction groups. Only copy if source or - * destination has a value and does not - * have the no copy flag. - * - * I'd rather be able to copy empty values - * as well, but that requires inserting - * default values in several differnt - * locations around the code. Better to - * keep it here and maintainable. - */ - - if (source->damage_direct != FACTION_GROUP_NONE - && !(source->damage_direct & FACTION_GROUP_NO_COPY) - && !(dest->damage_direct & FACTION_GROUP_NO_COPY)) { - dest->damage_direct = source->damage_direct; - } - - if (source->damage_indirect != FACTION_GROUP_NONE - && !(source->damage_indirect & FACTION_GROUP_NO_COPY) - && !(dest->damage_indirect & FACTION_GROUP_NO_COPY)) { - dest->damage_indirect = source->damage_indirect; - } - - if (source->hostile != FACTION_GROUP_NONE - && !(source->hostile & FACTION_GROUP_NO_COPY) - && !(dest->hostile & FACTION_GROUP_NO_COPY)) { - dest->hostile = source->hostile; - } - - if (source->member != FACTION_GROUP_NONE - && !(source->member & FACTION_GROUP_NO_COPY) - && !(dest->member & FACTION_GROUP_NO_COPY)) { - dest->member = source->member; - } - - /* - * Types. Same rule as faction groups. - */ - - if (source->type_damage_direct != TYPE_UNDECLARED - && !(source->type_damage_direct & TYPE_NO_COPY) - && !(dest->type_damage_direct & TYPE_NO_COPY)) { - - dest->type_damage_direct = source->type_damage_direct; - } - - if (source->type_damage_indirect != TYPE_UNDECLARED - && !(source->type_damage_indirect & TYPE_NO_COPY) - && !(dest->type_damage_indirect & TYPE_NO_COPY)) { - dest->type_damage_indirect = source->type_damage_indirect; - } - - if (source->type_hostile != TYPE_UNDECLARED - && !(source->type_hostile & TYPE_NO_COPY) - && !(dest->type_hostile & TYPE_NO_COPY)) { - dest->type_hostile = source->type_hostile; - } -} - -/* -* Caskey, Damon V. -* 2022-05-24 -* -* Read a text argument for model copy flag -* and output appropriate constant. -*/ -faction_group_mask_t faction_get_flag_from_string(const char* value) { - - const struct { - const char* text_name; - faction_group_mask_t flag; - - } flag_lookup_table[] = { - { "none", FACTION_GROUP_NONE }, - { "all", FACTION_GROUP_ALL_NORMAL }, - {"all0", FACTION_GROUP_ALL_NORMAL_0 }, - {"all1", FACTION_GROUP_ALL_NORMAL_1 }, - { "neutral", FACTION_GROUP_NEUTRAL }, - { "no_copy", FACTION_GROUP_NO_COPY }, - { "player_verses", FACTION_GROUP_PLAYER_VERSES }, - { "type_exclusive", FACTION_GROUP_TYPE_EXCLUSIVE }, - { "type_inclusive", FACTION_GROUP_TYPE_INCLUSIVE }, - { "a", FACTION_GROUP_A }, - { "b", FACTION_GROUP_B }, - { "c", FACTION_GROUP_C }, - { "d", FACTION_GROUP_D }, - { "e", FACTION_GROUP_E }, - { "f", FACTION_GROUP_F }, - { "g", FACTION_GROUP_G }, - { "h", FACTION_GROUP_H }, - { "i", FACTION_GROUP_I }, - { "j", FACTION_GROUP_J }, - { "k", FACTION_GROUP_K }, - { "l", FACTION_GROUP_L }, - { "m", FACTION_GROUP_M }, - { "n", FACTION_GROUP_N }, - { "o", FACTION_GROUP_O }, - { "p", FACTION_GROUP_P }, - { "q", FACTION_GROUP_Q }, - { "r", FACTION_GROUP_R }, - { "s", FACTION_GROUP_S }, - { "t", FACTION_GROUP_T }, - { "u", FACTION_GROUP_U }, - { "v", FACTION_GROUP_V }, - { "w", FACTION_GROUP_W }, - { "x", FACTION_GROUP_X }, - { "y", FACTION_GROUP_Y }, - { "z", FACTION_GROUP_Z }, - { "a1", FACTION_GROUP_A1 }, - { "b1", FACTION_GROUP_B1 }, - { "c1", FACTION_GROUP_C1 }, - { "d1", FACTION_GROUP_D1 }, - { "e1", FACTION_GROUP_E1 }, - { "f1", FACTION_GROUP_F1 }, - { "g1", FACTION_GROUP_G1 }, - { "h1", FACTION_GROUP_H1 }, - { "i1", FACTION_GROUP_I1 }, - { "j1", FACTION_GROUP_J1 }, - { "k1", FACTION_GROUP_K1 }, - { "l1", FACTION_GROUP_L1 }, - { "m1", FACTION_GROUP_M1 }, - { "n1", FACTION_GROUP_N1 }, - { "o1", FACTION_GROUP_O1 }, - { "p1", FACTION_GROUP_P1 }, - { "q1", FACTION_GROUP_Q1 }, - { "r1", FACTION_GROUP_R1 }, - { "s1", FACTION_GROUP_S1 }, - { "t1", FACTION_GROUP_T1 }, - { "u1", FACTION_GROUP_U1 }, - { "v1", FACTION_GROUP_V1 }, - { "w1", FACTION_GROUP_W1 }, - { "x1", FACTION_GROUP_X1 }, - { "y1", FACTION_GROUP_Y1 }, - { "z1", FACTION_GROUP_Z1 } - }; - - const size_t list_count = sizeof(flag_lookup_table) / sizeof(*flag_lookup_table); - - for (size_t i = 0; i < list_count; i++) { - if (stricmp(value, flag_lookup_table[i].text_name) == 0) { - return flag_lookup_table[i].flag; - } - } - - /* - * Couldn't find a match in the lookup - * table. Send alert to log and return - * none flag. - */ - - printf("\n\n Unknown faction (%s). \n", value); - return FACTION_GROUP_NONE; -} - -/* -- Caskey, Damon V. -- 2026-08-11 -- -- Read faction arguments directly from the source line and - combine their corresponding group flags. -*/ -faction_group_mask_t faction_get_flags_from_command_line( - const char* command_line -) -{ - const char* value; - s_command_argument_reader reader; - faction_group_mask_t result = FACTION_GROUP_NONE; - - command_argument_reader_initialize(&reader, command_line, 1); - - while(command_argument_reader_next(&reader, &value)) { - result |= faction_get_flag_from_string(value); - } - - return result; -} - -/* -* Caskey, Damon V. -* 2023-02-26 -* -* Return true if acting entity can -* hit target entity with attacks. -*/ -bool faction_check_can_damage(entity* acting_entity, entity* target_entity, const bool indirect) { - - e_entity_type acting_type; - e_entity_type target_type; - faction_group_mask_t acting_faction; - faction_group_mask_t acting_faction_filtered; - faction_group_mask_t target_faction; - - if (!acting_entity || !target_entity) { - return false; - } - - /* - * We will use different acting faction property - * and type if the indirect flag is set. - */ - - if (indirect) { - acting_faction = acting_entity->faction.damage_indirect; - acting_type = acting_entity->faction.type_damage_indirect; - - } else { - acting_faction = acting_entity->faction.damage_direct; - acting_type = acting_entity->faction.type_damage_direct; - } - - acting_faction_filtered = acting_faction; - - /* - * Remove special types. - */ - - acting_faction_filtered &= ~FACTION_GROUP_NO_CHECK; - acting_type &= ~TYPE_NO_CHECK; - - /* - * Check player interaction. - */ - - if (faction_check_player_verses(acting_entity, target_entity, acting_faction)) { - return false; - } - - target_type = target_entity->modeldata.type; - - /* - * If one of the acting factions is the - * type exclusive group, then we only - * check acting types vs. target type - * and ignore other factions. - */ - - if (acting_faction & FACTION_GROUP_TYPE_EXCLUSIVE) { - - if (acting_type & target_type) { - return true; - } else { - return false; - } - } - - /* - * Now we compare our acting faction(s) to the - * faction(s) target is a member of for any match. - */ - - target_faction = target_entity->faction.member; - - if (acting_faction_filtered & target_faction) { - /* - * If one of the acting factions is - * the tye inclusing group, then we - * also check acting types vs the - * target's type. - */ - - if (acting_faction & FACTION_GROUP_TYPE_INCLUSIVE) { - - if (acting_type & target_type) { - return true; - - } else { - return false; - } - } - - return true; - } - - return false; -} - -/* -* Caskey, Damon V. -* 2023-02-26 -* -* Return true if acting entity is -* hostile toward target entity. -*/ -int faction_check_is_hostile(entity* acting_entity, entity* target_entity) -{ - //printf("\n\n faction_check_is_hostile(%p, %p)", acting_entity, target_entity); - - e_entity_type acting_type; - e_entity_type target_type; - faction_group_mask_t acting_faction; - faction_group_mask_t filtered_faction; - faction_group_mask_t target_faction; - - if (!acting_entity || !target_entity) - { - return 0; - } - - //printf("\n\t acting_entity->name: %s, target_entity->name: %s", acting_entity->name, target_entity->name); - - acting_faction = acting_entity->faction.hostile; - filtered_faction = acting_faction; - acting_type = acting_entity->faction.type_hostile; - target_type = target_entity->modeldata.type; - - //printf("\n\t acting_faction: %d", acting_faction); - //printf("\n\t acting_type: %d", acting_type); - //printf("\n\t target_type: %d", target_type); - - /* - * Remove special types. - */ - - filtered_faction &= ~FACTION_GROUP_NO_CHECK; - acting_type &= ~TYPE_NO_CHECK; - - //printf("\n\t acting_faction: %d", acting_faction); - //printf("\n\t acting_type: %d", acting_type); - - /* - * Check player interaction. - */ - - if (faction_check_player_verses(acting_entity, target_entity, acting_faction)) - { - //printf("\n\t PLayer Vs. Return 0"); - - return 0; - } - - /* - * If one of the acting factions is the - * type exclusive group, then we only - * check acting types vs. target type - * and ignore other factions. - */ - - if (acting_faction & FACTION_GROUP_TYPE_EXCLUSIVE) - { - //printf("\n\t\t acting_faction & FACTION_GROUP_TYPE_EXCLUSIVE: %d", acting_faction & FACTION_GROUP_TYPE_EXCLUSIVE); - - if (acting_type & target_type) - { - //printf("\n\t\t acting_type & target_type: %d (yes)", acting_type & target_type); - - return 1; - } - else - { - printf("\n\t\t acting_type & target_type: %d (no)", acting_type & target_type); - - return 0; - } - } - - /* - * Now we compare our acting faction(s) to the - * faction(s) target is a member of for any match. - */ - - target_faction = target_entity->faction.member; - - if (filtered_faction & target_faction) - { - /* - * If one of the acting factions is - * the tye inclusing group, then we - * also check acting types vs the - * target's type. - */ - - if (acting_faction & FACTION_GROUP_TYPE_INCLUSIVE) - { - //printf("\n\t\t acting_faction & FACTION_GROUP_TYPE_INCLUSIVE: %d", acting_faction & FACTION_GROUP_TYPE_INCLUSIVE); - - if (acting_type & target_type) - { - //printf("\n\t\t acting_type & target_type: %d (yes)", acting_type & target_type); - - return 1; - } - else - { - //printf("\n\t\t acting_type & target_type: %d (no)", acting_type & target_type); - - return 0; - } - } - - return 1; - } - - //printf("\n\t No match."); - - return 0; -} - -/* -* Caskey, Damon V. -* 2023-02-28 -* -* Returs 1 if players are not allowed -* vs. interaction on a given faction -* property. Ex. Hostile, direct damage, -* indirect damage. -*/ -int faction_check_player_verses(entity* acting_entity, entity* target_entity, faction_group_mask_t faction_property) -{ - if (!acting_entity || !target_entity) - { - return 0; - } - - /* - * Both entites must be players. - */ - - if (!(acting_entity->modeldata.type & TYPE_PLAYER)) - { - return 0; - } - - if (!(target_entity->modeldata.type & TYPE_PLAYER)) - { - return 0; - } - - /* - * In faction group to override friendly - * fire settings? - */ - - if (faction_property & FACTION_GROUP_PLAYER_VERSES) - { - return 0; - } - - /* - * If VS. mode turned off in options - * or level nohit is enabled, then - * we are "friendly" toward target. - */ - - if (savedata.mode) - { - return 1; - } - - if (level && level->nohit == DAMAGE_FROM_PLAYER_OFF) - { - return 1; - } - - return 0; -} - -/* -* Caskey, Damon V. -* 2019-12-18 (refactor) -* -* Original author unknown (Tails?). Refactored to remove the ever-growing parameter list -* and consolidate projectile spawn logic. Spawns an entity and fires it as a projectile. -* Model used for spawn is determined by a hierarchy of legacy parameters (see detailed -* comments in function). -* -* Returns pointer of spawned projectile, or NULL on fail. -*/ -entity *knife_spawn(entity *parent, s_projectile *projectile) -{ - entity *projectile_entity = NULL; - - s_axis_principal_float position; - e_direction direction = DIRECTION_RIGHT; - e_projectile_prime projectile_prime = PROJECTILE_PRIME_NONE; - - /* If there's no projectile or parent setting, exit now. */ - if (!projectile || !parent) - { - return NULL; - } - - position.x = parent->position.x; - position.y = parent->position.y + projectile->position.y; - position.z = parent->position.z + projectile->position.z; - - /* - * Now we need to spawn the projectile entity. There are many haphazard legacy - * additions to sift through, so we need to prioritize which model to spawn. - * In general, we work back from most granular to most global. - * - * From highest to lowest priority: - * - * 1. Projectile Knife property. - * 2. Projectile Flash property. - * 3. Using weapon with model Project property. - * 4. Model Knife property. - * 5. Model Pshotno property. - * 6. Global hardcode model name, "Knife". - * 7. Global hardcode model name, "Shot". - */ - if (projectile->knife >= 0) - { - projectile_entity = spawn(position.x, position.z, position.y, direction, NULL, projectile->knife, NULL); - - projectile_prime |= PROJECTILE_PRIME_BASE_Y; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - projectile_prime |= PROJECTILE_PRIME_SOURCE_PROJ_KNIFE; - } - else if (projectile->flash >= 0) - { - projectile_entity = spawn(position.x, position.z, position.y, direction, NULL, projectile->flash, NULL); - - projectile_prime |= PROJECTILE_PRIME_BASE_FLOOR; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_STATIONARY; - projectile_prime |= PROJECTILE_PRIME_SOURCE_PROJ_FLASH; - } - else if (parent->weapent && parent->weapent->modeldata.project >= 0) - { - projectile_entity = spawn(position.x, position.z, position.y, direction, NULL, parent->weapent->modeldata.project, NULL); - - projectile_prime |= PROJECTILE_PRIME_BASE_Y; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - projectile_prime |= PROJECTILE_PRIME_SOURCE_WEAPON_PROJECTILE; - } - else if (parent->modeldata.knife >= 0) - { - projectile_entity = spawn(position.x, position.z, position.y, direction, NULL, parent->modeldata.knife, NULL); - - projectile_prime |= PROJECTILE_PRIME_BASE_Y; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - projectile_prime |= PROJECTILE_PRIME_SOURCE_MODEL_KNIFE; - } - else if (parent->modeldata.pshotno >= 0) - { - projectile_entity = spawn(position.x, position.z, position.y, direction, NULL, parent->modeldata.pshotno, NULL); - - projectile_prime |= PROJECTILE_PRIME_BASE_FLOOR; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_STATIONARY; - projectile_prime |= PROJECTILE_PRIME_SOURCE_MODEL_PSHOTNO; - } - else - { - /* - * No model indexes set, so let's fall back to - * the legacy hardcode model names. - * - * Try hardcode "knife" first. If that fails, we'll try - * "shot" next. - */ - projectile_entity = spawn(position.x, position.z, position.y, direction, "Knife", MODEL_INDEX_NONE, NULL); - - if (projectile_entity) - { - /* - * Hardcode knife spawn successful. Mark as legacy knife - * and continue. - */ - projectile_prime |= PROJECTILE_PRIME_SOURCE_GLOBAL_KNIFE; - } - else - { - /* Try "shot". */ - projectile_entity = spawn(position.x, position.z, position.y, direction, "Shot", MODEL_INDEX_NONE, NULL); - - projectile_prime |= PROJECTILE_PRIME_SOURCE_GLOBAL_SHOT; - } - - projectile_prime |= PROJECTILE_PRIME_BASE_Y; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - } - - /* If we never successfully spawned a projectile entity, exit. */ - if(!projectile_entity) - { - return NULL; - } - - /* - * Get result of direction adjustment. We need this before we can handle - * positioning on X axis. - */ - direction = direction_get_adjustment_result(projectile_entity, parent, projectile->direction_adjust); - - /* - * Let's set up the spawn position. Reverse X when - * parent faces left. - * - * Apply default X position if creator did not give - * us a value. - */ - - if (projectile->position.x == PROJECTILE_LEGACY_COMPATABILITY_POSITION_X) - { - projectile->position.x = PROJECTILE_DEFAULT_POSITION_X; - } - - if (direction == DIRECTION_RIGHT) - { - position.x = parent->position.x + projectile->position.x; - } - else - { - position.x = parent->position.x - projectile->position.x; - } - - projectile_entity->direction = direction; - projectile_entity->position.x = position.x; - - /* - * Player projectiles are always type "shot", unless - * using the current PROJECTILE type. - */ - if (!(projectile_entity->modeldata.type & TYPE_PROJECTILE)) - { - if (parent->modeldata.type & TYPE_PLAYER) - { - projectile_entity->modeldata.type = TYPE_SHOT; - } - else - { - projectile_entity->modeldata.type = parent->modeldata.type; - } - } - - /* Apply projectile prime flags. */ - projectile_entity->projectile_prime = projectile_prime; - - /* - * Copy offense values from parent offense settings - * to projectile enity if requested. - */ - if (projectile->offense == PROJECTILE_OFFENSE_PARENT) - { - memcpy(projectile_entity->offense, parent->offense, sizeof(*projectile_entity->offense) * max_attack_types); - } - - /* Apply color adjustment. */ - apply_color_set_adjust(projectile_entity, parent, projectile->color_set_adjust); - - - /* - * If no move, then all speed is 0. Otherwise check for use of - * projectile velocity. If player supplied any value other - * than MODEL_SPEED_NONE, we use player's value. If not, fall - * back to default values. This is a bit overcomplicated, but - * allows players to supply a 0 velocity value on any axis. - */ - if (projectile_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - projectile_entity->modeldata.speed.x = 0; - projectile_entity->modeldata.speed.y = 0; - projectile_entity->modeldata.speed.z = 0; - } - else - { - /* Copy speed values from animation projectile settings to model. */ - projectile->velocity = projectile_entity->modeldata.speed; - } - - /* Set up behavior flags. */ - projectile_entity->spawntype = SPAWN_TYPE_PROJECTILE_NORMAL; - projectile_entity->owner = parent; - projectile_entity->nograb = 1; - projectile_entity->attacking = ATTACKING_ACTIVE; - projectile_entity->think = common_think; - projectile_entity->nextthink = _time + 1; - projectile_entity->trymove = NULL; - projectile_entity->takedamage = arrow_takedamage; - projectile_entity->takeaction = NULL; - projectile_entity->modeldata.aimove = AIMOVE1_ARROW; - projectile_entity->speedmul = 2; - projectile_entity->modeldata.aiattack = AIATTACK1_NOATTACK; - - if(!projectile_entity->modeldata.offscreenkill) - { - projectile_entity->modeldata.offscreenkill = 200; //default value - } - - /* Kill self when we hit. */ - if (projectile_entity->modeldata.remove_config & REMOVE_CONFIG_HIT) - { - projectile_entity->autokill |= AUTOKILL_ATTACK_HIT; - } - - /* Kill self when we finish animation. */ - if (projectile_entity->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - projectile_entity->autokill |= AUTOKILL_ANIMATION_COMPLETE; - } - - /* Is this a floor or flying projectile ? Set base accordingly. */ - if(projectile_entity->projectile_prime & PROJECTILE_PRIME_BASE_FLOOR) - { - projectile_entity->base = 0; - } - else - { - projectile_entity->base = position.y; - } - - /* - * Copy faction data from parent. - */ - - faction_copy_all(projectile_entity, parent); - - /* - * If player damage turned off, remove player type from - * hostile (so homing projectiles leave players alone) and - * from candamage. - */ - if((parent->modeldata.type & TYPE_PLAYER) && ((level && level->nohit == DAMAGE_FROM_PLAYER_OFF) || savedata.mode)) - { - projectile_entity->faction.type_hostile &= ~TYPE_PLAYER; - projectile_entity->faction.type_damage_direct &= ~TYPE_PLAYER; - } - - /* - * Set terrain and movement behavior flags. Legacy - * behavior wouldn't allow movement along Y axis - * without an arc, but we can't fix this without - * breaking compatability, so we'll need a different - * setup depending on what function creator used. - */ - - projectile_entity->modeldata.move_config_flags |= (MOVE_CONFIG_PROJECTILE_BASE_DIE | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL | MOVE_CONFIG_PROJECTILE_WALL_BOUNCE); - projectile_entity->modeldata.move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - - if (projectile_entity->projectile_prime & PROJECTILE_PRIME_INITIALIZE_LEGACY_PROJECTILE_FUNCTION) - { - projectile_entity->modeldata.move_config_flags |= MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - else - { - projectile_entity->modeldata.move_config_flags &= ~MOVE_CONFIG_SUBJECT_TO_GRAVITY; - } - - /* Execute the projectile's on spawn event. */ - execute_onspawn_script(projectile_entity); - - return projectile_entity; -} - -void bomb_explode() -{ - if(self->animating) - { - return; - } - kill_entity(self, KILL_ENTITY_TRIGGER_BOMB_EXPLODE_ANIMATION_COMPLETE); -} - -/* -* Caskey, Damon V. -* 2019-12-22 (refactor) -* -* Original author unknown (Tails?). Refactored to remove the ever-growing parameter list -* and consolidate projectile spawn logic. Spawns an entity and fires it as a bomb projectile. -* Model used for spawn is determined by a hierarchy of legacy parameters (see detailed -* comments in function). -* -* Returns pointer of spawned projectile, or NULL on fail. -*/ -entity *bomb_spawn(entity *parent, s_projectile *projectile) -{ - entity* ent = NULL; - s_axis_principal_float position; - e_direction direction = DIRECTION_RIGHT; - e_projectile_prime projectile_prime = PROJECTILE_PRIME_NONE; - - // If there's no projectile or parent setting, exit now. - if (!projectile || !parent) - { - return NULL; - } - - position.x = parent->position.x; - position.y = parent->position.y + projectile->position.y; - position.z = parent->position.z + projectile->position.z; - - /* - * Now we need to spawn the projectile entity. There are many haphazard legacy - * additions to sift through, so we need to prioritize which model to spawn. - * In general, we work back from most granular to most global. - * - * From highest to lowest priority: - * - * 1. Projectile Bomb property. - * 2. Using weapon with model bomb property. - * 3. Model bomb property. - */ - - if(projectile->bomb >= 0) - { - ent = spawn(position.x, position.z, position.y, direction, NULL, projectile->bomb, NULL); - - projectile_prime |= PROJECTILE_PRIME_SOURCE_PROJ_BOMB; - } - else if (self->weapent && self->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && self->weapent->modeldata.project >= 0) - { - ent = spawn(position.x, position.z, position.y, direction, NULL, self->weapent->modeldata.project, NULL); - - projectile_prime |= PROJECTILE_PRIME_SOURCE_WEAPON_PROJECTILE; - } - else if(self->modeldata.bomb >= 0) - { - ent = spawn(position.x, position.z, position.y, direction, NULL, self->modeldata.bomb, NULL); - - projectile_prime |= PROJECTILE_PRIME_SOURCE_MODEL_BOMB; - } - - projectile_prime |= PROJECTILE_PRIME_BASE_FLOOR; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - - // If we never successfully spawned a projectile entity, exit. - if(!ent) - { - return NULL; - } - - /* - * Get result of direction adjustment. We need this before we can handle - * positioning on X axis. - */ - direction = direction_get_adjustment_result(ent, parent, projectile->direction_adjust); - - /* - * Let's set up the spawn position. Reverse X when - * parent faces left. - * - * Apply default X position if creator did not give - * us a value. - */ - - if (projectile->position.x == PROJECTILE_LEGACY_COMPATABILITY_POSITION_X) - { - projectile->position.x = PROJECTILE_DEFAULT_POSITION_X; - } - - if (direction == DIRECTION_RIGHT) - { - position.x = parent->position.x + projectile->position.x; - } - else - { - position.x = parent->position.x - projectile->position.x; - } - - ent->direction = direction; - ent->position.x = position.x; - - - ent->projectile_prime = projectile_prime; - - /* - * If no move, then all speed is 0. Otherwise check for use of - * projectile velocity. If player supplied any value other - * than MODEL_SPEED_NONE, we use player's value. If not, fall - * back to default values. This is a bit overcomplicated, but - * allows players to supply a 0 velocity value on any axis. - */ - - if (ent->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - ent->modeldata.speed.x = 0; - ent->modeldata.speed.y = 0; - ent->modeldata.speed.z = 0; - } - else - { - // Copy speed values from animation projectile settings to model. - projectile->velocity.x = ent->modeldata.speed.x; - } - - /* - * Toss the bomb entity in an arc. - * - * We want to handle legacy behavior (use projectile jumpheight - * for Y toss velocity), allow author to apply a 0 value for Y - * velocity, and use the same velocity structure members for bomb - * and knife projectiles. The last part is an extra challenge because - * the default velocity needs for knife and bomb are not compatible. - * To handle all of this this we will set the velocity.y member to - * MODEL_SPEED_NONE specfically when a bomb projectile is requested - * by the Throwframe command or "bomb" type from legacy script function - * projectile(). If the author does not modify this value, we know - * to fall back to legacy behavior and use the projectile entity's - * model jumpheight. - * - * If the value is anything other than MODEL_SPEED_NONE, then we know - * the author requested a specific velocity (including 0) and will - * use author value instead of model jumpheight. - */ - - if (projectile->velocity.y == MODEL_SPEED_NONE) - { - toss(ent, ent->modeldata.jumpheight); - } - else - { - toss(ent, projectile->velocity.y); - } - - /* Apply color adjustment. */ - apply_color_set_adjust(ent, parent, projectile->color_set_adjust); - - ent->spawntype = SPAWN_TYPE_PROJECTILE_BOMB; - ent->attacking = ATTACKING_ACTIVE; - ent->owner = parent; - ent->nograb = 1; - ent->toexplode |= (EXPLODE_PREPARE_TOUCH | EXPLODE_PREPARE_GROUND); - - ent->think = common_think; - ent->nextthink = _time + 1; - ent->trymove = NULL; - ent->takeaction = NULL; - ent->modeldata.aimove = AIMOVE1_BOMB; - ent->modeldata.aiattack = AIATTACK1_NOATTACK; - ent->takedamage = common_takedamage; - ent->autokill &= ~AUTOKILL_ATTACK_HIT; - - if (ent->modeldata.move_config_flags & MOVE_CONFIG_NO_MOVE) - { - ent->autokill |= AUTOKILL_ANIMATION_COMPLETE; - } - - ent->speedmul = 2; - - /* - * Copy faction data. - */ - - faction_copy_all(ent, parent); - - ent->modeldata.move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - ent->modeldata.move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_PROJECTILE_BASE_DIE | MOVE_CONFIG_PROJECTILE_WALL_BOUNCE | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL); - - // Execute the projectile's on spawn event. - execute_onspawn_script(ent); - - return ent; -} - -// Spawn 3 stars -// -// Caskey, Damon V. -// 2019-12-17 -// -// Spawn three "star" projectiles. Meant for Eiji enemies in -// original Beats of Rage, who would jump and throw three star -// shuriken diagonally downward at players. Original author -// Roel, but modified several times by unknown parties. Refactored -// by DC 2019-12-17 to work with current projectile system. -// Obviously, we need this for backward compatibility with legacy -// modules, but otherwise script is the best choice to handle -// multiple projectiles or any other sort of specialized -// projectile spawns. -// -// Return TRUE if stars spawned, FALSE on fail. -int star_spawn(entity *parent, s_projectile *projectile) -{ - const int MAX_STARS = 3; - - entity *ent = NULL; - int i = 0; - int index = MODEL_INDEX_NONE; - int first_sortid = 0; - - s_axis_principal_float position; - e_direction direction = DIRECTION_RIGHT; - e_projectile_prime projectile_prime = PROJECTILE_PRIME_NONE; - - // If there's no projectile or parent setting, exit now. - if (!projectile || !parent) - { - return FALSE; - } - - position.x = parent->position.x; - position.y = parent->position.y + projectile->position.y; - position.z = parent->position.z + projectile->position.z; - - // Same concept as knife spawn. Look for model to spawn. - // 1. Animation projectile. - // 2. Weapon model projectile. - // 3. Base model projectile. - // 4. Legacy default. - if(projectile->star >= 0) - { - index = projectile->star; - - projectile_prime |= PROJECTILE_PRIME_SOURCE_PROJ_STAR; - } - else if (parent->weapent && parent->weapent->modeldata.subtype == SUBTYPE_PROJECTILE && parent->weapent->modeldata.project >= 0) - { - index = parent->weapent->modeldata.project; - - projectile_prime |= PROJECTILE_PRIME_SOURCE_WEAPON_PROJECTILE; - } - else if(parent->modeldata.star >= 0) - { - index = parent->modeldata.star; - - projectile_prime |= PROJECTILE_PRIME_SOURCE_MODEL_STAR; - } - else - { - index = get_cached_model_index("Star"); - - projectile_prime |= PROJECTILE_PRIME_SOURCE_GLOBAL_STAR; - } - - projectile_prime |= PROJECTILE_PRIME_BASE_Y; - projectile_prime |= PROJECTILE_PRIME_LAUNCH_MOVING; - - // Loop to max star count. - for(i = 0; i < MAX_STARS; i++) - { - // Spawn the star entity. If we fail, exit and return false. - ent = spawn(position.x, position.z, position.y, direction, NULL, index, NULL); - if(ent == NULL) - { - return 0; - } - - // Get result of direction adjustment. We need this before we can handle - // positioning on X axis. - direction = direction_get_adjustment_result(ent, parent, projectile->direction_adjust); - - /* - * Apply default X position if - * creator did not give us a value. - */ - - if (projectile->position.x == PROJECTILE_LEGACY_COMPATABILITY_POSITION_X) - { - projectile->position.x = PROJECTILE_DEFAULT_STAR_POSITION_X; - } - - // Reverse X when parent faces left. - if (direction == DIRECTION_RIGHT) - { - position.x = parent->position.x + projectile->position.x; - } - else - { - position.x = parent->position.x - projectile->position.x; - } - - ent->position.x = position.x; - ent->direction = direction; - - // 2019-12-17 DC - Not sure why we set attacking off, but - // leaving it here for legacy behavior. - parent->attacking = ATTACKING_NONE; - - // First star spawned sort id serves as a base for sorting. - // Then the next star's sort is the base - loop index. Each - // subsequent star appears one step further behind in - // sorting order. - // - // Ex: Base (first star) = 20, 20 - 1 = 19, 20 - 2 = 18. - if (i <= 0) - { - first_sortid = ent->sortid; - } - - ent->sortid = first_sortid - i; - - ent->takedamage = arrow_takedamage; - ent->owner = parent; - ent->attacking = ATTACKING_ACTIVE; - ent->nograb = 1; - - // Get the star velocity setting from animation. - ent->velocity.x = projectile->star_velocity[i]; - - // Reverse X velocity if direction is left. - if (direction == DIRECTION_LEFT) - { - ent->velocity.x = -ent->velocity.x; - } - - ent->think = common_think; - ent->nextthink = _time + 1; - ent->trymove = NULL; - ent->takeaction = NULL; - ent->modeldata.aimove = AIMOVE1_STAR; - ent->modeldata.aiattack = AIATTACK1_NOATTACK; - - // Remove star on contact. - if (ent->modeldata.remove_config & REMOVE_CONFIG_HIT) - { - ent->autokill |= AUTOKILL_ATTACK_HIT; - } - - ent->position.y = position.y; - ent->base = position.y; - ent->speedmul = 2; - - /* - * Copy faction data. - */ - - faction_copy_all(ent, parent); - - // Basic terrian property setup. - ent->modeldata.move_config_flags |= (MOVE_CONFIG_SUBJECT_TO_BASEMAP | MOVE_CONFIG_SUBJECT_TO_GRAVITY | MOVE_CONFIG_SUBJECT_TO_HOLE | MOVE_CONFIG_SUBJECT_TO_PLATFORM | MOVE_CONFIG_SUBJECT_TO_WALL); - ent->modeldata.move_config_flags &= ~MOVE_CONFIG_NO_ADJUST_BASE; - - ent->spawntype = SPAWN_TYPE_PROJECTILE_STAR; - ent->projectile_prime = projectile_prime; - - // Execute the projectile's on spawn event. - execute_onspawn_script(ent); - } - return TRUE; -} - - - -void steam_think() -{ - if(!self->animating) - { - kill_entity(self, KILL_ENTITY_TRIGGER_STEAM_ANIMATION_COMPLETE); - return; - } - - self->base += 1; - self->position.y = self->base; -} - - - -// for the "trap" type 7-1-2005 trap start -void trap_think() -{ - self->attacking = ATTACKING_ACTIVE; -} -// 7-1-2005 trap end - - - - -void steam_spawn(float x, float z, float a) -{ - entity *e = NULL; - - e = spawn(x, z, a, 0, "Steam", -1, NULL); - - if(e == NULL) - { - return; - } - - e->spawntype = SPAWN_TYPE_STEAM; - e->base = a; - e->modeldata.move_config_flags |= MOVE_CONFIG_NO_ADJUST_BASE; - e->think = steam_think; - - // Execute the steams's on spawn event. - execute_onspawn_script(e); -} - - - -void steamer_think() -{ - steam_spawn(self->position.x, self->position.z, self->position.y); - self->nextthink = _time + (global_config.game_speed / 10) + (rand32() & 31); -} - - - -void text_think() // New function so text can be displayed -{ - // wait to suicide - if(!self->animating) - { - kill_entity(self, KILL_ENTITY_TRIGGER_TEXT_ANIMATION_COMPLETE); - } -} - -//////////////////////////////// - -//homing arrow find its target -// type : target type -entity *homing_find_target(entity* acting_entity) -{ - int i; - int min; - int max; - - entity* target_entity = NULL; - entity* cursor_entity; - - //use the walk animation's range - if(validanim(acting_entity, ANI_WALK)) - { - min = acting_entity->modeldata.animation[ANI_WALK]->range.x.min; - max = acting_entity->modeldata.animation[ANI_WALK]->range.x.max; - } - else - { - min = 0; - max = 999; - } - - //find the 'nearest' one - for(i = 0; i < ent_max; i++) - { - cursor_entity = ent_list[i]; - - if(cursor_entity->exists && cursor_entity != acting_entity // cant target self - && cursor_entity != acting_entity->owner // Don't go after owner. - && faction_check_is_hostile(acting_entity, cursor_entity) - && diff(cursor_entity->position.x, acting_entity->position.x) + diff(cursor_entity->position.z, acting_entity->position.z) >= min - && diff(cursor_entity->position.x, acting_entity->position.x) + diff(cursor_entity->position.z, acting_entity->position.z) <= max - && cursor_entity->animation->vulnerable[cursor_entity->animpos] ) - { - if(!target_entity || diff(cursor_entity->position.x, acting_entity->position.x) + diff(cursor_entity->position.z, acting_entity->position.z) < diff(target_entity->position.x, acting_entity->position.x) + diff(target_entity->position.z, acting_entity->position.z)) - { - target_entity = cursor_entity; - } - } - } - - return target_entity; -} - - -void bike_crash() -{ - int i; - if(self->direction == DIRECTION_RIGHT) - { - self->velocity.x = 2; - } - else - { - self->velocity.x = -2; - } - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if (savedata.joyrumble[i]) control_rumble(i, 1, 100); - } - //if(self->position.x < advancex-100 || self->position.x > advancex+(videomodes.hRes+100)) kill_entity(self); -} - - - -int biker_takedamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, int fall_flag, const s_defense* defense_object) -{ - entity *driver = NULL; - - if(target_entity->death_state & DEATH_STATE_DEAD) - { - return 0; - } - // Fell in a hole - if(target_entity->position.y < PIT_DEPTH) - { - kill_entity(target_entity, KILL_ENTITY_TRIGGER_TAKE_DAMAGE_BIKER_PIT); - return 0; - } - if(attacking_entity != target_entity) - { - set_opponent(attacking_entity, target_entity); - } - - if(attack_object->no_pain) // don't drop driver until it is dead, because the attack has no pain effect - { - checkdamage(target_entity, attacking_entity, attack_object, defense_object); - if(target_entity->energy_state.health_current > 0) - { - return 1; // not dead yet - } - } - - check_backpain(attacking_entity, target_entity); - set_pain(target_entity, target_entity->last_damage_type, 1); - target_entity->attacking = ATTACKING_ACTIVE; - if(!target_entity->modeldata.offscreenkill) - { - target_entity->modeldata.offscreenkill = 100; - } - target_entity->think = bike_crash; - // well, this is the real entity, the driver who take the damage - if((driver = drop_driver(target_entity))) - { - driver->position.y = target_entity->position.y; - driver->drop = 1; - driver->direction = target_entity->direction; - if(driver->takedamage) - { - driver->takedamage(driver, attacking_entity, attack_object, fall_flag, defense_object); - } - else - { - driver->energy_state.health_current -= attack_object->attack_force; - } - } - target_entity->energy_state.health_current = 0; - checkdeath(target_entity); - return 1; -} - - - -void obstacle_fall() -{ - if(inair(self)) - { - return; - } - - self->velocity.x = self->velocity.z = 0; - if((!self->animating && validanim(self, ANI_DIE)) || !validanim(self, ANI_DIE)) - { - kill_entity(self, KILL_ENTITY_TRIGGER_OBSTACLE_FALL_NO_DEATH_ANIMATION); // Fixed so ANI_DIE can be used - } -} - - - -void obstacle_fly() // Now obstacles can fly when hit like on Simpsons/TMNT -{ - //self->position.x += self->velocity.x * 4; // Equivelant of speed 40 - if(self->position.x > advancex + (videomodes.hRes + 200) || self->position.x < advancex - 200) - { - kill_entity(self, KILL_ENTITY_TRIGGER_OBSTACLE_FLY_OUT_OF_BOUNDS); - } -} - - - -int obstacle_takedamage(entity* target_entity, entity* attacking_entity, s_attack* attack_object, int fall_flag, const s_defense* defense_object) -{ - if(target_entity->position.y <= PIT_DEPTH) - { - kill_entity(target_entity, KILL_ENTITY_TRIGGER_TAKE_DAMAGE_OBSTACLE_PIT); - return 0; - } - - set_opponent(attacking_entity, target_entity); - if(target_entity->opponent && (target_entity->opponent->modeldata.type & TYPE_PLAYER)) - { - if (savedata.joyrumble[target_entity->opponent->playerindex]) control_rumble(target_entity->opponent->playerindex, 1, 75); - } - - /* Calculate and apply HP damage. */ - checkdamage(target_entity, attacking_entity, attack_object, defense_object); - - target_entity->playerindex = attacking_entity->playerindex; // Added so points go to the correct player - addscore(attacking_entity->playerindex, attack_object->attack_force * target_entity->modeldata.multiple); // Points can now be given for hitting an obstacle - - if(target_entity->energy_state.health_current <= 0) - { - - checkdeath(target_entity); - - if(attacking_entity->position.x < target_entity->position.x) - { - target_entity->velocity.x = 1; - } - else - { - target_entity->velocity.x = -1; - } - - target_entity->attacking = ATTACKING_ACTIVE; // So obstacles can explode and hurt players/enemies - - if(target_entity->modeldata.subtype == SUBTYPE_FLYDIE) // Now obstacles can fly like on Simpsons/TMNT - { - target_entity->velocity.x *= 4; - target_entity->think = obstacle_fly; - ent_set_anim(target_entity, ANI_FALL, 0); - } - else - { - target_entity->think = obstacle_fall; - - if(validanim(target_entity, ANI_DIE)) - { - ent_set_anim(target_entity, ANI_DIE, 0); // LTB 1-13-05 Die before toss - } - else - { - toss(target_entity, target_entity->modeldata.jumpheight / 1.333); - ent_set_anim(target_entity, ANI_FALL, 0); - } - - if(target_entity->modeldata.death_config_flags & DEATH_CONFIG_MACRO_BLINK) - { - target_entity->blink = 1; - } - } - } - - target_entity->nextthink = _time + 1; - return 1; -} - -// Caskey, Damon V. -// 2018-04-27 -// -// Allocate memory and set entity properties that will be transfered -// to a dropped item. -void initialize_item_carry(entity *ent, s_spawn_entry *spawn_entry) -{ - // It's possible to call this from script, so if - // there is already memory for an item allocated - // here, clear it out to make sure we don't end up - // with any memory leaks. - if(ent->item_properties) - { - free(ent->item_properties); - ent->item_properties = NULL; - } - - // Allocate memory for the item. - ent->item_properties = malloc(sizeof(*ent->item_properties)); - memset(ent->item_properties, 0, sizeof(*ent->item_properties)); - - if(spawn_entry) - { - ent->item_properties->index = spawn_entry->item_properties.index; - - if(spawn_entry->item_properties.alias[0]) - { - strcpy(ent->item_properties->alias, spawn_entry->item_properties.alias); - } - - if(spawn_entry->item_properties.colorset) - { - ent->item_properties->colorset = spawn_entry->item_properties.colorset; - } - - if(spawn_entry->item_properties.health) - { - ent->item_properties->health = spawn_entry->item_properties.health; - } - ent->item_properties->player_count = spawn_entry->item_properties.player_count; - } -} - -entity *smartspawn(s_spawn_entry *props) // 7-1-2005 Entire section replaced with lord balls code -{ - entity *e = NULL; - entity *wp = NULL; - int playercount; - - if( props == NULL /* || - (level == NULL && - !(screen_status & (IN_SCREEN_SELECT | IN_SCREEN_TITLE | IN_SCREEN_HALL_OF_FAME | IN_SCREEN_GAME_OVER | IN_SCREEN_SHOW_COMPLETE | IN_SCREEN_ENGINE_CREDIT | IN_SCREEN_MENU | IN_SCREEN_GAME_START_MENU | IN_SCREEN_NEW_GAME_MENU | IN_SCREEN_LOAD_GAME_MENU | IN_SCREEN_OPTIONS_MENU | IN_SCREEN_CONTROL_OPTIONS_MENU | IN_SCREEN_SOUND_OPTIONS_MENU | IN_SCREEN_VIDEO_OPTIONS_MENU | IN_SCREEN_SYSTEM_OPTIONS_MENU)) && - currentScene)*/ - ) - { - return NULL; - } - - /* Spawn item based on number of active players. */ - if(props->spawnplayer_count >= (playercount = MAX(1, count_ents(TYPE_PLAYER)))) - { - if(props->boss && level != NULL) - { - --level->bossescount; - } - return NULL; - } - - if( level != NULL && ((level->scrolldir & SCROLL_INWARD) || (level->scrolldir & SCROLL_OUTWARD)) ) - { - e = spawn(props->position.x, props->position.z + advancey, props->position.y, props->flip, props->name, props->index, props->model); - } - else - { - e = spawn(props->position.x + advancex, props->position.z, props->position.y, props->flip, props->name, props->index, props->model); - } - - if(e == NULL) - { - return NULL; - } - - //printf("%s, (%f, %f, %f) - (%f, %f, %f)", props->name, props->position.x, props->position.z, props->position.y, e->position.x, e->position.z, e->position.y); - - // Alias? - if(props->alias[0]) - { - memset(e->name, 0, sizeof(e->name)); - strcpy(e->name, props->alias); - } - - // If we have item properties in spawn entry, then prepare a set of - // properties to pass on to the item when it is dropped. - if(props->item) - { - initialize_item_carry(e, props); - } - - faction_copy_data(&e->modeldata.faction, &props->faction); - faction_copy_data(&e->faction, &props->faction); - - if(props->spawntype) - { - e->spawntype = props->spawntype; //2011_03_23, Pass spawntype. - } - - if(props->health[playercount - 1] != 0) - { - e->energy_state.health_current = e->modeldata.health = props->health[playercount - 1]; - } - - if(props->mp != 0) - { - e->energy_state.mp_current = e->modeldata.mp = props->mp; - } - - if(props->score != 0) - { - e->modeldata.score = props->score; // Overwrite score if exists in the level's. txt file - } - if(props->multiple != 0) - { - e->modeldata.multiple = props->multiple; // Overwrite multiple if exists in the level's .txt file - } - - if(!e->map && props->colourmap) - { - ent_set_colourmap(e, props->colourmap); - } - - if(props->aggression) - { - e->modeldata.aggression = props->aggression; // Aggression can be changed with spawn points now - } - if(props->item_properties.alpha) - { - e->item_properties->alpha = props->item_properties.alpha; - } - if(props->alpha) - { - e->modeldata.alpha = props->alpha; - } - - // Feb 26, 2005 - Store the original map to be able to restore with dying flash - if(props->dying) - { - e->dying = props->dying; // Feb 26, 2005 - Used to define which colourmap is used for the dying flash - e->per1 = props->per1; // Mar 21, 2005 - Used to store custom percentages - e->per2 = props->per2; // Mar 21, 2005 - Used to store custom percentages - e->dying2 = props->dying2; // Dec 15, 2016 - Used to define which colourmap is used for the dying flash for per2 By White Dragon - } - - if(props->nolife) - { - e->modeldata.nolife = props->nolife; // Overwrite whether live is visible or not - } - e->boss = props->boss; - - if(props->boss && level != NULL && level->bossmusic[0]) - { - music(level->bossmusic, 1, level->bossmusic_offset); - } - - // give the entity a weapon item - if(props->weapon) - { - wp = spawn(e->position.x, ITEM_HIDE_POSITION_Z, 0, 0, props->weapon, props->weaponindex, props->weaponmodel); - if(wp) - { - //ent_default_init(wp); - set_weapon(e, wp->modeldata.weapon_properties.weapon_index, 0); - e->weapent = wp; - - e->weapent->spawntype = SPAWN_TYPE_WEAPON; - } - } - - // set entity type: player, enemy, npc... - if(props->entitytype) - { - e->modeldata.type = props->entitytype; - } - - // set a parent - if(props->parent) //->varlist->vars->vt != VT_EMPTY - { - e->parent = (entity *)props->parent; - } - - //ent_default_init(e); - execute_onspawn_script(e); - execute_spawn_script(props, e); - return e; -} // 7-1-2005 replaced section ends here - -int is_incam(float x, float z, float a, float threshold) -{ - if (level) - { - if ( x >= advancex+threshold && x <= advancex+videomodes.hRes-threshold && z-a >= advancey+threshold && z-a <= advancey+videomodes.vRes-4 ) { - if ( x >= scrollminx && x <= scrollmaxx+videomodes.hRes && z >= PLAYER_MIN_Z && z <= PLAYER_MAX_Z ) { - return 1; - } - } - } - - return 0; -} - -void spawnplayer(int index) -{ - s_spawn_entry p; - //s_model * model = NULL; - int wall; - int xc, zc, find = 0; - index &= 3; - -// model = find_model(player[index].name); -// if(model == NULL) return; - - memset(&p, 0, sizeof(p)); - p.name = player[index].name; - p.index = -1; - p.item_properties.index = -1; - p.weaponindex = -1; - p.colourmap = player[index].colourmap; - p.spawnplayer_count = -1; - p.spawntype = SPAWN_TYPE_PLAYER_MAIN; - - if(level->scrolldir & SCROLL_LEFT) - { - if(level->spawn && level->spawn[index].x) - { - p.position.x = (float)(videomodes.hRes - level->spawn[index].x); - } - else - { - p.position.x = (float)((videomodes.hRes - 20) - 30 * index); - } - } - else - { - if(level->spawn && level->spawn[index].x) - { - p.position.x = (float)(level->spawn[index].x); - } - else - { - p.position.x = (float)(20 + 30 * index); - } - p.flip = 1; - } - - if(level->spawn && level->spawn[index].z) - { - if(level->scrolldir & (SCROLL_INWARD | SCROLL_OUTWARD)) - { - p.position.z = (float)(level->spawn[index].z); - } - else - { - p.position.z = (float)(PLAYER_MIN_Z + level->spawn[index].z); - } - } - else if(PLAYER_MAX_Z - PLAYER_MIN_Z > 5) - { - p.position.z = (float)(PLAYER_MIN_Z + 5); - } - else - { - p.position.z = (float)PLAYER_MIN_Z; - } - - if(p.position.z < PLAYER_MIN_Z) - { - p.position.z = PLAYER_MIN_Z; - } - else if(p.position.z > PLAYER_MAX_Z) - { - p.position.z = PLAYER_MAX_Z; - } - - //////////////////checking holes/ walls/////////////////////////////////// - for(xc = 0; xc < videomodes.hRes / 4; xc++) - { - if(p.position.x >= videomodes.hRes) - { - p.position.x -= videomodes.hRes; - } - if(p.position.x < 0) - { - p.position.x += videomodes.hRes; - } - if(PLAYER_MIN_Z == PLAYER_MAX_Z) - { - wall = checkwall_index(advancex + p.position.x, p.position.z); - if(wall >= 0 && level->walls[wall].height < MAX_WALL_HEIGHT) - { - break; //found - } - if(checkhole_in(advancex + p.position.x, p.position.z, p.position.y) || (wall >= 0 && level->walls[wall].height >= MAX_WALL_HEIGHT)) - { - find = 0; - } - else - { - break; // found - } - } - else for(zc = 0; zc < (PLAYER_MAX_Z - PLAYER_MIN_Z) / 3; zc++, p.position.z += 3) - { - if(p.position.z > PLAYER_MAX_Z) - { - p.position.z -= PLAYER_MAX_Z - PLAYER_MIN_Z; - } - if(p.position.z < PLAYER_MIN_Z) - { - p.position.z += PLAYER_MAX_Z - PLAYER_MIN_Z; - } - wall = checkwall_index(advancex + p.position.x, p.position.z); - if(wall >= 0 && level->walls[wall].height < MAX_WALL_HEIGHT) - { - find = 1; - break; - } - else if(wall >= 0 && level->walls[wall].height >= MAX_WALL_HEIGHT) - { - continue; - } - if(checkhole_in(advancex + p.position.x, p.position.z, p.position.y)) - { - continue; - } - find = 1; - break; - } - if(find) - { - break; - } - p.position.x += (level->scrolldir & SCROLL_LEFT) ? -4 : 4; - } - /////////////////////////////////////////////////////////////////////// - currentspawnplayer = index; - player[index].ent = smartspawn(&p); - - if(player[index].ent == NULL) - { - borShutdown(1, "Fatal: unable to spawn player from '%s'\n", p.name); - } - - player[index].ent->playerindex = index; - - if(nomaxrushreset[4] >= 1) - { - player[index].ent->rush.max = nomaxrushreset[index]; - } - else - { - player[index].ent->rush.max = 0; - } - - memset( - player[index].command_input_history, - 0, - sizeof(player[index].command_input_history) - ); - - memset( - player[index].command_input_hold_start_time, - 0, - sizeof(player[index].command_input_hold_start_time) - ); - - memset( - player[index].command_input_hold_trigger_time, - 0, - sizeof(player[index].command_input_hold_trigger_time) - ); - - player[index].command_input_hold_start_valid = 0; - player[index].command_input_hold_trigger_valid = 0; - player[index].command_input_count = 0; - player[index].command_input_index = 0; - - if(player[index].spawnhealth) - { - player[index].ent->energy_state.health_current = player[index].spawnhealth + 5; - } - if(player[index].ent->energy_state.health_current > player[index].ent->modeldata.health) - { - player[index].ent->energy_state.health_current = player[index].ent->modeldata.health; - } - - //mp little recorver after a level by tails - if(player[index].spawnmp) - { - player[index].ent->energy_state.mp_current = player[index].spawnmp + 2; - } - if(player[index].ent->energy_state.mp_current > player[index].ent->modeldata.mp) - { - player[index].ent->energy_state.mp_current = player[index].ent->modeldata.mp; - } - - if(player[index].weapnum) - { - set_weapon(player[index].ent, player[index].weapnum, 0); - } - else - { - set_weapon(player[index].ent, level->setweap, 0); - } -} - -int no_player_alive_to_join() -{ - int no_alive_players = 0; - int i; - for(i = 0; i < MAX_PLAYERS; i++) - { - if( ((!player[i].ent || player[i].lives <= 0 || (player[i].lives <= 1 && player[i].ent->energy_state.health_current <= 0)) && - ((noshare && player[i].credits <= 0) || (!noshare && credits <= 0))) - ) - { - ++no_alive_players; - } - } - no_alive_players = (no_alive_players >= MAX_PLAYERS) ? 1 : 0; - - return no_alive_players; -} - -void kill_all_players_by_timeover() -{ - int i; - s_attack attack_timeover = emptyattack; - s_attack attack_lose = emptyattack; - const s_defense* defense_object = NULL; - - attack_timeover.attack_type = ATK_TIMEOVER; - attack_timeover.dropv.y = default_model_dropv.y; - attack_timeover.dropv.x = default_model_dropv.x; - attack_timeover.dropv.z = default_model_dropv.z; - - attack_lose.attack_type = ATK_LOSE; - - - endgame = 1; - for(i = 0; i < MAX_PLAYERS; i++) - { - entity* tmp = self; - self = player[i].ent; - if(self && !validanim(self, ANI_LOSE)) - { - endgame = 0; - attack_timeover.attack_force = self->energy_state.health_current; - - defense_object = defense_find_current_object(self, NULL, attack_timeover.attack_type); - - self->takedamage(self, self, &attack_timeover, 0, defense_object); - } - else if(self) - { - endgame = 0; - - attack_lose.attack_force = self->energy_state.health_current; - if (inair(self) && validanim(self, ANI_FALLLOSE)) - { - attack_lose.dropv.y = default_model_dropv.y; - attack_lose.dropv.x = default_model_dropv.x; - attack_lose.dropv.z = default_model_dropv.z; - self->modeldata.death_config_flags |= DEATH_CONFIG_MACRO_DEATH_FALL_LAND; - } - else - { - self->modeldata.death_config_flags |= DEATH_CONFIG_MACRO_DEATH; - } - - defense_object = defense_find_current_object(self, NULL, attack_lose.attack_type); - - self->takedamage(self, self, &attack_lose, 0, defense_object); - } - self = tmp; - } -} - -void time_over() -{ - if(level->type == 1) - { - level_completed = 1; // Feb 25, 2005 - Used for bonus levels so a life isn't taken away if time expires.level->type == 1 means bonus level, else regular - } - else if(!level_completed) - { - kill_all_players_by_timeover(); - - if (!is_total_timeover) - { - if(global_sample_list.time_over >= 0) - { - sound_play_sample(global_sample_list.time_over, 0, savedata.effectvol, savedata.effectvol, 100); - } - - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - if(!endgame) - { - showtimeover = 1; - } - } - if (!is_total_timeover && no_player_alive_to_join()) - { - is_total_timeover = 1; - nojoin = 1; - } - } -} - - -// ----------------------- Update functions ------------------------------ - -void update_scroller() -{ - float to = 0; - int i, againstend = 0; - int numplay = 0; //4player - float tx = advancex, ty = advancey; - float rm = -9999, lm = 999999, bm = -9999, tm = 999999; //player boundary box - static int scrolladd = 0; - scrolldx = scrolldy = 0; - int p_alive = 0; - - if(_time < level->advancetime || freezeall) - { - return; // Added freezeall so backgrounds/scrolling don't update if animations are frozen - } - - /* - //level->advancetime = _time + (global_config.game_speed/100); // Changed so scrolling speeds up for faster players - level->advancetime = _time - - ((player[0].ent && (player[0].ent->modeldata.speed.x >= 12 || player[0].ent->modeldata.runspeed >= 12)) || - (player[1].ent && (player[1].ent->modeldata.speed.x >= 12 || player[1].ent->modeldata.runspeed >= 12)) || - (player[2].ent && (player[2].ent->modeldata.speed.x >= 12 || player[2].ent->modeldata.runspeed >= 12)) || - (player[3].ent && (player[3].ent->modeldata.speed.x >= 12 || player[3].ent->modeldata.runspeed >= 12)) ); // Changed so if your player is faster the backgrounds scroll faster*/ - - level->advancetime = _time; - - if(level_completed) - { - return; - } - - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].ent && !(player[i].ent->death_state & DEATH_STATE_DEAD)) - { - p_alive = 1; - break; - } - } - - //White Dragon: No more enemies! - if(current_spawn >= level->numspawns && !findent(TYPE_ENEMY) && p_alive) - { - if(!findent(TYPE_ENDLEVEL) && ((!findent(TYPE_ITEM | TYPE_OBSTACLE) && level->type == 1) || level->type == 0)) // Feb 25, 2005 - Added so obstacles - { - level_completed = 1; // can be used for bonus levels - } - } - else if(count_ents(TYPE_ENEMY) < groupmin) - { - while(count_ents(TYPE_ENEMY) < groupmax && - current_spawn < level->numspawns && - level->pos >= level->spawnpoints[current_spawn].at - ) - { - if(level->spawnpoints[current_spawn].musicfade) - { - musicfade[0] = (float)level->spawnpoints[current_spawn].musicfade; - musicfade[1] = (float)savedata.musicvol; - } - else if(level->spawnpoints[current_spawn].music[0]) - { - strncpy(musicname, level->spawnpoints[current_spawn].music, MAX_BUFFER_LEN); - musicoffset = level->spawnpoints[current_spawn].musicoffset; - musicloop = 1; - } - else if(level->spawnpoints[current_spawn].wait) - { - level->waiting = 1; - go_time = 0; - } - else if(level->spawnpoints[current_spawn].groupmin || level->spawnpoints[current_spawn].groupmax) - { - groupmin = level->spawnpoints[current_spawn].groupmin; - groupmax = level->spawnpoints[current_spawn].groupmax; - } - else if(level->spawnpoints[current_spawn].nojoin != 0) - { - nojoin = (level->spawnpoints[current_spawn].nojoin == 1); - } - else if(level->spawnpoints[current_spawn].scrollminz & 0x80000000) - { - scrollminz = (float)(level->spawnpoints[current_spawn].scrollminz & 0x7fffffff); - scrollmaxz = (float)level->spawnpoints[current_spawn].scrollmaxz; - if(!_time) - { - advancey = scrollminz; // reset y if spawn at very beginning - } - } - else if(level->spawnpoints[current_spawn].scrollminx & 0x80000000) - { - scrollminx = (float)(level->spawnpoints[current_spawn].scrollminx & 0x7fffffff); - scrollmaxx = (float)level->spawnpoints[current_spawn].scrollmaxx; - } - else if(level->spawnpoints[current_spawn].blockade) - { - // assume level spawn entry will not roll back, so just change it to 0 here - if(level->spawnpoints[current_spawn].blockade < 0) - { - level->spawnpoints[current_spawn].blockade = 0; - } - blockade = (float)level->spawnpoints[current_spawn].blockade; - } - else if(level->spawnpoints[current_spawn].palette != 0) - { - // assume level spawn entry will not roll back, so just change it to 0 here - if(level->spawnpoints[current_spawn].palette < 0) - { - level->spawnpoints[current_spawn].palette = 0; - } - change_system_palette(level->spawnpoints[current_spawn].palette); - } - else if(level->spawnpoints[current_spawn].light.y) // change light direction for gfxshadow - { - light.x = level->spawnpoints[current_spawn].light.x; - light.y = level->spawnpoints[current_spawn].light.y; - } - else if(level->spawnpoints[current_spawn].shadowcolor) // change color for gfxshadow - { - shadowcolor = level->spawnpoints[current_spawn].shadowcolor; - if(shadowcolor == -1) - { - shadowcolor = 0; - } - else if(shadowcolor == -2) - { - shadowcolor = -1; - } - } - else if(level->spawnpoints[current_spawn].shadowalpha) // change color for gfxshadow - { - shadowalpha = level->spawnpoints[current_spawn].shadowalpha; - if(shadowalpha == BLEND_MODE_MODEL) - { - shadowalpha = BLEND_MODE_NONE; - } - } - else if(level->spawnpoints[current_spawn].shadowopacity) // change color for gfxshadow - { - shadowopacity = level->spawnpoints[current_spawn].shadowopacity; - if(shadowopacity == -1) - { - shadowopacity = 0; - } - if(shadowopacity == -2) - { - shadowopacity = -1; - } - } - else - { - smartspawn(&level->spawnpoints[current_spawn]); - } - ++current_spawn; - } - } - - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].ent) - { - if(player[i].ent->position.x > rm) - { - rm = player[i].ent->position.x; - } - if(player[i].ent->position.x < lm) - { - lm = player[i].ent->position.x; - } - if(player[i].ent->position.z > bm) - { - bm = player[i].ent->position.z; - } - if(player[i].ent->position.z < tm) - { - tm = player[i].ent->position.z; - } - numplay++; - } - } - - if(level->waiting) - { - // Wait for all enemies to be defeated - if(!findent(TYPE_ENEMY)) - { - level->waiting = 0; - if(level->noreset <= 1) - { - timeleft = level->settime * global_config.counter_speed; // Feb 24, 2005 - This line moved here to set custom time - } - go_time = _time + 3 * global_config.game_speed; - } - } - - if(numplay == 0) - { - return; - } - - - - if(!level->waiting || global_config.cheats & CHEAT_OPTIONS_IMPLACABLE_ACTIVE) - { - if(level->scrolldir & SCROLL_RIGHT) - { - - againstend = (level->width <= videomodes.hRes); - - if(rm - lm > videomodes.hRes) - { - to = advancex; - } - else - { - to = (lm + rm) / 2 - videomodes.hRes / 2 + level->cameraxoffset; - } - - if(to < scrollminx) - { - to = scrollminx; - } - else if(to > scrollmaxx) - { - to = scrollmaxx; - } - - if((level->scrolldir & SCROLL_BACK) && to < blockade) - { - to = blockade; - } - - if(to > advancex) - { - if(to > advancex + level->scrollspeed) - { - to = advancex + level->scrollspeed; - } - advancex = to; - } - else if((level->scrolldir & SCROLL_BACK) && to < advancex) - { - if(to < advancex - level->scrollspeed) - { - to = advancex - level->scrollspeed; - } - advancex = to; - } - - if(advancex < 0) - { - advancex = 0; - } - if(advancex >= level->width - videomodes.hRes) - { - advancex = (float)level->width - videomodes.hRes; - againstend = 1; - } - - if(againstend) - { - level->pos++; - } - else - { - level->pos = (int)advancex; - } - - - } - else if(level->scrolldir & SCROLL_LEFT) - { - - againstend = (level->width <= videomodes.hRes); - - if(rm - lm > videomodes.hRes) - { - to = advancex; - } - else - { - to = (lm + rm) / 2 - videomodes.hRes / 2 + level->cameraxoffset; - } - - if(to < scrollminx) - { - to = scrollminx; - } - else if(to > scrollmaxx) - { - to = scrollmaxx; - } - - if((level->scrolldir & SCROLL_BACK) && level->width - videomodes.hRes - to < blockade) - { - to = level->width - videomodes.hRes - blockade; - } - - if(to < advancex) - { - if(to < advancex - level->scrollspeed) - { - to = advancex - level->scrollspeed; - } - advancex = to; - } - else if((level->scrolldir & SCROLL_BACK) && to > advancex) - { - if(to > advancex + level->scrollspeed) - { - to = advancex + level->scrollspeed; - } - advancex = to; - } - - if(advancex > level->width - videomodes.hRes) - { - advancex = (float)level->width - videomodes.hRes; - } - if(advancex <= 0) - { - advancex = 0; - againstend = 1; - } - - if(againstend) - { - level->pos++; - } - else - { - level->pos = (int)((level->width - videomodes.hRes) - advancex); - } - } - else if(level->scrolldir & SCROLL_OUTWARD) // z scroll only - { - - if(bm - tm > videomodes.vRes) - { - to = advancey; - } - else - { - to = (bm + tm) / 2 - videomodes.vRes / 2 + level->camerazoffset; - } - - if(to < scrollminz) - { - to = scrollminz; - } - else if(to > scrollmaxz) - { - to = scrollmaxz; - } - - if((level->scrolldir & SCROLL_BACK) && to < blockade) - { - to = blockade; - } - - if(to > advancey) - { - if(to > advancey + level->scrollspeed) - { - to = advancey + level->scrollspeed; - } - advancey = to; - } - else if((level->scrolldir & SCROLL_BACK) && to < advancey) - { - if(to < advancey - level->scrollspeed) - { - to = advancey - level->scrollspeed; - } - advancey = to; - } - - if(advancey > panel_height - videomodes.vRes) - { - advancey = (float)panel_height - videomodes.vRes; - againstend = 1; - } - if(advancey < 0) - { - advancey = 0; - } - - if(againstend) - { - level->pos++; - } - else - { - level->pos = (int)advancey; - } - } - else if(level->scrolldir & SCROLL_INWARD) - { - if(bm - tm > videomodes.vRes) - { - to = advancey; - } - else - { - to = (bm + tm) / 2 - videomodes.vRes / 2 + level->camerazoffset; - } - - if(to < scrollminz) - { - to = scrollminz; - } - else if(to > scrollmaxz) - { - to = scrollmaxz; - } - - if((level->scrolldir & SCROLL_BACK) && panel_height - videomodes.vRes - to < blockade) - { - to = panel_height - videomodes.vRes - blockade; - } - - if(to < advancey) - { - if(to < advancey - level->scrollspeed) - { - to = advancey - level->scrollspeed; - } - advancey = to; - } - else if((level->scrolldir & SCROLL_BACK) && to > advancey) - { - if(to > advancey + level->scrollspeed) - { - to = advancey + level->scrollspeed; - } - advancey = to; - } - - if(advancey > panel_height - videomodes.vRes) - { - advancey = (float)panel_height - videomodes.vRes; - } - if(advancey <= 0) - { - advancey = 0; - againstend = 1; - } - - if(againstend) - { - level->pos++; - } - else - { - level->pos = (int)((panel_height - videomodes.vRes) - advancey); - } - } - //up down, elevator stage - else if(level->scrolldir & (SCROLL_UP | SCROLL_DOWN)) - { - //advancey += 0.5; - if(scrolladd == 1) - { - scrolladd = 0; - advancey++; - } - else - { - scrolladd++; - } - level->pos = (int)advancey; - } - }//if(!level->waiting) - - // z auto-scroll - if((level->scrolldir & SCROLL_LEFT) || (level->scrolldir & SCROLL_RIGHT)) // added scroll type both; weird things can happen, but only if the modder is lazy in using blockades, lol - { - - if(cameratype == 1) - { - bm = -9999; - tm = 999999; //recalculate - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].ent) - { - if(player[i].ent->position.z - player[i].ent->position.y > bm) - { - bm = player[i].ent->position.z - player[i].ent->position.y; - } - if(player[i].ent->position.z - player[i].ent->position.y < tm) - { - tm = player[i].ent->position.z - player[i].ent->position.y; - } - } - } - } - if(bm - tm > videomodes.vRes) - { - to = advancey; - } - else - { - to = (bm + tm) / 2 - videomodes.vRes / 2 + level->camerazoffset; - } - - // new scroll limit - if(to > scrollmaxz) - { - to = scrollmaxz; - } - else if(to < scrollminz) - { - to = scrollminz; - } - - if(to != advancey) - { - if(to > advancey + level->scrollspeed) - { - to = advancey + level->scrollspeed; - } - else if(to < advancey - level->scrollspeed) - { - to = advancey - level->scrollspeed; - } - advancey = (float)to; - } - - if(advancey > panel_height - (level->rocking ? 16 : 12) - videomodes.vRes) - { - advancey = (float)(panel_height - (level->rocking ? 16 : 12) - videomodes.vRes); - } - if(advancey < 0) - { - advancey = 0; - } - } - // now x auto scroll - else if((level->scrolldir & SCROLL_INWARD) || (level->scrolldir & SCROLL_OUTWARD)) - { - if(rm - lm > videomodes.hRes) - { - to = advancex; - } - else - { - to = (lm + rm) / 2 - videomodes.hRes / 2 + level->cameraxoffset; - } - - // new scroll limit - if(to > scrollmaxx) - { - to = scrollmaxx; - } - else if(to < scrollminx) - { - to = scrollminx; - } - - if(to != advancex) - { - if(to > advancex + level->scrollspeed) - { - to = advancex + level->scrollspeed; - } - else if(to < advancex - level->scrollspeed) - { - to = advancex - level->scrollspeed; - } - advancex = (float)to; - } - - if(advancex > level->width - videomodes.hRes) - { - advancex = (float)(level->width - videomodes.hRes); - } - if(advancex < 0) - { - advancex = 0; - } - } - //end of z auto-scroll - // global value for type_panel - scrolldx = advancex - tx; - scrolldy = advancey - ty; -} - - -void update_scrolled_bg() -{ - float rocktravel; - unsigned char neonp[32];//3*8 - static int rockpos = 0; - static int rockoffssine[32] = - { - 2, 2, 3, 4, 5, 6, 7, 7, - 8, 8, 9, 9, 9, 9, 8, 8, - 7, 7, 6, 5, 4, 3, 2, 2, - 1, 1, 0, 0, 0, 0, 1, 1 - }; // normal rock - static int rockoffsshake[32] = - { - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 4, 2, 0, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 4, 2, 0, 4, 2, - }; // slow, constant jarring rock, like on a train - static int rockoffsrumble[32] = - { - 2, 2, 3, 3, 2, 2, 3, 3, - 2, 2, 3, 3, 2, 3, 2, 3, - 2, 2, 3, 3, 2, 2, 3, 3, - 2, 2, 3, 3, 2, 3, 2, 3, - }; // fast, constant rumbling, like in/on a van or trailer - int pb = pixelbytes[(int)PIXEL_32]; - - // Time to update neon and screen all flag false? - if(_time >= neon_time && !freezeall) - { - memcpy(neonp, neontable + 128 * pb, 8 * pb); - memcpy(neontable + 128 * pb, neonp + 2 * pb, 6 * pb); - memcpy(neontable + (128 + 6)*pb, neonp, 2 * pb); - - neon_time = _time + (global_config.game_speed / 3); - } - - if(!freezeall) - { - rocktravel = (level->rocking) ? ((_time - traveltime) / ((float)global_config.game_speed / 30)) : 0; // no like in real life, maybe - if(level->bgspeed < 0) - { - rocktravel = -rocktravel; - } - bgtravelled += (_time - traveltime) * level->bgspeed / 30 * 4 + rocktravel; - vbgtravelled += (_time - traveltime) * level->vbgspeed / 30 * 4; - } - else - { - texttime += _time - traveltime; - } - - timevar = _time - texttime; - - if(level->rocking) - { - rockpos = (timevar / (global_config.game_speed / 8)) & 31; - if(level->rocking == 1) - { - gfx_y_offset = level->quake - 4 - rockoffssine[rockpos]; - } - else if(level->rocking == 2) - { - gfx_y_offset = level->quake - 4 - rockoffsshake[rockpos]; - } - else if(level->rocking == 3) - { - gfx_y_offset = level->quake - 4 - rockoffsrumble[rockpos]; - } - } - else - { - if(level->quake >= 0) - { - gfx_y_offset = level->quake - 4; - } - else - { - gfx_y_offset = level->quake + 4; - } - } - - //if(level->scrolldir!=SCROLL_UP && level->scrolldir!=SCROLL_DOWN) gfx_y_offset -= advancey; - gfx_y_offset += gfx_y_offset_adj; //2011_04_03, DC: Apply modder adjustment. - - traveltime = _time; - - if(_time >= level->quaketime) - { - level->quake /= 2; - level->quaketime = _time + (global_config.game_speed / 25); - } -} - -void draw_scrolled_bg() -{ - int index = 0, x, z, i = 0, j, l, m; - s_layer *layer; - int width, height; - - int vpx, vpy, vpw, vph; - - if(viewportw > 0) - { - vpx = viewportx; - vpy = viewporty; - vpw = viewportw; - vph = viewporth; - } - else - { - vpx = vpy = 0; - vpw = videomodes.hRes; - vph = videomodes.vRes; - } - - //if(level) printf("%d %d %d %d\n", vpx, vpy, vpw, vph); - - s_drawmethod screenmethod = plainmethod; - - /*s_drawmethod *pscreenmethod = &screenmethod; - for(i = 0; i < level->numholes; i++) - { - spriteq_add_sprite((int)(level->holes[i].x - screenx + gfx_x_offset), (int)(level->holes[i].z - level->holes[i].depth - screeny + gfx_y_offset), HOLE_Z, holesprite, pscreenmethod, 0); - }*/ - - for(index = 0; index < level->numlayersref; index++) - { - layer = level->layersref + index; - - screenmethod = layer->drawmethod; - - //printf("layer %d, handle:%u, z:%d\n", index, layer->gfx.handle, layer->position.z); - - // Layer must be enabled and have at least one instace, or we don't draw it. - if(!screenmethod.xrepeat || !screenmethod.yrepeat || !layer->enabled) - { - continue; - } - - width = screenmethod.xspan = layer->size.x + layer->spacing.x; - height = screenmethod.yspan = layer->size.y + layer->spacing.z; - - x = (int)(layer->offset.x - (advancex + bgtravelled * layer->bgspeedratio) * (1.0 - layer->ratio.x) ) ; - - //printf("layerxratio %f %d %f\n ", layer->xratio, x, layer->bgspeedratio); - - if((level->scrolldir & SCROLL_UP)) - { - //z = (int)(layer->offset.z + advancey * (1.0 - layer->ratio.z) ) ; - z = (int)(layer->offset.z - (advancey + vbgtravelled * layer->bgspeedratio) * (1.0 - layer->ratio.z) ) ; - } - else - { - //z = (int)(layer->offset.z - advancey * (1.0 - layer->ratio.z) ) ; - z = (int)(layer->offset.z - (advancey + vbgtravelled * layer->bgspeedratio) * (1.0 - layer->ratio.z) ) ; - } - - if(layer->quake) - { - x += gfx_x_offset; - z += gfx_y_offset; - //printf("%d y %d %d\n", index, gfx_y_offset, z); - } - - x -= vpx; - z -= vpy; - - - if(x < 0) - { - i = (-x) / width; - x %= width; - } - else - { - i = 0; - } - - if(i > 0 && screenmethod.water.watermode != WATER_MODE_SHEAR && screenmethod.water.amplitude) - { - i--; - x -= width; - } - - if(z < 0) - { - j = (-z) / height; - z %= height; - } - else - { - j = 0; - } - - if(layer->neon) - { - screenmethod.table = neontable; - } - else - { - if(current_palette > 0) - { - screenmethod.table = level->palettes[current_palette - 1]; - } - else - { - screenmethod.table = NULL; - } - } - - screenmethod.water.wavetime = (int)(timevar * screenmethod.water.wavespeed); - screenmethod.xrepeat = screenmethod.yrepeat = 0; - for(m = z; j < layer->drawmethod.yrepeat && m < vph; m += height, j++, screenmethod.yrepeat++); - for(l = x; i < layer->drawmethod.xrepeat && l < vpw + (screenmethod.water.watermode == WATER_MODE_SHEAR ? 0 : screenmethod.water.amplitude * 2); l += width, i++, screenmethod.xrepeat++); - - if(layer->gfx.screen->magic == screen_magic) - { - spriteq_add_screen(x + vpx, z + vpy, layer->z, layer->gfx.screen, &screenmethod, index); - } - else if(layer->gfx.sprite->magic == sprite_magic) - { - spriteq_add_frame(x + vpx, z + vpy, layer->z, layer->gfx.sprite, &screenmethod, index); - } - - //printf("******%d\t%d\t%d\t%d\t%d*****\n", x+vpx, z+vpy, layer->.z, screenmethod.xrepeat, screenmethod.yrepeat); - } - - -} - -u32 getinterval() -{ - interval = timer_getinterval(global_config.game_speed); // so interval can be logged into movie - if(interval > global_config.game_speed) - { - interval = 1; - } - if(interval > global_config.game_speed / 4) - { - interval = global_config.game_speed / 4; - } - return interval; -} - -// Caskey, Damon V. -// 2019-04-22 -// -// Run input scripts. Similar to keys, but -// execute before processing any command functions. -void execute_input_scripts(int player_index) -{ - s_player *player_obj = NULL; - - player_obj = player + player_index; - - if (!player_obj) - { - return; - } - - if (player_obj->newkeys || (keyscriptrate && player->keys) || player->releasekeys) - { - // 2019-04-22 Don't exist yet - //if (level) - //{ - - //execute_level_key_script(player_index, player); - //execute_entity_key_script(player.ent); - //} - //execute_key_script(player_index, player); - - execute_input_script_all(player_index); - } -} - -/* -* Caskey, Damon V. -* 2026-07-17 -* -* Add direction-relative command flags to a physical -* input mask. -* -* Left and right remain in the result so hard-coded -* commands can continue to inspect the physical input. -*/ -static key_mask_t command_input_resolve_direction( - const key_mask_t input_flags, - const entity* acting_entity -) { - key_mask_t resolved_flags = input_flags; - - if(!acting_entity) { - return resolved_flags; - } - - if(input_flags & FLAG_MOVELEFT) { - resolved_flags |= acting_entity->direction - ? FLAG_BACKWARD - : FLAG_FORWARD; - - } else if(input_flags & FLAG_MOVERIGHT) { - resolved_flags |= acting_entity->direction - ? FLAG_FORWARD - : FLAG_BACKWARD; - } - - return resolved_flags; -} - -/* -* Caskey, Damon V. -* 2026-07-17 - Orginal by Utunnels, unknow date. -* -* Update the input state for each player. This includes -* physical keys, command input history, and automatic -* held edges. Refactored to support direction-relative -* command flags and extensible command system. -*/ -void inputrefresh(int playrecmode) { - - int p; - s_player *acting_player; - - control_update(playercontrolpointers, MAX_PLAYERS); - - bothkeys = 0; - bothnewkeys = 0; - - for(p = 0; p < MAX_PLAYERS; p++) - { - acting_player = player + p; - - if (playrecmode != A_REC_PLAY) { - - acting_player->releasekeys = (playercontrolpointers[p]->keyflags | acting_player->keys) - playercontrolpointers[p]->keyflags; - acting_player->releasekeys &= ~acting_player->disablekeys; - acting_player->keys = playercontrolpointers[p]->keyflags & ~acting_player->disablekeys; - acting_player->newkeys = playercontrolpointers[p]->newkeyflags & ~acting_player->disablekeys; - acting_player->playkeys |= acting_player->newkeys; - acting_player->playkeys &= acting_player->keys; - acting_player->playkeys &= ~acting_player->disablekeys; - - } else { - // in play mode: add pressed keys to rec keys - acting_player->releasekeys |= (playercontrolpointers[p]->keyflags | acting_player->prevkeys) - playercontrolpointers[p]->keyflags; - acting_player->releasekeys &= ~acting_player->disablekeys; - acting_player->keys |= playercontrolpointers[p]->keyflags & ~acting_player->disablekeys; - acting_player->newkeys |= playercontrolpointers[p]->newkeyflags & ~acting_player->disablekeys; - acting_player->playkeys |= acting_player->newkeys; - acting_player->playkeys &= acting_player->keys; - acting_player->playkeys &= ~acting_player->disablekeys; - } - - execute_input_scripts(p); - - /* - * Reset command sequence if the last command was - * too long ago. - */ - if(acting_player->ent && acting_player->ent->command_time < _time) { - memset( - acting_player->command_input_history, - 0, - sizeof(acting_player->command_input_history) - ); - - acting_player->command_input_count = 0; - acting_player->command_input_index = 0; - } - - /* - * Build one event every refresh so automatic held - * thresholds can create an edge without a physical - * button change. Store it only when at least one - * press, release, or automatic held edge exists. - */ - { - s_command_input_event input_event = {0}; - - input_event.press = command_input_resolve_direction( - acting_player->newkeys, - acting_player->ent - ); - - input_event.release = command_input_resolve_direction( - acting_player->releasekeys, - acting_player->ent - ); - - /* - * Released keys were held immediately before this - * edge. Include them in the event snapshot so a - * command such as a[50] + ~a can test both facts. - */ - input_event.held = command_input_resolve_direction( - acting_player->keys - | acting_player->releasekeys, - acting_player->ent - ); - - input_event.time = _time; - - command_input_hold_start_update( - acting_player, - input_event.press, - input_event.time - ); - - if(input_event.press) { - /* - * Capture inputs still held at this positive - * edge. The configurable command matcher - * applies each step's chord_time to their - * recorded press times. Hard-coded commands - * continue to inspect input_event.press only. - */ - input_event.press_chord = - command_input_resolve_direction( - acting_player->keys, - acting_player->ent - ); - } - - input_event.hold = - command_input_hold_trigger_collect( - acting_player, - input_event.held, - input_event.time - ); - - if(input_event.press - || input_event.hold - || input_event.release) { - - input_event.ticks = timer_gettick(); - command_input_history_push(acting_player, &input_event); - - if(acting_player->ent) { - acting_player->ent->command_time = - command_input_history_expiration_time_get( - acting_player->ent, - input_event.time - ); - } - } - - } - - bothkeys |= acting_player->keys; - bothnewkeys |= acting_player->newkeys; - - } - -} - -void execute_keyscripts() -{ - int p; - for(p = 0; p < levelsets[current_set].maxplayers; p++) - { - if(!_pause && (level || check_in_screen()) && (player[p].newkeys || (keyscriptrate && player[p].keys) || player[p].releasekeys)) - { - if(level) - { - execute_level_key_script(p); - execute_entity_key_script(player[p].ent); - } - execute_key_script(p); - execute_key_script_all(p); - } - } -} - -void execute_updatescripts() -{ - if(Script_IsInitialized(&update_script)) - { - Script_Execute(&(update_script)); - } - if(level && Script_IsInitialized(&(level->update_script))) - { - Script_Execute(&(level->update_script)); - } -} - -void execute_updatedscripts() -{ - if(Script_IsInitialized(&updated_script)) - { - Script_Execute(&(updated_script)); - } - if(level && Script_IsInitialized(&(level->updated_script))) - { - Script_Execute(&(level->updated_script)); - } -} - -/* -* Caskey, Damon V. -* 2026-08-21 -* -* Execute global and level scripts immediately before an -* engine logical clock tick is processed. -*/ -void execute_updatelogicscripts() -{ - if(Script_IsInitialized(&update_logic_script)) - { - Script_Execute(&update_logic_script); - } - if(level && Script_IsInitialized(&level->update_logic_script)) - { - Script_Execute(&level->update_logic_script); - } -} - -/* -* Caskey, Damon V. -* 2026-08-21 -* -* Execute global and level scripts after an engine logical -* clock tick is processed, before its clock value advances. -*/ -void execute_updatedlogicscripts() -{ - if(Script_IsInitialized(&updated_logic_script)) - { - Script_Execute(&updated_logic_script); - } - if(level && Script_IsInitialized(&level->updated_logic_script)) - { - Script_Execute(&level->updated_logic_script); - } -} - -void draw_textobjs() -{ - int i; - s_textobj *textobj; - if(!level) - { - return; - } - for(i = 0; i < level->numtextobjs ; i++) - { - textobj = level->textobjs + i; - - if(textobj->time && textobj->time <= _time) //If a time was set and passed, remove the text object. - { - level->textobjs[i].time = 0; - level->textobjs[i].position.x = 0; - level->textobjs[i].position.y = 0; - level->textobjs[i].font = 0; - level->textobjs[i].position.z = 0; - if(level->textobjs[i].text) - { - free(level->textobjs[i].text); - level->textobjs[i].text = NULL; - } - } - else - { - if(textobj->text) - { - font_print_length( - textobj->position.x, - textobj->position.y, - textobj->font, - textobj->position.z, - textobj->text, - strlen(textobj->text) - ); - } - } - } -} - -int recordInputs() -{ - int p = 0; - RecKeys reckey; - uint64_t window = 4096; - u32 max_rec_time = global_config.game_speed*60*10; // protection - - if(playrecstatus->status != A_REC_REC) return 0; - if ( !playrecstatus->begin ) - { - playrecstatus->starttime = _time; - playrecstatus->synctime = 0; - if (playrecstatus->buffer) - { - free(playrecstatus->buffer); - playrecstatus->buffer = NULL; - } - playrecstatus->buffer = (RecKeys*)calloc(window+playrecstatus->synctime*sizeof(RecKeys),sizeof(RecKeys)); - if (playrecstatus->buffer == NULL) - { - printf("Error to allocate buffer in record inputs mode.\n"); - return 0; - } - playrecstatus->begin = 1; - playrecstatus->seed = getseed(); - playrecstatus->cseed = _time; - srand(_time); - playrecstatus->ticks = timer_gettick(); - } - else - { - if ( playrecstatus->synctime%window >= window-2 ) // last is NULL bytes - { - playrecstatus->buffer = (RecKeys*)realloc(playrecstatus->buffer,sizeof(RecKeys)*((playrecstatus->synctime/window+1)*window+window)); - if (playrecstatus->buffer == NULL) - { - printf("Error to allocate buffer in record inputs mode.\n"); - return 0; - } else memset(playrecstatus->buffer+(playrecstatus->synctime+1),0,(playrecstatus->synctime/window+1)*window+window-(playrecstatus->synctime+1)-1); // -2 because -1 is to 0 to size-1 - } - } - - // now rec! - if(playrecstatus->buffer && playrecstatus->begin) - { - for ( p = 0; p < MAX_PLAYERS; p++ ) - { - reckey.keys[p] = player[p].keys; - reckey.newkeys[p] = player[p].newkeys; - reckey.releasekeys[p] = player[p].releasekeys; - reckey.playkeys[p] = player[p].playkeys; - } - reckey.time = _time; - reckey.interval = interval; - reckey.synctime = playrecstatus->synctime; - //reckey.seed = getseed(); - memcpy( &playrecstatus->buffer[playrecstatus->synctime], &reckey, sizeof(reckey) ); - } - - if ( _time >= max_rec_time ) stopRecordInputs(); // safe - if(playrecstatus->status == A_REC_REC) ++playrecstatus->synctime; - - //debug_printf("time: %d sync: %d",(u32)time,(u32)playrecstatus->synctime); - //debug_printf("keys: %d",player[0].releasekeys&FLAG_ATTACK); - - return 1; -} - -int playRecordedInputs() -{ - int p = 0; - RecKeys reckey; - char path[MAX_ARG_LEN + 1]; - size_t filesize = 0; - char header[6]; - - if(playrecstatus->status != A_REC_PLAY) return 0; - if ( !playrecstatus->begin ) //time >= playrecstatus->starttime && - { - if ( strlen(playrecstatus->path) <= 0 ) getBasePath(path, "Saves", 0); - else strcpy(path,playrecstatus->path); - if ( path[strlen(path)-1] != '/' ) strcpy(path,"/"); - - if (playrecstatus->buffer) - { - free(playrecstatus->buffer); - playrecstatus->buffer = NULL; - } - if(playrecstatus->handle) - { - fclose(playrecstatus->handle); - } - - playrecstatus->handle = fopen(strcat(path,playrecstatus->filename), "rb+"); - if(playrecstatus->handle) - { - fseek(playrecstatus->handle, 0L, SEEK_END); - filesize = ftell(playrecstatus->handle); - fseek(playrecstatus->handle, 0L, SEEK_SET); // or rewind(playrecstatus->handle) - - if (filesize <= 0) - { - printf("Empty recorded inputs file.\n"); - return 0; - } - playrecstatus->buffer = (RecKeys*)calloc(1,filesize+1); - if(!playrecstatus->buffer) - { - printf("Error to allocate buffer for recorded inputs.\n"); - return 0; - } - } else - { - printf("Error to open recorded inputs file.\n"); - return 0; - } - fread(&header, 6, 1, playrecstatus->handle); - fread(&playrecstatus->starttime, sizeof(u32), 1, playrecstatus->handle); - fread(&playrecstatus->endtime, sizeof(u32), 1, playrecstatus->handle); - fread(&playrecstatus->totsynctime, sizeof(u32), 1, playrecstatus->handle); - fread(&playrecstatus->cseed, sizeof(u32), 1, playrecstatus->handle); - fread(&playrecstatus->seed, sizeof(uint64_t), 1, playrecstatus->handle); - fread(&playrecstatus->ticks, sizeof(unsigned), 1, playrecstatus->handle); - fread(playrecstatus->buffer, sizeof(RecKeys)*(playrecstatus->endtime+1), 1, playrecstatus->handle); - - // sync at start time - _time = playrecstatus->starttime; - playrecstatus->synctime = 0; - playrecstatus->begin = 1; - srand(playrecstatus->cseed); - srand32(playrecstatus->seed); - //set_ticks(timer_gettick()-playrecstatus->ticks); - } - - // now play! - if(playrecstatus->buffer && playrecstatus->begin && playrecstatus->synctime < playrecstatus->totsynctime) - { - memcpy( &reckey, &playrecstatus->buffer[playrecstatus->synctime], sizeof(reckey) ); - - if( _time != reckey.time ) - { - u32 nextsynctime = reckey.synctime; - - //time = (u32)reckey.time; - printf("Play recorded inputs: Out of sync! Time: %d, RecTime: %d\n",time,reckey.time); - /*if ( interval != reckey.interval ) - { - //interval = (u32)reckey.interval; - printf("Play recorded inputs: Out of sync! Interval: %d, RecInterval: %d\n",interval,reckey.interval); - }*/ - - while( _time > reckey.time && nextsynctime > 0 ) { - memcpy( &reckey, &playrecstatus->buffer[--nextsynctime], sizeof(reckey) ); - } - _time = reckey.time; - - while( _time < reckey.time && nextsynctime < playrecstatus->totsynctime ) { - memcpy( &reckey, &playrecstatus->buffer[++nextsynctime], sizeof(reckey) ); - } - _time = reckey.time; - } - - if ( _time == reckey.time ) - { - if ( playrecstatus->synctime != reckey.synctime ) - { - u32 nextsynctime = reckey.synctime; - - printf("Play recorded inputs: Out of sync! SyncTime: %d, RecSyncTime: %d\n",playrecstatus->synctime,reckey.synctime); - - while( playrecstatus->synctime > reckey.synctime && nextsynctime > 0 ) { - memcpy( &reckey, &playrecstatus->buffer[--nextsynctime], sizeof(reckey) ); - } - playrecstatus->synctime = reckey.synctime; - - while( playrecstatus->synctime < reckey.synctime && nextsynctime < playrecstatus->totsynctime ) { - memcpy( &reckey, &playrecstatus->buffer[++nextsynctime], sizeof(reckey) ); - } - playrecstatus->synctime = reckey.synctime; - } - - if ( interval != reckey.interval ) interval = reckey.interval; - //srand32(reckey.seed); - for ( p = 0; p < MAX_PLAYERS; p++ ) - { - player[p].keys = reckey.keys[p]; - player[p].newkeys = reckey.newkeys[p]; - player[p].releasekeys = reckey.releasekeys[p]; - player[p].playkeys = reckey.playkeys[p]; - } - //inputrefresh(playrecstatus->status); - } - } - - //debug_printf("synctim: %d totsync: %d status:%d",playrecstatus->synctime,playrecstatus->totsynctime,playrecstatus->status); - if(playrecstatus->status == A_REC_PLAY) ++playrecstatus->synctime; - if ( playrecstatus->synctime >= playrecstatus->totsynctime || _time >= playrecstatus->endtime ) stopRecordInputs(); - - //debug_printf("time: %d sync: %d",(u32)time,(u32)playrecstatus->synctime); - //debug_printf("keys: %d",player[0].releasekeys&FLAG_ATTACK); - - return 1; -} - -int stopRecordInputs() -{ - if(playrecstatus) - { - switch(playrecstatus->status) - { - case A_REC_REC: - { - char path[MAX_ARG_LEN + 1]; - char header[6] = "INP10"; - - if ( strlen(playrecstatus->path) <= 0 ) getBasePath(path, "Saves", 0); - else strcpy(path,playrecstatus->path); - if ( path[strlen(path)-1] != '/' ) strcpy(path,"/"); - - if (playrecstatus->buffer) - { - playrecstatus->handle = fopen(strcat(path,playrecstatus->filename), "wb+"); - if(playrecstatus->handle) - { - playrecstatus->endtime = _time; - if (playrecstatus->synctime < 2) playrecstatus->synctime = 2; - else playrecstatus->synctime -= 2; - - fwrite(header, 6, 1, playrecstatus->handle); - fwrite(&playrecstatus->starttime, sizeof(u32), 1, playrecstatus->handle); - fwrite(&playrecstatus->endtime, sizeof(u32), 1, playrecstatus->handle); - fwrite(&playrecstatus->synctime, sizeof(u32), 1, playrecstatus->handle); - fwrite(&playrecstatus->cseed, sizeof(u32), 1, playrecstatus->handle); - fwrite(&playrecstatus->seed, sizeof(uint64_t), 1, playrecstatus->handle); - fwrite(&playrecstatus->ticks, sizeof(unsigned), 1, playrecstatus->handle); - fwrite(playrecstatus->buffer, sizeof(RecKeys)*(playrecstatus->synctime+1), 1, playrecstatus->handle); - fflush(playrecstatus->handle); // safe - fclose(playrecstatus->handle); - } else return 0; - - free(playrecstatus->buffer); - playrecstatus->buffer = NULL; - } else return 0; - break; - } - case A_REC_PLAY: - { - if(playrecstatus->handle) - { - if (playrecstatus->handle) fclose(playrecstatus->handle); - else return 0; - } - break; - } - case A_REC_STOP: - { - if(playrecstatus->handle) - { - if (playrecstatus->handle) fclose(playrecstatus->handle); - else return 0; - } - break; - } - } - - playrecstatus->status = A_REC_STOP; - playrecstatus->begin = 0; - playrecstatus->synctime = 0; - freeRecordedInputs(); - } return 0; - - return 1; -} - -int freeRecordedInputs() -{ - playrecstatus->status = A_REC_STOP; - if(playrecstatus->handle) fclose(playrecstatus->handle); - if(playrecstatus->buffer) - { - free(playrecstatus->buffer); - playrecstatus->buffer = NULL; - return 1; - } - - return 0; -} - -a_playrecstatus* init_input_recorder() -{ - playrecstatus = (a_playrecstatus*)calloc(1,sizeof(*playrecstatus)); - - return playrecstatus; -} - -void free_input_recorder() -{ - if(playrecstatus) - { - if(playrecstatus->buffer) - { - if(playrecstatus->handle) fclose(playrecstatus->handle); - free(playrecstatus->buffer); - playrecstatus->buffer = NULL; - } - free(playrecstatus); - playrecstatus = NULL; - } -} - -void update(int ingame, int usevwait) -{ - int i = 0; - int p_keys = 0; - -#if SDL - if (savedata.fpslimit == 1) // vsync enabled - { - // To reduce input latency, wait until the last 4 ms (4000 us) of the current - // frame to read inputs or do anything else. We can get away with this because - // the CPUs of all modern computers - even phones and low-end, outdated PCs - - // are complete overkill for OpenBOR's needs. - s64 target_time = timer_uticks() + 1000000/video_current_refresh_rate() - 4000; - u64 current_time = timer_uticks(); - while (current_time < target_time) - { - usleep(target_time - current_time); - current_time = timer_uticks(); - } - } -#endif - - getinterval(); - if(playrecstatus->status == A_REC_PLAY && !_pause && level) if ( !playRecordedInputs() ) stopRecordInputs(); - inputrefresh(playrecstatus->status); -#ifdef WEBM - movie_playback_update( - (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON)) != 0 - ); -#endif - if(playrecstatus->status == A_REC_REC && !_pause && level) if ( !recordInputs() ) stopRecordInputs(); - - if ((!_pause && ingame == 1) || alwaysupdate) - { - execute_updatescripts(); - } - - newtime = 0; - if(!_pause) - { - if(ingame == 1 || check_in_screen()) - { - execute_keyscripts(); - } - - if((level_completed && level->boss_slow == BOSS_SLOW_ON && !tospeedup) || slowmotion.toggle > SLOW_MOTION_OFF) - { - if(slowmotion.duration == slowmotion.counter) - { - newtime = _time + interval; - } - } - else - { - newtime = _time + interval; - } - - slowmotion.counter++; - if(slowmotion.counter == (slowmotion.duration + 1)) - { - slowmotion.counter = 0; - if(slowmotion.toggle > SLOW_MOTION_ON) - { - slowmotion.duration = slowmotion.toggle; - } - } - if(newtime > _time + 100) - { - newtime = _time + 100; - } - - while(_time < newtime) - { - if(ingame == 1 || alwaysupdate) - { - execute_updatelogicscripts(); - } - - if(ingame == 1) - { - update_scroller(); - if(!freezeall) - { - int all_p_alive = 0; - - for(i = 0; i < MAX_PLAYERS; i++) - { - if (!player[i].ent) ++all_p_alive; - } - all_p_alive = (all_p_alive >= MAX_PLAYERS) ? 1 : 0; - - if(level->settime > 0 || (level->type != 2 && all_p_alive)) - //if(level->settime > 0 || (level->type != 2 && !player[0].ent && !player[1].ent && !player[2].ent && !player[3].ent)) - { - int all_p_nojoin = 0, all_p_nocredits = 0; - - for(i = 0; i < MAX_PLAYERS; i++) - { - if (!player[i].joining) ++all_p_nojoin; - } - all_p_nojoin = (all_p_nojoin >= MAX_PLAYERS) ? 1 : 0; - - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].credits < 1) ++all_p_nocredits; - } - all_p_nocredits = (all_p_nocredits >= MAX_PLAYERS) ? 1 : 0; - - if(timeleft > 0) - { - --timeleft; - } - else if((level->settime > 0 && all_p_nojoin) || - ( ((!noshare && credits < 1) || (noshare && all_p_nocredits)) - && all_p_nojoin ) - ) - { - time_over(); - } - } - } - update_scrolled_bg(); - if(level->type != 2) - { - updatestatus(); - } - } - if(ingame == 1 || check_in_screen()) - { - update_ents(); - } - - if(ingame == 1 || alwaysupdate) - { - execute_updatedlogicscripts(); - } - - ++_time; - } - - } - - /************ gfx queueing ************/ - - clearscreen(vscreen); - - if(ingame == 1 && !_pause) - { - draw_scrolled_bg(); - if(level->type != 2) - { - predrawstatus(); - } - if(level->type != 2) - { - drawstatus(); - } - draw_textobjs(); - } - - if(!ingame) - { - if(background) - { - spriteq_add_screen(0, 0, MIN_INT, background, NULL, 0); - } - } - - // entity sprites queueing - if(ingame == 1 || check_in_screen()) - if(!_pause) - { - display_ents(); - } - - /************ updated script ************/ - if(ingame == 1 || alwaysupdate) - { - execute_updatedscripts(); - } - - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].ent && (player[i].newkeys & FLAG_START)) - { - p_keys = 1; - break; - } - } - - // 2011/10/22 UT: move pause menu logic here - /*if(ingame == 1 && !_pause && !nopause && - ((player[0].ent && (player[0].newkeys & FLAG_START)) || - (player[1].ent && (player[1].newkeys & FLAG_START)) || - (player[2].ent && (player[2].newkeys & FLAG_START)) || - (player[3].ent && (player[3].newkeys & FLAG_START))) - )*/ - if(ingame == 1 && !_pause && !nopause && p_keys) - { - if ( !(goto_mainmenu_flag&1) ) - { - sound_pause_music(1); - sound_pause_sample(1); - sound_play_sample(global_sample_list.pause, 0, savedata.effectvol, savedata.effectvol, 100); - pausemenu(); - return; - } - } - if( ingame == 1 && (goto_mainmenu_flag&1) ) - { - backto_mainmenu(); - return; - } - - /********** update screen **************/ - - spriteq_draw(vscreen, 0, MIN_INT, MAX_INT, 0, 0); // notice, always draw sprites at the very end of other methods - - if(_pause != 2 && !noscreenshot && (bothnewkeys & FLAG_SCREENSHOT)) - { - screenshot(vscreen, getpal, 1); - } - - // Debug stuff, should not appear on screenshot - if(debug_time == 0xFFFFFFFF) - { - debug_time = _time + global_config.game_speed * 5; - } - if(_time < debug_time && debug_msg[0]) - { - if( debug_xy_msg.x >= 0 && debug_xy_msg.y >= 0 ) - { - if ( debug_xy_msg.font_index < 0 ) debug_xy_msg.font_index = 0; - screen_printf(vscreen, debug_xy_msg.x, debug_xy_msg.y, debug_xy_msg.font_index, debug_msg); - } else screen_printf(vscreen, 0, videomodes.vRes-fontheight(0), 0, debug_msg); - } - else - { - debug_msg[0] = 0; - debug_xy_msg.x = -1; - debug_xy_msg.y = -1; -#ifdef DEBUG_MODE - if(level->pos) - { - debug_printf("Position: %i, width: %i, spawn: %i, offsets: %i/%i", level->pos, level->width, current_spawn, level->quake, gfx_y_offset); - } -#endif - } - - if(usevwait) - { - vga_vwait(); - } - video_copy_screen(vscreen); - spriteq_clear(); - - check_music(); - sound_update_music(); -} - - - - -// ---------------------------------------------------------------------- -/* Plombo 9/4/2010: New function that can use brightness/gamma correction - * independent from the global palette on platforms where it's available. - * Hardware accelerated brightness/gamma correction is available on OpenGL - * platforms using GLSL. Returns 1 on success, 0 on error. - */ -int set_color_correction(int gm, int br) -{ - video_set_color_correction(gm, br); - return 1; -} - -// Simple palette fade / vscreen fade -void fade_out(int type, int speed) -{ - int i, j = 0; - int b, g = 0; - u32 interval = 0; - int current = speed ? speed : fade; - s_screen *fbuffer = NULL; - s_drawmethod dm = plainmethod; - dm.alpha = BLEND_MODE_AVERAGE; - - for(i = 0, j = 0; j < 64; ) - { - while(j <= i && j < 64) - { - if(!type || type == 1) - { - b = ((savedata.brightness + 256) * (64 - j) / 64) - 256; - g = 256 - ((savedata.gamma + 256) * (64 - j) / 64); - vga_vwait(); - if(!set_color_correction(g, b)) - { - if(!fbuffer) - { - fbuffer = allocscreen(vscreen->width, vscreen->height, vscreen->pixelformat); - copyscreen(fbuffer, vscreen); - } - //255 + alpha BLEND_MODE_AVERAGE is actually half blend, so use 254 instead - dm.channelr = dm.channelg = dm.channelb = 254 * (64 - j) / 64; - clearscreen(vscreen); - putscreen(vscreen, fbuffer, 0, 0, &dm); - } - } - j++; - if(!type || type == 1) - { - video_copy_screen(vscreen); - } - } - if(!type || type == 2) - { - sound_update_music(); - if(!musicoverlap) - { - sound_volume_music(savedata.musicvol * (64 - j) / 64, savedata.musicvol * (64 - j) / 64); - } - } - interval = timer_getinterval(current); - if(interval > current) - { - interval = current / 60; - } - if(interval > current / 4) - { - interval = current / 4; - } - i += interval; - } - - if(!type || type == 2) - { - if(!musicoverlap) - { - sound_close_music(); - } - } - - if(!type || type == 1) - { - clearscreen(vscreen); - video_copy_screen(vscreen); - vga_vwait(); - //the black screen, so we return to normal palette - set_color_correction(savedata.gamma, savedata.brightness); - } - - if(fbuffer) - { - freescreen(&fbuffer); - } -} - - - -void apply_controls() -{ - int p; - - for(p = 0; p < MAX_PLAYERS; p++) - { - control_setkey(playercontrolpointers[p], FLAG_ESC, CONTROL_ESC); - control_setkey(playercontrolpointers[p], FLAG_MOVEUP, savedata.keys[p][SDID_MOVEUP]); - control_setkey(playercontrolpointers[p], FLAG_MOVEDOWN, savedata.keys[p][SDID_MOVEDOWN]); - control_setkey(playercontrolpointers[p], FLAG_MOVELEFT, savedata.keys[p][SDID_MOVELEFT]); - control_setkey(playercontrolpointers[p], FLAG_MOVERIGHT, savedata.keys[p][SDID_MOVERIGHT]); - control_setkey(playercontrolpointers[p], FLAG_ATTACK, savedata.keys[p][SDID_ATTACK]); - control_setkey(playercontrolpointers[p], FLAG_ATTACK2, savedata.keys[p][SDID_ATTACK2]); - control_setkey(playercontrolpointers[p], FLAG_ATTACK3, savedata.keys[p][SDID_ATTACK3]); - control_setkey(playercontrolpointers[p], FLAG_ATTACK4, savedata.keys[p][SDID_ATTACK4]); - control_setkey(playercontrolpointers[p], FLAG_JUMP, savedata.keys[p][SDID_JUMP]); - control_setkey(playercontrolpointers[p], FLAG_SPECIAL, savedata.keys[p][SDID_SPECIAL]); - control_setkey(playercontrolpointers[p], FLAG_START, savedata.keys[p][SDID_START]); - control_setkey(playercontrolpointers[p], FLAG_SCREENSHOT, savedata.keys[p][SDID_SCREENSHOT]); - } -} - - - -// ---------------------------------------------------------------------- - -void display_credits() -{ - u32 finishtime = _time + 10 * global_config.game_speed; - int done = 0; - int s = videomodes.vShift / 2 + 3; - int v = (videomodes.vRes - videomodes.vShift) / 24; - int m = 0; - int h = videomodes.hRes / 2; - int col1 = h - fontmonowidth(0) * 16; - int col2 = h + fontmonowidth(0) * 4; - - if(savedata.logo != 1) - { - return; - } - fade_out(0, 0); - - unload_level(); - - bothnewkeys = 0; - - while(!done) - { - m = 2; - - font_printf(_strmidx(2, "Credits"), s, 2, 0, "Credits"); - - font_printf(_strmidx(1, "OpenBOR"), s + v * m, 1, 0, "OpenBOR"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Caskey, Damon V."); - font_printf(col2, s + v * m, 0, 0, "Project Lead"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Msmalik681"); - font_printf(col2, s + v * m, 0, 0, "Developer"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Kratus"); - font_printf(col2, s + v * m, 0, 0, "Developer"); ++m; - - font_printf(_strmidx(1, "Former Staff"), s + v * m, 1, 0, "Former Staff"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Fightn Words"); - font_printf(col2, s + v * m, 0, 0, "Fugue"); ++m; - - font_printf(col1, s + v * m, 0, 0, "KBAndressen"); - font_printf(col2, s + v * m, 0, 0, "Kirby"); ++m; - - font_printf(col1, s + v * m, 0, 0, "LordBall"); - font_printf(col2, s + v * m, 0, 0, "Orochi_X"); ++m; - - font_printf(col1, s + v * m, 0, 0, "SX"); - font_printf(col2, s + v * m, 0, 0, "Tails"); ++m; - - font_printf(col1, s + v * m, 0, 0, "uTunnels"); - font_printf(col2, s + v * m, 0, 0, "White Dragon"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Plombo"); ++m; - - font_printf(_strmidx(1, "Ports"), s + v * m, 1, 0, "Ports"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Linux/OSX"); - font_printf(col2, s + v * m, 0, 0, "SX"); ++m; - - font_printf(col1, s + v * m, 0, 0, "Android"); - font_printf(col2, s + v * m, 0, 0, "CRxTRDude, Plombo,"); ++m; - font_printf(col2, s + v * m, 0, 0, "uTunnels, Msmalik681"); ++m; - font_printf(col2, s + v * m, 0, 0, "White Dragon"); ++m; - - update(2, 0); - - done |= (_time > finishtime); - done |= (bothnewkeys & (FLAG_START + FLAG_ESC)); - } - fade = 75; - fade_out(0, 0); -} - - -void borShutdown(int status, const char *msg, ...) -{ - va_list arglist; - va_list output_arguments; - int i; - - static int shuttingdown = 0; - - if(shuttingdown) - { - return; - } - - shuttingdown = 1; - va_start(arglist, msg); - - //printf("savedata.logo %d\n", savedata.logo); - - if(!disablelog) - { - switch(status) - { - case 0: - printf("\n************ Shutting Down ************\n\n"); - break; - default: - printf("\n********** An Error Occurred **********" - "\n* Shutting Down *\n\n"); - break; - } - } - - if(!disablelog) - { - va_copy(output_arguments, arglist); - writeToLogFileV(msg, output_arguments); - va_end(output_arguments); - } - - - getRamStatus(BYTES); - savesettings(); - - /* entry point for the engine credits screen. */ - //screen_status |= IN_SCREEN_ENGINE_CREDIT; - - // if(status != 2) - // { - // display_credits(); - // } - - if(startup_done) - { - screen_status &= ~IN_SCREEN_ENGINE_CREDIT; - term_videomodes(); - } - - if(!disablelog) - { - printf("Release level data"); - } - if (startup_done) - { - unload_levelorder(); - } - if(!disablelog) - { - printf("...........\n"); - } - if(startup_done) - { - unload_level(); - } - if(!disablelog) - { - printf("Done!\n\n"); - } - - if(!disablelog) - { - printf("Release graphics data"); - } - if(!disablelog) - { - printf(".."); - } - if(startup_done) - { - freescreen(&vscreen); // allocated by init_videomodes - } - if(startup_done && pixelformat == PIXEL_x8) for(i = 0; i < MAX_BLENDINGS; i++) - { - free(blendtables[i]); - } - if(!disablelog) - { - printf(".."); - } - if(startup_done) - { - freescreen(&background); - } - if(!disablelog) - { - printf(".."); - } -#ifdef CACHE_BACKGROUNDS - if(startup_done) for(i = 0; i < MAX_CACHED_BACKGROUNDS; i++) - { - freescreen(&bg_cache[i]); - } - if(!disablelog) - { - printf(".."); - } -#endif - if(startup_done) - { - freesprites(); - } - if(!disablelog) - { - printf(".."); - } - if(startup_done) - { - unload_all_fonts(); - } - if(!disablelog) - { - printf("\tDone!\n"); - } - - - if(!disablelog) - { - printf("Release game data............\n\n"); - } - - if(startup_done) - { - free_ents(); - } - if(startup_done) - { - free_models(); - } - if(startup_done) - { - free_modelcache(); - } - if(startup_done) - { - clear_scripts(); - } - if(!disablelog) - { - printf("\nRelease game data............\tDone!\n"); - } - - if(!disablelog) - { - printf("Release timer................"); - } - if(startup_done) - { - borTimerExit(); - } - if(!disablelog) - { - printf("\tDone!\n"); - } - - if(!disablelog) - { - printf("Release input hardware......."); - } - if(startup_done) - { - control_exit(); - } - if(!disablelog) - { - printf("\tDone!\n"); - } - - if(!disablelog) - { - printf("Release sound system........."); - } - if(startup_done) - { - sound_exit(); - } - if(!disablelog) - { - printf("\tDone!\n"); - } - - if(!disablelog) - { - printf("Release FileCaching System..."); - } - if(startup_done) - { - pak_term(); - } - if(!disablelog) - { - printf("\tDone!\n"); - } - - if(modelcmdlist) - { - freeCommandList(modelcmdlist); // moved here because list is not initialized if shutdown is initiated from inside the menu - } - if(modelstxtcmdlist) - { - freeCommandList(modelstxtcmdlist); - } - if(levelcmdlist) - { - freeCommandList(levelcmdlist); - } - if(levelordercmdlist) - { - freeCommandList(levelordercmdlist); - } - - freeModelList(); - clear_saved_allowselect_arguments(); - free(savelevel_allowselect_args); - savelevel_allowselect_args = NULL; - if(savelevel) - { - free(savelevel); - savelevel = NULL; - } - savelevel_count = 0; - free(allowselect_args); - allowselect_args = NULL; - freefilenamecache(); - ob_termtrans(); - - // free input recorder - free_input_recorder(); - - if(!disablelog) - { - printf("\n**************** Done *****************\n\n"); - } - - if(!disablelog) - { - va_copy(output_arguments, arglist); - writeToLogFileV(msg, output_arguments); - va_end(output_arguments); - } - - va_end(arglist); - shuttingdown = 0; - borExit(status); -} - - -void guistartup() -{ - int i; - - if(!font_load(0, "menu/font1", packfile, 0)) - { - borShutdown(1, "Unable to load font #1!\n"); - } - if(!font_load(1, "menu/font2", packfile, 0)) - { - borShutdown(1, "Unable to load font #2!\n"); - } - if(!font_load(2, "menu/font3", packfile, 0)) - { - borShutdown(1, "Unable to load font #3!\n"); - } - - - borTimerInit(); - - control_init(2); - apply_controls(); - - init_videomodes(0); - if(!video_set_mode(videomodes)) - { - borShutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes); - } - - for(i = 0; i < 256; i++) - { - neontable[i] = i; - } -} - - -void startup() -{ - int i; - - printf("FileCaching System Init.......\t"); - if(pak_init()) - { - printf("Enabled\n"); - } - else - { - printf("Disabled\n"); - } - - loadHighScoreFile(); - clearSavedGame(); - - init_videomodes(1); - if(!video_set_mode(videomodes)) - { - borShutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes); - } - - printf("Timer init...................\t"); - borTimerInit(); - printf("Done!\n"); - - printf("Initialize Sound.............\t"); - if(sound_init()) - { - if(load_special_sounds()) - { - printf("Done!\n"); - } - else - { - printf("\n"); - } - if(!sound_start_playback()) - { - printf("Warning: can't play sound!\n"); - } - SB_setvolume(SB_MASTERVOL, savedata.soundvol); - SB_setvolume(SB_VOICEVOL, savedata.soundvol); - } - else - { - borShutdown(1, "Unable to Initialize Sound.\n"); - } - - // init. input recorder - init_input_recorder(); - - printf("Loading fonts................\t"); - load_all_fonts(); - printf("Done!\n"); - - printf("Loading sprites..............\t"); - load_special_sprites(); - printf("Done!\n"); - - printf("Loading level order..........\t"); - load_levelorder(); - printf("Done!\n"); - - printf("Loading model constants......\t"); - load_model_constants(); - printf("Done!\n"); - - printf("Loading script settings......\t"); - load_script_setting(); - printf("Done!\n"); - - printf("Loading scripts..............\t"); - load_scripts(); - printf("Done!\n"); - - printf("Loading models...............\n\n"); - load_models(); - - printf("Object engine init...........\t"); - if(!alloc_ents()) - { - borShutdown(1, "Not enough memory for game objects!\n"); - } - printf("Done!\n"); - - printf("Loading menu.txt.............\t"); - load_menu_txt(); - printf("Done!\n"); - - /* - Kratus (01-2024) Moved the translation and menu functions to the end of the engine "startup" function, - but before the "control init" function (reverted the font function to load before scripts) - */ - printf("Loading translation..........\t"); - ob_inittrans(); - printf("Done!\n"); - - printf("Input init...................\t"); - control_init(savedata.usejoy); - apply_controls(); - printf("Done!\n"); - -#ifdef CACHE_BACKGROUNDS - printf("Caching backgrounds..........\t"); - cache_all_backgrounds(); - printf("Done!\n"); -#endif - - printf("Create blending tables.......\t"); - if(pixelformat == PIXEL_x8) - { - create_blend_tables_x8(blendtables); - } - - for(i = 0; i < MAX_PAL_SIZE / 4; i++) - { - neontable[i] = i; - } - printf("Done!\n"); - - if(savedata.logo++ > 10) - { - savedata.logo = 0; - } - - printf("Save settings so far.........\t"); - savesettings(); - printf("Done!\n"); - - startup_done = 1; - - printf("\n\n"); - -} - - - -// ---------------------------------------------------------------------------- - - -// Returns 0 on error, -1 on escape -int playgif(char *filename, int x, int y, int noskip) -{ - anigif_info *info = calloc(1, sizeof(*info)); - s_screen *backbuffer = NULL; - s_screen *tempbg = background; - int result = 1; - u32 synctosound; - u32 lasttime; - u32 milliseconds; - u32 temptime, tempnewtime; // temporary patch for ingame gif play - - synctosound = (sound_getinterval() != 0xFFFFFFFF); - temptime = _time; - tempnewtime = newtime; - _time = 0; - milliseconds = 0; - lasttime = 0; - background = NULL; - - if(!(result = anigif_open(filename, packfile, info))) - { - goto playgif_end; - } - - while(!info->done) - { - if(milliseconds >= info->info[0].nextframe) - { - anigif_decode_frame(info); - } - if(!(backbuffer = anigif_getbuffer(info))) - { - break; - } - spriteq_add_screen(x, y, 0, backbuffer, NULL, 0); - if(info->frame == 0) - { - vga_vwait(); - update(0, 0); - } - else - { - update(0, 1); - } - - if(synctosound) - { - milliseconds += sound_getinterval(); - } - else - { - milliseconds += (_time - lasttime) * 1000 / global_config.game_speed; - } - - lasttime = _time; - - if(!noskip && (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON))) - { - result = -1; - break; - } - } - - -playgif_end: - anigif_close(info); - free(info); - _time = temptime; - newtime = tempnewtime; - background = tempbg; - //standard_palette(1); //Kratus (01-2024) Disabled to fix the fps drop issue - - if(0 == result) - { - printf("\nWarning, an error occurred while playing animated gif file '%s'.\n", filename); - } - return result; - -} - - -#ifdef WEBM -/* -* Caskey, Damon V. -* 2026-08-12 -* -* Preserve blocking playwebm() behavior as a wrapper around -* the reusable movie APIs. Return 1 on completion, 0 on error, -* or -1 when creator-enabled input interrupts playback. -*/ -int playwebm(const char *path, int noskip) -{ - int retval = 1; - int source_id = -1; - s_movie_playback *playback = NULL; - s_screen *screenshot_frame = NULL; - - movie_playback_stop_all(); - source_id = movie_source_load(path, MOVIE_LOADING_STREAM); - if(source_id < 0) { - return 0; - } - playback = movie_playback_play( - source_id, - MOVIE_CHANNEL_AUTO, - savedata.musicvol, - true - ); - if(!playback) { - retval = 0; - goto quit; - } - if(!movie_playback_set_interrupt(playback, !noskip)) { - retval = 0; - goto quit; - } - - /* Legacy playback uses the WebM display size and hardware YUV output. */ - movie_playback_set_width(playback, MOVIE_SIZE_NATIVE); - movie_playback_set_height(playback, MOVIE_SIZE_NATIVE); - - while(playback->active) { - int interrupt_requested; - int present_frame; - - inputrefresh(playrecstatus->status); - interrupt_requested = - (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON)) != 0; - if(interrupt_requested && playback->interrupt) { - retval = -1; - } - movie_playback_update(interrupt_requested); - if(!playback->active) { - break; - } - present_frame = playback->frame_dirty; - if(present_frame) { - if(!movie_playback_draw_to_yuv(playback->index)) { - retval = 0; - break; - } - } - if(playback->current_frame && - !noscreenshot && - (bothnewkeys & FLAG_SCREENSHOT)) { - if(!screenshot_frame || - screenshot_frame->width != playback->current_frame->width || - screenshot_frame->height != playback->current_frame->height) { - if(screenshot_frame) { - freescreen(&screenshot_frame); - } - screenshot_frame = allocscreen( - playback->current_frame->width, - playback->current_frame->height, - PIXEL_32 - ); - } - if(screenshot_frame) { - yuv_to_rgb(playback->current_frame, screenshot_frame); - screenshot(screenshot_frame, NULL, 0); - } - } - usleep(1000); - } - -quit: - if(screenshot_frame) { - freescreen(&screenshot_frame); - } - if(playback && playback->failed && retval > 0) { - retval = 0; - } - if(playback && playback->active) { - movie_playback_stop(playback); - } - while(source_id >= 0 && !movie_source_unload(source_id)) { - movie_playback_update(0); - usleep(1000); - } - return retval; -} -#endif - - - -void playscene(char *filename) -{ - char *buf; - size_t size; - int pos; - char *command = NULL; - char videofile[MAX_BUFFER_LEN]; - int x = 0, y = 0, skipone = 0, noskip = 0, i; - int closing = 0, status; - - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - - // Read file - if(buffer_pakfile(filename, &buf, &size) != 1) - { - return; - } - - currentScene = filename; - - // Now interpret the contents of buf line by line - pos = 0; - while(buf[pos]) - { - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - if(command[0]) - { - if(!closing && stricmp(command, "music") == 0) - { - music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3))); - } - else if(!closing && stricmp(command, "animation") == 0) - { - strcpy(videofile, GET_ARG(1)); - x = GET_INT_ARG(2); - y = GET_INT_ARG(3); - skipone = GET_INT_ARG(4); - noskip = GET_INT_ARG(5); - status = playgif(videofile, x, y, noskip); - if(status == -1 && !skipone) - { - closing = 1; - } - } - else if(!closing && stricmp(command, "video") == 0) - { -#ifdef WEBM - strcpy(videofile, GET_ARG(1)); - skipone = GET_INT_ARG(2); - noskip = GET_INT_ARG(3); - status = playwebm(videofile, noskip); - if(status == -1 && !skipone) - { - closing = 1; - } - else if(status == 0) - { - printf("An error occurred when trying to play the video %s\n", videofile); - } -#else - printf("Skipping video %s; WebM playback not supported on this platform\n"); -#endif - } - else if(stricmp(command, "silence") == 0) - { - sound_close_music(); - } - } - // Go to next non-blank line - pos += getNewLineStart(buf + pos); - } - if(buf != NULL) - { - free(buf); - buf = NULL; - } - currentScene = NULL; - for(i = 0; i < MAX_PLAYERS; i++) - { - player[i].disablekeys = player[i].newkeys = player[i].playkeys = 0; - } -} - - - - -// ---------------------------------------------------------------------------- - - - - -void gameover() -{ - int done = 0; - char tmpBuff[MAX_BUFFER_LEN] = {""}; - - music("data/music/gameover", 0, 0); - - _time = 0; - screen_status |= IN_SCREEN_GAME_OVER; - - if(custScenes != NULL) - { - strcpy(tmpBuff, custScenes); - strcat(tmpBuff, "gameover.txt"); - if(testpackfile(tmpBuff, packfile) >= 0) - { - playscene(tmpBuff); - done = 1; - } - } - else - { - if(testpackfile("data/scenes/gameover.txt", packfile) >= 0) - { - playscene("data/scenes/gameover.txt"); - done = 1; - } - - } - - while(!done) - { - font_printf(_strmidx(3, Tr("GAME OVER")), 110 + videomodes.vShift, 3, 0, Tr("GAME OVER")); - done |= (_time > global_config.game_speed * 8 && !sound_query_music(NULL, NULL)); - done |= (bothnewkeys & (FLAG_ESC | FLAG_ANYBUTTON)); - update(0, 0); - } - - screen_status &= ~IN_SCREEN_GAME_OVER; -} - - - - -void hallfame(int addtoscore) -{ - int done = 0; - int topten[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - uint64_t score; - char name[MAX_NAME_LEN + 1]; - int i, p, y; - char tmpBuff[MAX_BUFFER_LEN] = {""}; - int col1 = -8; - int col2 = 6; - - screen_status |= IN_SCREEN_HALL_OF_FAME; - - if(hiscorebg) - { - // New alternative background path. - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "hiscore"); - load_background(tmpBuff); - } - else - { - load_cached_background("data/bgs/hiscore"); - } - } - - if(addtoscore) - { - for(p = 0; p < levelsets[current_set].maxplayers; p++) - { - if(player[p].score > savescore.highsc[9]) - { - savescore.highsc[9] = player[p].score; - strcpy(savescore.hscoren[9], player[p].name); - topten[9] = 1; - - for(i = 8; i >= 0 && player[p].score > savescore.highsc[i]; i--) - { - score = savescore.highsc[i]; - strcpy(name, savescore.hscoren[i]); - savescore.highsc[i] = player[p].score; - strcpy(savescore.hscoren[i], player[p].name); - topten[i] = 1; - savescore.highsc[i + 1] = score; - strcpy(savescore.hscoren[i + 1], name); - topten[i + 1] = 0; - } - } - } - saveHighScoreFile(); - } - - _time = 0; - - while(!done) - { - y = 56; - if(!hiscorebg) - { - font_printf(_strmidx(3, Tr("Hall Of Fame")), y - fontheight(3) - 10 + videomodes.vShift, 3, 0, Tr("Hall Of Fame")); - } - - for(i = 0; i < 10; i++) - { - font_printf(_colx(topten[i], col1), y + videomodes.vShift, topten[i], 0, "%2i. %s", i + 1, savescore.hscoren[i]); - font_printf(_colx(topten[i], col2), y + videomodes.vShift, topten[i], 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), savescore.highsc[i]); - y += (videomodes.vRes - videomodes.vShift - 56 - 32) / 10; //font_heights[topten[i]] + 6; - } - - // Kratus (01-2023) Added the "FLAG_ANYBUTTON" to exit the Hall of Fame screen - update(0, 0); - done |= (_time > global_config.game_speed * 8); - done |= (bothnewkeys & (FLAG_START | FLAG_ANYBUTTON | FLAG_ESC)); - } - unload_background(); - screen_status &= ~IN_SCREEN_HALL_OF_FAME; -} - - - - -// Level completed, show bonus stuff -void showcomplete(int num) -{ - int done = 0; - int i, j, k; - u32 clearbonus[4] = { 10000, 10000, 10000, 10000 }; - u32 lifebonus[4] = { 10000, 10000, 10000, 10000 }; - u32 rushbonus[4] = { 10000, 10000, 10000, 10000 }; - u32 nexttime = 0; - u32 finishtime = 0; - int chan = 0; - char tmpBuff[MAX_BUFFER_LEN] = {""}; - - screen_status |= IN_SCREEN_SHOW_COMPLETE; - - if(completebg) - { - // New alternative background path. - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "complete"); - load_background(tmpBuff); - } - else - { - load_cached_background("data/bgs/complete"); - } - } - - music("data/music/complete", 0, 0); - - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(rush[0] >= 1 && showrushbonus == 1) - { - rushbonus[i] = nomaxrushreset[i] * scbonuses[2]; - } - if(scbonuses[3] == 1) - { - clearbonus[i] = num * scbonuses[0]; - } - else - { - clearbonus[i] = scbonuses[0]; - } - lifebonus[i] = player[i].lives * scbonuses[1]; - } - - update(0, 0); - - _time = 0; - while(!done) - { - if(!scomplete[5]) - { - font_printf(videomodes.hShift + scomplete[0], videomodes.vShift + scomplete[1], 3, 0, Tr("Stage %i Complete!"), num); - } - else - { - font_printf(videomodes.hShift + scomplete[0], videomodes.vShift + scomplete[1], 3, 0, Tr("Stage")); - font_printf(videomodes.hShift + scomplete[2], videomodes.vShift + scomplete[3], 3, 0, "%i", num); - font_printf(videomodes.hShift + scomplete[4], videomodes.vShift + scomplete[5], 3, 0, Tr("Complete")); - } - - font_printf(videomodes.hShift + cbonus[0], videomodes.vShift + cbonus[1], 0, 0, Tr("Clear Bonus")); - for(i = 0, j = 2, k = 3; i < levelsets[current_set].maxplayers; i++, j = j + 2, k = k + 2) if(player[i].lives > 0) - { - font_printf(videomodes.hShift + cbonus[j], videomodes.vShift + cbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), clearbonus[i]); - } - font_printf(videomodes.hShift + lbonus[0], videomodes.vShift + lbonus[1], 0, 0, Tr("Life bonus")); - for(i = 0, j = 2, k = 3; i < levelsets[current_set].maxplayers; i++, j = j + 2, k = k + 2) if(player[i].lives > 0) - { - font_printf(videomodes.hShift + lbonus[j], videomodes.vShift + lbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), lifebonus[i]); - } - if(rush[0] >= 1 && showrushbonus == 1) - { - font_printf(videomodes.hShift + rbonus[0], videomodes.vShift + rbonus[1], 0, 0, Tr("Rush Bonus")); - for(i = 0, j = 2, k = 3; i < levelsets[current_set].maxplayers; i++, j = j + 2, k = k + 2) if(player[i].lives > 0) - { - font_printf(videomodes.hShift + rbonus[j], videomodes.vShift + rbonus[k], 0, 0, (scoreformat ? "%09lu" : "%lu"), rushbonus[i]); - } - } - font_printf(videomodes.hShift + tscore[0], videomodes.vShift + tscore[1], 0, 0, Tr("Total Score")); - for(i = 0, j = 2, k = 3; i < levelsets[current_set].maxplayers; i++, j = j + 2, k = k + 2) if(player[i].lives > 0) - { - font_printf(videomodes.hShift + tscore[j], videomodes.vShift + tscore[k], 0, 0, (scoreformat ? "%09" PRIu64 : "%" PRIu64), player[i].score); - } - - while(_time > nexttime) - { - if(!finishtime) - { - finishtime = _time + 4 * global_config.game_speed; - } - - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].lives > 0) - { - if(clearbonus[i] > 0) - { - addscore(i, 10); - clearbonus[i] -= 10; - finishtime = 0; - } - else if(lifebonus[i] > 0) - { - addscore(i, 10); - lifebonus[i] -= 10; - finishtime = 0; - } - else if(rush[0] >= 1 && showrushbonus == 1 && (rushbonus[i] > 0)) - { - addscore(i, 10); - rushbonus[i] -= 10; - finishtime = 0; - } - } - } - - if(!finishtime && !(nexttime & 15)) - { - sound_stop_sample(chan); - chan = sound_play_sample(global_sample_list.beep, 0, savedata.effectvol / 2, savedata.effectvol / 2, 100); - } - nexttime++; - } - - if(bothnewkeys & (FLAG_ANYBUTTON | FLAG_ESC)) - { - done = 1; - } - if(finishtime && _time > finishtime) - { - done = 1; - } - - update(0, 0); - } - - // Add remainder of score, incase player skips counter - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].lives > 0) - { - if(rush[0] >= 1 && showrushbonus == 1) - { - addscore(i, rushbonus[i]); - } - addscore(i, clearbonus[i]); - addscore(i, lifebonus[i]); - } - } - unload_background(); - - screen_status &= ~IN_SCREEN_SHOW_COMPLETE; -} - -void savelevelinfo() -{ - int i; - s_set_entry *set = levelsets + current_set; - s_savelevel *save = savelevel + current_set; - - save->flag = set->saveflag; - // don't check flag here save all info, for simple logic - for(i = 0; i < set->maxplayers; i++) - { - save->pLives[i] = player[i].lives; - save->pCredits[i] = player[i].credits; - save->pScores[i] = player[i].score; - save->pSpawnhealth[i] = player[i].spawnhealth; - save->pSpawnmp[i] = player[i].spawnmp; - save->pWeapnum[i] = player[i].weapnum; - save->pColourmap[i] = player[i].colourmap; - strncpy(save->pName[i], player[i].name, MAX_NAME_LEN); - } - save->credits = credits; - save->level = current_level; - save->stage = current_stage; - save->which_set = current_set; - strncpy(save->dName, set->name, MAX_NAME_LEN - 1); - set_saved_allowselect_arguments(current_set, allowselect_args); -} - -void tryvictorypose(entity *ent) -{ - if( ent && - ent->inpain & ~IN_PAIN_NONE && - !ent->falling && - !(ent->death_state & DEATH_STATE_DEAD) && - !ent->rising && - (ent->idling & IDLING_ACTIVE) && - ent->position.y <= ent->base ) - { - ent->takeaction = NULL; - ent->velocity.x = ent->velocity.z = 0; - ent->idling = IDLING_NONE; - ent_set_anim(ent, ANI_VICTORY, 0); - } -} - -static void check_victory_pose() -{ - if ( (endgame & 1) && level_completed_defeating_boss ) - { - int i; - for(i = 0; i < MAX_PLAYERS; i++) - { - entity* tmp = self; - self = player[i].ent; - if(self && validanim(self, ANI_VICTORY) && self->animnum != ANI_VICTORY) - { - tryvictorypose(self); - endgame = 0; - } - else if (self && self->animnum == ANI_VICTORY && self->animating) - { - endgame = 0; - } - - self = tmp; - } - } -} - -int playlevel(char *filename) -{ - int i, type, p_alive = 0; - - kill_all(); - - savelevelinfo(); // just in case we lose them after level is freed - - load_level(filename); - - if(!nosave) - { - saveGameFile(); - saveHighScoreFile(); - saveScriptFile(); - } - nosave = 0; - - _time = 0; - nextplan = 0; - stalker = NULL; - firstplayer = NULL; - type = level->type; - - // Fixes the start level executing last button bug - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].lives > 0) - { - player[i].disablekeys = player[i].newkeys = player[i].playkeys = 0; - player[i].weapnum = level->setweap; - player[i].joining = 0; - player[i].hasplayed = 1; - spawnplayer(i); - player[i].ent->rush.max = 0; - } - } - - //execute a script when level started - if(Script_IsInitialized(&level_script)) - { - Script_Execute(&level_script); - } - if(Script_IsInitialized(&(level->level_script))) - { - Script_Execute(&(level->level_script)); - } - - while(!endgame) - { - update(1, 0); - - if (level->force_finishlevel) - { - level_completed = 1; - endgame |= 1; - level->force_finishlevel = 0; - } - if (level->force_gameover) - { - //entity* temp = self; - for(i = 0; i < MAX_PLAYERS; i++) //levelsets[current_set].maxplayers - { - player[i].lives = 0; - if(noshare) - { - player[i].credits = 0; - } - else - { - credits = 0; - } - if (player[i].ent) - { - kill_entity(player[i].ent, KILL_ENTITY_TRIGGER_LEVEL_GAME_OVER); - player[i].ent = NULL; - } - //self = player[i].ent; - //player_die(); - } - //self = temp; - //kill_all(); - endgame |= 1; - level->force_gameover = 0; - } - if(level_completed) - { - endgame |= (!findent(TYPE_ENEMY) || level->type || findent(TYPE_ENDLEVEL)); // Ends when all enemies die or a bonus level - check_victory_pose(); - } - } - //execute a script when level finished - if(Script_IsInitialized(&endlevel_script)) - { - Script_Execute(&endlevel_script); - } - if(Script_IsInitialized(&(level->endlevel_script))) - { - Script_Execute(&(level->endlevel_script)); - } - if(!nofadeout) - { - fade_out(0, 0); - } - - for(i = 0; i < levelsets[current_set].maxplayers; i++) - { - if(player[i].ent) - { - nomaxrushreset[i] = player[i].ent->rush.max; - player[i].spawnhealth = player[i].ent->energy_state.health_current; - player[i].spawnmp = player[i].ent->energy_state.mp_current; - } - // reset - player[i].weapnum = 0; - } - - if(!musicoverlap) - { - sound_close_music(); - } - sound_stopall_sample(false); - - unload_level(); - - // Are any players alive? - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].lives > 0) - { - p_alive = 1; - break; - } - } - - return ((type == 2 && endgame != 2) || p_alive); -} - -// Caskey, Damon V (retool, OA unknown) -// 2019-01-03 -// -// For select screen. Spawn sample entity for player_index. -static entity *spawnexample(int player_index) -{ - char* SPAWN_MODEL_NAME = NULL; - const int SPAWN_MODEL_INDEX = MODEL_INDEX_NONE; - - entity *example; - s_model *model; - s_set_entry *set; - - float pos_x; - float pos_y; - float pos_z; - int direction; - - set = levelsets + current_set; - - // Get spawn attributes and spawn entity. - pos_x = (float)psmenu[player_index][0]; - pos_y = 0; - pos_z = (float)psmenu[player_index][1]; - direction = spdirection[player_index]; - - // Next selectable model in cycle. We'll use this - // to decide what we spawn. - model = nextplayermodeln(NULL, player_index); - - example = spawn(pos_x, pos_z, pos_y, direction, SPAWN_MODEL_NAME, SPAWN_MODEL_INDEX, model); - - // Copy model's name to player property. - strcpy(player[player_index].name, model->name); - - // If color selection is allowed and we want - // players with same models to use different - // maps, then use next map in cycle. Otherwise - // just go with default map. - if (colourselect && (set->nosame & 2)) - { - player[player_index].colourmap = nextcolourmapn(model, -1, player_index); - } - else - { - player[player_index].colourmap = 0; - } - - // Apply map to spawned entity. - ent_set_colourmap(example, player[player_index].colourmap); - - // So the entity knows how it came to be. - example->spawntype = SPAWN_TYPE_PLAYER_SELECT; - - return example; -} - -// load saved select screen -static void load_select_screen_info(s_savelevel *save) -{ - int i = 0; - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - char *filename = ""; // not used, just fused into GET_INT_ARG() - char *command = ""; // not used, just fused into GET_INT_ARG() - - // load model_loads - for(i = 0; i < save->selectLoadCount; i++) - { - s_model *tempmodel; - command = GET_ARG(0); - - if(!command || !command[0]) continue; - ParseArgs(&arglist, save->selectLoad[i], argbuf); - - tempmodel = findmodel(GET_ARG(1)); - if (tempmodel) - { - update_model_loadflag(tempmodel, GET_INT_ARG(2)); - } - } - - ParseArgs(&arglist, save->selectMusic, argbuf); - command = GET_ARG(0); - if(command && command[0]) music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3))); - - ParseArgs(&arglist, save->selectBackground, argbuf); - command = GET_ARG(0); - if(command && command[0]) load_background(GET_ARG(1)); - - return; -} - -int selectplayer(int *players, char *filename, int useSavedGame) -{ - s_model *tempmodel; - s_model *model_new[MAX_PLAYERS] = { NULL }; - int i; - int exit = 0; - int escape = 0; - int defaultselect = 0; - unsigned exitdelay = 0; - int players_busy = 0; - int players_ready = 0; - char string[MAX_BUFFER_LEN] = { "" }; - char *buf, *command; - size_t size = 0; - ptrdiff_t pos = 0; - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - s_set_entry *set = levelsets + current_set; - s_savelevel *save = savelevel + current_set; - int load_count = 0; - int saved_select_screen = 0; - int is_first_select = 1; - - savelevelinfo(); - - screen_status |= IN_SCREEN_SELECT; - - kill_all(); - - // Initialize player sized arrays. - entity *example[set->maxplayers]; - int ready[set->maxplayers]; - - // Initialize - for (i = 0; i < set->maxplayers; i++) - { - example[i] = NULL; - ready[i] = 0; - } - - // Allow select? 'a' is the first char of allowselect, - // if there's 'a' then there is allowselect. - if (!allowselect_args - || (allowselect_args[0] != 'a' - && allowselect_args[0] != 'A')) - { - reset_playable_list(1); - } - - // Reset memory for player array. - memset(player, 0, sizeof(*player) * MAX_PLAYERS); - - // Load game selected and a save game available? - if (useSavedGame && save) - { - if (save->selectFlag) - { - load_select_screen_info(save); - load_playable_list( - get_saved_allowselect_arguments(current_set) - ); - saved_select_screen = 1; - } - } - - // Mark "hasplayed" for all players. - for (i = 0; i < set->maxplayers; i++) - { - player[i].hasplayed = players[i]; - } - - for (i = 0; i < set->maxplayers; i++) - { - if (savelevel[current_set].pLives[i] > 0) - { - is_first_select = 0; - break; - } - } - - // Load and apply selection text file. - if (filename && filename[0]) - { - if (buffer_pakfile(filename, &buf, &size) != 1) - { - borShutdown(1, "Failed to load player select file '%s'", filename); - } - while (pos < size) - { - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - if (command && command[0]) - { - if (stricmp(command, "music") == 0) - { - music(GET_ARG(1), GET_INT_ARG(2), atol(GET_ARG(3))); - // SAVE - multistrcatsp(save->selectMusic, command, GET_ARG(1), GET_ARG(2), GET_ARG(3), NULL); - } - else if (stricmp(command, "allowselect") == 0) - { - load_playable_list(buf + pos); - set_saved_allowselect_arguments( - current_set, - allowselect_args - ); - } - else if (stricmp(command, "background") == 0) - { - load_background(GET_ARG(1)); - // SAVE - multistrcatsp(save->selectBackground, command, GET_ARG(1), NULL); - } - else if (stricmp(command, "load") == 0) - { - tempmodel = findmodel(GET_ARG(1)); - if (!tempmodel) - { - load_cached_model(GET_ARG(1), filename, GET_INT_ARG(2)); - } - else - { - update_model_loadflag(tempmodel, GET_INT_ARG(2)); - } - // SAVE - if (load_count < MAX_SELECT_LOADS) - { - multistrcatsp(save->selectLoad[load_count], command, GET_ARG(1), GET_ARG(2), NULL); - load_count++; - } - } - else if (command && command[0]) - { - printf("Command '%s' is not understood in file '%s'\n", command, filename); - } - } - - pos += getNewLineStart(buf + pos); - } - save->selectLoadCount = load_count; // SAVE number of LOAD command - save->selectFlag = 1; - - if (buf != NULL) - { - free(buf); - buf = NULL; - } - } - else // without select.txt - { - if (is_first_select || (!skipselect[0][0] && !set->noselect)) // no select is skipselect without names - { - defaultselect = 1; // normal select or skipselect/noselect? 1 == normal select - } - - if (!noshare) - { - credits = CONTINUES; - } - else for (i = 0; i < set->maxplayers; i++) - { - if (players[i]) - { - player[i].credits = CONTINUES; - } - } - - if (skipselect[0][0] || set->noselect) - { - for (i = 0; i < set->maxplayers; i++) - { - if (!players[i]) - { - continue; - } - strncpy(player[i].name, skipselect[i], MAX_NAME_LEN); - - if (defaultselect) - { - player[i].lives = PLAYER_LIVES; - if (!(global_config.cheats & CHEAT_OPTIONS_CREDITS_ACTIVE)) - { - if (noshare) - { - --player[i].credits; - } - else - { - --credits; - } - } - } - else - { - player[i].lives = savelevel[current_set].pLives[i]; - player[i].score = savelevel[current_set].pScores[i]; - if (noshare) player[i].credits = savelevel[current_set].pCredits[i]; - else credits = savelevel[current_set].credits; - } - } - - screen_status &= ~IN_SCREEN_SELECT; - - return 1; - } - - if (!saved_select_screen) - { - if (unlockbg && bonus) - { - // New alternative background path. - if (custBkgrds != NULL) - { - strcpy(string, custBkgrds); - strcat(string, "unlockbg"); - load_background(string); - } - else - { - load_cached_background("data/bgs/unlockbg"); - } - } - else - { - // New alternative background path. - if (custBkgrds != NULL) - { - strcpy(string, custBkgrds); - strcat(string, "select"); - load_background(string); - } - else - { - load_cached_background("data/bgs/select"); - } - } - if (!music("data/music/menu", 1, 0)) - { - music("data/music/remix", 1, 0); - } - } - } - - for (i = 0; i < set->maxplayers; i++) - { - if (players[i]) - { - example[i] = spawnexample(i); - player[i].playkeys = 0; - if (defaultselect) - { - player[i].lives = PLAYER_LIVES; - if (!(global_config.cheats & CHEAT_OPTIONS_CREDITS_ACTIVE)) - { - if (noshare) - { - --player[i].credits; - } - else - { - --credits; - } - } - } - else - { - player[i].lives = savelevel[current_set].pLives[i]; - player[i].score = savelevel[current_set].pScores[i]; - if (noshare) player[i].credits = savelevel[current_set].pCredits[i]; - else credits = savelevel[current_set].credits; - } - } - } - - _time = 0; - - // Stay in selection until escape or exit. - // - // exit = all players ready (selected) and exit delay expired. - // escape = Escape key pressed. - while (!(exit || escape)) - { - players_busy = 0; - players_ready = 0; - - // Loop through players. - for (i = 0; i < set->maxplayers; i++) - { - // Current player index not yet selected? - if (!ready[i]) - { - - // This is where we present player selections. The logic is long - // and a little messy, so buckle up! Basically, we want to spawn - // an example entity to get started, and that example entity - // is what player sees on the selection screen. Then we switch - // its model/color/animation based on the situation and player - // input. - // - // 1. If an example entity exists and is playing a transition - // then we... - // - // a) do nothing if the animation isn't finished. - // - // b) If it IS finished... - // - // -- 1. If the animation is ANI_SELECTIN, then play ANI_SELECT. - // - // -- 2. If aniamton is ANI_SELECTOUT, then we switch to new - // model (if available). - // - // 2. If player hasn't played yet, has some credits or - // can draw from credit pool and pressed any action button, - // then we'll deal with their credit pool and spawn the - // first example (selectable model preview). Having an - // example spawned also tells us the player has completed - // this step, and so it's OK to run actions from any of - // the others. - // - // 3. If the player pressed Left or Right instead and there's - // an example spawned, then we find the previous/next - // character in line, and record it to a variable. Then we - // see if example has ANI_SELECTIN. if it doesn't we switch - // to new model. If it does, play ANI_SELECT. - // - // 4. If the player presses Up or Down, we have an example - // spawned and colourselect is enabled, then cycle to the - // model's previous/next color set choice. - // - // 5. If the player presses any action button and we have - // an example spawned, then we mark the player's ready delay - // flag, and stalltime. See the parent logic block for - // selection delay & exit details. This is the player - // making their selection choice. - - // Example exists and select transition animation? - if (example[i] - && (example[i]->animnum == ANI_SELECTIN || example[i]->animnum == ANI_SELECTOUT)) - { - // If still animating than do nothing. Let the transition finish. - if (example[i]->animating) - { - } - else - { - // Transition to select animation. - if (example[i]->animnum == ANI_SELECTIN) - { - ent_set_anim(example[i], ANI_SELECT, 0); - } - - // Transition from select (player selected another model, and the - // select out transition is now finished). Repeat of left/right key - // logic below and probably needs consolidation. - if (example[i]->animnum == ANI_SELECTOUT && model_new[i]) - { - // Apply new model. - ent_set_model(example[i], model_new[i]->name, 0); - model_new[i] = NULL; - - // Copy example model name to player name variable. - strcpy(player[i].name, example[i]->model->name); - - // If colorselect is enabled and nosame 2 is enabled, skip to - // start at next avaialble color cycle. Otherwise just start - // with default color set (0). - if (colourselect && (set->nosame & 2)) - { - player[i].colourmap = nextcolourmapn(example[i]->model, -1, i); - } - else - { - player[i].colourmap = 0; - } - - // Apply color set. - ent_set_colourmap(example[i], player[i].colourmap); - } - } - } - else if (!player[i].hasplayed - && (noshare || credits > 0) - && (player[i].newkeys & FLAG_ANYBUTTON)) - { - - // Now this player has played. - players[i] = player[i].hasplayed = 1; - //printf("%d %d %d\n", i, player[i].lives, immediate[i]); - - // Noshare means each player has their own credit pool. - if (noshare) - { - player[i].credits = CONTINUES; - } - - // Credits cheat = infinite credits. If that's not enabled, - // then deduct a credit. - if (!(global_config.cheats & CHEAT_OPTIONS_CREDITS_ACTIVE)) - { - if (noshare) - { - --player[i].credits; - } - else - { - --credits; - } - } - - // Give player default number of lives, spawn - // example model and cancel the key flag. - player[i].lives = PLAYER_LIVES; - example[i] = spawnexample(i); - player[i].playkeys = 0; - - // Play sound effect. - if (global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - else if ((player[i].newkeys & FLAG_ANYBUTTON) && example[i]) //Kratus (01-05-21) Moved the "anybutton" code to before of the "left/right" code to fix a bug that makes no character chosen when both are pressed together - { - if (global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - // yay you picked me! - if (validanim(example[i], ANI_PICK)) - { - ent_set_anim(example[i], ANI_PICK, 0); - } - example[i]->stalltime = _time + global_config.game_speed * 2; - ready[i] = 1; - } - else if (player[i].newkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT) && example[i]) - { - // Give player a feedback sound. - if (global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - // Get model in use right now. - // Let's get the new model. Left key = previous model - // in cycle. Right key = next. - if ((player[i].newkeys & FLAG_MOVELEFT)) - { - model_new[i] = prevplayermodeln(example[i]->model, i); - } - else - { - model_new[i] = nextplayermodeln(example[i]->model, i); - } - - // Do we have a select out transition? If so play it here. - // Otherwise switch to new model. - if (validanim(example[i], ANI_SELECTOUT)) - { - ent_set_anim(example[i], ANI_SELECTOUT, 0); - } - else - { - // Apply new model. - ent_set_model(example[i], model_new[i]->name, 0); - model_new[i] = NULL; - - // Copy example model name to player name variable. - strcpy(player[i].name, example[i]->model->name); - - // If colorselect is enabled and nosame 2 is enabled, skip to - // start at next avaialble color cycle. Otherwise just start - // with default color set (0). - if (colourselect && (set->nosame & 2)) - { - player[i].colourmap = nextcolourmapn(example[i]->model, -1, i); - } - else - { - player[i].colourmap = 0; - } - - // Apply color set. - ent_set_colourmap(example[i], player[i].colourmap); - } - } - else if (player[i].newkeys & (FLAG_MOVEUP | FLAG_MOVEDOWN) && colourselect && example[i]) - { - player[i].colourmap = ((player[i].newkeys & FLAG_MOVEUP) ? nextcolourmapn : prevcolourmapn)(example[i]->model, player[i].colourmap, i); - ent_set_colourmap(example[i], player[i].colourmap); - } - } - else if (ready[i] == 1) - { - if (((!validanim(example[i], ANI_PICK) || example[i]->modeldata.animation[ANI_PICK]->loop.mode) && _time > example[i]->stalltime) || !example[i]->animating) - { - ready[i] = 2; - exitdelay = _time + global_config.game_speed; - } - } - else if (ready[i] == 2) - { - font_printf(psmenu[i][2], psmenu[i][3], 0, 0, Tr("Ready!")); - } - - if (example[i] != NULL) - { - players_busy++; - } - if (ready[i] == 2) - { - players_ready++; - } - } - - if (players_busy && players_busy == players_ready && exitdelay && _time > exitdelay) - { - exit = 1; - } - update(0, 0); - - if (bothnewkeys & FLAG_ESC || escape_flag == 11) //Kratus (20-04-21) Added the new "escape" flag in the select screen by using the "gotomainmenu" function and the flag "11" - { - escape = 1; - escape_flag = 0; - } - } - - // No longer at the select screen - kill_all(); - sound_close_music(); - screen_status &= ~IN_SCREEN_SELECT; - - return (!escape); -} - -void playgame(int *players, unsigned which_set, int useSavedGame) -{ - int i; - current_level = 0; - current_stage = 1; - current_set = which_set; - s_set_entry *set = levelsets + current_set; - s_savelevel *save = savelevel + current_set; - s_level_entry *le; - - useSave = 0; - useSet = -1; - - if(which_set >= num_difficulties) - { - return; - } - // borShutdown(1, "Illegal set chosen: index %i (there are only %i sets)!", which_set, num_difficulties); - - allow_secret_chars = set->ifcomplete; - PLAYER_LIVES = set->lives; - musicoverlap = set->musicoverlap; - fade = set->custfade; - CONTINUES = set->credits; - magic_type = set->typemp; - if(PLAYER_LIVES == 0) - { - PLAYER_LIVES = 3; // default - } - if(CONTINUES == 0) - { - CONTINUES = 5; // default - } - if(fade == 0) - { - fade = 24; // default - } - sameplayer = set->nosame; - - if(useSavedGame == 1 && save->flag) - { - memset(player, 0, sizeof(*player) * 4); - if(!loadScriptFile()) - { - printf("Warning, failed to load script save!\n"); - } - current_level = save->level; - current_stage = save->stage; - if(save->flag == 2) // don't check 1 or 0 becuase if we use saved game the flag must be >0 - { - for(i = 0; i < set->maxplayers; i++) - { - player[i].lives = save->pLives[i]; - player[i].credits = save->pCredits[i]; - player[i].score = save->pScores[i]; - player[i].colourmap = save->pColourmap[i]; - player[i].weapnum = save->pWeapnum[i]; - player[i].spawnhealth = save->pSpawnhealth[i]; - player[i].spawnmp = save->pSpawnmp[i]; - strncpy(player[i].name, save->pName[i], MAX_NAME_LEN); - } - credits = save->credits; - } - load_playable_list( - get_saved_allowselect_arguments(current_set) - ); - //reset_playable_list(1); // add this because there's no select screen, temporary solution - } - - nosave = 1; - - // fix save an inexistent level - if ( current_level >= set->numlevels ) - { - current_level = set->numlevels-1; - } - - le = set->levelorder + current_level; - set->noselect = le->noselect; - if (save->selectSkipSelect[0]) le = load_skipselect(save->selectSkipSelect, set); // LOAD skipselect - for(i = 0; i < MAX_PLAYERS; i++) - { - if(le->skipselect[i]) - { - strcpy(skipselect[i], le->skipselect[i]); - } - else - { - skipselect[i][0] = 0; - } - } - - if((useSavedGame == 1 && save->flag == 2) || useSavedGame == 2 || selectplayer(players, NULL, useSavedGame)) // if save flag is 2 don't select player - { - while(current_level < set->numlevels) - { - if(branch_name[0]) // branch checking - { - //current_stage = 1; //jump, jump... perhaps we don't need to reset it, modders should take care of it. - for(i = 0; i < set->numlevels; i++) - { - if(set->levelorder[i].branchname && stricmp(set->levelorder[i].branchname, branch_name) == 0) - { - current_level = i; - break; - } - //if(levelorder[which_set][i]->gonext==1) ++current_stage; OX. Commented this line out. Seems to be cause of inacurate stage # complete message. - } - branch_name[0] = 0;// clear up so we won't stuck here - } - le = set->levelorder + current_level; - PLAYER_MIN_Z = le->z_coords[0]; - PLAYER_MAX_Z = le->z_coords[1]; - BGHEIGHT = le->z_coords[2]; - - if(le->type == LE_TYPE_CUT_SCENE) - { - playscene(le->filename); - } - else if(le->type == LE_TYPE_SELECT_SCREEN) - { - memset(save->selectSkipSelect,0,sizeof(save->selectSkipSelect)); // RESET skipselect - set->noselect = 0; - for(i = 0; i < set->maxplayers; i++) // reset skipselect - { - if(le->skipselect[i]) - { - skipselect[i][0] = 0; - } - } - for(i = 0; i < set->maxplayers ; i++) - { - players[i] = (player[i].lives > 0); - } - if(selectplayer(players, le->filename, useSavedGame) == 0) - { - break; - } - } - else if(le->type == LE_TYPE_SKIP_SELECT) - { - set->noselect = le->noselect; - for(i = 0; i < MAX_PLAYERS; i++) - { - if(le->skipselect[i]) - { - strcpy(skipselect[i], le->skipselect[i]); - } - else - { - skipselect[i][0] = 0; - } - } - save_skipselect(save->selectSkipSelect, skipselect); // TO SAVE FILE - selectplayer(players, NULL, useSavedGame); // re-select a player - } - else if(!playlevel(le->filename)) - { - int all_p_lives_zero = 0; - for(i = 0; i < MAX_PLAYERS; i++) - { - if (player[i].lives <= 0) ++all_p_lives_zero; - } - all_p_lives_zero = (all_p_lives_zero >= MAX_PLAYERS) ? 1 : 0; - - //if( (player[0].lives <= 0 && player[1].lives <= 0 && player[2].lives <= 0 && player[3].lives <= 0) ) - if(all_p_lives_zero) - { - if( (!set->noshowgameover && !(goto_mainmenu_flag&2)) ) - { - gameover(); - } - if(!set->noshowhof && !(goto_mainmenu_flag&4)) - { - hallfame(1); - } - for(i = 0; i < set->maxplayers; i++) - { - player[i].hasplayed = 0; - player[i].weapnum = 0; - } - } - break; - } - if(le->gonext == 1) - { - if (!set->noshowcomplete) showcomplete(current_stage); - for(i = 0; i < set->maxplayers; i++) - { - player[i].spawnhealth = 0; - player[i].spawnmp = 0; - } - ++current_stage; - save->stage = current_stage; - } - current_level++; - le = set->levelorder + current_level; - save->level = current_level; - //2007-2-24, gonext = 2, end game - if((le - 1)->gonext == 2) - { - current_level = set->numlevels; - } - if(useSave) - { - goto endgame; //quick exit without saving, for script load game logic - } - }//while - - if(current_level >= set->numlevels) - { - /* - Kratus (01-2024) Reset level/stage values when a game is finished before saving it. - It will automatically erase the current game progress but only after the ending. - However, it will maintain the "times_completed" intact. - Without this fix the player can increase the "times_completed" infinitely by - just finishing the game once and loading the ending directly how many times he want. - */ - bonus += save->times_completed++; - current_level = 0; - current_stage = 1; - save->level = current_level; - save->stage = current_stage; - saveGameFile(); - if(!nofadeout) - { - fade_out(0, 0); - } - if(!set->noshowhof) - { - hallfame(1); - } - } - } - -endgame: - // clear global script variant list - branch_name[0] = 0; - sound_close_music(); -} - -int menu_difficulty() -{ - int quit = 0; - int selector = 0; - int maxdisplay = 5; - int i, j, t; - //float slider = 0; - int barx, bary, barw, barh; - s_drawmethod drawmethod = plainmethod; - drawmethod.alpha = BLEND_MODE_ALPHA; - - barx = videomodes.hRes / 5; - bary = _liney(0, 0) - 2; - barw = videomodes.hRes * 3 / 5; - barh = 5 * (fontheight(0) + 1) + 4; - screen_status |= IN_SCREEN_NEW_GAME_MENU; - bothnewkeys = 0; - - loadGameFile(); - - while(!quit) - { - if(num_difficulties > 1) - { - _menutextm(2, -2, 0, Tr("Game Mode")); - t = (selector - (selector == num_difficulties)) / maxdisplay * maxdisplay; - for(j = 0, i = t; i < maxdisplay + t && i < num_difficulties; j++, i++) - { - if(j < maxdisplay) - { - // Kratus (10-2021) Added translation feature to the "set" name - // It will get the "set" name in the "levels.txt" file and translate it - // You need to add a new "msgid/msgstr" instance in your "translation.txt" file and put - // the same names as used by all level sets - if(bonus >= levelsets[i].ifcomplete) - { - _menutextm((selector == i), j, 0, "%s", Tr(levelsets[i].name)); - } - else - { - if(levelsets[i].ifcomplete > 1) - { - _menutextm((selector == i), j, 0, Tr("%s - Finish Game %i Times To UnLock"), Tr(levelsets[i].name), levelsets[i].ifcomplete); - } - else - { - _menutextm((selector == i), j, 0, Tr("%s - Finish Game To UnLock"), Tr(levelsets[i].name)); - } - } - } - else - { - break; - } - } - _menutextm((selector == i), 6, 0, Tr("Back")); - - //draw the scroll bar - if(num_difficulties > maxdisplay) - { - spriteq_add_box(barx, bary, barw, barh, 0, color_black, &drawmethod); //outerbox - spriteq_add_line(barx, bary, barx + 8, bary, 1, color_white, NULL); - spriteq_add_line(barx, bary, barx, bary + barh, 1, color_white, NULL); - spriteq_add_line(barx + 8, bary, barx + 8, bary + barh, 1, color_white, NULL); - spriteq_add_line(barx, bary + barh, barx + 8, bary + barh, 1, color_white, NULL); - spriteq_add_box(barx + 1, bary + selector * (barh - 3) / num_difficulties, 7, 3, 2, color_white, NULL); //slider - } - } - - update(0, 0); - - if(num_difficulties == 1) // OX. Mods with only one set will auto load that difficulty. - { - if(selector == num_difficulties) - { - quit = 1; - } - else if(bonus >= levelsets[selector].ifcomplete) - { - saveslot = selector; - strncpy(savelevel[saveslot].dName, levelsets[saveslot].name, MAX_NAME_LEN - 1); - screen_status &= ~IN_SCREEN_NEW_GAME_MENU; - return saveslot; - } - } - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(selector < 0) - { - selector = num_difficulties; - } - if(selector > num_difficulties) - { - selector = 0; - } - //if(selector= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(selector == num_difficulties) - { - quit = 1; - } - else if(bonus >= levelsets[selector].ifcomplete) - { - saveslot = selector; - strncpy(savelevel[saveslot].dName, levelsets[saveslot].name, MAX_NAME_LEN - 1); - screen_status &= ~IN_SCREEN_NEW_GAME_MENU; - return saveslot; - } - } - } - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_NEW_GAME_MENU; - return -1; -} - -int load_saved_game() -{ - int quit = 0; - int selector = 0; - int savedStatus = 0; - char name[MAX_BUFFER_LEN] = {""}; - int col1 = -8, col2 = 6; - - screen_status |= IN_SCREEN_LOAD_GAME_MENU; - bothnewkeys = 0; - - if((savedStatus = loadGameFile())) - { - getPakName(name, 0); - } - for(saveslot = 0; saveslot < num_difficulties; saveslot++) if(savelevel[saveslot].flag && savelevel[saveslot].level) - { - break; - } - - while(!quit) - { - if(saveslot >= num_difficulties) // not found - { - _menutextm(2, -4, 0, Tr("Load Game")); - _menutext(0, col1, -2, Tr("Saved File:")); - _menutext(0, col2, -2, Tr("Not Found!")); - _menutextm(1, 6, 0, Tr("Back")); - - /* - Kratus (01-2024) Minor fix in the selector number if no save is found. - There's no selector "2" in this menu, only 0 (load) or 1 (back). - */ - selector = 1; - } - else - { - _menutextm(2, -4, 0, Tr("Load Game")); - _menutext(0, col1, -2, Tr("Saved File:")); - if(savedStatus) - { - _menutext(0, col2, -2, "%s", name); - } - else - { - _menutext(0, col2, -2, Tr("Not Found!")); - } - - if(savedStatus) - { - _menutext((selector == 0), col1, -1, Tr("Mode:")); - _menutext((selector == 0), col2, -1, "%s", savelevel[saveslot].dName); - _menutext(0, col1, 0, Tr("Stage:")); - _menutext(0, col2, 0, "%d", savelevel[saveslot].stage); - _menutext(0, col1, 1, Tr("Level:")); - _menutext(0, col2, 1, "%d", savelevel[saveslot].level); - _menutext(0, col1, 2, Tr("Credits:")); - - if(noshare){ - _menutext(0, col2, 2, "%d/%d/%d/%d", - savelevel[saveslot].pCredits[0], - savelevel[saveslot].pCredits[1], savelevel[saveslot].pCredits[2], - savelevel[saveslot].pCredits[3]); - } else { - _menutext(0, col2, 2, "%d", savelevel[saveslot].credits); - } - - _menutext(0, col1, 3, Tr("Player Lives:")); - _menutext(0, col2, 3, "%d/%d/%d/%d", - savelevel[saveslot].pLives[0], - savelevel[saveslot].pLives[1], savelevel[saveslot].pLives[2], - savelevel[saveslot].pLives[3]); - } - _menutextm((selector == 1), 6, 0, Tr("Back")); - } - update(0, 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(selector == 0 && (bothnewkeys & FLAG_MOVELEFT)) - { - while(1) - { - --saveslot; - if(saveslot < 0) - { - saveslot = num_difficulties - 1; - } - if(savelevel[saveslot].flag && savelevel[saveslot].level) - { - break; - } - } - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(selector == 0 && (bothnewkeys & FLAG_MOVERIGHT)) - { - while(1) - { - ++saveslot; - if(saveslot > num_difficulties - 1) - { - saveslot = 0; - } - if(savelevel[saveslot].flag && savelevel[saveslot].level) - { - break; - } - } - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(savedStatus) - { - if(selector < 0) - { - selector = 1; - } - if(selector > 1) - { - selector = 0; - } - } - else - { - selector = 1; - } - - if((bothnewkeys & FLAG_ANYBUTTON)) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - switch(selector) - { - case 0: - return saveslot; - break; - case 1: - quit = 1; - break; - } - } - } - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_LOAD_GAME_MENU; - return -1; -} - -int choose_mode(int *players) -{ - int quit = 0; - int relback = 0; - int selector = 0; - int status = 0; - - screen_status |= IN_SCREEN_GAME_START_MENU; - bothnewkeys = 0; - - while(!quit) - { - _menutextm(2, 1, 0, Tr("Choose Mode")); - _menutextm((selector == 0), 3, 0, Tr("New Game")); - _menutextm((selector == 1), 4, 0, Tr("Load Game")); - _menutextm((selector == 2), 6, 0, Tr("Back")); - - update(0, 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(selector < 0) - { - selector = 2; - } - if(selector > 2) - { - selector = 0; - } - - if(bothnewkeys & FLAG_ANYBUTTON) - { - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - switch(selector) - { - case 0: - status = menu_difficulty(); - if(status != -1) - { - playgame(players, status, 0); - relback = 1; - quit = 1; - } - break; - case 1: - status = load_saved_game(); - if(status != -1) - { - playgame(players, status, 1); - relback = 1; - quit = 1; - } - break; - default: - quit = 1; - break; - } - } - } - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_GAME_START_MENU; - return relback; -} - -void term_videomodes() -{ - videomodes.hRes = 0; - videomodes.vRes = 0; - video_set_mode(videomodes); - if(custScenes != NULL) - { - free(custScenes); - } - custScenes = NULL; - if(custBkgrds != NULL) - { - free(custBkgrds); - } - custBkgrds = NULL; - if(custLevels != NULL) - { - free(custLevels); - } - custLevels = NULL; - if(custModels != NULL) - { - free(custModels); - } - custModels = NULL; -} - -// Load Video Mode from file -void init_videomodes(int log) -{ - char *filename = "data/video.txt"; - int tmp; - ptrdiff_t pos, len; - size_t size; - char *buf = NULL; - char *command = NULL; - char *value = NULL, *value2; - ArgList arglist; - char argbuf[MAX_ARG_LEN + 1] = ""; - - // - - if(log) - { - printf("Initializing video............\n"); - } - - // Use an alternative video.txt if there is one. Some of these are long filenames; create your PAKs with borpak and you'll be fine. -#define tryfile(X) if((tmp=openpackfile(X,packfile))!=-1) { closepackfile(tmp); filename=X; goto readfile; } -#if WIN || LINUX - tryfile("data/videopc.txt"); -#endif -#undef tryfile - -readfile: - // Read file - if(buffer_pakfile(filename, &buf, &size) != 1) - { - videoMode = 0; - printf("'%s' not found.\n", filename); - goto VIDEOMODES; - } - - printf("Reading video settings from '%s'.\n", filename); - - // Now interpret the contents of buf line by line - pos = 0; - while(pos < size) - { - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - - if(command && command[0]) - { - if(stricmp(command, "video") == 0) - { - value = GET_ARG(1); - if((value2 = strchr(value, 'x'))) - { - videomodes.hRes = atoi(value); - videomodes.vRes = atoi(value2 + 1); - videoMode = 255; - } - else - { - videoMode = GET_INT_ARG(1); - } - } - else if(stricmp(command, "scenes") == 0) - { - len = strlen(GET_ARG(1)); - custScenes = malloc(len + 1); - strcpy(custScenes, GET_ARG(1)); - custScenes[len] = 0; - } - else if(stricmp(command, "backgrounds") == 0) - { - len = strlen(GET_ARG(1)); - custBkgrds = malloc(len + 1); - strcpy(custBkgrds, GET_ARG(1)); - custBkgrds[len] = 0; - } - else if(stricmp(command, "levels") == 0) - { - len = strlen(GET_ARG(1)); - custLevels = malloc(len + 1); - strcpy(custLevels, GET_ARG(1)); - custLevels[len] = 0; - } - else if(stricmp(command, "models") == 0) - { - len = strlen(GET_ARG(1)); - custModels = malloc(len + 1); - strcpy(custModels, GET_ARG(1)); - custModels[len] = 0; - } - else if(stricmp(command, "colourdepth") == 0) - { - printf("\nColordepth is not supported anymore. All modules are displayed with a 32bit color screen.\n\n"); - } - else if(stricmp(command, "forcemode") == 0) {} - else if(command && command[0]) - { - printf("Command '%s' not understood in file '%s'!\n", command, filename); - } - } - // Go to next line - pos += getNewLineStart(buf + pos); - } - - if(buf != NULL) - { - free(buf); - buf = NULL; - } - -VIDEOMODES: - videomodes.mode = videoMode; - videomodes.filter = savedata.swfilter; - switch (videoMode) - { - // 320x240 - QVGA - case 0: - videomodes.hRes = 320; - videomodes.vRes = 240; - videomodes.hScale = 1; - videomodes.vScale = 1; - videomodes.hShift = 0; - videomodes.vShift = 0; - videomodes.dOffset = 231; - PLAYER_MIN_Z = 160; - PLAYER_MAX_Z = 232; - BGHEIGHT = 160; - break; - - // 480x272 - WQVGA - case 1: - videomodes.hRes = 480; - videomodes.vRes = 272; - videomodes.hScale = (float)1.5; - videomodes.vScale = (float)1.13; - videomodes.hShift = 80; - videomodes.vShift = 20; - videomodes.dOffset = 263; - PLAYER_MIN_Z = 182; - PLAYER_MAX_Z = 264; - BGHEIGHT = 182; - break; - - // 640x480 - VGA - case 2: - videomodes.hRes = 640; - videomodes.vRes = 480; - videomodes.hScale = 2; - videomodes.vScale = 2; - videomodes.hShift = 160; - videomodes.vShift = 35; - videomodes.dOffset = 464; - PLAYER_MIN_Z = 321; - PLAYER_MAX_Z = 465; - BGHEIGHT = 321; - break; - - // 720x480 - DVD - case 3: - videomodes.hRes = 720; - videomodes.vRes = 480; - videomodes.hScale = 2.25; - videomodes.vScale = 2; - videomodes.hShift = 200; - videomodes.vShift = 35; - videomodes.dOffset = 464; - PLAYER_MIN_Z = 321; - PLAYER_MAX_Z = 465; - BGHEIGHT = 321; - break; - - // 800x480 - WVGA - case 4: - videomodes.hRes = 800; - videomodes.vRes = 480; - videomodes.hScale = 2.5; - videomodes.vScale = 2; - videomodes.hShift = 240; - videomodes.vShift = 35; - videomodes.dOffset = 464; - PLAYER_MIN_Z = 321; - PLAYER_MAX_Z = 465; - BGHEIGHT = 321; - break; - - // 800x600 - SVGA - case 5: - videomodes.hRes = 800; - videomodes.vRes = 600; - videomodes.hScale = 2.5; - videomodes.vScale = 2.5; - videomodes.hShift = 240; - videomodes.vShift = 44; - videomodes.dOffset = 580; - PLAYER_MIN_Z = 401; - PLAYER_MAX_Z = 582; - BGHEIGHT = 401; - break; - - // 960x540 - qHD - case 6: - videomodes.hRes = 960; - videomodes.vRes = 540; - videomodes.hScale = 3; - videomodes.vScale = 2.25; - videomodes.hShift = 320; - videomodes.vShift = 40; - videomodes.dOffset = 522; - PLAYER_MIN_Z = 362; - PLAYER_MAX_Z = 524; - BGHEIGHT = 362; - break; - - // Custom video mode - case 255: - videomodes.dOffset = videomodes.vRes * 0.9625; - printf("\nUsing debug video mode: %d x %d\n", videomodes.hRes, videomodes.vRes); - break; - default: - borShutdown(1, "Invalid video mode: %d in 'data/video.txt', supported modes:\n" - "0 - 320x240\n" - "1 - 480x272\n" - "2 - 640x480\n" - "3 - 720x480\n" - "4 - 800x480\n" - "5 - 800x600\n" - "6 - 960x540\n\n", videoMode); - break; - } - - video_stretch(savedata.stretch); - - if((vscreen = allocscreen(videomodes.hRes, videomodes.vRes, PIXEL_32)) == NULL) - { - borShutdown(1, "Not enough memory!\n"); - } - videomodes.pixel = pixelbytes[(int)vscreen->pixelformat]; - //video_set_mode(videomodes); - clearscreen(vscreen); - - if(log) - { - printf("Initialized video............\t%dx%d (Mode: %d)\n\n", videomodes.hRes, videomodes.vRes, videoMode); - } -} - - - -// ---------------------------------------------------------------------------- - - -// Set key or button safely (with switching) -void safe_set(int *arr, int index, int newkey, int oldkey) -{ - int i; - for(i = 0; i < 12; i++) - { - if(arr[i] == newkey) - { - arr[i] = oldkey; - } - } - arr[index] = newkey; -} - -void keyboard_setup(int player) -{ - int quit = 0; - int sdid = 0; - int selector = 0; - int setting = -1; - int i = 0; - int k = 0; - int ok = 0; - int disabledkey[MAX_BTN_NUM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - int col1 = -8; - int col2 = 6; - - ptrdiff_t voffset; - ptrdiff_t pos; - - char* buf; - char* command; - char* filename = "translation/menu.txt"; - - char buttonnames[MAX_BTN_NUM][32]; - - size_t size; - ArgList arglist; - - char argbuf[MAX_ARG_LEN + 1] = ""; - int OPTIONS_NUM = MAX_BTN_NUM + 3; - - screen_status |= IN_SCREEN_BUTTON_CONFIG_MENU; - - printf("Loading control settings.......\t"); - - strcpy(buttonnames[SDID_MOVEUP], "Move Up"); - strcpy(buttonnames[SDID_MOVEDOWN], "Move Down"); - strcpy(buttonnames[SDID_MOVELEFT], "Move Left"); - strcpy(buttonnames[SDID_MOVERIGHT], "Move Right"); - strcpy(buttonnames[SDID_ATTACK], "Attack 1"); - strcpy(buttonnames[SDID_ATTACK2], "Attack 2"); - strcpy(buttonnames[SDID_ATTACK3], "Attack 3"); - strcpy(buttonnames[SDID_ATTACK4], "Attack 4"); - strcpy(buttonnames[SDID_JUMP], "Jump"); - strcpy(buttonnames[SDID_SPECIAL], "Special"); - strcpy(buttonnames[SDID_START], "Start"); - strcpy(buttonnames[SDID_SCREENSHOT], "Screenshot"); - strcpy(buttonnames[SDID_ESC], "Exit"); - - savesettings(); - bothnewkeys = 0; - - /* - Kratus (10-2021) Added an alternative location for the translation file, now it's possible to use in an external folder - Now the modder can load exported translation files by using "filestream" script functions - Useful for creating custom translations without unpack the game - The default engine translation location will be maintained for backward compatibility - - Kratus (11-2021) Inverted the path priority, now the external file will override the internal file - Useful to maintain the english translation intact inside the pak file if no other language file is found in the external path - Otherwise you will need to rollback the english file every time another language is used and then removed - This operation is needed only if the english translation file uses some custom menu texts for english language too - */ - if(buffer_pakfile(filename, &buf, &size) != 1) - { - goto default_file; - } - else - { - goto proceed; - } - -default_file: - - if(buffer_pakfile("data/menu.txt", &buf, &size) != 1) - { - goto finish; - } - else - { - goto proceed; - } - -proceed: - - // Read file - // Now interpret the contents of buf line by line - pos = 0; - while(pos < size) - { - ParseArgs(&arglist, buf + pos, argbuf); - command = GET_ARG(0); - if(command[0]) - { - if(stricmp(command, "disablekey") == 0) - { - sdid = translate_SDID(GET_ARG(1)); - if(sdid >= 0) - { - disabledkey[sdid] = 1; - } - } - else if(stricmp(command, "renamekey") == 0) - { - sdid = translate_SDID(GET_ARG(1)); - if(sdid >= 0) - { - strcpy(buttonnames[sdid], GET_ARG(2)); - } - } - - } - // Go to next line - pos += getNewLineStart(buf + pos); - } - if(buf != NULL) - { - free(buf); - buf = NULL; - } - -finish: - - while(disabledkey[selector]) if(++selector > MAX_BTN_NUM - 1) break; - - while(!quit) - { - voffset = -6; - _menutextm(2, -8, 0, Tr("Player %i"), player + 1); - for(i = 0; i < MAX_BTN_NUM; i++) - { - if(!disabledkey[i]) - { - _menutext((selector == i), col1, voffset, "%s", buttonnames[i]); - _menutext((selector == i), col2, voffset, "%s", control_getkeyname(savedata.keys[player][i])); - voffset++; - } - } - - ++voffset; - if(savedata.joyrumble[player]) - { - _menutext((selector == OPTIONS_NUM - 3), col1, voffset++, Tr("Rumble Enabled")); - } - else - { - _menutext((selector == OPTIONS_NUM - 3), col1, voffset++, Tr("Rumble Disabled")); - } - - _menutextm((selector == OPTIONS_NUM - 2), ++voffset, 0, Tr("OK")); - _menutextm((selector == OPTIONS_NUM - 1), ++voffset, 0, Tr("Cancel")); - _menutextm((selector == OPTIONS_NUM), ++voffset, 0, Tr("Default")); - update((level != NULL), 0); - - if(setting > -1) - { - if(bothnewkeys & FLAG_ESC) - { - savedata.keys[player][setting] = ok; - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 50); - setting = -1; - } - if(setting > -1) - { - k = control_scankey(); - if(k) - { - safe_set(savedata.keys[player], setting, k, ok); - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - setting = -1; - // Prevent accidental screenshot - bothnewkeys = 0; - } - } - } - else - { - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - do - { - if(--selector < 0) - { - break; - } - } - while(selector < MAX_BTN_NUM && disabledkey[selector]); - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - do - { - if(++selector > MAX_BTN_NUM - 1) break; - } - while(disabledkey[selector]); - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - if(selector < 0) - { - selector = OPTIONS_NUM; - } - if(selector > OPTIONS_NUM) - { - selector = 0; - while(disabledkey[selector]) if(++selector > MAX_BTN_NUM - 1) break; - } - - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - - if (selector != OPTIONS_NUM - 3 && - bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT)) continue; - - if(selector == OPTIONS_NUM - 3) - { - savedata.joyrumble[player] ^= 1; - } - else if(selector == OPTIONS_NUM - 2) // OK - { - quit = 2; - } - else if(selector == OPTIONS_NUM - 1) // cancel - { - quit = 1; - } - else if(selector == OPTIONS_NUM) // default - { - clearbuttons(player); - } - else - { - setting = selector; - ok = savedata.keys[player][setting]; - savedata.keys[player][setting] = 0; - keyboard_getlastkey(); - } - } - } - } - - if(quit == 2) - { - apply_controls(); - savesettings(); - } - else - { - loadsettings(); - } - - screen_status &= ~IN_SCREEN_BUTTON_CONFIG_MENU; - - update(0, 0); - bothnewkeys = 0; - printf("Done!\n"); -} - -void menu_options_input() -{ - int quit = 0; - int selector = 1; // 0 - int x_pos = -6; - #if ANDROID - int OPTIONS_NUM = 6; - #else - int OPTIONS_NUM = 5; - #endif - - screen_status |= IN_SCREEN_CONTROL_OPTIONS_MENU; - bothnewkeys = 0; - - // Kratus (10-2021) Added a second instance of the "control_init" function while in the Control Options - // Useful to refresh some text translation if the language is changed "on-the-fly" and re-detect all active controls - control_init(savedata.usejoy); - - while(!quit) - { - _menutextm(2, x_pos-1, 0, Tr("Control Options")); - if(savedata.usejoy) - { - _menutext((selector == 0), x_pos, -2, Tr("GamePads Enabled")); - if(!control_getjoyenabled()) - { - _menutext((selector == 0), x_pos+11, -2, Tr(" - Device Not Ready")); - } - } - else - { - _menutext((selector == 0), x_pos, -2, Tr("GamePads Disabled")); - } - _menutext((selector == 1), x_pos,-1, Tr("Setup Player 1...")); - _menutext((selector == 2), x_pos, 0, Tr("Setup Player 2...")); - _menutext((selector == 3), x_pos, 1, Tr("Setup Player 3...")); - _menutext((selector == 4), x_pos, 2, Tr("Setup Player 4...")); - #if ANDROID - if(savedata.is_touchpad_vibration_enabled) - { - _menutextm((selector == 5), 4, 0, Tr("Touchpad Vibration Enabled")); - } - else - { - _menutextm((selector == 5), 4, 0, Tr("Touchpad Vibration Disabled")); - } - _menutextm((selector == 6), 6, 0, Tr("Back")); - #else - _menutextm((selector == 5), 5, 0, Tr("Back")); - #endif - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(selector < 0) - { - selector = OPTIONS_NUM; - } - if(selector > OPTIONS_NUM) - { - selector = 0; - } - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - switch(selector) - { - case 0: - control_usejoy((savedata.usejoy ^= 1)); - break; - case 1: - keyboard_setup(0); - break; - case 2: - keyboard_setup(1); - break; - case 3: - keyboard_setup(2); - break; - case 4: - keyboard_setup(3); - break; - #if ANDROID - case 5: - savedata.is_touchpad_vibration_enabled ^= 1; - break; - #endif - default: - quit = (bothnewkeys & FLAG_ANYBUTTON); - } - } - } - savesettings(); - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_CONTROL_OPTIONS_MENU; -} - - -/* - Kratus (02-2023) Readjusted the master / effectvol / musicvol range and increment - Round values like 100 by default make more sense than some like 70/120 - So, I transferred the hardcoded volume adjustment to the "soundmix" code instead of changing the default volumes - Master now goes from 0 to 100 and default to 100 - Effects (samples) now goes from 0 to 100 and default to 100 - Music now goes from 0 to 200 and default to 100 -*/ -void menu_options_sound() -{ - int quit = 0; - int selector = 0; - int dir; - int col1 = -8; - int col2 = 6; - - screen_status |= IN_SCREEN_SOUND_OPTIONS_MENU; - bothnewkeys = 0; - - while(!quit) - { - _menutextm(2, -5, 0, Tr("Sound Options")); - _menutext((selector == 0), col1, -2, Tr("Master Volume:")); // Kratus (02-2023) Renamed from Sound to Master volume - _menutext((selector == 0), col2, -2, "%i", savedata.soundvol); - _menutext((selector == 1), col1, -1, Tr("Effects Volume:")); // Kratus (02-2023) Renamed from SFX to Effects volume - _menutext((selector == 1), col2, -1, "%i", savedata.effectvol); - _menutext((selector == 2), col1, 0, Tr("Music Volume:")); - _menutext((selector == 2), col2, 0, "%i", savedata.musicvol); - _menutext((selector == 3), col1, 1, Tr("BGM:")); - _menutext((selector == 3), col2, 1, (savedata.usemusic ? Tr("Enabled") : Tr("Disabled"))); - _menutext((selector == 4), col1, 2, Tr("Show Titles:")); - _menutext((selector == 4), col2, 2, (savedata.showtitles ? Tr("Yes") : Tr("No"))); - _menutextm((selector == 5), 5, 0, Tr("Back")); - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(selector < 0) - { - selector = 5; - } - if(selector > 5) - { - selector = 0; - } - - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - dir = 0; - - if(bothnewkeys & FLAG_MOVELEFT) - { - dir = -1; - } - else if(bothnewkeys & FLAG_MOVERIGHT) - { - dir = 1; - } - - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - // Kratus (02-2023) Reworked the old and unuseful "soundvol" to act as the Master Volume for both sound/music - switch(selector) - { - case 0: - savedata.soundvol += 5 * dir; - if(savedata.soundvol < 0) - { - savedata.soundvol = 0; - } - if(savedata.soundvol > 100) - { - savedata.soundvol = 100; - } - SB_setvolume(SB_VOICEVOL, savedata.soundvol); - - // Kratus (02-2023) Synchronize sound/music volumes to master - savedata.effectvol = savedata.soundvol; - savedata.musicvol = savedata.soundvol; - break; - case 1: - savedata.effectvol += 5 * dir; - if(savedata.effectvol < 0) - { - savedata.effectvol = 0; - } - if(savedata.effectvol > 100) - { - savedata.effectvol = 100; - } - break; - case 3: - if(!dir) - { - break; - } - if(!savedata.usemusic) - { - savedata.usemusic = 1; - music("data/music/remix", 1, 0); - } - else - { - savedata.usemusic = 0; - sound_close_music(); - } - break; - case 2: - savedata.musicvol += 5 * dir; - if(savedata.musicvol < 0) - { - savedata.musicvol = 0; - } - if(savedata.musicvol > 200) - { - savedata.musicvol = 200; - } - sound_volume_music(savedata.musicvol, savedata.musicvol); - break; - case 4: - savedata.showtitles = !savedata.showtitles; - break; - default: - quit = 1; - } - } - } - savesettings(); - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_SOUND_OPTIONS_MENU; -} - -void menu_options_config() // OX. Load from / save to default.cfg. Restore OpenBoR "factory" settings. -{ - int quit = 0; - int selector = 0; - int saved = 0; - int loaded = 0; - int restored = 0; - - bothnewkeys = 0; - - // Kratus (11-2021) Removed spaces on the " Done!" text to fix translation - while(!quit) - { - _menutextm(2, -5, 0, Tr("Configuration Settings")); - - if(saved == 1) - { - _menutextm((selector == 0), -3, 0, Tr("Save Settings To Default.cfg%s"), Tr(" Done!")); - } - else - { - _menutextm((selector == 0), -3, 0, Tr("Save Settings To Default.cfg%s"), ""); - } - - if(loaded == 1) - { - _menutextm((selector == 1), -2, 0, Tr("Load Settings From Default.cfg%s"), Tr(" Done!")); - } - else - { - _menutextm((selector == 1), -2, 0, Tr("Load Settings From Default.cfg%s"), ""); - } - - if(restored == 1) - { - _menutextm((selector == 2), -1, 0, Tr("Restore OpenBoR Defaults%s"), Tr(" Done!")); - } - else - { - _menutextm((selector == 2), -1, 0, Tr("Restore OpenBoR Defaults%s"), ""); - } - - _menutextm((selector == 3), 6, 0, Tr("Back")); - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - - if(selector < 0) - { - selector = 3; - } - if(selector > 3) - { - selector = 0; - } - - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - switch(selector) - { - case 0: - saveasdefault(); - saved = 1; - break; - - case 1: - loadfromdefault(); - //borShutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n"); - init_videomodes(0); - if(!video_set_mode(videomodes)) - { - borShutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes); - } - SB_setvolume(SB_VOICEVOL, savedata.soundvol); - sound_volume_music(savedata.musicvol, savedata.musicvol); - loaded = 1; - break; - case 2: - clearsettings(); - //borShutdown(2, "\nSettings Loaded From Default.cfg. Restart Required.\n\n"); - init_videomodes(0); - if(!video_set_mode(videomodes)) - { - borShutdown(1, "Unable to set video mode: %d x %d!\n", videomodes.hRes, videomodes.vRes); - } - SB_setvolume(SB_VOICEVOL, savedata.soundvol); - sound_volume_music(savedata.musicvol, savedata.musicvol); - restored = 1; - break; - default: - quit = 1; - } - } - } - savesettings(); - bothnewkeys = 0; -} - -/* -* Caskey, Damon V. -* 2026-07-06 -* -* Return menu display text for a collision debug -* display pair. -*/ -static char* collision_debug_type_string(e_debug_display debug_field, e_debug_display flat_bit, e_debug_display projected_bit) { - - if ((debug_field & flat_bit) && (debug_field & projected_bit)) { - return Tr("Flat + Projected"); - } else if (debug_field & flat_bit) { - return Tr("Flat"); - } else if (debug_field & projected_bit) { - return Tr("Projected"); - } else { - return Tr("Disabled"); - } -} - -/* -* Caskey, Damon V. -* 2026-07-06 -* -* Cycle collision debug display mode for one collision type. -* -* Each collision type uses two debug bits: -* -* flat_bit = draw the normal 2D rectangle overlay. -* projected_bit = draw the projected 3D cube overlay. -* -* The two bits combine into four possible states: -* -* 0 = None -* 1 = Flat -* 2 = Projected -* 3 = Flat + Projected -* -* Direction controls cycle order: -* -* TOGGLE_DIRECTION_BACKWARD = cycle backward. -* TOGGLE_DIRECTION_FORWARD = cycle forward. -* -* Return value is the updated debug bitfield. -*/ -static e_debug_display collision_debug_type_cycle(const e_debug_display debug_field, const e_debug_display flat_bit, const e_debug_display projected_bit, const e_menu_toggle_direction toggle_direction) { - - /* - * Local only. Actual state is controlled by - * the savedata.debuginfo bitfield. This just - * gives us a simple linear value to work with - * for cycling so we do't need a massive if/else - * chain. - */ - #define COLLISION_DEBUG_DISPLAY_NONE 0 - #define COLLISION_DEBUG_DISPLAY_FLAT 1 - #define COLLISION_DEBUG_DISPLAY_PROJECTED 2 - #define COLLISION_DEBUG_DISPLAY_BOTH 3 - - /* - * Int scratchpads. These are enum values, but compiler - * will throw a fit if we try to use them in operations - * that cause implicit integer promotion. - */ - int state; - int debug_flags; - - /* - * Work in an int scratch value because enum values are - * still bitfields, and bitwise operators promote them - * to int anyway. - */ - debug_flags = debug_field; - - /* - * Convert current bitfield state into a compact - * display mode value. - * - * Bit 0 = flat display enabled. - * Bit 1 = projected display enabled. - */ - state = COLLISION_DEBUG_DISPLAY_NONE; - - if (debug_flags & flat_bit) { - state |= COLLISION_DEBUG_DISPLAY_FLAT; - } - - if (debug_flags & projected_bit) { - state |= COLLISION_DEBUG_DISPLAY_PROJECTED; - } - - /* - * Step through the four display modes. - * - * Backward: - * None <- Flat <- Projected <- Both <- None - * - * Forward: - * None -> Flat -> Projected -> Both -> None - */ - switch(toggle_direction) { - case TOGGLE_DIRECTION_BACKWARD: - state--; - - if (state < COLLISION_DEBUG_DISPLAY_NONE) { - state = COLLISION_DEBUG_DISPLAY_BOTH; - } - - break; - - case TOGGLE_DIRECTION_FORWARD: - default: - state++; - - if (state > COLLISION_DEBUG_DISPLAY_BOTH) { - state = COLLISION_DEBUG_DISPLAY_NONE; - } - - break; - } - - /* - * Clear only the two bits managed by this collision - * debug option. Leave all other debug flags untouched. - */ - debug_flags &= ~(flat_bit | projected_bit); - - /* - * Expand compact state back into the debug bitfield. - */ - if (state & COLLISION_DEBUG_DISPLAY_FLAT) { - debug_flags |= flat_bit; - } - - if (state & COLLISION_DEBUG_DISPLAY_PROJECTED) { - debug_flags |= projected_bit; - } - - return (e_debug_display)debug_flags; - - #undef COLLISION_DEBUG_DISPLAY_NONE - #undef COLLISION_DEBUG_DISPLAY_FLAT - #undef COLLISION_DEBUG_DISPLAY_PROJECTED - #undef COLLISION_DEBUG_DISPLAY_BOTH -} - -void menu_options_debug() { - #define MENU_POS_Y -4 - #define MENU_ITEMS_MARGIN_Y 2 - #define COLUMN_1_POS_X -11 - #define COLUMN_2_POS_X COLUMN_1_POS_X + 14 - #define MENU_ITEM_FIRST_INDEX 0 - - // Selections enumerator. All - // selection items should be placed - // here first. - typedef enum { - - // First item can be - // whatever we like, - // but it must be set - // to the MENU_ITEM_FIRST_INDEX - // constant. - ITEM_PERFORMANCE = MENU_ITEM_FIRST_INDEX, - - // Items between the first - // and last can go in any - // order. - ITEM_POSITION, - ITEM_COL_ATTACK, - ITEM_COL_BODY, - ITEM_COL_SPACE, - ITEM_COL_RANGE, - - // This is the "Back" - // selection and should - // always be last. - ITEM_EXIT - } e_selections; - - int pos_y; - int quit = 0; - e_selections selector = 0; - bothnewkeys = 0; - - e_menu_toggle_direction toggle_direction = TOGGLE_DIRECTION_FORWARD; - - while(!quit) { - - // Display menu title. - _menutextm(2, MENU_POS_Y, 0, Tr("Debug Settings")); - - // Menu items. - // Y position is controlled by a incremented integer. - // Integer has a base value of the Menu title Y - // plus static offset. Below each item, this Y value - // increments by one. We can then add or remove - // menu items here and the on screen position will - // take care of itself without us needing to mess - // with a bunch of hard constants. - - // Reset menu item position Y. - pos_y = MENU_POS_Y + MENU_ITEMS_MARGIN_Y; - - _menutext((selector == ITEM_PERFORMANCE), COLUMN_1_POS_X, pos_y, Tr("Performance:")); - _menutext((selector == ITEM_PERFORMANCE), COLUMN_2_POS_X, pos_y, (savedata.debuginfo & DEBUG_DISPLAY_PERFORMANCE ? Tr("Enabled") : Tr("Disabled"))); - pos_y++; - - _menutext((selector == ITEM_POSITION), COLUMN_1_POS_X, pos_y, Tr("Basic Properties:")); - _menutext((selector == ITEM_POSITION), COLUMN_2_POS_X, pos_y, (savedata.debuginfo & DEBUG_DISPLAY_PROPERTIES ? Tr("Enabled") : Tr("Disabled"))); - pos_y++; - - _menutext((selector == ITEM_COL_ATTACK), COLUMN_1_POS_X, pos_y, Tr("Collision Attack:")); - _menutext((selector == ITEM_COL_ATTACK), COLUMN_2_POS_X, pos_y, collision_debug_type_string(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_ATTACK_2D, DEBUG_DISPLAY_COLLISION_ATTACK_3D)); - pos_y++; - - _menutext((selector == ITEM_COL_BODY), COLUMN_1_POS_X, pos_y, Tr("Collision Body:")); - _menutext((selector == ITEM_COL_BODY), COLUMN_2_POS_X, pos_y, collision_debug_type_string(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_BODY_2D, DEBUG_DISPLAY_COLLISION_BODY_3D)); - pos_y++; - - _menutext((selector == ITEM_COL_SPACE), COLUMN_1_POS_X, pos_y, Tr("Collision Space:")); - _menutext((selector == ITEM_COL_SPACE), COLUMN_2_POS_X, pos_y, collision_debug_type_string(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_SPACE_2D, DEBUG_DISPLAY_COLLISION_SPACE_3D)); - pos_y++; - - _menutext((selector == ITEM_COL_RANGE), COLUMN_1_POS_X, pos_y, Tr("Range:")); - _menutext((selector == ITEM_COL_RANGE), COLUMN_2_POS_X, pos_y, (savedata.debuginfo & DEBUG_DISPLAY_RANGE ? Tr("Enabled") : Tr("Disabled"))); - pos_y++; - - // Display exit title - _menutextm((selector == ITEM_EXIT), pos_y + (MENU_ITEMS_MARGIN_Y), 0, Tr("Back")); - - // Run an engine update. - update((level != NULL), 0); - - // If user presses up/down or esc, let's act accordingly. - if(bothnewkeys & (FLAG_MOVEUP | FLAG_MOVEDOWN | FLAG_ESC)) { - - // If user presses escape, then set quit - // flag immediately. Else wise, increment - // or decrement selector as needed. - if(bothnewkeys & FLAG_ESC) { - quit = 1; - - } else if(bothnewkeys & FLAG_MOVEUP) { - // Play beep if available. - // Kratus (04-2022) Moved the BEEP sound to work only with UP/DOWN keys - if(global_sample_list.beep >= 0) { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - // If we are at the top item, loop - // to last. Otherwise, move one up. - if(selector <= MENU_ITEM_FIRST_INDEX) { - selector = ITEM_EXIT; - } else { - --selector; - } - - } else if(bothnewkeys & FLAG_MOVEDOWN) { - - // Play beep if available. - // Kratus (04-2022) Moved the BEEP sound to work only with UP/DOWN keys - if(global_sample_list.beep >= 0) { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - // If we are at the last item - // (which should be "back"), then - // loop back to first. Otherwise - // move one down. - if(selector >= ITEM_EXIT) { - selector = MENU_ITEM_FIRST_INDEX; - - } else { - ++selector; - } - } - } - - - // Toggle selection value on left/right or - // trigger button press. - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) { - - if(global_sample_list.beep_2 >= 0) { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - toggle_direction = (bothnewkeys & FLAG_MOVELEFT) ? TOGGLE_DIRECTION_BACKWARD : TOGGLE_DIRECTION_FORWARD; - - // This is where menu items are executed. - switch(selector) { - case ITEM_PERFORMANCE: - savedata.debuginfo ^= DEBUG_DISPLAY_PERFORMANCE; - break; - case ITEM_POSITION: - savedata.debuginfo ^= DEBUG_DISPLAY_PROPERTIES; - break; - case ITEM_COL_ATTACK: - savedata.debuginfo = collision_debug_type_cycle(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_ATTACK_2D, DEBUG_DISPLAY_COLLISION_ATTACK_3D, toggle_direction); - break; - case ITEM_COL_BODY: - savedata.debuginfo = collision_debug_type_cycle(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_BODY_2D, DEBUG_DISPLAY_COLLISION_BODY_3D, toggle_direction); - break; - case ITEM_COL_SPACE: - savedata.debuginfo = collision_debug_type_cycle(savedata.debuginfo, DEBUG_DISPLAY_COLLISION_SPACE_2D, DEBUG_DISPLAY_COLLISION_SPACE_3D, toggle_direction); - break; - case ITEM_COL_RANGE: - savedata.debuginfo ^= DEBUG_DISPLAY_RANGE; - break; - case ITEM_EXIT: - quit = 1; - } - } - } - - savesettings(); - bothnewkeys = 0; - - #undef MENU_POS_Y - #undef MENU_ITEMS_MARGIN_Y - #undef COLUMN_1_POS_X - #undef COLUMN_2_POS_X - #undef MENU_ITEM_FIRST_INDEX -} - -/* -* Caskey, Damon V. -* 2022-05-05 -* -* Display cheat options menu and -* apply player selections. -*/ -void menu_options_cheats() -{ -#define MENU_POS_Y -4 -#define MENU_ITEMS_MARGIN_Y 2 -#define COLUMN_1_POS_X -11 -#define COLUMN_2_POS_X COLUMN_1_POS_X + 14 - - typedef struct s_option_list - { - e_cheat_options active; - e_cheat_options menu; - char label[20]; - } s_option_list; - - int option_list_count = 7; - s_option_list option_list[] = { - {.active = CHEAT_OPTIONS_IMPLACABLE_ACTIVE, .menu = CHEAT_OPTIONS_IMPLACABLE_MENU, .label = "Implacable March:" }, - {.active = CHEAT_OPTIONS_CREDITS_ACTIVE, .menu = CHEAT_OPTIONS_CREDITS_MENU, .label = "Infinite Credits:" }, - {.active = CHEAT_OPTIONS_ENERGY_ACTIVE, .menu = CHEAT_OPTIONS_ENERGY_MENU, .label = "Infinite Energy:" }, - {.active = CHEAT_OPTIONS_HEALTH_ACTIVE, .menu = CHEAT_OPTIONS_HEALTH_MENU, .label = "Infinite Health:" }, - {.active = CHEAT_OPTIONS_LIVES_ACTIVE, .menu = CHEAT_OPTIONS_LIVES_MENU, .label = "Infinite Lives:" }, - {.active = CHEAT_OPTIONS_MULTIHIT_ACTIVE, .menu = CHEAT_OPTIONS_MULTIHIT_MENU, .label = "Multihit Glitch:" }, - {.active = CHEAT_OPTIONS_TOD_ACTIVE, .menu = CHEAT_OPTIONS_TOD_MENU, .label = "Touch of Death:" } - }; - - int option_list_cursor = 0; - int option_available_count = 0; - int option_available_first = 0; - int pos_y = 0; - int quit = 0; - int selector = 0; - - bothnewkeys = 0; - - screen_status |= IN_SCREEN_CHEAT_OPTIONS_MENU; - - //printf("\n\n menu_options_cheats()"); - - while (!quit) - { - /* Display menu title. */ - _menutextm(2, MENU_POS_Y, 0, Tr("Cheat Options")); - - /* - * Reset menu item position Y and - * valid menu item count. - */ - option_available_count = 0; - option_available_first = 0; - pos_y = MENU_POS_Y + MENU_ITEMS_MARGIN_Y; - - /* - * Iterate through the option list - * array and display available items. - * - * At each valid option, increment - * option count and Y position. - */ - - for (option_list_cursor = 0; option_list_cursor < option_list_count; option_list_cursor++) - { - if (global_config.cheats & option_list[option_list_cursor].menu) - { - /* - * If option available count is still 0, this - * is the first available option. Record the - * index for use downstream. - */ - - if (!option_available_count) - { - option_available_first = option_list_cursor; - } - - /* Print the menu text and on/off status. */ - _menutext((selector == option_list_cursor), COLUMN_1_POS_X, pos_y, Tr(option_list[option_list_cursor].label)); - _menutext((selector == option_list_cursor), COLUMN_2_POS_X, pos_y, (global_config.cheats & option_list[option_list_cursor].active ? Tr("On") : Tr("Off"))); - - option_available_count++; - pos_y++; - } - } - - /* No items avaialble. Alert player. */ - if (!option_available_count) - { - _menutextm(0, pos_y, 0, Tr("No cheats available.")); - } - - /* - * Add the exit option. We can use the array size - * for a selector index due to 0 indexing. - */ - - pos_y++; - _menutextm((selector == option_list_count), pos_y, 0, Tr("Back")); - - /* Run an engine update. */ - update((level != NULL), 0); - - /* - * Handle user input and populate selector to - * appropriate value. - * - * First we set selector to first item in case - * the first available's index is not 0. - * - * Next, handle buttons. ESC quits the menu - * instantly. Up/Down select target item. - * Left/Right/Action buttons toggle value. - */ - - if (!selector && option_available_first) - { - selector = option_available_first; - } - - if (bothnewkeys & FLAG_ESC) - { - quit = 1; - } - - if (bothnewkeys & FLAG_MOVEUP) - { - /* Play beep if available. */ - if (global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - /* Wrap around if needed. */ - if (selector <= option_available_first) - { - selector = option_list_count; - } - else - { - selector--; - } - - /* Skip disabled items. */ - while (!(global_config.cheats & option_list[selector].menu) && selector > option_available_first) - { - selector--; - } - } - - if (bothnewkeys & FLAG_MOVEDOWN) - { - /* Play beep if available. */ - if (global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - /* Wrap around if needed. */ - if (selector >= option_list_count) - { - selector = option_available_first; - } - else - { - selector++; - } - - /* Skip disabled items. */ - while (!(global_config.cheats & option_list[selector].menu) && selector < option_list_count) - { - selector++; - } - } - - /* - * Toggle selection value on left/right or - * trigger button press. - */ - if (bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - if (global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - /* - * Take action based on selector. - * - * The last option is the exit item, so if that's - * our selector value we exit this menu. - * - * Otherwise use selector as array key to get the - * bit we want to toggle in our target value. - */ - - if (selector < option_list_count) - { - global_config.cheats ^= option_list[selector].active; - } - else - { - quit = 1; - } - } - } - - //savesettings(); - - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_CHEAT_OPTIONS_MENU; - -#undef MENU_POS_Y -#undef MENU_ITEMS_MARGIN_Y -#undef COLUMN_1_POS_X -#undef COLUMN_2_POS_X -} - -void menu_options_system() -{ - #define SYS_OPT_Y_POS -4 - - enum { - SYS_OPT_LOG, - SYS_OPT_VSDAMAGE, - SYS_OPT_CHEATS, - SYS_OPT_DEBUG, - SYS_OPT_CONFIG, - SYS_OPT_BACK - }; - - int quit = 0; - int selector = 0; - int col1 = -11; - int col2 = col1+14; - int ex_labels = 0; - int RET = SYS_OPT_BACK; - int line = 0; - - screen_status |= IN_SCREEN_SYSTEM_OPTIONS_MENU; - bothnewkeys = 0; - if (nodebugoptions) ex_labels = 1; - RET -= ex_labels; - - while(!quit) - { - line = 0; - - _menutextm(2, SYS_OPT_Y_POS-2, 0, Tr("System Options")); - - _menutext(0, col1, SYS_OPT_Y_POS + line, Tr("Total RAM:")); - _menutext(0, col2, SYS_OPT_Y_POS + line, Tr("%s KB"), commaprint(getSystemRam(KBYTES))); - line++; - - _menutext(0, col1, SYS_OPT_Y_POS + line, Tr("Used RAM:")); - _menutext(0, col2, SYS_OPT_Y_POS + line, Tr("%s KB"), commaprint(getUsedRam(KBYTES))); - line++; - - _menutext(0, col1, SYS_OPT_Y_POS + line, Tr("Max Players:")); - _menutext(0, col2, SYS_OPT_Y_POS + line, Tr("%i"), levelsets[current_set].maxplayers); - line++; - - _menutext((selector == SYS_OPT_LOG), col1, SYS_OPT_Y_POS + line, Tr("File Logging:")); - _menutext((selector == SYS_OPT_LOG), col2, SYS_OPT_Y_POS + line, (savedata.uselog ? Tr("Enabled") : Tr("Disabled"))); - line++; - - _menutext((selector == SYS_OPT_VSDAMAGE), col1, SYS_OPT_Y_POS + line, Tr("Versus Damage:"), 0); - if(versusdamage == 0) - { - _menutext((selector == SYS_OPT_VSDAMAGE), col2, SYS_OPT_Y_POS + line, Tr("Disabled by Module")); - } - else if(versusdamage == 1) - { - _menutext((selector == SYS_OPT_VSDAMAGE), col2, SYS_OPT_Y_POS + line, Tr("Enabled by Module")); - } - else - { - if(savedata.mode) - { - _menutext((selector == SYS_OPT_VSDAMAGE), col2, SYS_OPT_Y_POS + line, Tr("Disabled")); //Mode 1 - Players CAN'T attack each other - } - else - { - _menutext((selector == SYS_OPT_VSDAMAGE), col2, SYS_OPT_Y_POS + line, Tr("Enabled")); //Mode 2 - Players CAN attack each other - } - } - line++; - - if (global_config.cheats & CHEAT_OPTIONS_MASTER_MENU) - { - _menutext((selector == SYS_OPT_CHEATS), col1, SYS_OPT_Y_POS + line, Tr("Cheat Options...")); - line++; - } - - if (!nodebugoptions) - { - _menutext((selector == SYS_OPT_DEBUG), col1, SYS_OPT_Y_POS + line, Tr("Debug Settings...")); - line++; - } - - _menutext((selector == SYS_OPT_CONFIG), col1, SYS_OPT_Y_POS + line, Tr("Config Settings...")); - - /* Extra lines for spacing. */ - line += 2; - - _menutextm((selector == RET), SYS_OPT_Y_POS + line, 0, Tr("Back")); - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - - /* Skip disabled items. */ - - if (selector == SYS_OPT_CHEATS && !(global_config.cheats & CHEAT_OPTIONS_MASTER_MENU)) - { - --selector; - } - - if (selector == SYS_OPT_DEBUG && nodebugoptions) - { - --selector; - } - - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - - /* Skip disabled items. */ - - if (selector == SYS_OPT_CHEATS && !(global_config.cheats & CHEAT_OPTIONS_MASTER_MENU)) - { - ++selector; - } - - if (selector == SYS_OPT_DEBUG && nodebugoptions) - { - ++selector; - } - - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(selector < 0) - { - selector = RET; - } - if(selector > RET) - { - selector = 0; - } - - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - - if (selector == RET) quit = 1; - else if (selector == SYS_OPT_LOG) savedata.uselog = !savedata.uselog; - else if (selector == SYS_OPT_VSDAMAGE) - { - if (versusdamage > 1) - { - if (savedata.mode) - { - savedata.mode = 0; - } - else - { - savedata.mode = 1; - } - } - } - else if (selector == SYS_OPT_CHEATS) - { - menu_options_cheats(); - } - else if (selector == SYS_OPT_DEBUG && !nodebugoptions) - { - menu_options_debug(); - } - else if (selector == SYS_OPT_CHEATS) - { - menu_options_cheats(); - } - else if (selector == SYS_OPT_DEBUG && !nodebugoptions) menu_options_debug(); - else if (selector==SYS_OPT_CONFIG) menu_options_config(); - else quit = 1; - } - } - savesettings(); - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_SYSTEM_OPTIONS_MENU; - - #undef SYS_OPT_Y_POS -} - - -void menu_options_video() -{ - int quit = 0; - int selector = 0; - int dir; - int col1 = -15, col2 = 1; - - screen_status |= IN_SCREEN_VIDEO_OPTIONS_MENU; - bothnewkeys = 0; - - while(!quit) - { - _menutextm(2, -5, 0, Tr("Video Options")); - _menutext((selector == 0), col1, -3, Tr("Brightness:")); - _menutext((selector == 0), col2, -3, "%i", savedata.brightness); - _menutext((selector == 1), col1, -2, Tr("Gamma:")); - _menutext((selector == 1), col2, -2, "%i", savedata.gamma); - _menutext((selector == 2), col1, -1, Tr("Window Offset:")); - _menutext((selector == 2), col2, -1, "%i", savedata.windowpos); - -#if SDL - _menutext((selector == 3), col1, 0, Tr("Display Mode:")); - _menutext((selector == 3), col2, 0, savedata.fullscreen ? Tr("Full") : Tr("Window")); - - _menutext((selector == 4), col1, 1, Tr("Video Backend:")); - _menutext((selector == 4), col2, 1, (opengl ? Tr("OpenGL") : Tr("SDL"))); - - _menutext((selector == 5), col1, 2, Tr("Scale:")); -#ifdef ANDROID - if(savedata.hwscale == 0) -#else - if(savedata.fullscreen) -#endif - { - _menutext((selector == 5), col2, 2, Tr("Automatic")); - } - else - { - _menutext((selector == 5), col2, 2, "%4.2fx - %ix%i", savedata.hwscale, (int)(videomodes.hRes * savedata.hwscale), (int)(videomodes.vRes * savedata.hwscale)); - } - - _menutext((selector == 6), col1, 3, Tr("Hardware Filter:")); - { - char *filterName; - if (savedata.hwscale == 1.0 && !savedata.fullscreen) - filterName = "Disabled"; - else if (opengl) - filterName = "High Quality"; - else if (savedata.hwfilter) - filterName = "Simple"; - else - filterName = "Bilinear"; - _menutext((selector == 6), col2, 3, Tr(filterName)); - } - - _menutext((selector == 7), col1, 4, Tr("Software Filter:")); - _menutext((selector == 7), col2, 4, ((savedata.hwscale >= 2.0 || savedata.fullscreen) ? Tr(GfxBlitterNames[savedata.swfilter]) : Tr("Disabled"))); - - char fpslimit_text[32]; - switch (savedata.fpslimit) - { - case 0: - snprintf(fpslimit_text, sizeof(fpslimit_text), "%s", Tr("Disabled")); - break; - case 1: - snprintf(fpslimit_text, sizeof(fpslimit_text), "%i (VSync)", video_current_refresh_rate()); - break; - case 2: - snprintf(fpslimit_text, sizeof(fpslimit_text), "%i", 200); - break; - case 3: - snprintf(fpslimit_text, sizeof(fpslimit_text), "%i", 500); - break; - default: - snprintf(fpslimit_text, sizeof(fpslimit_text), "%s", Tr("Unknown")); - break; - } - - _menutext((selector == 8), col1, 5, Tr("FPS Limit:")); - _menutext((selector == 8), col2, 5, fpslimit_text); - - if(savedata.fullscreen) - { - _menutext((selector == 9), col1, 6, Tr("Fullscreen Type:")); - _menutext((selector == 9), col2, 6, (savedata.stretch ? Tr("Stretch to Screen") : Tr("Preserve Aspect Ratio"))); - } - else if(selector == 9) - { - selector = (bothnewkeys & FLAG_MOVEUP) ? 8 : 10; - } - - _menutextm((selector == 10), 9, 0, Tr("Back")); - if(selector < 0) - { - selector = 10; - } - if(selector > 10) - { - selector = 0; - } -#endif - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - dir = 0; - - if(bothnewkeys & FLAG_MOVELEFT) - { - dir = -1; - } - else if(bothnewkeys & FLAG_MOVERIGHT) - { - dir = 1; - } - - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - switch(selector) - { - case 0: - savedata.brightness += 8 * dir; - if(savedata.brightness < -256) - { - savedata.brightness = -256; - } - if(savedata.brightness > 256) - { - savedata.brightness = 256; - } - vga_vwait(); - set_color_correction(savedata.gamma, savedata.brightness); - break; - case 1: - savedata.gamma += 8 * dir; - if(savedata.gamma < -256) - { - savedata.gamma = -256; - } - if(savedata.gamma > 256) - { - savedata.gamma = 256; - } - vga_vwait(); - set_color_correction(savedata.gamma, savedata.brightness); - break; - case 2: - savedata.windowpos += dir; - if(savedata.windowpos < -2) - { - savedata.windowpos = -2; - } - if(savedata.windowpos > 20) - { - savedata.windowpos = 20; - } - break; -#if SDL - case 3: - video_fullscreen_flip(); - break; - case 4: - savedata.usegl = !savedata.usegl; - video_set_mode(videomodes); - set_color_correction(savedata.gamma, savedata.brightness); - break; - case 5: -#ifndef ANDROID - if(savedata.fullscreen) - { - break; - } - savedata.hwscale += dir * 0.25; - if(savedata.hwscale < 0.25) - { - savedata.hwscale = 0.25; - } - if(savedata.hwscale > 4.00) - { - savedata.hwscale = 4.00; - } - video_set_mode(videomodes); -#else - savedata.hwscale += dir * 0.25; - if(savedata.hwscale < 0.0) - { - savedata.hwscale = 0.0; - } - if(savedata.hwscale > 4.00) - { - savedata.hwscale = 4.00; - } -#endif - case 6: -#ifndef ANDROID - if (opengl || (!savedata.fullscreen && savedata.hwscale == 1.0)) - { - break; - } -#endif - savedata.hwfilter += dir; - if(savedata.hwfilter < 0) - { - savedata.hwfilter = 1; - } - if(savedata.hwfilter > 1) - { - savedata.hwfilter = 0; - } - video_set_mode(videomodes); - break; - case 7: - if(!savedata.fullscreen && savedata.hwscale < 2.0) - { - break; - } - videomodes.filter += dir; - if(videomodes.filter > BLITTER_MAX - 1) - { - videomodes.filter = 0; - } - if(videomodes.filter < 0) - { - videomodes.filter = BLITTER_MAX - 1; - } - savedata.swfilter = videomodes.filter; - memset(pDeltaBuffer, 0x00, 1244160); - video_set_mode(videomodes); - break; - case 8: - savedata.fpslimit = (savedata.fpslimit + dir) % 4; - if (savedata.fpslimit < 0) savedata.fpslimit += 4; - video_set_mode(videomodes); - break; - case 9: - video_stretch((savedata.stretch ^= 1)); - break; -#endif - default: - quit = 1; - } - } - } - savesettings(); - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_VIDEO_OPTIONS_MENU; -} - - -void menu_options() -{ - #define OPT_Y_POS -1 - #define OPT_X_POS -7 - - typedef enum { - VIDEO_OPTION, - SOUND_OPTION, - CONTROL_OPTION, - SYSTEM_OPTION, - - END_OPTION - } e_selector; - - int quit = 0; - int y_offset = OPT_Y_POS; - int BACK_OPTION = END_OPTION; - e_selector selector = VIDEO_OPTION; - - screen_status |= IN_SCREEN_OPTIONS_MENU; - bothnewkeys = 0; - - while(!quit) - { - _menutextm((selector == VIDEO_OPTION), y_offset+VIDEO_OPTION, 0, Tr("Video Options...")); - _menutextm((selector == SOUND_OPTION), y_offset+SOUND_OPTION, 0, Tr("Sound Options...")); - _menutextm((selector == CONTROL_OPTION), y_offset+CONTROL_OPTION, 0, Tr("Control Options...")); - _menutextm((selector == SYSTEM_OPTION), y_offset+SYSTEM_OPTION, 0, Tr("System Options...")); - - _menutextm((selector == BACK_OPTION), y_offset+BACK_OPTION+2, 0, Tr("Back")); - - update((level != NULL), 0); - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - if(bothnewkeys & FLAG_MOVEUP) - { - if(selector <= VIDEO_OPTION) - { - selector = BACK_OPTION; - } - else --selector; - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(selector > BACK_OPTION) - { - selector = VIDEO_OPTION; - } - - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & (FLAG_MOVELEFT | FLAG_MOVERIGHT | FLAG_ANYBUTTON)) - { - - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - - if(selector==BACK_OPTION) quit = 1; - else if(selector==VIDEO_OPTION) menu_options_video(); - else if(selector==SOUND_OPTION) menu_options_sound(); - else if(selector==CONTROL_OPTION) menu_options_input(); - else if(selector==SYSTEM_OPTION) - { - menu_options_system(); - } - - else quit = 1; - } - } - savesettings(); - if(_pause == 1) - { - _pause = 2; - } - bothnewkeys = 0; - screen_status &= ~IN_SCREEN_OPTIONS_MENU; - - #undef TOT_CHEATS - #undef OPT_Y_POS - #undef OPT_X_POS - #undef CHEAT_PAUSE_POSY -} - -// ---------------------------------------------------------------------------- - - -void openborMain(int argc, char **argv) -{ - sprite_map = NULL; - int quit = 0; - int relback = 1; - int selector = 0; - u32 introtime = 0; - int started = 0; - char tmpBuff[MAX_BUFFER_LEN] = {""}; - int players[MAX_PLAYERS] = {0, 0, 0, 0}; - int i; - int argl; - - printf("OpenBoR %s, Compile Date: " __DATE__ "\n\n", VERSION); - - if(argc > 1) - { - argl = strlen(argv[1]); - if(argl > 14 && !memcmp(argv[1], "offscreenkill=", 14)) - { - DEFAULT_OFFSCREEN_KILL = getValidInt((char *)argv[1] + 14, "", ""); - } - if(argl > 14 && !memcmp(argv[1], "showfilesused=", 14)) - { - printFileUsageStatistics = getValidInt((char *)argv[1] + 14, "", ""); - } - } - - - modelcmdlist = createModelCommandList(); - modelstxtcmdlist = createModelstxtCommandList(); - levelcmdlist = createLevelCommandList(); - levelordercmdlist = createLevelOrderCommandList(); - createModelList(); - - // Load necessary components. - printf("Game Selected: %s\n\n", packfile); - loadsettings(); - startup(); - bothnewkeys = 0; - - if(skiptoset < 0) - { - - // New alternative background path. - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "logo"); - load_background(tmpBuff); - } - else - { - load_cached_background("data/bgs/logo"); - } - - while(_time < global_config.game_speed * 6 && !(bothnewkeys & (FLAG_ANYBUTTON | FLAG_ESC))) - { - update(0, 0); - } - - music("data/music/remix", 1, 0); - - // New alternative scene path. - if(custScenes != NULL) - { - strcpy(tmpBuff, custScenes); - strcat(tmpBuff, "logo.txt"); - playscene(tmpBuff); - } - else - { - playscene("data/scenes/logo.txt"); - } - } - clearscreen(background); - - while(!quit) - { - if(skiptoset < 0 && !(goto_mainmenu_flag&8)) - { - if(_time >= introtime) - { - // New alternative scene path. - if(custScenes != NULL) - { - strcpy(tmpBuff, custScenes); - strcat(tmpBuff, "intro.txt"); - playscene(tmpBuff); - } - else - { - playscene("data/scenes/intro.txt"); - } - update(0, 0); - introtime = _time + global_config.game_speed * 20; - relback = 1; - started = 0; - } - - if(bothnewkeys & FLAG_ESC) - { - quit = 1; - } - } - else - { - started = 1; - relback = 0; - } - - if (goto_mainmenu_flag != 0) goto_mainmenu_flag = 0; - if(!started) - { - if((_time % global_config.game_speed) < (global_config.game_speed / 2)) - { - _menutextm(0, 0, 0, Tr("PRESS START")); - } - if(bothnewkeys & (FLAG_ANYBUTTON)) - { - started = 1; - relback = 1; - } - } - else if(skiptoset >= 0) - { - loadGameFile(); - playgame(players, useSet >= 0 ? useSet : skiptoset, useSave); - } - else - { - _menutextm((selector == 0), 2, 0, Tr("Start Game")); - _menutextm((selector == 1), 3, 0, Tr("Options")); - _menutextm((selector == 2), 4, 0, Tr("How To Play")); - _menutextm((selector == 3), 5, 0, Tr("Hall Of Fame")); - _menutextm((selector == 4), 6, 0, Tr("Quit")); - if(selector < 0) - { - selector = 4; - } - if(selector > 4) - { - selector = 0; - } - - if(bothnewkeys) - { - introtime = _time + global_config.game_speed * 20; - } - - if(bothnewkeys & FLAG_MOVEUP) - { - --selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & FLAG_MOVEDOWN) - { - ++selector; - if(global_sample_list.beep >= 0) - { - sound_play_sample(global_sample_list.beep, 0, savedata.effectvol, savedata.effectvol, 100); - } - } - if(bothnewkeys & (FLAG_ANYBUTTON)) - { - if(global_sample_list.beep_2 >= 0) - { - sound_play_sample(global_sample_list.beep_2, 0, savedata.effectvol, savedata.effectvol, 100); - } - switch(selector) - { - case 0: - for(i = 0; i < MAX_PLAYERS; i++) - { - players[i] = player[i].newkeys & (FLAG_ANYBUTTON); - } - relback = choose_mode(players); - if(relback) - { - started = 0; - } - break; - case 1: - menu_options(); - break; - case 2: - { - int previousLoop = musicloop; - char previousMusic[sizeof(currentmusic)]; - - memset(previousMusic, 0, sizeof(previousMusic)); - strcpy(previousMusic, currentmusic); - - if(custScenes != NULL) - { - strcpy(tmpBuff, custScenes); - strcat(tmpBuff, "howto.txt"); - playscene(tmpBuff); - } - else - { - playscene("data/scenes/howto.txt"); - } - if(stricmp(previousMusic, currentmusic) != 0) - { - music(previousMusic, previousLoop, 0); - } - relback = 1; - break; - } - case 3: - hallfame(0); - relback = 1; - break; - default: - quit = 1; - break; - } - introtime = _time + global_config.game_speed * 20; - } - } - if(relback) - { - if(started) - { - /* - Kratus (10-2021) Added an additional instance of the translation function at menu screen - Used to refresh all text without close and reopen the engine - - Kratus (02-2023) Added an additional instance of the video_mode function at menu screen - Used to refresh the touchscreen properties on Android without restarting - */ - video_set_mode(videomodes); - ob_inittrans(); - - screen_status |= IN_SCREEN_MENU; - screen_status &= ~IN_SCREEN_TITLE; - - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "titleb"); - load_background(tmpBuff); - } - else - { - load_cached_background("data/bgs/titleb"); - } - } - else - { - screen_status &= ~IN_SCREEN_MENU; - screen_status |= IN_SCREEN_TITLE; - - if(custBkgrds != NULL) - { - strcpy(tmpBuff, custBkgrds); - strcat(tmpBuff, "title"); - load_background(tmpBuff); - } - else - { - load_cached_background("data/bgs/title"); - } - } - - if(!sound_query_music(NULL, NULL)) - { - music("data/music/remix", 1, 0); - } - relback = 0; - } - update(0, 0); - } - borShutdown(0, DEFAULT_SHUTDOWN_MESSAGE); -} - -#undef GET_ARG -#undef GET_ARG_LEN -#undef GET_ARGP -#undef GET_ARGP_LEN -#undef GET_INT_ARG -#undef GET_FLOAT_ARG -#undef GET_INT_ARGP -#undef GET_FLOAT_ARGP + newchar->move_config_flags &= ~MOVE_CONFIG_NO_A×n÷çÏÊ׬¢h­µçHB‚ˆYŠÙ[‹O˜Ý\ÝÛWÝ\™Ù]OH•S\Ù[‹O˜Ý\ÝÛWÝ\™Ù] O™^\ÝÈ +H\™Ù]H›Ü›X[Ùš[™Ý\™Ù] + LK +Nˆ[ÙH\™Ù]HÙ[‹O˜Ý\ÝÛWÝ\™Ù]‚ˆYŠ\™Ù] ‰ˆJ˜XÝ[Û—ØÚXÚרØ[—Ù[XYÙJÙ[‹\™Ù] [™\™XÝ +JJBˆˆ™]\›ˆ ˆB‚ˆYˆ + +Ù[‹O™XÚÚ[™È ˆPÒ×ÐPÕU‘JH ‰ˆÙ[‹O˜[š[[�[HOHS’WÑPÒÊBˆˆYˆ +]\™Ù][˜Z\Š\™Ù] +HJ\™Ù] O™XÚÚ[™È ˆPÒ×ÐPÕU‘JHˆ +XÚXÚ×ܘ[™ÙWÝ\™Ù]Ø[ +Ù[‹\™Ù] S’WÑPÒË  +H ‰‚ˆY™ŠÙ[‹OœÜÚ][Û‹ž \™Ù] OœÜÚ][Û‹ž +Hˆܘ[™Ù^ ‰ˆY™ŠÙ[‹OœÜÚ][Û‹ž‹\™Ù] OœÜÚ][Û‹žŠHˆܘ[™Ù^ŠH +BˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆžYXÚÜš\ÙJÙ[ŠNˆ™]\›ˆ NˆBˆB‚ˆYŠ]\™Ù]J\™Ù] O™XÚÚ[™È ˆPÒ×ÐPÕU‘JJBˆˆ™]\›ˆ ˆBˆ[ÙBˆˆYˆ +Ù[‹O™XÚÚ[™È ˆPÒ×ÐPÕU‘JBˆˆ™]\›ˆ NˆBˆ[ÙBˆˆ[�˜[™ÙWÙ›YÈHÚXÚ×ܘ[™ÙWÝ\™Ù]Ø[ +Ù[‹\™Ù] S’WÑPÒË  +NˆYˆ +\˜[™ÙWÙ›YÊBˆˆYˆ +Y™ŠÙ[‹OœÜÚ][Û‹ž \™Ù] OœÜÚ][Û‹ž +HHܘ[™Ù^ ‰‚ˆY™ŠÙ[‹OœÜÚ][Û‹ž‹\™Ù] OœÜÚ][Û‹žŠHHܘ[™Ù^ŠH˜[™ÙWÙ›YÈH NˆBˆYˆ +\˜[™ÙWÙ›YÊH™]\›ˆ ‚ˆYŠÙ[‹O™XÚÚ[™ÈOHPÒ×Ó“Ó‘JBˆˆžYXÚÊÙ[ŠNˆBˆ™]\›ˆ NˆBˆB‚ˆ™]\›ˆ ŸB‚‚‹ËÈK’H›ÛÝ�›ÚYÛÛ[[Û—Ý[šÊ +BžÂ‚ˆYŠÙ[‹O™X]ÜÝ]H ˆPUÔÕUWÑPQ +Bˆˆ™]\›ŽÂˆH‚ˆ ËÚYŠÚXÚÜ[›™Y + +JH™]\›ŽÂ‚ˆ ËÈÛȘ\ˆ]Ø^H ÈHØ\œˆYŠZWØÚXÚ×Ü™XØ[ + +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈš\ÙOÈžHš\ÙH]XÚˆYŠZWØÚXÚ×ÛYJ +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈ\ØØ\OˆYŠZWØÚXÚ×ÙܘX˜™Y + +JBˆˆ™]\›ŽÂˆB‚ˆ ËÙܘX˜š[™ÈÛÛY][™ÂˆYŠZWØÚXÚ×ÙܘXŠ +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈ[™[ZY\ÈØ[ˆ›ÝÈ\ØØ\H›Û‹ZÛ›ØÚÙÝÛˆÜ[[XYÙH +Ú]HÙZ\™˜\ÙJHBˆYŠZWØÚXÚ×Ù\ØØ\J +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈ�\ÞHšYÚ›ÝψYŠZWØÚXÚר�\ÞJ +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈYKÛÈžHÈ]XÚÈ܈�YÙH™^[Ý™Bˆ ËÈÛ�[Ý™HYˆ˜[[�ÈHÛH܈Ù™ˆHØ[ˆYŠÛÛ[[Û—Ø]XÚÊ +JBˆˆ™]\›ŽÂˆB‚ˆ ËÈ\™Ù]\ÈXÚÚ[™ÏÈžHÈXÚÚ[™Ë‹‚ˆYŠZWØÚXÚ×ÙXÚÚ[™Ê +JBˆˆ™]\›ŽÂˆB‚ˆÛÛ[[Û—Û[Ý™J +NŸB‚‹ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË‚�›ÚYÝZXÚYJ +BžÂˆˆYŠÝ[YHÙ[‹OœÝ[[YJBˆˆ™]\›ŽÂˆBˆ]™[ØÛÛ\]YHÙ[‹O˜›ÜÜΈ]™[ØÛÛ\]YÙY™X][™×Ø›ÜÜÈHÙ[‹O˜›ÜÜ΂ˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÔÕRPÒQJNŸB‚‚‚‹ËÈ™KY[�\ˆ^YšY[‹ËÈ\ÙYžH^Y\—Ù˜[[™^Y\—ÝZÙY[XYÙB�›ÚY^Y\—ÙYWÙ[�]J[�]JˆXÝ[™×Ù[�]JBžÂˆ[�^Y\š[™^HXÝ[™×Ù[�]KOœ^Y\š[™^ˆ[�HH ‚ˆYŠJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÓU‘T×ÐPÕU‘JJBˆˆ K\^Y\–Ü^Y\š[™^K›]™\ΈB‚ˆYŠš\œÝ^Y\ˆOHXÝ[™×Ù[�]JBˆˆš\œÝ^Y\ˆH•SˆB‚ˆ^XÝ]WÜYWÜØÜš\ +^Y\š[™^ +N‚ˆYŠ›ÛX^�\Ú™\Ù]ÍH�H JBˆˆ›ÛX^�\Ú™\Ù]Ü^Y\š[™^HH^Y\–Ü^Y\š[™^K™[� Oœ�\Ú ›X^ˆBˆ^Y\–Ü^Y\š[™^K™[�H•Sˆ^Y\–Ü^Y\š[™^KœÜ]ÛšX[HXÝ[™×Ù[�]KO›[Ù[]KšX[ˆ^Y\–Ü^Y\š[™^KœÜ]Û›\HXÝ[™×Ù[�]KO›[Ù[]K›\‚ˆ ʈˆ +ˆ[™HH›ÙKˆYˆ[žHÛÜœÙH›Y܈ +ˆ\™HÙ] ÙHX]™H[�]HÛˆØÜ™Y[ˆˆ +ˆ[™XZÙH][™\� ˆÝ\�Ú\ÙHÙHØ[‚ˆ +ˆ�\Ý�[ˆÚ[�[˜Ý[ۈș[[Ý™K‚ˆ +ˆˆ +ˆ‘SSÕ‘WÐÓÔ”ÑWʈ›YÜÈ™Y™\ˆÈÝȈ +ˆH]™H[�]H\È™[[Ý™Yœ›ÛHHˆ +ˆØ[YHÚ[HX]š[™ÈHÛÜœÙH™Z[™ ‚ˆ +‹Â‚ˆÝ]XÈÛÛœÝWÙX]ØÛÛ™šY×Ù›YÜÈX]™WØÛÜœÙHHPUÐÓÓ‘’Q×Ô‘SSÕ‘WÐÓÔ”ÑWÐRTˆPUÐÓÓ‘’Q×Ô‘SSÕ‘WÐÓÔ”ÑWÑÔ“ÕS‘‚ˆYˆ +XÝ[™×Ù[�]KO›[Ù[]K™X]ØÛÛ™šY×Ù›YÜÈ ˆX]™WØÛÜœÙJHˆXÝ[™×Ù[�]KO�[šÈH•SˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆH•SˆXÝ[™×Ù[�]KO™X]ÜÝ]HHPUÔÕUWÐÓÔ”ÑNˆH[ÙHˆÚ[Ù[�]JXÝ[™×Ù[�]KÒSÑS•UWÕ’QÑÑT—ÔVQT—ÑPU +NˆB‚ˆYŠ^Y\–Ü^Y\š[™^K›]™\ÈH +Bˆˆ[�[ÜÚÛÈH ‚‚BKËÈÛÝ[��[X™\ˆÙˆÓÉÙ +XY +H^Y\œËžHÛÜ[™È^Y\‚‚BKËÈ[™^\È[™[˜Ü™[Y[�[™ÈÚ[ˆ^Y\ˆÙ\È›Ý]™B‚BKËÈ[ˆ[�]K‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆ‚BBZYˆ +\^Y\–ÚWK™[� +B‚BB^‚BBBJÊØ[ÜÚÛ΂BB_BˆBˆ‚BKËÈYˆ[^Y\œÈ\™HÓÉÙ [ˆÓÈÛÝ[�H K‚‚BKËÈÝ\�Ú\ÙKÙ]]È ‚‚BX[ÜÚÛÈH +[ÜÚÛÈ�HPVÔVQT”ÊHÈ Hˆ ‚‚BKËÈ[^Y\œÈÓÉÙˆYŠ[ÜÚÛÊBˆ‚BBZ[�[ÜÛ›Ú›Ú[ˆH ‚BBZ[�[ÜÛ›ØÜ™Y]ÈH ‚‚BBKËÈ[^Y\œÈ“Õ›Ú[š[™Ï‚BBKËÈØ[YHÙÚXÈ\È[^Y\ˆÓˈˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆ‚BBBZYˆ +\^Y\–ÚWKš›Ú[š[™ÊB‚BBB^‚BBBBJÊØ[ÜÛ›Ú›Ú[ŽÂ‚BBB_BˆB‚ˆ[ÜÛ›Ú›Ú[ˆH +[ÜÛ›Ú›Ú[ˆ�HPVÔVQT”ÊHÈ Hˆ ‚‚BBKËÈ[^Y\œÈÝ]وܙY]Ï‚BBKËÈØ[YHÙÚXÈ\È[^Y\ˆÓË‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆ‚BBBZYˆ +^Y\–ÚWK˜Ü™Y]È JB‚BBB^‚BBBBJÊØ[ÜÛ›ØÜ™Y]΂BBB_BˆBBBB‚ˆ[ÜÛ›ØÜ™Y]ÈH +[ÜÛ›ØÜ™Y]È�HPVÔVQT”ÊHÈ Hˆ ‚‚BBKËÈÙ]H[Y\ˆÈH LÙXÛÛ™ÛÝ[�ÝÛ‹‚ˆ[Y[Y�H L +ˆÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYY‚‚BBKËÈ›ÈÛ™H›Ú[š[™È[�ˆYŠ[ÜÛ›Ú›Ú[ŠBˆ‚BBBKËÈYˆH^Y\ˆØ[‰ÝÛÛ�[�YK] ÜÈÙ]H[YHÝ™\‚‚BBBKËÈÈ[™[[ÜÝ[œÝ[�HÛÈ^HÛÛ‰Ý]™HÈØZ] ‚‚‚BBBKËÈYˆ›ÜÚ\™H\È[˜X›Y Ü™Y]Ú\™\È\™H›Ý[ÝÙY ˆ™\šYžH[‚BBBKËÈ^Y\ˆ[™]šYX[Ü™Y]Ý\Y\È\™H[\KˆÝ\�Ú\ÙHÜ™Y]‚BBBKËÈÚ\™\È\™H[ÝÙY ÛÈ™\šYžHÛÛوܙY]È\È[\K‚‚BBBZYˆ +›ÜÚ\™JB‚BBB^‚BBBBZYˆ +[ÜÛ›ØÜ™Y]ÊB‚BBBB^‚BBBBB][Y[Y�HÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYY È ŽÂ‚BBBB_BBBBBB‚BBB_B‚BBBY[ÙB‚BBB^‚BBBBZYˆ +Ü™Y]È JB‚BBBB^‚BBBBB][Y[Y�HÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYY È ŽÂ‚BBBB_B‚BBB_BˆBˆB‚ˆYŠXÝ[™×Ù[�]KO›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜרÛÛ™][Ûˆ ˆÑPTÓ—ÓÔÔ×ÐÓÓ‘USÓ—ÔÕQÑJBˆˆ^Y\–Ü^Y\š[™^K�ÙX\�[HH]™[ OœÙ]ÙX\ˆB‚ˆYŠ›ÛX^�\Ú™\Ù]ÍHOH ŠBˆˆ›ÛX^�\Ú™\Ù]Ü^Y\š[™^HH ˆBˆ‚B\™]\›ŽÂˆBˆ[ÙBˆˆÜ]Ûœ^Y\Š^Y\š[™^ +Nˆ^XÝ]WÜ™\Ü]Û—ÜØÜš\ +^Y\š[™^ +NˆYŠ[›Ù›Ü[ŠBˆˆYˆ +Ø]™Y]Kš›Þ\�[X›VÜ^Y\š[™^JHÛÛ�›ÛÜ�[X›J^Y\š[™^  K L�JNˆ›ÜØ[Ù[™[ZY\Ê +NˆBˆB‚ˆYŠ[]™[ O››Ü™\Ù] +Bˆˆ[Y[Y�H]™[ OœÙ][YH +ˆÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYYÈ ËÈ™Xˆ �  Œ H H\È[™H[Ý™Y\™HÈÙ]Ý\ÝÛH[YBˆB‚ŸB‚�›ÚY^Y\—ÙYJ›ÚY +BžÂˆ^Y\—ÙYWÙ[�]JÙ[ŠNŸB‚‚‚š[�^Y\—Ýž[[Ý™J›Ø]\‹›Ø]™\ŠBžÂˆ™]\›ˆÛÛ[[Û—Ýž[[Ý™J\‹™\ŠNŸB‚š[�ÚXÚ×Ù[™\™ÞJWØÛÜÝØÚXÚÈÚXÚ [�[šJBžÂˆ[�™\Ý[H�SÑNˆWÙ[�]WÝ\H\NÈ ËÑ[�]H\K‚ˆ×Ù[™\™ÞWØÛÜÝ[™\™ÞWØÛÜÝ‚Hˆ ËÈÙ][š[X][Û‰ÜÈ[™\™ÞWØÛÜÝ]K‚ˆ[™\™ÞWØÛÜÝ ˜ÛÜÝHÙ[‹O›[Ù[]K˜[š[X][Û–Ø[šWKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ‚Y[™\™ÞWØÛÜÝ ™\ØX›HHÙ[‹O›[Ù[]K˜[š[X][Û–Ø[šWKO™[™\™ÞWØÛÜÝ ™\ØX›N‚Y[™\™ÞWØÛÜÝ ›\Û›HHÙ[‹O›[Ù[]K˜[š[X][Û–Ø[šWKO™[™\™ÞWØÛÜÝ ›\Û›N‚ˆ ËÈÙ][�]H\K‚ˆ\BHHÙ[‹O›[Ù[]K�\N‚ˆ ËÈYˆÙIÜ™Hš[™[™ÜXÚX[\ÈÝ™\œšY[‹[‚ˆ ËÈ™]\›ˆ˜[ÙK‚ˆYŠ\H ˆ +TWÑS‘SVHTWÓ”ÊJBˆˆYŠÚXÚרš[™ÛÝ™\œšYJÙ[‹’S‘ÐÓÓ‘’Q×ÓÕ‘T”’QWÔÔPÒPSÐRJJBˆˆ™]\›ˆ�SÑNˆBˆBˆ[ÙHYŠ\H ˆTWÔVQTŠBˆˆYŠÚXÚרš[™ÛÝ™\œšYJÙ[‹’S‘ÐÓÓ‘’Q×ÓÕ‘T”’QWÔÔPÒPSÔVQTŠJBˆˆ™]\›ˆ�SÑNˆBˆB‚ˆYŠ˜[Y[š[JÙ[‹[šJJBˆˆ ËÈØ\ÚÙ^K[[Ûˆ‹‚ˆ ËÈ Œ L L KLˆ ˈ ËÈ]\È›ÝÈÜÜÚX›HÈ[™]šYX[H\ØX›HÜXÚX[ˈ[‚ˆ ËÈX[žHØ\Ù\È +ÙX\ÛœÈ[ˆ\�XÝ[\ŠH\ÈØ[‚Z[Ý]ÝÛˆH™YY›Ü‚ˆ ËÈÝ\\™›[Ý\È[Ù[ÈÚ[ˆY™™\š[™ÈXš[]Y\È\™H\Ú\™Y›Üˆ^Y\œËˆ ËÈ[™[ZY\Ë܈œÜË‚ˆ ËÈܘ]\È + L LŒ ŒJHš^YH™]Èœ›ÚÙ[ˆÛÙH›Üˆ™\ØX›Hˆ›YÈÚXÚ˘XÚÈÈH™]š[Ý\ÈÛÙBˆYŠJ[™\™ÞWØÛÜÝ ™\ØX›HOH\BBBBBBBBBBBBBKËÈ\ØX›YžH\Oˆ +[™\™ÞWØÛÜÝ ™\ØX›HOH LJBBBBBBBBBBBH ËÈ\ØX›Y›Üˆ[ˆ +[™\™ÞWØÛÜÝ ™\ØX›HOH Lˆ ‰ˆ +\H ˆ +TWÑS‘SVHTWÓ”ÊJJBBH ËÈ\ØX›Y›Üˆ[ROˆ +[™\™ÞWØÛÜÝ ™\ØX›HOH LÈ ‰ˆ +\H ˆ +TWÔVQTˆTWÓ”ÊJJBH ËÈ\ØX›Y›Üˆ^Y\œÈ ˆ”Üψ +[™\™ÞWØÛÜÝ ™\ØX›HOH M ‰ˆ +\H ˆ +TWÔVQTˆTWÑS‘SVJJJJJH ËÈ\ØX›Y›Üˆ[ROˆˆ ËÈ›ÈÙX[܈ÙX[\È\ÜËÜØ[YH\È[™\™ÞHÛÜ݈Yˆ +\Ù[‹OœÙX[Ù[‹OœÙX[�H[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠ +ÚXÚOHS‘T‘ÖWÕTWÓT ‰ˆ +[™\™ÞWØÛÜÝ ›\Û›HOHÓÔÕÕTWÒÓÓ“JH ‰ˆ +Ù[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[��H[™\™ÞWØÛÜÝ ˜ÛÜÝ +JH‚BBBB_ +ÚXÚOHS‘T‘ÖWÕTWÒ ‰ˆ +[™\™ÞWØÛÜÝ ›\Û›HOHÓÔÕÕTWÓTÓÓ“JH ‰ˆ +Ù[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ[™\™ÞWØÛÜÝ ˜ÛÜÝ +JJBˆˆ™\Ý[H•QNˆBˆ[ÙBˆˆ ËÑÈ Œ KL KLŒÂˆ ËÕšYY][™ÈHÐS•[š[X][Ûˆ\™HÈÙY\ÛÙHÛÛ\XÝY �]ÛÛ‰ÝÛܚˈIÛÛÛYH˜XÚÈÈ\Ë‚ˆ ËÚYˆ +˜[Y[š[JÙ[‹[šJJ^ˆ ËÈ[�ÜÙ]Ø[š[JÙ[‹S’WÐÐS•  +Nˆ ËÈÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆ ËÈ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\ÈH ˆ ËßBˆBˆBˆBˆB‚ˆ™]\›ˆ™\Ý[ŸB‚‹ËÈØ\ÚÙ^H[[Ûˆ‹‚‹ËÈ Œ N L KLL‹Ë‹ËÈ™\XÙ\È[œ™XYX›HÚXÚ×ܘ[™ÙJ +HXXܛˈ�[œÈ[™]šYX[‹ËÈÚXÚȘ[™ÙH�[˜Ý[ۜț܈XXÚ^\È[™™]\›œÈ�YB‹ËÈYˆ\™Ù]\ÈÚ][ˆ˜[™ÙHÙˆS ‚˜›ÛÛÚXÚ×ܘ[™ÙWÝ\™Ù]Ø[ +ÛÛœÝ[�]H +™[� ÛÛœÝ[�]H +�\™Ù] ÛÛœÝ[š[X][Û—ÚYÝ[š[X][Û—ÚY [� �ݘ[™ÙWÛZ[‹[� �ݘ[™ÙWÛX^ +BžÂˆ ËÈ]\Ý]™HH˜[Y\™Ù][�]K‚ˆYŠ]\™Ù] +Bˆˆ™]\›ˆ˜[ÙNˆB‚ˆ ËÈÙ]Ú[�\ˆÈ[š[X][Û‹‚ˆÛÛœÝר[š[H +˜[š[X][ÛˆH[� O›[Ù[]K˜[š[X][Û–Ø[š[X][Û—ÚYN‚ˆYˆ +XÚXÚ×ܘ[™ÙWÝ\™Ù]Þ +[� \™Ù] [š[X][Û‹˜[™ÙWÛZ[‹˜[™ÙWÛX^ +JBˆˆ™]\›ˆ˜[ÙNˆB‚ˆYˆ +XÚXÚ×ܘ[™ÙWÝ\™Ù]ÞJ[� \™Ù] [š[X][Û‹˜[™ÙWÛZ[‹˜[™ÙWÛX^ +JBˆˆ™]\›ˆ˜[ÙNˆB‚ˆYˆ +XÚXÚ×ܘ[™ÙWÝ\™Ù]ÞŠ[� \™Ù] [š[X][Û‹˜[™ÙWÛZ[‹˜[™ÙWÛX^ +JBˆˆ™]\›ˆ˜[ÙNˆB‚ˆYˆ +XÚXÚ×ܘ[™ÙWÝ\™Ù]ؘ\ÙJ[� \™Ù] [š[X][Û‹˜[™ÙWÛZ[‹˜[™ÙWÛX^ +JBˆˆ™]\›ˆ˜[ÙNˆB‚ˆ™]\›ˆ�YNŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ N L KLL‚‹Ë‹ËÈ™]\›ˆ�YHYˆ\™Ù]\ÈÚ][ˆ˜\ÙH˜[™ÙB‹ËÈÙˆ[�]IÜÈ[š[X][Û‹‚˜›ÛÛÚXÚ×ܘ[™ÙWÝ\™Ù]ؘ\ÙJÛÛœÝ[�]H +˜XÝ[™×Ù[�]KÛÛœÝ[�]H +�\™Ù] ÛÛœÝר[š[H +˜[š[X][Û‹[� �ݘ[™ÙWÛZ[‹[� �ݘ[™ÙWÛX^ +BžÂˆ[�[�ؘ\ÙNˆ[�\™Ù]ؘ\ÙN‚ˆ×ÛY]šX×ܘ[™ÙH˜[™ÙN‚ˆ ËÈ]\Ý]™HH\™Ù] ‚ˆYŠXXÝ[™×Ù[�]H]\™Ù] +Bˆˆ™]\›ˆ˜[ÙNˆB‚ˆ˜[™ÙK›X^H˜[™ÙWÛX^ˆ˜[™ÙK›Z[ˆH˜[™ÙWÛZ[ŽÂ‚ˆYˆ +[š[X][ÛŠBˆˆ˜[™ÙK›X^ +ÏH[š[X][Û‹Oœ˜[™ÙK˜˜\ÙK›X^ˆ˜[™ÙK›Z[ˆ +ÏH[š[X][Û‹Oœ˜[™ÙK˜˜\ÙK›Z[ŽÂˆB‚ˆ ËÈÙ]ÜÚ][ÛœÈØ\Ý\È[�YÙ\œË‚ˆ[�ؘ\ÙHH +[� +XXÝ[™×Ù[�]KO˜˜\ÙNˆ\™Ù]ؘ\ÙHH +[� +]\™Ù] O˜˜\ÙN‚ˆ ËÈÝX�˜XÝ[�]H˜\ÙHÜÚ][Ûˆœ›ÛH\™Ù]ÜÚ][Û‹‚ˆ\™Ù]ؘ\ÙH OH[�ؘ\ÙN‚ˆ ËÈ™]\›ˆ�YHYˆš[˜[\™Ù]ØØ][Ûˆ\ˆ ËÈÚ][ˆ˜[™ÙHZ[ˆ[™X^ ‚ˆ™]\›ˆ +\™Ù]ؘ\ÙH�H˜[™ÙK›Z[‚ˆ ‰ˆ\™Ù]ؘ\ÙHH˜[™ÙK›X^ +HÈ�YHˆ˜[ÙNŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ N L KLL‹Ë‹ËÈ™]\›ˆ�YHYˆ\™Ù]\ÈÚ][ˆ˜[™ÙB‹ËÈÙˆ[�]IÜÈ[š[X][Û‹‚˜›ÛÛÚXÚ×ܘ[™ÙWÝ\™Ù]Þ +ÛÛœÝ[�]H +˜XÝ[™×Ù[�]KÛÛœÝ[�]H +�\™Ù] ÛÛœÝר[š[H +˜[š[X][Û‹[� �ݘ[™ÙWÛZ[‹[� �ݘ[™ÙWÛX^ +BžÂˆ ËÈ]\Ý]™H[�]Y\Ë‚ˆYŠXXÝ[™×Ù[�]H]\™Ù] +Bˆˆ™]\›ˆ˜[ÙNˆB‚ˆ ËÈÙ]ÜÚ][ÛœÈØ\Ý\È[�YÙ\œË‚ˆÛÛœÝ[�[�ÞH +[� +XXÝ[™×Ù[�]KOœÜÚ][Û‹žˆÛÛœÝ[�\™Ù]ÞH +[� +]\™Ù] OœÜÚ][Û‹ž‚ˆ×ÛY]šX×ܘ[™ÙH˜[™ÙN‚ˆ˜[™ÙK›X^H˜[™ÙWÛX^ˆ˜[™ÙK›Z[ˆH˜[™ÙWÛZ[ŽÂ‚ˆYˆ +[š[X][ÛŠBˆˆ˜[™ÙK›X^ +ÏH[š[X][Û‹Oœ˜[™ÙKž ›X^ˆ˜[™ÙK›Z[ˆ +ÏH[š[X][Û‹Oœ˜[™ÙKž ›Z[ŽÂˆB‚ˆ ËÈ™]\›ˆ�YHYˆš[˜[\™Ù]ØØ][Ûˆ\ˆ ËÈÚ][ˆ˜[™ÙHZ[ˆ[™X^ ˆ˜[™ÙHÛÛ\\š\ÛÛ‚ˆ ËÈ\È™]™\œÙYÚ[ˆ[�]H˜XÙ\ÈY� ‚ˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +Bˆˆ ËÈY˜[™ÙHÈ[�]HÜÚ][Û‚ˆ Ëț܈š[˜[˜[™ÙHÛÛÜ™[˜]\Ë‚ˆ˜[™ÙK›Z[ˆH[�Þ +Ș[™ÙK›Z[ŽÂˆ˜[™ÙK›X^H[�Þ +Ș[™ÙK›X^‚ˆ™]\›ˆ +\™Ù]Þ�H˜[™ÙK›Z[‚ˆ ‰ˆ\™Ù]ÞH˜[™ÙK›X^ +HÈ�YHˆ˜[ÙNˆBˆ[ÙBˆˆ ËÈÝX�˜Xݘ[™ÙHœ›ÛH[�]Hˆ ËÈÜÚ][Ûˆ›Üˆš[˜[˜[™ÙHÛÛÜ™[˜]\Ë‚ˆ˜[™ÙK›Z[ˆH[�Þ H˜[™ÙK›Z[ŽÂˆ˜[™ÙK›X^H[�Þ H˜[™ÙK›X^‚ˆ™]\›ˆ +\™Ù]ÞH˜[™ÙK›Z[‚ˆ ‰ˆ\™Ù]Þ�H˜[™ÙK›X^ +HÈ�YHˆ˜[ÙNˆBŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ N L KLL‹Ë‹ËÈ™]\›ˆ�YHYˆ\™Ù]\ÈÚ][ˆH˜[™ÙB‹ËÈÙˆ[�]IÜÈ[š[X][Û‹‚˜›ÛÛÚXÚ×ܘ[™ÙWÝ\™Ù]ÞJÛÛœÝ[�]H +˜XÝ[™×Ù[�]KÛÛœÝ[�]H +�\™Ù] ÛÛœÝר[š[H +˜[š[X][Û‹[� �ݘ[™ÙWÛZ[‹[� �ݘ[™ÙWÛX^ +BžÂˆ ËÈ]\Ý]™HH\™Ù] ‚ˆYŠXXÝ[™×Ù[�]H]\™Ù] +Bˆˆ™]\›ˆ˜[ÙNˆB‚ˆ×ÛY]šX×ܘ[™ÙH˜[™ÙN‚ˆ˜[™ÙK›X^H˜[™ÙWÛX^ˆ˜[™ÙK›Z[ˆH˜[™ÙWÛZ[ŽÂ‚ˆYˆ +[š[X][ÛŠBˆˆ˜[™ÙK›X^ +ÏH[š[X][Û‹Oœ˜[™ÙKžK›X^ˆ˜[™ÙK›Z[ˆ +ÏH[š[X][Û‹Oœ˜[™ÙKžK›Z[ŽÂˆB‚ˆ ËÈÙ]ÜÚ][ÛœÈØ\Ý\È[�YÙ\œË‚ˆÛÛœÝ[�[�ÞHH +[� +XXÝ[™×Ù[�]KOœÜÚ][Û‹žNˆÛÛœÝ[�\™Ù]ÞHH +[� +]\™Ù] OœÜÚ][Û‹žH H[�ÞN‚ˆ ËÈ™]\›ˆ�YHYˆš[˜[\™Ù]ØØ][Ûˆ\ˆ ËÈÚ][ˆ˜[™ÙHZ[ˆ[™X^ ‚ˆ™]\›ˆ +\™Ù]ÞH�H˜[™ÙK›Z[‚ˆ ‰ˆ\™Ù]ÞHH˜[™ÙK›X^ +HÈ�YHˆ˜[ÙNŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ N L KLL‚‹Ë‹ËÈ™]\›ˆ�YHYˆ\™Ù]\ÈÚ][ˆˆ˜[™ÙB‹ËÈÙˆ[�]IÜÈ[š[X][Û‹‚˜›ÛÛÚXÚ×ܘ[™ÙWÝ\™Ù]ÞŠÛÛœÝ[�]H +ˆXÝ[™×Ù[�]KÛÛœÝ[�]H +�\™Ù] ÛÛœÝר[š[H +˜[š[X][Û‹[� �ݘ[™ÙWÛZ[‹[� �ݘ[™ÙWÛX^ +BžÂˆ ËÈ]\Ý]™HH\™Ù] ‚ˆYŠXXÝ[™×Ù[�]H]\™Ù] +Bˆˆ™]\›ˆ˜[ÙNˆB‚ˆ×ÛY]šX×ܘ[™ÙH˜[™ÙN‚ˆ˜[™ÙK›Z[ˆH˜[™ÙWÛZ[ŽÂˆ˜[™ÙK›X^H˜[™ÙWÛX^‚ˆYˆ +[š[X][ÛŠBˆˆ˜[™ÙK›X^ +ÏH[š[X][Û‹Oœ˜[™ÙKž‹›X^ˆ˜[™ÙK›Z[ˆ +ÏH[š[X][Û‹Oœ˜[™ÙKž‹›Z[ŽÂˆB‚ˆ ËÈÙ]ÜÚ][ÛœÈØ\Ý\È[�YÙ\œË‚ˆÛÛœÝ[�[�ÞˆH +[� +XXÝ[™×Ù[�]KOœÜÚ][Û‹žŽÂˆÛÛœÝ[�\™Ù]ÞˆH +[� +]\™Ù] OœÜÚ][Û‹žˆ H[�ގ‚ˆ ËÈ™]\›ˆ�YHYˆš[˜[\™Ù]ØØ][Ûˆ\ˆ ËÈÚ][ˆ˜[™ÙHZ[ˆ[™X^ ‚ˆ™]\›ˆ +\™Ù]Þˆ�H˜[™ÙK›Z[‚ˆ ‰ˆ\™Ù]ÞˆH˜[™ÙK›X^ +HÈ�YHˆ˜[ÙNŸB‚š[�ÚXÚ×ÜÜXÚX[ + +BžÂˆ[�]H +™NˆYŠ +[]™[ O››ÜÜXÚX[]™[ O››ÜÜXÚX[OH ÊH ‰ˆ˜[Y[š[JÙ[‹S’WÔÔPÒPS +H ‰‚ˆ +ÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÒ S’WÔÔPÒPS +HÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÔÔPÒPS +JBˆ +BˆˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊÙ[ŠNˆY[\Ù] +Ù[‹O˜ÛÛX›ÜÝ\  Ú^™[ÙŠ +œÙ[‹O˜ÛÛX›ÜÝ\ +H +ˆ JN‚ˆHHÙ[‹O›[šÎˆYŠJBˆˆKO�ZÙXXÝ[ÛˆH•Sˆ[�Ý[›[šÊÙ[ŠNˆÙ]ÚYJJNˆB‚ˆYŠÙ[‹O›[Ù[]KœÛX\�›ÛXˆ ‰ˆ\Ù[‹O›[Ù[]K™Ùœ™Y^™JBˆˆÛX\�Ø›ÛXŠÙ[‹Ù[‹O›[Ù[]KœÛX\�›ÛXŠNÈ ËÈÈÛX\�›ÛXˆ[[YYX][HYˆ]Ù\ۉݜ™Y^™HØÜ™Y[‚ˆB‚ˆÙ[‹Oœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NÈ ËÈYˆÜXÚX[\È^XÝ]YÚ[H�[›š[™ËÙX\Ù\ÈÈ�[‚ˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JÙ[‹S’WÔÔPÒPS  +N‚ˆYŠÙ[‹O›[Ù[]K™Ùœ™Y^™JBˆˆÛX\�›ÛX™\ˆHÙ[ŽÈ ËÈœ™Y^™\ÈH[š[X][ÛœÈÙˆ[[™[ZY\ËÜ^Y\œÈÚ[HÜXÚX[\È^XÝ]YˆB‚ˆ ËÈܘ]\È + L LŒ ŒJH›ÝÈHš[™š[š]HX[ÚX]ˆY™™XÝÈ^Y\œÈÛ›K›Ý[™[ZY\È܈œˆ ËÈ[™›ÝÈHš[™š[š]HX[ÚX]ˆÚ[Û›HÛÜšÈÚ[ˆHÛÜÝ\ÈPS Ú[›ÝÛÜšÈÚ[ˆHÛÜÝ\ÈT[ž[[Ü™BˆYŠÙ[‹O›[Ù[]K�\H ˆTWÔVQTŠBˆˆYŠ[›ØÛÜÝ +BˆˆYŠJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÒPSÐPÕU‘JJBˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÔÔPÒPS +JBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈Bˆ[ÙBˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆ[ÙBˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÔÔPÒPS +JBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆBˆBˆ[ÙBˆˆYŠ[›ØÛÜÝ +BˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÔÔPÒPS +JBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈Bˆ[ÙBˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆBˆ™]\›ˆ NˆBˆ™]\›ˆ ŸB‚‹ËÈÚXÚÈÙ^\ț܈ÜXÚX[[Ý™Kˆ\ÙYÙ]™\˜[[Y\ËÛÈH�[˜ÉÙ] ‚‹ËÈܘ]\È + L LŒ ŒJHYY™]È›YÜÈÈ\ÙHÚ][›Ý\ˆUPÒÈÈÙ^\È\È[ˆ™]È[\›˜]]™Bš[�^Y\—ØÚXÚ×ÜÜXÚX[ + +BžÂˆÙ^WÛX\Ú×ÝZÙ^HH ˆÙ^WÛX\Ú×Ý^Y\—ÚÙ^\ÈH^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\΂ˆÝÚ]Ú +Ûؘ[ØÛÛ™šY˘ZœÜXÚX[ +BˆˆØ\ÙHR”ÔPÒPSÒÑVWÔÔPÒPS‚ˆˆYˆ +^Y\—ÚÙ^\È ˆ“Q×ÔÔPÒPS +BˆˆZÙ^HH“Q×ÔÔPÒPSˆH‚ˆœ™XZ΂ˆØ\ÙHR”ÔPÒPSÒÑVWÑÕP“N‚‚ˆYˆ +]˜[Y[š[JÙ[‹S’WГÐÒÊH ‰ˆ^Y\—ÚÙ^\È ˆ“Q×ÔÔPÒPS +BˆˆZÙ^HH“Q×ÔÔPÒPSˆBˆ[ÙHYˆ +^Y\—ÚÙ^\È ˆ“Q×Ò•ST ‰ˆ^Y\—ÚÙ^\È ˆ“Q×ÐUPÒÊBˆˆZÙ^HH“Q×Ò•ST“Q×ÐUPÒΈBˆœ™XZ΂ˆØ\ÙHR”ÔPÒPSÒÑVWÐUPÒÌŽ‚‚ˆYˆ +^Y\—ÚÙ^\È ˆ“Q×ÐUPÒÌŠBˆˆZÙ^HH“Q×ÐUPÒ̎ˆBˆœ™XZ΂ˆØ\ÙHR”ÔPÒPSÒÑVWÐUPÒÌ΂‚ˆYˆ +^Y\—ÚÙ^\È ˆ“Q×ÐUPÒÌÊBˆˆZÙ^HH“Q×ÐUPÒÌΈBˆœ™XZ΂ˆØ\ÙHR”ÔPÒPSÒÑVWÐUPÒÍ‚‚ˆYˆ +^Y\—ÚÙ^\È ˆ“Q×ÐUPÒÍ +BˆˆZÙ^HH“Q×ÐUPÒ͈Bˆœ™XZΈˆY˜][‚ˆZÙ^HH ˆB‚ˆYˆ +]ZÙ^JBˆˆ™]\›ˆ ˆB‚ˆYŠÚXÚ×ÜÜXÚX[ + +JBˆˆÙ[‹OœÝ[[YHH ˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H�ZÙ^Nˆ™]\›ˆ NˆBˆ[ÙBˆˆ™]\›ˆ ˆBŸB‚‚�›ÚYÛÛ[[Û—Û[™ + +BžÂˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆB‚ˆÙ[‹O�ZÙXXÝ[ÛˆH•SˆÙ]ÚYJÙ[ŠNŸB‚‚‹ËØ[š[X[�[ˆÚ[ˆ[ÝHÜÝ] È[Y\ÈžHZ[Â�›ÚY�[˜[š[X[ + +BžÂˆÛÛ[[Û—ÝØ[ר[š[JÙ[ŠNˆ ËÙ[�ÜÙ]Ø[š[JÙ[‹S’WÕÐSË +N‚ˆYŠÙ[‹OœÜÚ][Û‹žY˜[˜Ù^ H Ù[‹OœÜÚ][Û‹žˆY˜[˜Ù^ +È +šY[Û[Ù\Ëš™\È +È +JBˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÐS’SPSÔ•S—ÓÕUÓїГÕS‘ÊNˆ™]\›ŽÂˆB‚ˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÙ[‹OœÜÚ][Û‹ž +ÏHÙ[‹O›[Ù[]KœÜYY žˆBˆ[ÙBˆˆÙ[‹OœÜÚ][Û‹ž OHÙ[‹O›[Ù[]KœÜYY žˆBŸB‚‚�›ÚY^Y\—Ø›[šÊ +BžÂˆÙ[‹O˜›[šÈH NˆYŠÝ[YH�HÙ[‹OœÝ[[YJBˆˆ^Y\—ÙYJ +NˆBŸB‚‚�›ÚYÛÛ[[Û—ÙܘX˜]XÚÊ +BžÂˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆB‚ˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘N‚ˆYŠJÙ[‹O˜ÛÛX›ÜÝ\ÌHÙ[‹O˜ÛÛX›ÜÝ\ÌWHˆÙ[‹O˜ÛÛX›ÜÝ\Ì—HÙ[‹O˜ÛÛX›ÜÝ\Ì×HˆÙ[‹O˜ÛÛX›ÜÝ\ÍJJBˆˆ[�Ý[›[šÊÙ[ŠNˆB‚ˆYŠÙ[‹O›[šÊBˆˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙܘXŽÂˆÙ[‹O›[šËO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙܘX˜™YˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘Nˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P‹ +NˆÙ]ÜZ[ŠÙ[‹O›[šË LK +Nˆ\]WÙœ˜[YJÙ[‹Ù[‹O˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆ\]WÙœ˜[YJÙ[‹O›[šËÙ[‹O›[šËO˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆBˆ[ÙBˆˆÙ[‹O�ZÙXXÝ[ÛˆH•SˆY[\Ù] +Ù[‹O˜ÛÛX›ÜÝ\  Ú^™[ÙŠ +œÙ[‹O˜ÛÛX›ÜÝ\ +H +ˆ JNˆÙ]ÚYJÙ[ŠNˆBŸB‚‹ËÈ�[˜Ý[Ûˆ]Ø]\Ù\ÈH^Y\ˆÈÛÛ�[�YHÈ[Ý™H\܈ÝÛˆ[�[H[š[X][Ûˆ\Èš[š\ÚY^Z[™Â�›ÚYÛÛ[[Û—ÙÙÙJ +H ËÈ™]È�[˜Ý[ÛˆÛÈ^Y\œÈØ[ˆÙÙHÚ]\\܈ÝÛˆÝÛ‚žÂˆYŠÙ[‹O˜[š[X][™ÊH ËÈÛÛ�[�Y\ÈÈ[Ý™H\ÈÛ™È\ÈH^Y\ˆ\È[š[X][™Âˆˆ™]\›ŽÂˆBˆ[ÙH ËÈÛ˜ÙHÛ™H[š[X][™Ë™]\›œÈÈ[šÚ[™ÂˆˆÙ[‹O�ZÙXXÝ[ÛˆH•SˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆÙ]ÚYJÙ[ŠNˆBŸB‚‚�›ÚYÛÛ[[Û—Ü™YXÚÊ +BžÂˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆBˆÙXÚÊÙ[ŠNŸB‚‚�›ÚYÛÛ[[Û—ÚYJ +BžÂˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆBˆÙ[‹O�ZÙXXÝ[ÛˆH•SˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘NˆÙ[‹OšY[™ÈHQS‘×Ô‘TT‘QˆÛÛ[[Û—ÚYWØ[š[JÙ[ŠNŸB‚‚�›ÚYžYXÚÊ[�]H +™[� +BžÂˆ[� Oœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NˆYŠ˜[Y[š[J[� S’WÑPÒÒS‘ÊJBˆˆ[� O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ü™YXÚΈ[� O�™[ØÚ]KžH[� O�™[ØÚ]KžˆH ˆ[� O™XÚÚ[™ÈHPÒ×Ô‘TT‘Qˆ[� OšY[™ÈHQS‘×Ó“Ó‘Nˆ[�ÜÙ]Ø[š[J[� S’WÑPÒÒS‘Ë +NˆBˆ[ÙBˆˆÙXÚÊ[� +NˆBŸB‚‚�›ÚYžYXÚÜš\ÙJ[�]H +™[� +BžÂˆ[� Oœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NˆYŠ˜[Y[š[J[� S’WÑPÒÔ’TÑJJBˆˆ[� O�ZÙXXÝ[ÛˆHÛÛ[[Û—ÚYNˆ[� O�™[ØÚ]KžH[� O�™[ØÚ]KžˆH ˆ[� O™XÚÚ[™ÈHPÒ×Ô’TÑNˆ[� OšY[™ÈHQS‘×Ó“Ó‘Nˆ[�ÜÙ]Ø[š[J[� S’WÑPÒÔ’TÑK +NˆBˆ[ÙBˆˆ[� O�ZÙXXÝ[ÛˆH•Sˆ[� OšY[™ÈHQS‘×Ô‘TT‘QˆÛÛ[[Û—ÚYWØ[š[JÙ[ŠNˆBŸB‚‚�›ÚYÙXÚÊ[�]H +™[� +BžÂˆ[� O�ZÙXXÝ[ÛˆH•Sˆ[� O�™[ØÚ]KžH[� O�™[ØÚ]KžˆH ˆ[� O™XÚÚ[™ÈHPÒ×ÐPÕU‘Nˆ[� OšY[™ÈHQS‘×Ô‘TT‘Qˆ[�ÜÙ]Ø[š[J[� S’WÑPÒË +NŸB‚‚�›ÚYÛÛ[[Û—Ü™Z�[\ + +BžÂˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆBˆÚ�[\ +Ù[‹Oš�[\ �™[ØÚ]KžKÙ[‹Oš�[\ �™[ØÚ]Kž Ù[‹Oš�[\ �™[ØÚ]Kž‹Ù[‹Oš�[\ ˜[š[X][Û—ÚY +NŸB‚‚�›ÚYžZ�[\ +›Ø]�[\‹›Ø]�[\ ›Ø]�[\‹[š[X][Û—ÚYÝ[š[X][Û—ÚY +BžÂˆÙ[‹Oš�[\ �™[ØÚ]KžHH�[\ŽÂˆÙ[‹Oš�[\ �™[ØÚ]KžH�[\ˆÙ[‹Oš�[\ �™[ØÚ]KžˆH�[\ŽÂˆÙ[‹Oš�[\ ˜[š[X][Û—ÚYH[š[X][Û—ÚY‚ˆÙ[‹O™XÚÚ[™ÈHPÒ×Ó“Ó‘NˆYŠ˜[Y[š[JÙ[‹S’WÒ•STSVJJBˆˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ü™Z�[\ˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ‚ˆÙ[‹OšY[™ÈHQS‘×Ó“Ó‘Nˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STSVK +NˆBˆ[ÙBˆˆÚ�[\ +�[\‹�[\ �[\‹[š[X][Û—ÚY +NˆBŸB‚‚�›ÚYÚ�[\ +›Ø]�[\‹›Ø]�[\ ›Ø]�[\‹[š[X][Û—ÚYÝ[š[X][Û—ÚY +BžÂˆ[�]H +™\Ý‚ˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ú�[\‚ˆYŠÛؘ[ÜØ[\WÛ\Ý š�[\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý š�[\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ËÔÜ]Ûˆ�[\Ý\�\Ý ‚ˆYŠÙ[‹O›[Ù[]K™\Ý š�[\ÜÝ\��H +Bˆˆ\ÝHÜ]ÛŠÙ[‹OœÜÚ][Û‹ž Ù[‹OœÜÚ][Û‹ž‹Ù[‹OœÜÚ][Û‹žKÙ[‹O™\™XÝ[Û‹•S Ù[‹O›[Ù[]K™\Ý š�[\ÜÝ\� •S +NˆYŠ\Ý +Bˆˆ\Ý OœÜ]Û�\HHÔUÓ—ÕTWÑTÕÒ•STˆ\Ý O˜˜\ÙHHÙ[‹OœÜÚ][Û‹žNˆ\Ý O˜]]ÚÚ[HUUÒÒSÐS’SPUSÓ—ÐÓÓTUNˆ^XÝ]WÛÛœÜ]Û—ÜØÜš\ +\Ý +NˆBˆB‚ˆÙ]Ú�[\[™ÊÙ[ŠN‚ˆÜÜÊÙ[‹�[\ŠN‚ˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +BˆˆÙ[‹O�™[ØÚ]KžH Z�[\ˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžH�[\ˆB‚ˆÙ[‹O�™[ØÚ]KžˆH�[\ŽÂˆ[�ÜÙ]Ø[š[JÙ[‹[š[X][Û—ÚY  +NŸB‚‹ËÈ�[˜Ý[ۈܙX]YÈÛÛXš[™HHXÝ[ÛˆZÙ[ˆYˆZ]\ˆXÚÚ[™È\[ˆ][K܈�[›š[™È[�È[ˆ][H]\ÈB‹ËÈÕP•TWÕÕPÒ ^XÝ][™ÈH\›ÜšX]HXÝ[Ûˆ˜\ÙYÛˆÚXÚ\HÙˆ][H\ÈXÚÙY\�›ÚYYš[™Ú][J[�]H +›Ý\ŠBžÂˆ ËÈ�[˜Ý[Ûˆ]ZÙ\ÈØ\™HÙˆ][\ÈÚ[ˆXÚÙY\ˆÙ]ÛÜÛ™[� +Ù[‹Ý\ŠN‚ˆ Ê‚ˆ +ˆYØXÞH[Z]Y\ÙH™\[š\Ú ‚ˆ +ˆˆ +ˆYˆ][H\ÈH\ÙWØY˜[YH[™ÛÛXÝ[™Âˆ +ˆ[�]H\ÈH[Z]Y\ÙHÙX\Û‹ÙHYˆ +ˆ\ÙWØYÈ\Ù\È™[XZ[š[™Ë‚ˆ +‹Â‚ˆYŠÝ\‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØY +BˆˆYŠÙ[‹O�ÙX\[� ‰ˆÙ[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÓSRUQÕTÑJBˆˆÙ[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØÛÝ[� +ÏHÝ\‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØY‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙBˆˆYØÛÜ™JÙ[‹Oœ^Y\š[™^ Ý\‹O›[Ù[]KœØÛÜ™JNˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆB‚ˆ ËÙ[™ÙˆÙX\ÛœÈ][\ÈÙXÝ[Û‚ˆ[ÙHYŠÝ\‹O›[Ù[]KœØÛÜ™JBˆˆYØÛÜ™JÙ[‹Oœ^Y\š[™^ Ý\‹O›[Ù[]KœØÛÜ™JNˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� +BˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� +ÏHÝ\‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�‚ˆYŠÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆÙ[‹O›[Ù[]KšX[ +BˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�HÙ[‹O›[Ù[]KšX[ˆB‚ˆÝ\‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]K›\ +BˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� +ÏHÝ\‹O›[Ù[]K›\‚ˆYŠÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�ˆÙ[‹O›[Ù[]K›\ +BˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�HÙ[‹O›[Ù[]K›\ˆB‚ˆÝ\‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�H ˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆ[ÙHYŠÝšXÛ\ +Ý\‹O›[Ù[]K›˜[YK•[YHŠHOH +Bˆˆ[Y[Y�H]™[ OœÙ][YH +ˆÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYYÈ ËÈ™Xˆ �  Œ H H\È[™H[Ý™Y\™HÈÙ]Ý\ÝÛH[YB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]K›XZÙZ[�ŠBˆˆ ËÈX\ˆ ‹ Œ H H™]È][HXZÙ\È^Y\ˆ[�š[˜ÚX›BˆÙ[‹Oš[�š[˜ÚX›HHS•’S�ÒP“WÒS•S‘ÒP“NˆÙ[‹Oš[�š[˜Ý[YHHÝ[YH +ÈP”ÊÝ\‹O›[Ù[]K›XZÙZ[�ŠNˆÙ[‹O˜›[šÈH +Ý\‹O›[Ù[]K›XZÙZ[�ˆˆ +N‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]KœÛX\�›ÛXŠBˆˆ ËÈ[XYÙ\È]™\ž][™ÈÛˆHØÜ™Y[‚ˆÛX\�Ø›ÛXŠÙ[‹Ý\‹O›[Ù[]KœÛX\�›ÛXŠN‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]KœÝX�\HOHÕP•TWÕÑPTÓŠBˆˆ›ÜÙX\ÛŠÙ[‹ +NˆÙ[‹O�ÙX\[�HÝ\ŽÂˆÙ]ÝÙX\ÛŠÙ[‹Ý\‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—Ú[™^  +N‚ˆ ʈ[Ý™HÈÙX\ÛˆØØ][ÛˆYˆ] ÜÈ[ˆ˜[š[X[‹ˆ +‹ÂˆYŠÙ[‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÐS’SPS +BˆˆÙ[‹O™\™XÝ[ÛˆHÝ\‹O™\™XÝ[ێˆÙ[‹OœÜÚ][Û‹žHÝ\‹OœÜÚ][Û‹žˆÙ[‹OœÜÚ][Û‹žˆHÝ\‹OœÜÚ][Û‹žŽÂˆB‚ˆYŠJÝ\‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÓSRUQÕTÑJH ‰ˆÙ[‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÓSRUQÕTÑJBˆˆÝ\‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]HHÑPTÓ—ÔÕUWÓSRUQÕTÑNˆB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]KœÝX�\HOHÕP•TWÔ“Ò‘PÕSJBˆˆ›ÜÙX\ÛŠÙ[‹ +NˆÙ[‹O�ÙX\[�HÝ\ŽÂ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ™Ù]�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ™Ù]  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙHYŠÝ\‹O›[Ù[]K˜Ü™Y] +BˆˆYŠ[›ÜÚ\™JBˆˆÜ™Y]ÊÊΈBˆ[ÙBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^K˜Ü™Y]ÊÊΈB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ›Û™WÝ\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ›Û™WÝ\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆ[ÙBˆˆ ËÈ]\Ý™HH ]\[‹‚ˆ^Y\–ÜÙ[‹Oœ^Y\š[™^K›]™\ÊÊ΂ˆYŠÛؘ[ÜØ[\WÛ\Ý ›Û™WÝ\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ›Û™WÝ\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆB‚ˆYŠÝ\‹O›[Ù[]KœÝX�\HOHÕP•TWÕÑPTÓˆ ‰ˆÝ\‹O›[Ù[]KœÝX�\HOHÕP•TWÔ“Ò‘PÕSJBˆˆÝ\‹O�ZÙXXÝ[ÛˆHÝZXÚYNˆYŠ[Ý\‹O›[Ù[]Kš[œÝ[�][YX] +BˆˆÝ\‹O›™^[šÈHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ΈBˆBˆ[ÙBˆˆYŠJÝ\‹O›™^[š[H ˆSVWÑ“Q×ÒS‘’S’UJJHˆÝ\‹O›™^[š[HH[š[X][Û—Ý[Y\Ý[\ØYØ›Ý[™Y +ˆÝ[YKˆ[^WÛ][\WØ›Ý[™Y +ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY ˆRS• �ÐÊNNNNNJBˆ +Bˆ +NˆBˆÝ\‹O›™^[šÈHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆNNNNNNˆBˆÝ\‹OœÜÚ][Û‹žˆHUSWÒQWÔÔÒUSӗ֎ŸB‚�›ÚY^Y\—Ù˜[ØÚXÚÊ +BžÂˆYŠ]]Û[™OH ˆ ‰ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×Ò•ST +JHOH +“Q×ÓSÕ‘UT“Q×Ò•ST +JBˆ‚BKËÈX\šÈ] ÛÈÙHÚ[^H[™[š[X][ÛˆÚ[ˆ]HÜ›Ý[™ ‚ˆÙ[‹O™[XYÙWÛÛ—Û[™[™Ë˜]XÚ×ٛܘÙHHUPÒ×Ñ“Ô�ÑWÓS‘ÐÓÓSPS‘ȈBŸB‚�›ÚY^Y\—ÙܘX—ØÚXÚÊ +BžÂˆ[�]H +›Ý\ˆHÙ[‹O›[šÎ‚ˆYŠÝ\ˆOH•S +Ù[‹O›[Ù[]K™Ü˜X™š[š\Ú ‰ˆÙ[‹O˜[š[X][™È ‰ˆ\Ù[‹O™Ü˜X�Ø[Ú[™ÊJBˆˆ™]\›ŽÂˆB‚ˆYŠÙ[‹O˜˜\ÙHOHÝ\‹O˜˜\ÙJBˆˆ ËÈÚ[™ÙH\Èœ›ÛH OœÜÚ][Û‹žHÈ O˜˜\ÙBˆÙ[‹O�ZÙXXÝ[ÛˆH•Sˆ[�Ý[›[šÊÙ[ŠNˆÙ]ÚYJÙ[ŠNˆ™]\›ŽÂˆB‚ˆYŠ^Y\—ØÚXÚ×ÜÜXÚX[ + +JBˆˆ™]\›ŽÂˆB‚ˆYŠ[›ÛÜÝ ‰ˆÙ[‹O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜרÛÛ™][Ûˆ ˆÑPTÓ—ÓÔÔ×ÐÓÓ‘USÓ—ÑÔ�P�’S‘ÊBˆˆ›ÜÙX\ÛŠÙ[‹ JNˆB‚ˆ ËÈܘX�\›ˆÛÙBˆYŠÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•T“—JBˆˆ ËÈÝ[\›š[™ÏÈۉݛÝ\ˆÚ][ž][™È[ÙBˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆB‚ˆ ËÈÛ™H\›š[™ÏÈÝÚ]Ú\™XÝ[ÛœÈ[™™]\›ˆÈܘXˆ[š[X][Û‚ˆ[ÙBˆˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆÝ\‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆ[ÙBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆÝ\‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆÝ\‹OœÜÚ][Û‹žHÙ[‹OœÜÚ][Û‹ž +È + + +Ù[‹O™\™XÝ[Ûˆ +ˆ ŠH H JH +ˆÙ[‹O›[Ù[]K™Ü˜X™\Ý[˜ÙJNˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P‹ +NˆÙ]ÜZ[ŠÝ\‹ LK +Nˆ\]WÙœ˜[YJÙ[‹Ù[‹O˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆ\]WÙœ˜[YJÝ\‹Ý\‹O˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆBˆB‚ˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘NÈ Ëٛ܈ÚXÚÚ[™ÂˆÙ[‹O™Ü˜X�Ø[Ú[™ÈH ‚‚KËÈ[Ý™HÙ^HÜÜÚ]HœËˆXÜ™][Û�ˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒÈ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +Hˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆ ËÈ[š]X][™ÈܘX�\›‚ˆYŠÙ[‹O›[Ù[]K™Ü˜X�\›ŠBˆˆ ËÈÝ\�[š[X][ÛˆYˆ]^\ÝË‹‹‚ˆYŠ˜[Y[š[JÙ[‹S’WÑÔ�P•T“ŠJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P•T“‹ +NˆYŠ˜[Y[š[JÝ\‹S’WÑÔ�P�‘QT“ŠJBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘QT“‹ +NˆBˆ[ÙHYŠ˜[Y[š[JÝ\‹S’WÑÔ�P�‘Q +JBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘Q  +NˆBˆ[ÙBˆˆYˆ + + +[Ý\‹O™\™XÝ[Ûˆ ‰ˆÙ[‹OœÜÚ][Û‹žˆÝ\‹OœÜÚ][Û‹ž +H +Ý\‹O™\™XÝ[Ûˆ ‰ˆÙ[‹OœÜÚ][Û‹žÝ\‹OœÜÚ][Û‹ž +JH ‰ˆ˜[Y[š[JÝ\‹S’WÐ�PÒÔRSŠH +H[�ÜÙ]Ø[š[JÝ\‹S’WÐ�PÒÔRS‹ +Nˆ[ÙH[�ÜÙ]Ø[š[JÝ\‹S’WÔRS‹ +NˆBˆÝ\‹O�™[ØÚ]KžHÝ\‹O�™[ØÚ]KžˆHÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆÝ\‹OœÜÚ][Û‹žHÙ[‹OœÜÚ][Û‹žˆ™]\›ŽÂˆB‚ˆ ËÈÝ\�Ú\ÙK�\Ý\›ˆ\›Ý[™ˆ[ÙBˆˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆÝ\‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆ[ÙBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆÝ\‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P‹ +NˆÙ]ÜZ[ŠÝ\‹ LK +Nˆ\]WÙœ˜[YJÙ[‹Ù[‹O˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆ\]WÙœ˜[YJÝ\‹Ý\‹O˜[š[X][Û‹O›�[Yœ˜[Y\È H JNˆÝ\‹OœÜÚ][Û‹žHÙ[‹OœÜÚ][Û‹ž +È + + +Ù[‹O™\™XÝ[Ûˆ +ˆ ŠH H JH +ˆÙ[‹O›[Ù[]K™Ü˜X™\Ý[˜ÙJNˆBˆBˆ[ÙHYŠ]˜[Y[š[JÙ[‹S’WÑÔ�P•ÐSÊH ‰ˆÝ[YHˆÙ[‹Oœ™[X\Ù][YJBˆˆ ËÈ™[X\ÙBˆÙ[‹O�ZÙXXÝ[ÛˆH•Sˆ[�Ý[›[šÊÙ[ŠNˆÙ]ÚYJÙ[ŠNˆ™]\›ŽÂˆBˆBˆ[ÙBˆˆÙ[‹Oœ™[X\Ù][YHHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È ŠNˆB‚ˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰‚ˆ +Ù[‹O™\™XÝ[Ûˆˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H‚ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JJBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È OH“Q×ÐUPÒΈYŠ˜[Y[š[JÙ[‹S’WÑÔ�P��PÒÕÐT‘ +JBˆˆÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÐ�PÒÕÐT‘ +NˆBˆ[ÙHYŠ˜[Y[š[JÙ[‹S’WÕ“ÕÊJBˆˆYŠÙ[‹O›[Ù[]K�›ÝÙœ˜[Y]ØZ]�H +BˆˆÜ™]›ÝÊ +NˆBˆ[ÙBˆˆÝ›ÝÊ +NˆBˆBˆ[ÙBˆˆÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÐUPÒÊNˆBˆBˆ ËÈܘXˆ›Ü�Ø\™ˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰‚ˆ˜[Y[š[JÙ[‹S’WÑÔ�P‘“Ô•ÐT‘ +H ‰‚ˆ +\Ù[‹O™\™XÝ[Ûˆˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H‚ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JJBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕѓԕÐT‘ +NˆBˆ ËÈܘXˆ\ˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰‚ˆ˜[Y[š[JÙ[‹S’WÑÔ�P•T +H ‰ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +JBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÕT +NˆBˆ ËÈܘXˆÝÛ‚ˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰‚ˆ˜[Y[š[JÙ[‹S’WÑÔ�P‘ÕÓŠH ‰ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠJBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÑÕÓŠNˆBˆ ËțܛX[ܘXˆ]XÚˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰ˆ˜[Y[š[JÙ[‹S’WÑÔ�P�UPÒÊJBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÐUPÒÊNˆB‚KËÈܘ]\È + L LŒ ŒJHYYH˜][[š[X][Û‚ˆ[ÙHYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×Ò•ST ‰ˆ˜[Y[š[JÙ[‹S’WÕ�US +JBˆˆ ËÈܘ]\È + ËLŒ ŒŠHš^YHŒË]˜][ȈÛÜ�YË›ÝÈÚ[^XÝ]HÛ˜ÙH\È[�[™Yˆ ËÈܘ]\È + KLŒ ŒÊHš^Y[ˆ\ÜÝYHÚ\™HܘX˜]XÚ̈[š[X][Ûˆ�[YšY\Ș][Yˆ›Ý\™HXÛ\™Yˆ ËÈܘ]\È + KLŒ ŒÊHYYÛÛYH˜]]™H™Z]š[Ý\œÂˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×Ò•STˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘NˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙܘX˜]XÚΈY[\Ù] +Ù[‹O˜ÛÛX›ÜÝ\  Ú^™[ÙŠ +œÙ[‹O˜ÛÛX›ÜÝ\ +H +ˆ JNˆ[�ÜÙ]Ø[š[JÙ[‹S’WÕ�US  +NˆBˆ ËÈܘXˆ]XÚÈš[š\Ú\‚ˆ[ÙHYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ +“Q×ÐUPÒÈ“Q×Ò•ST +JBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �HŠ“Q×ÐUPÒÈ“Q×Ò•ST +N‚ˆ ËÈ\™›Ü›Hš[˜[›݈YŠ˜[Y[š[JÙ[‹S’WÑÔ�P�UPÒÌŠH˜[Y[š[JÙ[‹S’WÐUPÒÌÊJBˆˆÙܘX˜]XÚÊÔ�P—ÐPÕSÓ—ÔÑSPÕÑ’S’TÒ +NˆBˆ[ÙBˆˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘NˆY[\Ù] +Ù[‹O˜ÛÛX›ÜÝ\  Ú^™[ÙŠ +œÙ[‹O˜ÛÛX›ÜÝ\ +H +ˆ JNˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙܘX˜]XÚΈžZ�[\ +Ù[‹O›[Ù[]Kš�[\ZYÚ Ù[‹O›[Ù[]Kš�[\ÜYY  S’WÒ•ST +NˆBˆB‚ˆ ËÈܘXˆØ[ÈÛÙBˆ[ÙHYŠ˜[Y[š[JÙ[‹S’WÑÔ�P•ÐSÊH ËÈÚXÚÈYˆܘX�Ø[È[š[X][Ûˆ^\Ý‚ˆ ËÈYˆ[�]H\ÈÝ[[š[X][™È[ž][™È™\ÚY\ÈHܘX�Ø[Ș\šX[� Û‰Ý][H[Ý™Bˆ ‰ˆ +\Ù[‹O˜[š[X][™ÈÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•ÐS×BˆÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•ÐSÕTBˆÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•ÐSÑÕÓ—BˆÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P��PÒÕÐS×JJBˆ‚ˆ ËȈ^\È[Ý™[Y[�ˆYŠVQT—ÓRS—ÖˆOHVQT—ÓPVÖŠBˆˆYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +BˆˆYŠÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY +BˆˆÙ[‹O�™[ØÚ]KžˆH \Ù[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY È ŽÂˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžˆH \Ù[‹O›[Ù[]KœÜYY ž È ŽÂˆBˆBˆ[ÙHYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆYŠÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY +BˆˆÙ[‹O�™[ØÚ]KžˆHÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY È ŽÂˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžˆHÙ[‹O›[Ù[]KœÜYY ž È ŽÂˆBˆBˆ[ÙHYŠJ^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓŠJJBˆˆÙ[‹O�™[ØÚ]KžˆH ˆBˆB‚ˆ ËÈ^\È[Ý™[Y[�ˆYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +BˆˆYŠÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY +BˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYYˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O›[Ù[]KœÜYY žˆBˆB‚ˆ[ÙHYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +BˆˆYŠÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYY +BˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O›[Ù[]K™Ü˜X�Ø[ÜÜYYˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O›[Ù[]KœÜYY žˆBˆBˆ[ÙHYŠJ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JH +BˆˆÙ[‹O�™[ØÚ]KžH ˆB‚ˆ ËÈÙ][™ÈH[š[X][ۜȘ\ÙYÛˆH™[ØÚ]HÙ]X›Ý™BˆYŠÙ[‹O�™[ØÚ]KžÙ[‹O�™[ØÚ]KžŠBˆˆYŠ + +Ù[‹O�™[ØÚ]Kžˆ  ‰ˆÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +H +Ù[‹O�™[ØÚ]Kž  ‰ˆÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +JH ‰ˆ˜[Y[š[JÙ[‹S’WÑÔ�P��PÒÕÐSÊJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P��PÒÕÐSË +NˆBˆ[ÙHYŠÙ[‹O�™[ØÚ]Kžˆ  ‰ˆ˜[Y[š[JÙ[‹S’WÑÔ�P•ÐSÕT +JBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P•ÐSÕT  +NˆBˆ[ÙHYŠÙ[‹O�™[ØÚ]Kžˆˆ  ‰ˆ˜[Y[š[JÙ[‹S’WÑÔ�P•ÐSÑÕÓŠJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P•ÐSÑÕÓ‹ +NˆBˆ[ÙBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P•ÐSË +NˆBˆYŠÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•ÐSÕTH ‰ˆ˜[Y[š[JÝ\‹S’WÑÔ�P�‘QÐSÕT +JBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘QÐSÕT  +NˆBˆ[ÙHYŠÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P•ÐSÑÕÓ—H ‰ˆ˜[Y[š[JÝ\‹S’WÑÔ�P�‘QÐSÑÕÓŠJBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘QÐSÑÕÓ‹ +NˆBˆ[ÙHYŠÙ[‹O˜[š[X][ÛˆOHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÑÔ�P��PÒÕÐS×H ‰ˆ˜[Y[š[JÝ\‹S’WÑÔ�P�‘Q�PÒÕÐSÊJBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘Q�PÒÕÐSË +NˆBˆ[ÙHYŠ˜[Y[š[JÝ\‹S’WÑÔ�P�‘QÐSÊJBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘QÐSË +NˆBˆ[ÙHYˆ +˜[Y[š[JÝ\‹S’WÑÔ�P�‘Q +JBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘Q  +NˆBˆ[ÙBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÔRS‹ +NˆBˆBˆ[ÙBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÑÔ�P‹ +NˆYˆ +˜[Y[š[JÝ\‹S’WÑÔ�P�‘Q +JBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÑÔ�P�‘Q  +NˆBˆ[ÙBˆˆ[�ÜÙ]Ø[š[JÝ\‹S’WÔRS‹ +NˆBˆBˆ ËÈ\ÙHÚXÚ×Û[š×Û[Ý™HÈÙ]™[ØÚ]KÛ‰ÝÚ[™ÙH]\™BˆÝ\‹O�™[ØÚ]KžˆHÝ\‹O�™[ØÚ]KžH ˆÙ[‹O™Ü˜X�Ø[Ú[™ÈH NˆB‚ˆYŠÙ[‹O˜]XÚÚ[™ÈOHUPÒÒS‘×Ó“Ó‘JBˆˆÙ[‹Oœ™[X\Ù][YHHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È ŠNÈ ËÈ™\Ù]™[X\Ù][YHÚ[ˆÈÛÛ\Ú[Û‚ˆBŸB‚�›ÚY^Y\—ÝØ[ÛÙ™—ØÚXÚÊ +BžÂˆ Ê‚ˆ +ˆ\›‹ˆˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—ÕT“ŠBˆˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆB‚ˆ Ê‚ˆ +ˆÝÜ ˆYˆ›ÝÛ[™ÈHY�Ü‚ˆ +ˆšYÚÙ^KÚ[Üš^›Û�[[ÛY[�[K‚ˆ +‹ÂˆYˆ +Ù[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—ÖÔÕÔ +BˆˆYˆ +J^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +JJBˆˆYˆ +Ù[‹O�™[ØÚ]KžOH +BˆˆÙ[‹O�™[ØÚ]Kž +�HRT—ÐÓÓ•“ÓÔÕÔÑ�PÕԎˆBˆBˆB‚ˆ Ê‚ˆ +ˆˆÝÜ ˆYˆ›ÝÛ[™È[ˆ\Ü‚ˆ +ˆÝÛˆÙ^KÚ[]\˜[[ÛY[�[K‚ˆ +‹ÂˆYˆ +Ù[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—Ö—ÔÕÔ +BˆˆYˆ +J^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓŠJJBˆˆYˆ +Ù[‹O�™[ØÚ]KžˆOH +BˆˆÙ[‹O�™[ØÚ]Kžˆ +�HRT—ÐÓÓ•“ÓÔÕÔÑ�PÕԎˆBˆBˆB‚ˆ ʈÜš^›Û�[[Ý™HÛÛ�›Û +Yˆ[™XYH[Ýš[™ÊKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—ÖÐQ•TÕ +H ËÛ[Ý™OˆˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆÙ[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O�™[ØÚ]KžˆBˆB‚ˆ ʈÜš^›Û�[[Ý™HÛÛ�›Û +[žHØ[ÛÙ™ŠKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—ÖÓSÕ‘JBˆˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆÙ[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O�™[ØÚ]KžˆB‚ˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆ +\Ù[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]Kž OHÙ[‹O›[Ù[]KœÜYY žˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆ +\Ù[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O›[Ù[]KœÜYY žˆBˆB‚ˆ ʈˆ[Ý™HÛÛ�›Û +Yˆ[™XYH[Ýš[™ÊKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—Ö—ÐQ•TÕ +BˆˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆÙ[‹O�™[ØÚ]Kžˆˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆÙ[‹O�™[ØÚ]Kžˆ +JBˆˆÙ[‹O�™[ØÚ]KžˆH \Ù[‹O�™[ØÚ]KžŽÂˆBˆB‚ˆ ʈˆ[Ý™HÛÛ�›Û +[žHØ[ÛÙ™ŠKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÕÐSÓÑ‘—Ö—ÓSÕ‘JBˆÈˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆ +\Ù[‹O�™[ØÚ]KžŠJBˆˆÙ[‹O�™[ØÚ]Kžˆ OH + �H +ˆÙ[‹O›[Ù[]KœÜYY ž +NˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆ +\Ù[‹O�™[ØÚ]KžŠJBˆˆÙ[‹O�™[ØÚ]KžˆH + �H +ˆÙ[‹O›[Ù[]KœÜYY ž +NˆBˆB‚ˆ™]\›ŽÂŸB‚�›ÚY^Y\—Ú�[\ØÚXÚÊ +BžÂˆ[�Ø[™ÜÜXÚX[H ‚ˆ ËÈܘ]\È + L LŒ ŒJHš^YH›ØZ\˜Ø[˜Ù[�[˜Ý[Û‚ˆ ËÈ›ÝÈH›YÈŒˆˆÛÜšÜÈ\È[�[™Y[™ÛÛ\][H\ØX›\ÈHØ[˜Ù[][Ûˆ™]ÙY[ˆ[�[\[™È]XÚ܈ ËÈ[ˆH™]š[Ý\ÈÛÙK›Ý›YÜÈ H[™ ˆ]™HHØ[YHY™™XÝ[™[ÝÈHØ[˜Ù[][ÛˆY�\ˆ\Ý�[\]XÚÈ\Èš[š\ÚYˆYŠ +[›ØZ\˜Ø[˜Ù[ +H +›ØZ\˜Ø[˜Ù[ ŒH ‰ˆ\Ù[‹O˜[š[X][™ÊH +›ØZ\˜Ø[˜Ù[ ŒÈ ‰ˆ +Ù[‹O˜[š[[�[HOHÙ[‹Oš�[\ ˜[š[X][Û—ÚY +JJBˆˆ ËØZ\ˆÜXÚX[ ÛÜYY[™Ú[™ÙYœ›ÛH�YÝYIÜÈÛÙBˆYŠ +[]™[ O››ÜÜXÚX[]™[ O››ÜÜXÚX[OH ÊH ‰ˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÔÔPÒPS +BˆˆYŠ˜[Y[š[JÙ[‹S’WÒ•STÔPÒPS +JBˆˆ ËÈܘ]\È + L LŒ ŒJH›ÜˆØY™KYY[ˆ™]ÈÝ\ÈÚXÚÈYˆH[�]H\È›Ý[ˆHš�[\ÜXÚX[ˆ[š[X][Û‚ˆ ËÈš^\ÈH�YÈ]ÛÛœÝ[�HÛÛœÝ[Y\ÈX[܈\YˆHÜXÚX[�]Ûˆ\ÈÛÛœÝ[�H™\ÜÙY ]™[ˆY‚ˆ ËÈHÝ\œ™[�š�[\ÜXÚX[ˆ[š[X][ÛˆÞXÛH\țݚ[š\ÚYY]ˆYŠÙ[‹O˜[š[[�[HOHS’WÒ•STÔPÒPS +BˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÒ•STÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ ‰ˆÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÒ•STÔPÒPS +JBˆˆ ËÈܘ]\È + L LŒ ŒJH›ÝÈHš[™š[š]HX[ÚX]ˆÚ[Û›HÛÜšÈÚ[ˆHÛÜÝ\ÈPS Ú[›ÝÛÜšÈÚ[ˆHÛÜÝ\ÈT[ž[[Ü™BˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÒ•STÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈Ø[™ÜÜXÚX[H NˆBˆ[ÙHYŠÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÒ•STÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜÝ ‰ˆÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÒ S’WÒ•STÔPÒPS +JBˆˆYŠJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÒPSÐPÕU‘JJBˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÒ•STÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆØ[™ÜÜXÚX[H NˆBˆ[ÙHYŠ˜[Y[š[JÙ[‹S’WÒ•STÐS• +JBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STÐS•  +NˆÙ[‹O�™[ØÚ]KžHH ˆBˆB‚ˆYŠØ[™ÜÜXÚX[ +Bˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÔÔPÒPSˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘N‚ˆ ËÈܘ]\È + L LŒ ŒJHYHÜ[ÛˆÈÚ[܈›ÝH^ˆ[Ý™[Y[�ˆ ËÈܘ]\È + LŒ ŒŠHZ[›Üˆš^ÛˆH�[\ÜXÚX[ÛÙBˆYŠJÙ[‹O›[Ù[]Kš�[\ÜXÚX[ ˆ JJBˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH È ËÈÚ[[Ý™[Y[�Ú[ˆHÜXÚX[Ý\�ˆÙ[‹O�™[ØÚ]KžHH ˆB‚ˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STÔPÒPS  +NˆBˆBˆKËÙ[™Ùˆ�[\ÜXÚX[‚ˆ ËÚ�[\]XÚÜË\ÝÛˆ›Ü�Ø\™›Ü›X[ ‹‹‹�ÙHÛ‰ÝÚXÚÈ[™\™ÞHÛÜ݈[ÙHYŠ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘N‚ˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆ˜[Y[š[JÙ[‹S’WÒ•STUPÒÌŠJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STUPÒÌ‹ +NˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆ˜[Y[š[JÙ[‹S’WÒ•STUPÒÌÊJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STUPÒÌË +NˆBˆ[ÙHYŠÙ[‹Oœ�[›š[™È ‰ˆ˜[Y[š[JÙ[‹S’WÔ•S’•STUPÒÊJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÔ•S’•STUPÒË +NÈ ËÈYYÛÈ[ˆ^˜HݛۙÈ�[\]XÚÈØ[ˆ™H^XÝ]YˆBˆ[ÙHYŠÙ[‹O�™[ØÚ]KžOH  ‰ˆ˜[Y[š[JÙ[‹S’WÒ•ST“Ô•ÐT‘ +JBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•ST“Ô•ÐT‘  +NÈ ËÈYˆ[Ýš[™È[™Ù] È\È]XÚˆBˆ[ÙHYŠ˜[Y[š[JÙ[‹S’WÒ•STUPÒÊJBˆˆ[�ÜÙ]Ø[š[JÙ[‹S’WÒ•STUPÒË +NˆBˆKËÙ[™Ùˆ�[\]XÚˆB‚ˆ ʈˆ +ˆ�[\ZYÚÛÛ�›Û ˆÝÜš\Ú[™ÈYˆ�[\ˆ +ˆÙ^H\È[˜XÝ]™K‚ˆ +‹ÂˆYˆ +Ù[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖWÔÕÔ +BˆˆYˆ +J^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×Ò•ST +JBˆˆYˆ +Ù[‹O�™[ØÚ]KžHˆ +BˆˆÙ[‹O�™[ØÚ]KžH +�HRT—ÐÓÓ•“ÓÔÕÔÑ�PÕԎˆBˆBˆB‚ˆ ʈˆ +ˆ�[\ÝÜ ˆYˆ›ÝÛ[™ÈHY�Ü‚ˆ +ˆšYÚÙ^KÚ[Üš^›Û�[[ÛY[�[K‚ˆ +‹ÂˆYˆ +Ù[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖÔÕÔ +BˆˆYˆ +J^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +JJBˆˆYˆ +Ù[‹O�™[ØÚ]KžOH +BˆˆÙ[‹O�™[ØÚ]Kž +�HRT—ÐÓÓ•“ÓÔÕÔÑ�PÕԎˆBˆBˆB‚ˆ Ê‚ˆ +ˆ�[\ˆÝÜ ˆYˆ›ÝÛ[™È[ˆ\Ü‚ˆ +ˆÝÛˆÙ^KÚ[]\˜[[ÛY[�[K‚ˆ +‹ÂˆYˆ +Ù[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖ—ÔÕÔ +BˆˆYˆ +J^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓŠJJBˆˆYˆ +Ù[‹O�™[ØÚ]KžˆOH +BˆˆÙ[‹O�™[ØÚ]Kžˆ +�HRT—ÐÓÓ•“ÓÔÕÔÑ�PÕԎˆBˆBˆB‚ˆ ʈ�[\\›ˆÛÛ�›Û ˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÕT“ŠBˆˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆB‚ˆ ʈ�[\Üš^›Û�[[Ý™HÛÛ�›Û +Yˆ[™XYH[Ýš[™ÊKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖÐQ•TÕ +BˆˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆÙ[‹O�™[ØÚ]Kžˆ  +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆÙ[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O�™[ØÚ]KžˆBˆBˆˆ ʈ�[\Üš^›Û�[[Ý™HÛÛ�›Û +[žH�[\ +Kˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖÓSÕ‘JBˆÈˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆÙ[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžH \Ù[‹O�™[ØÚ]KžˆB‚ˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H ‰ˆ +\Ù[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]Kž OHÙ[‹O›[Ù[]KœÜYY žˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +H ‰ˆ +\Ù[‹O�™[ØÚ]Kž +JBˆˆÙ[‹O�™[ØÚ]KžHÙ[‹O›[Ù[]KœÜYY žˆBˆBˆˆ ʈ�[\ˆ[Ý™HÛÛ�›Û +Yˆ[™XYH[Ýš[™ÊKˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖ—ÐQ•TÕ +BˆˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆÙ[‹O�™[ØÚ]Kžˆˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆÙ[‹O�™[ØÚ]Kžˆ +JBˆˆÙ[‹O�™[ØÚ]KžˆH \Ù[‹O�™[ØÚ]KžŽÂˆBˆB‚ˆ ʈ�[\ˆ[Ý™HÛÛ�›Û +[žH�[\ +Kˆ +‹ÂˆYŠÙ[‹O›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖ—ÓSÕ‘JBˆˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆB‚ˆYŠ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆÙ[‹O�™[ØÚ]Kžˆˆ +Hˆ + +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆÙ[‹O�™[ØÚ]Kžˆ +JBˆˆÙ[‹O�™[ØÚ]KžˆH \Ù[‹O�™[ØÚ]KžŽÂˆB‚ˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰ˆ +\Ù[‹O�™[ØÚ]KžŠJBˆˆÙ[‹O�™[ØÚ]Kžˆ OH + �H +ˆÙ[‹O›[Ù[]KœÜYY ž +NˆBˆ[ÙHYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆ +\Ù[‹O�™[ØÚ]KžŠJBˆˆÙ[‹O�™[ØÚ]KžˆH + �H +ˆÙ[‹O›[Ù[]KœÜYY ž +NˆBˆB‚ˆ™]\›ŽÂŸB‚�›ÚY^Y\—ÜZ[—ØÚXÚÊ +BžÂˆYŠ^Y\—ØÚXÚ×ÜÜXÚX[ + +JBˆˆÙ[‹Oš[œZ[ˆHS—ÔRS—Ó“Ó‘NˆÙ[‹Oœš\Ú[™ÈH’TÒS‘×Ó“Ó‘NˆÙ[‹O™XÚÚ[™ÈHPÒ×Ó“Ó‘NˆÙ[‹Oš[˜˜XÚÜZ[ˆH ˆBŸB‚‹ËÈÚXÚÈš\ÙX]XÚÈ[œ]\ +Ø]XÚÂ�›ÚY^Y\—ÛYWØÚXÚÊ +BžÂˆYŠ˜[Y[š[JÙ[‹S’WÔ’TÑPUPÒÊH ‰‚ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰‚ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘UT +H ‰‚ˆ +Ù[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ  ‰ˆÝ[YHˆÙ[‹OœÝ^YÝÛ‹œš\ÙX]XÚ×ÜÝ[ +JBˆˆ^Y\–ÜÙ[‹Oœ^Y\š[™^Kœ^ZÙ^\È �H‘“Q×ÐUPÒΈYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆYŠ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆÙ[‹O™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆÙ[‹OœÝ[[YHH ˆÙ]Üš\ÙX]XÚÊÙ[‹Ù[‹O›\ÝÙ[XYÙWÝ\K +NˆBŸB‚�›ÚY^Y\—ØÚ\™ÙWØÚXÚÊ +BžÂˆYŠJ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×Ò•ST +H ‰‚ˆ +^Y\–ÜÙ[‹Oœ^Y\š[™^KšÙ^\È ˆ“Q×ÔÔPÒPS +JJBˆˆÙ[‹O�ZÙXXÝ[ÛˆH•SˆÙ[‹O˜Ú\™Ú[™ÈH ˆÙ]ÚYJÙ[ŠNˆBŸB‚‹ËÈXZÙHH�[˜Ý[ÛˆÛÈ[™[ZY\ÈØ[ˆ\ÙB‹ËÈUˆ�[\XÚÈ\ÈH[\ܘ\žHš^›Üˆ�[\Ø[˜Ù[š[�ÚXÚרÛÜÝ[Ý™J[�Ë[�œË[��[\XÚÊBžÂˆYŠ + +œÈOH H ‰ˆ]™[ O››ÜÜXÚX[ ŠH +œÈOH  ‰ˆ]™[ O››ÜÜXÚX[OH +H +œÈOH  ‰ˆ]™[ O››ÜÜXÚX[OH ÊJH ‰‚ˆ +ÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÒ ÊHˆÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT ÊJH +BˆˆYŠZ�[\XÚÊBˆˆÙ[‹O�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆBˆ ËÈܘ]\È + L LŒ ŒJH›ÝÈHš[™š[š]HX[ÚX]ˆY™™XÝÈ^Y\œÈÛ›K›Ý[™[ZY\È܈œˆ ËÈ[™›ÝÈHš[™š[š]HX[ÚX]ˆÚ[Û›HÛÜšÈÚ[ˆHÛÜÝ\ÈPS Ú[›ÝÛÜšÈÚ[ˆHÛÜÝ\ÈT[ž[[Ü™BˆYŠÙ[‹O›[Ù[]K�\H ˆTWÔVQTŠBˆˆYŠ[›ØÛÜÝ +BˆˆYŠJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÒPSÐPÕU‘JJBˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT ÊJBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜ݈Bˆ[ÙBˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆ[ÙBˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT ÊJBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆBˆBˆ[ÙBˆˆYŠ[›ØÛÜÝ +BˆˆYŠÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜÝ +BˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT ÊJBˆˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜ݈Bˆ[ÙBˆˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–Ü×KO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆBˆBˆB‚‚B\Ù[‹Oœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆÙ]Ø]XÚÚ[™ÊÙ[ŠNˆÙ[‹Oš[œZ[ˆHS—ÔRS—Ó“Ó‘NˆÙ[‹Oœš\Ú[™ÈH’TÒS‘×Ó“Ó‘NˆÙ[‹Oš[˜˜XÚÜZ[ˆH ˆY[\Ù] +Ù[‹O˜ÛÛX›ÜÝ\  Ú^™[ÙŠ +œÙ[‹O˜ÛÛX›ÜÝ\ +H +ˆ JNˆ[�Ý[›[šÊÙ[ŠNˆ[�ÜÙ]Ø[š[JÙ[‹Ë +Nˆ™]\›ˆ NˆBˆ™]\›ˆ ŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚Šˆ™XÛÜ™HÝ\�[™È[YH›Üˆ]™\žH™]ÛH™\ÜÙYŠˆÛÛ[X[™[œ]›YË‚Š‚Šˆ\ÚXØ[[™\™XÝ[Û‹\™[]]™H›YÜÈÚ\™HHØ[YBŠˆ � Xš]˜[Y\ÜXÙKˆ\Ú[™ÈH›YÉÜÈš][™^›ÝšY\ŠˆÛ[Z[™ÈÚ]Ý]H\˜[[ÛÛ[X[™ Z\ÝÜžHš[™Ë‚Š‹ÂœÝ]XÈ›ÚYÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý\]Jˆ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆÛÛœÝÙ^WÛX\Ú×Ý™\ÜÙYÙ›YÜˈÛÛœÝZ[� �Ý]™[�Ý[YBŠHˆÙ^WÛX\Ú×ÝØØ[—ÛX\ÚÈH™\ÜÙYÙ›YÜ΂ˆÚ[JØØ[—ÛX\ÚÊHˆÛÛœÝZ[� �Ý[œ]Ú[™^Bˆš]X\ÚÍ�ÙÙ]ÛÝÙ\ÝÚ[™^ +ØØ[—ÛX\ÚÊN‚ˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÈBˆš]X\ÚÍ�Ùœ›ÛWÚ[™^ +[œ]Ú[™^ +N‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YVˆ[œ]Ú[™^ˆHH]™[�Ý[YN‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�ݘ[YBˆ[œ]Ù›Y΂ˆ Ê‚ˆ +ˆH™]È™\ÜÈ™YÚ[œÈH™]ÈÛÛ�[�[Ý\ÈÛ ˆÛX\‚ˆ +ˆH]]ÛX]XË]šYÙÙ\ˆ™XÛÜ™ÛÈ[YH™\›ÈØ[‚ˆ +ˆšYÙÙ\ˆYØZ[ˆ›ÜˆH™]ÈÛ ‚ˆ +‹ÂˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ݘ[Y �Bˆš[œ]Ù›Y΂ˆØØ[—ÛX\ÚÈ �Hš[œ]Ù›YΈBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚ŠˆÛÛXÝ]]ÛX]XÈ[ Z[œ]YÙ\ÈÚXÚ™XXÚZ\‚ŠˆÛÛ™šYÝ\™Y™\ÚÛÛˆ\ÈÙÚXØ[XÚË‚Š‚Šˆ™\ÚÛÈÛÛYHœ›ÛHHXÝ[™È[�]IÜÈÛÛ™šYÝ\˜X›BŠˆÜXÚX[ÛÛ[X[™ˈH\‹Z[œ][Y\Ý[\™]™[�ÈBŠˆÙXÛÛ™[œ]™Yœ™\Ú\š[™ÈHØ[YHXÚÈœ›ÛH[Z][™ÂŠˆHØ[YHYÙHYØZ[‹ˆY™™\™[�™\ÚÛț܈HØ[YBŠˆ[œ]™[XZ[ˆ[™\[™[�™XØ]\ÙHXXÚ\È™XXÚYÛˆBŠˆY™™\™[�ÙÚXØ[XÚÈ\š[™ÈÛ™HÛÛ�[�[Ý\ÈÛ ‚Š‹ÂœÝ]XÈÙ^WÛX\Ú×ÝÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ØÛÛXÝ +ˆ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆÛÛœÝÙ^WÛX\Ú×Ý[Ù›YÜˈÛÛœÝZ[� �Ý]™[�Ý[YBŠHˆÛÛœÝ[�]JˆXÝ[™×Ù[�]N‚ˆÙ^WÛX\Ú×ÝÛÛXÝYÙ›YÜÈH ‚ˆ[�ÜXÚX[Ú[™^‚ˆYŠXXÝ[™×Ü^Y\ˆXXÝ[™×Ü^Y\‹O™[� +Hˆ™]\›ˆ ˆB‚ˆXÝ[™×Ù[�]HHXÝ[™×Ü^Y\‹O™[�‚ˆ›ÜŠÜXÚX[Ú[™^H ˆÜXÚX[Ú[™^XÝ[™×Ù[�]KO›[Ù[]KœÜXÚX[×ÛØYYˆÜXÚX[Ú[™^ +ÊÊH‚ˆÛÛœÝרÛÛJˆÜXÚX[ØÛÛ[X[™Bˆ ˜XÝ[™×Ù[�]KO›[Ù[]KœÜXÚX[ÜÜXÚX[Ú[™^N‚ˆ[�Ý\Ú[™^‚ˆYŠÜXÚX[ØÛÛ[X[™ OœÝ\ÈH ˆÜXÚX[ØÛÛ[X[™ OœÝ\ȈPVÔÔPÒPSÒS”UÊHˆÛÛ�[�YNˆB‚ˆ›ÜŠÝ\Ú[™^H ˆÝ\Ú[™^ÜXÚX[ØÛÛ[X[™ OœÝ\ΈÝ\Ú[™^ +ÊÊH‚ˆÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\ +ˆ[œ]ÜÝ\Bˆ œÜXÚX[ØÛÛ[X[™ Oš[œ]ÜÝ\Ú[™^N‚ˆÙ^WÛX\Ú×ÝØØ[—ÛX\ÚÈBˆ[œ]ÜÝ\ OšÛÝšYÙÙ\ˆ ˆ[Ù›YÜ΂ˆÚ[JØØ[—ÛX\ÚÊHˆÛÛœÝZ[� �Ý[œ]Ú[™^Bˆš]X\ÚÍ�ÙÙ]ÛÝÙ\ÝÚ[™^ +ØØ[—ÛX\ÚÊN‚ˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÈBˆš]X\ÚÍ�Ùœ›ÛWÚ[™^ +[œ]Ú[™^ +N‚ˆÛÛœÝZ[� �ÝÛÜÝ\�Ý[YHBˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YVˆ[œ]Ú[™^ˆN‚ˆÛۜݛÛÛ[™XYWÙ[Z]YÝ\×ÝXÚÈBˆ +XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ݘ[Yˆ ˆ[œ]Ù›YÊBˆ ‰ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—Ý[YVˆ[œ]Ú[™^ˆHOH]™[�Ý[YN‚ˆYŠ +XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�ݘ[Yˆ ˆ[œ]Ù›YÊBˆ ‰ˆÛÜÝ\�Ý[YHH]™[�Ý[YBˆ ‰ˆ]™[�Ý[YH HÛÜÝ\�Ý[YBˆOH[œ]ÜÝ\ OšÛÝ[YBˆ ‰ˆX[™XYWÙ[Z]YÝ\×ÝXÚÊH‚ˆÛÛXÝYÙ›YÜÈH[œ]Ù›YΈB‚ˆØØ[—ÛX\ÚÈ �Hš[œ]Ù›YΈBˆBˆB‚ˆ Ê‚ˆ +ˆ™XÛÜ™[Z]Y›YÜÈÛ›HY�\ˆØØ[›š[™È]™\žBˆ +ˆÛÛ[X[™ ˆÛÛ[X[™ÈÚ\š[™ÈHØ[YH[œ][™ˆ +ˆ™\ÚÛ[X™\˜][HÚ\™HÛ™H\ÝÜžHYÙK‚ˆ +‹ÂˆˆÙ^WÛX\Ú×ÝØØ[—ÛX\ÚÈHÛÛXÝYÙ›YÜ΂ˆÚ[JØØ[—ÛX\ÚÊHˆÛÛœÝZ[� �Ý[œ]Ú[™^Bˆš]X\ÚÍ�ÙÙ]ÛÝÙ\ÝÚ[™^ +ØØ[—ÛX\ÚÊN‚ˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÈBˆš]X\ÚÍ�Ùœ›ÛWÚ[™^ +[œ]Ú[™^ +N‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—Ý[YVˆ[œ]Ú[™^ˆHH]™[�Ý[YN‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ݘ[YBˆ[œ]Ù›Y΂ˆØØ[—ÛX\ÚÈ �Hš[œ]Ù›YΈBˆB‚ˆ™]\›ˆÛÛXÝYÙ›YÜΟB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚Šˆ\[™Û™H]™[�ÈH^Y\‰ÜÈÛÛ[X[™\ÝÜžK‚Š‹ÂœÝ]XÈ›ÚYÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ\Ú +×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[� +HˆˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžVØXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^HH +š[œ]Ù]™[�‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^H +XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^ +È JH ˆÔPÒPSÒS”UÒS‘VÓPTÒ΂ˆYŠXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�PVÔÔPÒPSÒS”UÊHˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[� +ÊΈBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚ŠˆÛÛœÝ[YHH™]Ù\Ý™\ÜÈYÙHœ›ÛHH^Y\‰ÜÈÛÛ[X[™Šˆ\ÝÜžK‚Š‚ŠˆÙ]™\˜[\™ XÛÙY[Ý™[Y[�ÛÛ[X[™ÈÛÛœÝ[YHZ\‚ŠˆšYÙÙ\š[™È™\ÜˈHÛÛXš[™Y]™[�X^H[ÛÈÛÛ�Z[ˆBŠˆ™[X\ÙH܈]]ÛX]XÈÛYÙKÛÈÛ›H™[[Ý™HBŠˆÛÛ\]H[�žHÚ[ˆ›ÈÝ\ˆYÙH™[XZ[œË‚Š‹ÂœÝ]XÈ›ÚYÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\Üʈ×Ü^Y\ŠˆXÝ[™×Ü^Y\‚ŠHˆרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆZ[� �Ý[œ]Ú[™^‚ˆYŠXXÝ[™×Ü^Y\ˆXXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[� +Hˆ™]\›ŽÂˆB‚ˆ[œ]Ú[™^Bˆ +XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^ H JBˆ ˆÔPÒPSÒS”UÒS‘VÓPTÒ΂ˆ[œ]Ù]™[�Bˆ ˜XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžVˆ[œ]Ú[™^ˆN‚ˆ[œ]Ù]™[� Oœ™\ÜÈH ˆ[œ]Ù]™[� Oœ™\ÜרÚÜ™H ‚ˆYŠ[œ]Ù]™[� OšÛ[œ]Ù]™[� Oœ™[X\ÙJHˆ™]\›ŽÂˆB‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^H[œ]Ú[™^‚ˆY[\Ù] +[œ]Ù]™[�  Ú^™[ÙŠ +š[œ]Ù]™[� +JN‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[� KNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚ŠˆÛÛœÝ[YHÙ[XÝY]]ÛX]XÈ[ Z[œ]›YÜÈœ›ÛHBŠˆ]™[�ÚXÚšYÙÙ\™YHÛÛ™šYÝ\˜X›HÛÛ[X[™ ‚Š‚ŠˆÝ\ˆ›YÜÈ™[XZ[ˆ]˜Z[X›HÚ[ˆHØ[YH\ÝÜžBŠˆ[�žH[ÛÈÛÛ�Z[œÈH™\ÜË™[X\ÙK܈[›Ý\ˆ[ŠˆYÙKˆ[\H›Û‹[]\Ý[�šY\ÈÝ^H[ˆXÙHÛÈš[™ÂŠˆÜ™\ˆ[™ÝÜ™Y]™[�YÙ\ÈțݙYYÛÛ\XÝ[Û‹‚Š‹ÂœÝ]XÈ›ÚYÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÚÛÝšYÙÙ\Šˆ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆÛÛœÝZ[� �Ý]™[�ØYÙKˆÛÛœÝÙ^WÛX\Ú×ÝšYÙÙ\—Ù›YÜŠHˆרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆZ[� �Ý[œ]Ú[™^‚ˆYŠXXÝ[™×Ü^Y\‚ˆ]šYÙÙ\—Ù›Y܈]™[�ØYÙH�HXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[� +Hˆ™]\›ŽÂˆB‚ˆ[œ]Ú[™^Bˆ +XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^ H]™[�ØYÙH H JBˆ ˆÔPÒPSÒS”UÒS‘VÓPTÒ΂ˆ[œ]Ù]™[�Bˆ ˜XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžVÚ[œ]Ú[™^N‚ˆ[œ]Ù]™[� OšÛ �H�šYÙÙ\—Ù›YÜ΂ˆYŠ[œ]Ù]™[� Oœ™\܈[œ]Ù]™[� OšÛˆ[œ]Ù]™[� Oœ™[X\ÙBˆ]™[�ØYÙJHˆ™]\›ŽÂˆB‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^H[œ]Ú[™^‚ˆY[\Ù] +[œ]Ù]™[�  Ú^™[ÙŠ +š[œ]Ù]™[� +JN‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[� KNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚Šˆ™XYH™XÙY[™È˜[Y]™[�œ›ÛHH^Y\‰ÜŠˆÛÛ[X[™\ÝÜžK‚Š‹ÂœÝ]XÈÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\ʈÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆZ[� �Ý +ˆ\ÝÜžWÚ[™^ ˆZ[� �Ý +ˆ™[XZ[š[™×Ù]™[�ŠHˆYŠJœ™[XZ[š[™×Ù]™[�ÊHˆ™]\›ˆ•SˆB‚ˆ +š\ÝÜžWÚ[™^Bˆ + +š\ÝÜžWÚ[™^ H JH ˆÔPÒPSÒS”UÒS‘VÓPTÒ΂ˆ + +œ™[XZ[š[™×Ù]™[�ÊKKN‚ˆ™]\›ˆ ˜XÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžVˆ +š\ÝÜžWÚ[™^ˆNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚Šˆ™XYH™XÙY[™È™\ÜÈ]™[�œ›ÛHH^Y\‰ÜŠˆÛÛ[X[™\ÝÜžK‚Š‚Šˆ›Û‹\™\ÜÈ[�šY\È\™HÚÚ\YÛÈ™[X\ÙH[™[YYŠˆÛ]™[�ÈØ[ˆ™HYYÚ]Ý]Ú[™Ú[™ÈYØXÞBŠˆ\™ XÛÙYÛÛ[X[™™Z]š[Ü‹‚Š‹ÂœÝ]XÈÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×Ü™\ÜʈÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆZ[� �Ý +ˆ\ÝÜžWÚ[™^ ˆZ[� �Ý +ˆ™[XZ[š[™×Ù]™[�ŠHˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆÚ[J +[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\ʈXÝ[™×Ü^Y\‹ˆ\ÝÜžWÚ[™^ ˆ™[XZ[š[™×Ù]™[�ˆ +JJH‚ˆYŠ[œ]Ù]™[� Oœ™\ÜÊHˆ™]\›ˆ[œ]Ù]™[�ˆBˆB‚ˆ™]\›ˆ•SŸB‚‹Ê‚ŠˆÚXÚÈÚ]\ˆH^Y\‰ÜÈ[ÜÝ™XÙ[�™\ÜŠˆ]™[�ÈØ]\ÙžHH\™ XÛÙYÛÛ[X[™Ù\]Y[˜ÙK‚Š‚ŠˆXXÚÙ\]Y[˜ÙH[�žH\ÈHš]X\ÚÈÙˆ™\]Z\™YŠˆ[œ]ˈH™XÛÜ™Y™\ÜÈX^HÛÛ�Z[ˆY][Û˜[Šˆ›YÜÈ[™Ý[X]Ú ‚Š‚Šˆ™[X\ÙH[™[YYÛ]™[�È\™H[X™\˜][BŠˆYۛܙYÛÈ^\Ý[™È\™ XÛÙYÛÛ[X[™È™]Z[‚ŠˆZ\ˆÜÚ]]™KYYÙH™Z]š[Ü‹‚Š‹ÂœÝ]XÈ›ÛÛX]ÚØÛÛX›ÊÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙV×KÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ÛÛœÝZ[� �Ý[™Ý +HˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆZ[� �Ý\ÝÜžWÚ[™^ˆZ[� �Ý™]Ù\—Ù]™[�Ý[YNˆZ[� �Ý™[XZ[š[™×Ù]™[�ΈZ[� �ÝÙ\]Y[˜ÙWÚ[™^‚ˆYŠ\Ù\]Y[˜ÙBˆXXÝ[™×Ü^Y\‚ˆ[[™Ýˆ[™ÝˆPVÔÔPÒPSÒS”UÊHˆ™]\›ˆ˜[ÙNˆB‚ˆ\ÝÜžWÚ[™^HXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^ˆ™]Ù\—Ù]™[�Ý[YHHÝ[YNˆ™[XZ[š[™×Ù]™[�ÈHXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�‚ˆ›ÜŠÙ\]Y[˜ÙWÚ[™^H[™ÝˆÙ\]Y[˜ÙWÚ[™^ˆ ˆÙ\]Y[˜ÙWÚ[™^ KJH‚ˆÛÛœÝÙ^WÛX\Ú×Ý™\]Z\™YÜ™\ÜÈBˆÙ\]Y[˜ÙVÜÙ\]Y[˜ÙWÚ[™^ H WN‚ˆ[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×Ü™\ÜʈXÝ[™×Ü^Y\‹ˆ š\ÝÜžWÚ[™^ ˆ œ™[XZ[š[™×Ù]™[�ˆ +N‚ˆYŠZ[œ]Ù]™[�ˆ +[œ]Ù]™[� Oœ™\ÜÈ ˆ™\]Z\™YÜ™\ÜÊBˆOH™\]Z\™YÜ™\܈™]Ù\—Ù]™[�Ý[YH H[œ]Ù]™[� O�[YBˆˆÛؘ[ØÛÛ™šY˘ÛÛ[X[™Ý[YJHˆ™]\›ˆ˜[ÙNˆB‚ˆ™]Ù\—Ù]™[�Ý[YHH[œ]Ù]™[� O�[YNˆB‚ˆ™]\›ˆ�YNŸB‚‹Ê‚Šˆ™]\›ˆHܘXÙH[YH\ÙYžHÛ™HÛÛ™šYÝ\˜X›HÛÛ[X[™ŠˆÙ\]Y[˜ÙKˆÛÛ[X[™ÈÚ]Ý][ˆ^XÚ]Ý™\œšYH[š\š]ŠˆH[™Ú[™K]ÚYHÙ][™È]X]Ú[YK‚Š‹ÂœÝ]XÈZ[� �ÝÛÛ[X[™ÜÙ\]Y[˜ÙWÙܘXÙWÝ[YWÙÙ] +ˆÛÛœÝרÛÛJˆÜXÚX[ØÛÛ[X[™ŠHˆ\ÜÙ\� +ÜXÚX[ØÛÛ[X[™ +N‚ˆ™]\›ˆÜXÚX[ØÛÛ[X[™ OœÙ\]Y[˜ÙWÙܘXÙWÝ[YWÛÝ™\œšYBˆÈÜXÚX[ØÛÛ[X[™ OœÙ\]Y[˜ÙWÙܘXÙWÝ[YBˆˆÛؘ[ØÛÛ™šY˘ÛÛ[X[™Ý[YNŸB‚‹Ê‚Šˆ™]\›ˆHÛ™Ù\ÝܘXÙH[YH™YYYžHHXÝ[™ÂŠˆ[�]IÜÈÛÛ™šYÝ\˜X›H[™\™ XÛÙYÛÛ[X[™Ë‚Š‚Šˆ[œ]\ÝÜžH\ÈÚ\™YžH]™\žHÛÛ[X[™ ˆ™]Z[š[™È]Šˆ›ÜˆHÛ™Ù\ÝÛÛ™šYÝ\™YܘXÙH™]™[�ÈHÛÛ[X[™ŠˆÚ]HÛ™Ù\ˆØØ[Ý™\œšYHœ›ÛHÜÚ[™È]ÈX\›Y\‚ŠˆÝ\ÈÈHÛؘ[\ÝÜžH[Y[Ý] ‚Š‹ÂœÝ]XÈZ[� �ÝÛÛ[X[™Ú[œ]Ú\ÝÜžWÙܘXÙWÝ[YWÙÙ] +ˆÛÛœÝ[�]JˆXÝ[™×Ù[�]BŠHˆZ[� �Ý\ÝÜžWÙܘXÙWÝ[YHHÛؘ[ØÛÛ™šY˘ÛÛ[X[™Ý[YN‚ˆ[�ÜXÚX[Ú[™^‚ˆYŠXXÝ[™×Ù[�]JHˆ™]\›ˆ\ÝÜžWÙܘXÙWÝ[YNˆB‚ˆ›ÜŠÜXÚX[Ú[™^H ˆÜXÚX[Ú[™^XÝ[™×Ù[�]KO›[Ù[]KœÜXÚX[×ÛØYYˆÜXÚX[Ú[™^ +ÊÊH‚ˆÛÛœÝרÛÛJˆÜXÚX[ØÛÛ[X[™Bˆ ˜XÝ[™×Ù[�]KO›[Ù[]KœÜXÚX[ÜÜXÚX[Ú[™^N‚ˆÛÛœÝZ[� �ÝÙ\]Y[˜ÙWÙܘXÙWÝ[YHBˆÛÛ[X[™ÜÙ\]Y[˜ÙWÙܘXÙWÝ[YWÙÙ] +ÜXÚX[ØÛÛ[X[™ +N‚ˆYŠÙ\]Y[˜ÙWÙܘXÙWÝ[YHˆ\ÝÜžWÙܘXÙWÝ[YJHˆ\ÝÜžWÙܘXÙWÝ[YHHÙ\]Y[˜ÙWÙܘXÙWÝ[YNˆBˆB‚ˆ™]\›ˆ\ÝÜžWÙܘXÙWÝ[YNŸB‚‹Ê‚Šˆ™]\›ˆHXœÛÛ]HÙÚXØ[XÚÈÚ[ˆÚ\™YÛÛ[X[™Šˆ\ÝÜžH^\™\ˈØ]\˜][Ûˆ™\Ù\�™\È^™[Y[H\™ÙBŠˆÜ™X]Ü‹YYš[™YܘXÙH˜[Y\ÈÚ]Ý]ܘ\[™ÈBŠˆ^\˜][Ûˆ[YH\›Ý[™ÈH™YÚ[›š[™ÈÙˆHÛØÚË‚Š‹ÂœÝ]XÈZ[� �ÝÛÛ[X[™Ú[œ]Ú\ÝÜžWÙ^\˜][Û—Ý[YWÙÙ] +ˆÛÛœÝ[�]JˆXÝ[™×Ù[�]KˆÛÛœÝZ[� �Ý]™[�Ý[YBŠHˆÛÛœÝZ[� �Ý\ÝÜžWÙܘXÙWÝ[YHBˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÙܘXÙWÝ[YWÙÙ] +XÝ[™×Ù[�]JN‚ˆYŠ\ÝÜžWÙܘXÙWÝ[YHˆRS• �ÓPV H]™[�Ý[YJHˆ™]\›ˆRS• �ÓPVˆB‚ˆ™]\›ˆ]™[�Ý[YH +È\ÝÜžWÙܘXÙWÝ[YNŸB‚‹Ê‚Šˆ™]\›ˆÚ]\ˆ[ˆ[œ]]™[�Ø]\ÙšY\ÈHÜÚ]]™BŠˆYÙH™\]Z\™[Y[�›ÜˆÛ™HÛÛ™šYÝ\˜X›HÛÛ[X[™Ý\ ‚Š‚ŠˆÚ[™ÛKZÙ^HÝ\È™]Z[ˆ^XÝYØXÞH™Z]š[܈[™\ÙBŠˆÛ›HH\ÚXØ[™\ÜÈYÙKˆ][KZÙ^HÝ\È\ÙHBŠˆÚܙۘ\ÚÝ[™Z\ˆÛÛ™šYÝ\™YÚÜ™Ý[YKˆ™\›ÂŠˆ™\]Z\™\È]™\žHY[X™\ˆÈ™YÚ[ˆÛˆHØ[YHÙÚXØ[XÚË‚Šˆ]X\ÝÛ™H™\]Z\™YÙ^H]\Ý™H\ÚXØ[H™\ÜÙY[‚ŠˆHšYÙÙ\š[™È]™[� ™]™[�[™È[ˆ[œ™[]Y\™Ù^BŠˆœ›ÛH™]šYÙÙ\š[™ÈHÚÜ™ÚXÚY\™[H™[XZ[œÈ[ ‚Š‹ÂœÝ]XÈ›ÛÛÛÛ[X[™Ú[œ]Ù]™[�ÛX]Ú\×Ü™\ÜʈÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\ +ˆ[œ]ÜÝ\ ˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[� ˆÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‚ŠHˆÛÛœÝÙ^WÛX\Ú×Ý™\]Z\™YÜ™\ÜÈH[œ]ÜÝ\ Oœ™\Ü΂ˆÙ^WÛX\Ú×ÝØØ[—ÛX\Ú΂ˆYŠ\™\]Z\™YÜ™\ÜÊHˆ™]\›ˆ�YNˆB‚ˆ Ê‚ˆ +ˆHX\ÚÈÚ]Û™HXÝ]™Hš]\È›ÈÙXÛÛ™š]Y�\‚ˆ +ˆ™[[Ýš[™È]ÈÝÙ\Ýš] ‚ˆ +‹ÂˆYŠJ™\]Z\™YÜ™\ÜÈ ˆ +™\]Z\™YÜ™\ÜÈ H JJJHˆ™]\›ˆ +[œ]Ù]™[� Oœ™\ÜÈ ˆ™\]Z\™YÜ™\ÜÊBˆOH™\]Z\™YÜ™\ÜΈB‚ˆYŠJ[œ]Ù]™[� Oœ™\ÜÈ ˆ™\]Z\™YÜ™\ÜÊBˆ +[œ]Ù]™[� Oœ™\ÜרÚÜ™ ˆ™\]Z\™YÜ™\ÜÊBˆOH™\]Z\™YÜ™\ÜÊHˆ™]\›ˆ˜[ÙNˆB‚ˆØØ[—ÛX\ÚÈH™\]Z\™YÜ™\Ü΂ˆÚ[JØØ[—ÛX\ÚÊHˆÛÛœÝZ[� �Ý[œ]Ú[™^Bˆš]X\ÚÍ�ÙÙ]ÛÝÙ\ÝÚ[™^ +ØØ[—ÛX\ÚÊN‚ˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÈBˆš]X\ÚÍ�Ùœ›ÛWÚ[™^ +[œ]Ú[™^ +N‚ˆÛÛœÝZ[� �Ý™\Ü×Ý[YHBˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YVˆ[œ]Ú[™^ˆN‚ˆYŠJXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�ݘ[Yˆ ˆ[œ]Ù›YÊBˆ™\Ü×Ý[YHˆ[œ]Ù]™[� O�[YBˆ[œ]Ù]™[� O�[YH H™\Ü×Ý[YBˆˆ[œ]ÜÝ\ O˜ÚÜ™Ý[YJHˆ™]\›ˆ˜[ÙNˆB‚ˆØØ[—ÛX\ÚÈ �Hš[œ]Ù›YΈB‚ˆ™]\›ˆ�YNŸB‚‹Ê‚Šˆ™]\›ˆÚ]\ˆ[ˆ[œ]]™[�Ø]\ÙšY\È]™\žH\ÜÚ]™BŠˆ[™]]ÛX]XÈ[™\]Z\™[Y[�›ÜˆÛ™HÛÛ[X[™Ý\ ‚Š‹ÂœÝ]XÈ›ÛÛÛÛ[X[™Ú[œ]Ù]™[�ÛX]Ú\×ÚÛ +ˆÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\ +ˆ[œ]ÜÝ\ ˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[� ˆÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‚ŠHˆÛÛœÝÙ^WÛX\Ú×Ý™\]Z\™YÚÛÙ›YÜÈBˆ[œ]ÜÝ\ OšÛ[œ]ÜÝ\ OšÛÝšYÙÙ\ŽÂ‚ˆÙ^WÛX\Ú×ÝØØ[—ÛX\Ú΂ˆYŠ\™\]Z\™YÚÛÙ›YÜÊHˆ™]\›ˆ�YNˆB‚ˆYŠ +[œ]Ù]™[� Oš[ ˆ™\]Z\™YÚÛÙ›YÜÊBˆOH™\]Z\™YÚÛÙ›YÜÊHˆ™]\›ˆ˜[ÙNˆB‚ˆØØ[—ÛX\ÚÈH™\]Z\™YÚÛÙ›YÜ΂ˆÚ[JØØ[—ÛX\ÚÊHˆÛÛœÝZ[� �Ý[œ]Ú[™^Bˆš]X\ÚÍ�ÙÙ]ÛÝÙ\ÝÚ[™^ +ØØ[—ÛX\ÚÊN‚ˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÈBˆš]X\ÚÍ�Ùœ›ÛWÚ[™^ +[œ]Ú[™^ +N‚ˆÛÛœÝZ[� �ÝÛÜÝ\�Ý[YHBˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YVˆ[œ]Ú[™^ˆN‚ˆYŠJXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�ݘ[Yˆ ˆ[œ]Ù›YÊBˆÛÜÝ\�Ý[YHˆ[œ]Ù]™[� O�[YJHˆ™]\›ˆ˜[ÙNˆB‚ˆˆÛÛœÝZ[� �Ý[Ý[YHBˆ[œ]Ù]™[� O�[YH HÛÜÝ\�Ý[YN‚ˆ Ê‚ˆ +ˆ\ÜÚ]™HÛÈXØÙ\H[˜Û\Ú]™HZ[š[][Bˆ +ˆ›ÝYÚHÜ[Û˜[[˜Û\Ú]™HX^[][KˆBˆ +ˆ™\›ÈX^[][HX]™\ÈH\\ˆ›Ý[™Ü[‹‚ˆ +ˆ]]ÛX]XÈÛÈX]ÚÛ›HZ\ˆ^X݈ +ˆZ[š[][H™\ÚÛYÙK™]™[�[™ÈH]\‚ˆ +ˆ™\Úۛ܈HØ[YHÙ^Hœ›ÛH™]šYÙÙ\š[™Âˆ +ˆ[ˆX\›Y\ˆ]]ÛX]XÈÛÛ[X[™ ‚ˆ +‹ÂˆYŠ + +[œ]ÜÝ\ OšÛ ˆ[œ]Ù›YÊBˆ ‰ˆ +[Ý[YH[œ]ÜÝ\ OšÛÝ[YBˆ +[œ]ÜÝ\ OšÛÝ[YWÛX^[][Bˆ ‰ˆ[Ý[YBˆˆ[œ]ÜÝ\ OšÛÝ[YWÛX^[][JJJBˆ + +[œ]ÜÝ\ OšÛÝšYÙÙ\ˆ ˆ[œ]Ù›YÊBˆ ‰ˆ[Ý[YHOH[œ]ÜÝ\ OšÛÝ[YJJHˆ™]\›ˆ˜[ÙNˆBˆB‚ˆØØ[—ÛX\ÚÈ �Hš[œ]Ù›YΈB‚ˆ™]\›ˆ�YNŸB‚‹Ê‚Šˆ™XYH™XÙY[™È]™[�ÚÜÙHYÙH\H\È™[]˜[�ŠˆÈHÛÛ™šYÝ\˜X›HÛÛ[X[™Ý\ ‚Š‚Šˆ™[X\ÙK[Û›H]™[�ÈÈ›Ý\Ý\˜ˆ™\ÜË[Û›HÝ\ËŠˆ[™™\ÜË[Û›H]™[�ÈÈ›Ý\Ý\˜ˆ™[X\ÙK[Û›BŠˆÝ\ˈ[ˆ]™[�ÙˆH™\]Z\™Y\HÚ]HܛۙÈÙ^BŠˆ\È™]\›™YÛÈ]ÛÜœ™XÝH[�\œ�\ÈHÙ\]Y[˜ÙK‚Š‹ÂœÝ]XÈÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×ٛܗÜÝ\ +ˆÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\ +ˆ[œ]ÜÝ\ ˆZ[� �Ý +ˆ\ÝÜžWÚ[™^ ˆZ[� �Ý +ˆ™[XZ[š[™×Ù]™[�ŠHˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆÚ[J +[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\ʈXÝ[™×Ü^Y\‹ˆ\ÝÜžWÚ[™^ ˆ™[XZ[š[™×Ù]™[�ˆ +JJH‚ˆYŠ +[œ]ÜÝ\ Oœ™\ÜÈ ‰ˆ[œ]Ù]™[� Oœ™\ÜÊBˆ +[œ]ÜÝ\ Oœ™[X\ÙH ‰ˆ[œ]Ù]™[� Oœ™[X\ÙJBˆ +[œ]ÜÝ\ OšÛÝšYÙÙ\ˆ ‰ˆ[œ]Ù]™[� OšÛ +JHˆ™]\›ˆ[œ]Ù]™[�ˆBˆB‚ˆ™]\›ˆ•SŸB‚‹Ê‚ŠˆÚXÚÈÚ]\ˆH^Y\‰ÜÈ[ÜÝ™XÙ[�[œ]]™[�ŠˆØ]\ÙžHHÛÛ™šYÝ\˜X›HÜXÚX[ÛÛ[X[™ ‚Š‚Šˆ™\ÜË™[X\ÙK[™]]ÛX]XÈÛX\ÚÜÈ\™HYÙBŠˆ™\]Z\™[Y[�ˈ\ÜÚ]™HÛ\ÈHÝ]H[™Z[š[][BŠˆ\˜][Ûˆ™\]Z\™[Y[�]˜[X]Y]HšYÙÙ\š[™È]™[� ‚Š‹ÂœÝ]XÈ›ÛÛX]ÚÜÜXÚX[ØÛÛ[X[™ +ˆÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\Ù\]Y[˜ÙV×KˆÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\‹ˆÛÛœÝZ[� �Ý[™Ý ˆÛÛœÝZ[� �ÝÙ\]Y[˜ÙWÙܘXÙWÝ[YKˆZ[� �Ý +ˆX]ÚÝ[YKˆZ[� �Ý +ˆX]ÚØYÙBŠHˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ[œ]Ù]™[�‚ˆZ[� �Ý\ÝÜžWÚ[™^ˆZ[� �Ý™]Ù\—Ù]™[�Ý[YNˆZ[� �Ý™[XZ[š[™×Ù]™[�ΈZ[� �ÝÙ\]Y[˜ÙWÚ[™^‚ˆYŠ\Ù\]Y[˜ÙBˆXXÝ[™×Ü^Y\‚ˆ[X]ÚÝ[YBˆ[X]ÚØYÙBˆ[[™Ýˆ[™ÝˆPVÔÔPÒPSÒS”UÊHˆ™]\›ˆ˜[ÙNˆB‚ˆ +›X]ÚÝ[YHH ˆ +›X]ÚØYÙHHRS• �ÓPV‚ˆ\ÝÜžWÚ[™^HXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^ˆ™]Ù\—Ù]™[�Ý[YHHÝ[YNˆ™[XZ[š[™×Ù]™[�ÈHXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�‚ˆ›ÜŠÙ\]Y[˜ÙWÚ[™^H[™ÝˆÙ\]Y[˜ÙWÚ[™^ˆ ˆÙ\]Y[˜ÙWÚ[™^ KJH‚ˆÛÛœÝרÛÛ[X[™Ú[œ]ÜÝ\ +ˆ[œ]ÜÝ\Bˆ œÙ\]Y[˜ÙVÜÙ\]Y[˜ÙWÚ[™^ H WN‚ˆ[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×ٛܗÜÝ\ +ˆXÝ[™×Ü^Y\‹ˆ[œ]ÜÝ\ ˆ š\ÝÜžWÚ[™^ ˆ œ™[XZ[š[™×Ù]™[�ˆ +N‚ˆYŠZ[œ]Ù]™[�ˆXÛÛ[X[™Ú[œ]Ù]™[�ÛX]Ú\×Ü™\Üʈ[œ]ÜÝ\ ˆ[œ]Ù]™[� ˆXÝ[™×Ü^Y\‚ˆ +Bˆ +[œ]Ù]™[� Oœ™[X\ÙH ˆ[œ]ÜÝ\ Oœ™[X\ÙJBˆOH[œ]ÜÝ\ Oœ™[X\ÙBˆ +[œ]Ù]™[� OšÛ ˆ[œ]ÜÝ\ OšÛÝšYÙÙ\ŠBˆOH[œ]ÜÝ\ OšÛÝšYÙÙ\‚ˆ™]Ù\—Ù]™[�Ý[YH H[œ]Ù]™[� O�[YBˆˆÙ\]Y[˜ÙWÙܘXÙWÝ[YBˆXÛÛ[X[™Ú[œ]Ù]™[�ÛX]Ú\×ÚÛ +ˆ[œ]ÜÝ\ ˆ[œ]Ù]™[� ˆXÝ[™×Ü^Y\‚ˆ +JHˆ™]\›ˆ˜[ÙNˆB‚ˆYŠÙ\]Y[˜ÙWÚ[™^OH[™Ý +Hˆ +›X]ÚÝ[YHH[œ]Ù]™[� O�[YNˆ +›X]ÚØYÙHBˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�ˆ H™[XZ[š[™×Ù]™[�È H NˆB‚ˆ™]Ù\—Ù]™[�Ý[YHH[œ]Ù]™[� O�[YNˆB‚ˆ™]\›ˆ�YNŸB‚˜›ÛÛÚXÚרÛÛX›Ê×Ü^Y\ŠˆXÝ[™×Ü^Y\ŠH‚ˆ[œÚYÛ™Y[�Nˆ[�X^Ý\H LNˆ[�X^Ù^\ÈH LNˆ[�˜[YH LN‚ˆZ[� �ÝZ[—ÛX]ÚØYÙHHRS• �ÓPVˆZ[� �ÝX^ÛX]ÚÝ[YHH ˆÙ^WÛX\Ú×ÝÙ[XÝYÚÛÝšYÙÙ\—Ù›YÜÈH ‚ˆ›ÛÛX]ÚÙ›Ý[™H˜[ÙN‚ˆרÛÛH +˜ÛÛN‚ˆ›ÜŠHH ÈHÙ[‹O›[Ù[]KœÜXÚX[×ÛØYYÈJÊÊH‚ˆÛÛHHÙ[‹O›[Ù[]KœÜXÚX[ +ÈN‚ˆYŠÙ[‹O˜[š[X][Û‹O˜Ø[˜Ù[OHS’SPUSÓ—ÐÐS�ÑSÑTÐP“Q ‰‚ˆ +Ù[‹O˜[š[[�[HOHÛÛKO˜Ø[˜Ù[ˆÛÛKO™œ˜[YK›Z[ˆˆÙ[‹O˜[š[\ÜȈÛÛKO™œ˜[YK›X^Ù[‹O˜[š[\ÜȈÙ[‹O˜[š[X][Û‹Oš]ØÛÝ[�ÛÛKOš]ÊJHˆˆÛÛ�[�YNˆˆH[ÙHYŠÙ[‹O˜[š[X][Û‹O˜Ø[˜Ù[OHS’SPUSÓ—ÐÐS�ÑSÑTÐP“Qˆ ‰ˆ +ÛÛKO˜Ø[˜Ù[\^Y\—ØXØÙ\×ÚYWÚ[œ] +Ù[ŠHY™ŠÙ[‹OœÜÚ][Û‹žKÙ[‹O˜˜\ÙJHˆ JJHˆˆÛÛ�[�YNˆB‚ˆˆZ[� �ÝÛÛ[X[™ÛX]ÚØYÙNˆZ[� �ÝÛÛ[X[™ÛX]ÚÝ[YN‚ˆÛÛœÝZ[� �ÝÙ\]Y[˜ÙWÙܘXÙWÝ[YHBˆÛÛ[X[™ÜÙ\]Y[˜ÙWÙܘXÙWÝ[YWÙÙ] +ÛÛJN‚ˆYŠ˜[Y[š[JÙ[‹ÛÛKO˜[š[JBˆ ‰ˆ +ÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT ÛÛKO˜[š[JHÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÒ ÛÛKO˜[š[JJBˆ ‰ˆX]ÚÜÜXÚX[ØÛÛ[X[™ +ˆÛÛKOš[œ] ˆXÝ[™×Ü^Y\‹ˆÛÛKOœÝ\ˈÙ\]Y[˜ÙWÙܘXÙWÝ[YKˆ ˜ÛÛ[X[™ÛX]ÚÝ[YKˆ ˜ÛÛ[X[™ÛX]ÚØYÙBˆ +JH‚ˆ Ê‚ˆ +ˆ™Y™\ˆHÛÛ[X[™šYÙÙ\™YžHH™]Ù\݈ +ˆ[œ]]™[� ˆš[™ÈYÙH™\ÛÛ™\È]™[�È™XÛÜ™Yˆ +ˆ\š[™ÈHØ[YHÙÚXØ[XÚˈÛÛ[X[™ÈÚ\š[™Âˆ +ˆ]]™[�™]Z[ˆH^\Ý[™ÈÛ™Ù\Ý \Ù\]Y[˜ÙKˆ +ˆ[ˆÜ™X]\Ý XÚÜ™ \Ú^™H˜[šÚ[™Ë‚ˆ +‹ÂˆÛۜݛÛÛ™]\—ÛX]ÚBˆ[X]ÚÙ›Ý[™ˆÛÛ[X[™ÛX]ÚØYÙHZ[—ÛX]ÚØYÙBˆ +ÛÛ[X[™ÛX]ÚØYÙHOHZ[—ÛX]ÚØYÙBˆ ‰ˆ +ÛÛ[X[™ÛX]ÚÝ[YHˆX^ÛX]ÚÝ[YBˆ +ÛÛ[X[™ÛX]ÚÝ[YHOHX^ÛX]ÚÝ[YBˆ ‰ˆ +ÛÛKOœÝ\ȈX^Ý\ˆ +ÛÛKOœÝ\ÈOHX^Ý\ˆ ‰ˆÛÛKO›�[ZÙ^\ȈX^Ù^\ÊJJJJN‚ˆYŠX™]\—ÛX]Ú +HˆÛÛ�[�YNˆB‚ˆ˜[YHÛÛKO˜[š[NˆZ[—ÛX]ÚØYÙHHÛÛ[X[™ÛX]ÚØYÙNˆX^ÛX]ÚÝ[YHHÛÛ[X[™ÛX]ÚÝ[YNˆX^Ý\HÛÛKOœÝ\ΈX^Ù^\ÈHÛÛKO›�[ZÙ^\ΈÙ[XÝYÚÛÝšYÙÙ\—Ù›YÜÈBˆÛÛKOš[œ]ØÛÛKOœÝ\È H WKšÛÝšYÙÙ\ŽÂˆX]ÚÙ›Ý[™H�YNˆBˆB‚ˆB‚ˆYŠ˜[Y�H  ‰ˆÚXÚרÛÜÝ[Ý™J˜[Y  KÙ[‹Oš�[\[™ÊJHˆ Ê‚ˆ +ˆ]]ÛX]XÈ[YÙ\È\™HÛ™K\ÚÝ[œ]]™[�Ë‚ˆ +ˆÛÛœÝ[YHHÙ[XÝYš[˜[ \Ý\›YÜÈÛ›HY�\‚ˆ +ˆH[Ý™HÝ\�ÈÝXØÙ\ÜÙ�[Kˆ™\ÜË™[X\ÙKˆ +ˆ[™[œ™[]Y]]ÛX]XÈ›YÜÈ™[XZ[ˆ]˜Z[X›K‚ˆ +‹ÂˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÚÛÝšYÙÙ\ŠˆXÝ[™×Ü^Y\‹ˆZ[—ÛX]ÚØYÙKˆÙ[XÝYÚÛÝšYÙÙ\—Ù›Y܈ +N‚ˆ™]\›ˆ�YNˆB‚ˆ™]\›ˆ˜[ÙNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËL�ˆ HÜšYÚ[˜[HÜš][ˆžH�YÝYH +[šÛ›ÝÛˆ]JK‚Š‚Šˆ™]ÛÜšÈ]˜[X]\ÈÚ]\ˆH^Y\ˆŠˆ\ÈH[™[™ÈÛÛ[X[™Ù\]Y[˜ÙHÈ^XÝ]K‚Š‹Â˜›ÛÛ^Y\—Ü™Z[œ] + +Hˆˆ×Ü^Y\ˆ +˜XÝ[™×Ü^Y\ˆH^Y\ˆ +ÈÙ[‹Oœ^Y\š[™^‚ˆYŠÚXÚרÛÛX›ÊXÝ[™×Ü^Y\ŠJHˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÐÓÓ•“ÓÑVT΂ˆ™]\›ˆ�YNˆB‚ˆ™]\›ˆ˜[ÙNŸB‚‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËLL‹LŽHŠˆŠˆÝÜ�[›š[™ÈYˆ^Y\‚Šˆ›ÈÛ™Ù\ˆ[œ]È\™XÝ[Û‚Šˆ]Ý\�YH�[‹‚Š‹Â�›ÚY�[—ÝžWÜ�[œÝÜØÚXÚÊ[�]JˆXÝ[™×Ù[�]KÛÛœÝWÔ�[–\™XÝ[Ûˆ[Ý™^ ÛÛœÝWÔ�[–‘\™XÝ[Ûˆ[Ý™^‹ÛÛœÝWÔ�[–\™XÝ[Ûˆ�[›š[™×Þ ÛÛœÝWÔ�[–‘\™XÝ[Ûˆ�[›š[™×Þ‹ÛÛœÝ[��[�ÛÛ™šYÑ›YÜËÛÛœÝ[�\ÚÛÛ[X[™›YËÛÛœÝ[�\Úš^Y›YËÛÛœÝ[�[˜X›Y›YËÛÛœÝ[�ÝÜÝ]Q›YÊHˆYˆ +J�[�ÛÛ™šYÑ›YÜÈ ˆ[˜X›Y›YÊHˆ +\Úš^Y›YÈ ‰ˆXXÝ[™×Ù[�]KO˜[š[X][™ÊBˆ + +\ÚÛÛ[X[™›YÈ ‰ˆXXÝ[™×Ù[�]KO˜[š[X][™ÊBˆ +Y™Š[Ý™^ �[›š[™×Þ +H ‰ˆ +[Ý™^ˆOH•S—ÑT—Ö—Ó“Ó‘HXÝ[™×Ù[�]KOœ�[›š[™È ˆ•S—ÔÕUWÔÕT•Ö +JBˆ +Y™Š[Ý™^‹�[›š[™×ÞŠH ‰ˆ +[Ý™^OH•S—ÑT—ÖÓ“Ó‘HXÝ[™×Ù[�]KOœ�[›š[™È ˆ•S—ÔÕUWÔÕT•ÖŠJJJHˆXÝ[™×Ù[�]KOœ�[›š[™ÈHÝÜÝ]Q›YΈBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËLL‹LŽBŠˆŠˆÚXÚÈ^Y\ˆ[œ][™�[ˆÝÜŠˆ�[˜Ý[ÛˆYˆ™YYY ‚Š‹Â�›ÚY�[—ÝžWÜ�[œÝÜÜ^Y\Š[�]JˆXÝ[™×Ù[�]KÛÛœÝ×Ü^Y\ŠˆXÝ[™×Ü^Y\ŠBžÈˆÛÛœÝWÜ�[—ÜÝ]H�[—ÜÝ]HHXÝ[™×Ù[�]KOœ�[›š[™Î‚ˆYˆ +�[—ÜÝ]HOH•S—ÔÕUWÓ“Ó‘JBˆˆ™]\›ŽÂˆB‚ˆ Ê‚ˆ +ˆÙ]^Y\ˆ\™XÝ[Û˜[[œ]ˆ +ˆœ›ÛHÙ^HÝ]\Ë‚ˆ +‹Â‚ˆÛÛœÝWÔ�[–‘\™XÝ[Ûˆ[Ý™^ˆH +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘UT +HÈ•S—ÑT—Ö—ÕTˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠHÈ•S—ÑT—Ö—ÑÕÓˆˆ•S—ÑT—Ö—Ó“Ó‘NˆÛÛœÝWÔ�[–\™XÝ[Ûˆ[Ý™^H +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• +HÈ•S—ÑT—ÖÓQ•ˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +HÈ•S—ÑT—ÖÔ’QÒˆ•S—ÑT—ÖÓ“Ó‘N‚ˆ Ê‚ˆ +ˆÙ]H�[›š[™È\™XÝ[Ûˆœ›ÛBˆ +ˆ™[ØÚ]K‚ˆ +‹Â‚ˆÛÛœÝWÔ�[–‘\™XÝ[Ûˆ�[›š[™×ÞˆH�[—ÜÝ]HÈ + +XÝ[™×Ù[�]KO�™[ØÚ]Kžˆ +HÈ•S—ÑT—Ö—ÕTˆ +XÝ[™×Ù[�]KO�™[ØÚ]Kžˆˆ +HÈ•S—ÑT—Ö—ÑÕÓˆˆ•S—ÑT—Ö—Ó“Ó‘JHˆ•S—ÑT—Ö—Ó“Ó‘NˆÛÛœÝWÔ�[–\™XÝ[Ûˆ�[›š[™×ÞH�[—ÜÝ]HÈ + +XÝ[™×Ù[�]KO�™[ØÚ]Kž +HÈ•S—ÑT—ÖÓQ•ˆ +XÝ[™×Ù[�]KO�™[ØÚ]Kžˆ +HÈ•S—ÑT—ÖÔ’QÒˆ•S—ÑT—ÖÓ“Ó‘JHˆ•S—ÑT—ÖÓ“Ó‘N‚ˆ ʈ�\ݛ܈™XYXš[]H™[Ýˈ +‹ÂˆÛÛœÝWÜ�[—ØÛÛ™šY×Ù›YÜÈXÝ[™×Ü�[—ØÛÛ™šY×Ù›YÜÈHXÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜ΂ˆ Ê‚ˆ +ˆÝÜ�[›š[™Ïˆ +‚ˆ +ˆ Kˆ^\È\™XÝ[Û‹‚ˆ +ˆ ‹ˆX›HÈ�[ˆ[ˆ\™XÝ[Û�ˆ +ˆ ˈš^Y\ÚÈš^Y\Ú\ÈÝ܈ +ˆÚ[ˆH[š[X][ÛˆÛÛ\]\ˈ^Bˆ +ˆYۛܙH™[X\Ú[™ÈHÙ^H[™È›Ýˆ +ˆÝÜÛˆH\œ[™XÝ[\ˆ^\ÈÛÛ[X[™ˆ +ˆ]™[ˆYˆÙHØ[‰Ý[Ý™HÛˆHÝ\‚ˆ +ˆ^\ˈ›ÝHHÝ\ˆ^\È\ÈYۛܙYˆ +ˆžHÙÚXÈÝۜݙX[K‚ˆ +‚ˆ +ˆ ˆÝÜÛˆ›ÛÝÚ[™Î‚ˆ +ˆ H›È\™XÝ[ÛˆÛÛ[X[™ ‚ˆ +ˆ H\™XÝ[ÛˆÛÛ[X[™ÜÜÙ\ÈÝ\œ™[�\™XÝ[Û‹‚ˆ +ˆ H\œ[™XÝ[\ˆ^\ÈÛÛ[X[™Ú[ˆÙHÛ‰Ý]™HH›YÈ[˜X›Y ‚ˆ +‚ˆ +ˆ™\X]ÚXÚț܈ÜÜÚ]H\™XÝ[Û‚ˆ +ˆ[™›Üˆˆ^\Ë‚ˆ +‹Â‚ˆÝÚ]Ú +�[›š[™×Þ +HˆØ\ÙH•S—ÑT—ÖÓQ•‚ˆ�[—ÝžWÜ�[œÝÜØÚXÚÊXÝ[™×Ù[�]K[Ý™^ [Ý™^‹�[›š[™×Þ �[›š[™×Þ‹XÝ[™×Ü�[—ØÛÛ™šY×Ù›YÜË•S—ÐÓÓ‘’Q×ÖÓQ•ÑTÒÐÓÓSPS‘ •S—ÐÓÓ‘’Q×ÖÓQ•ÑTÒÑ’VQ •S—ÐÓÓ‘’Q×ÖÓQ•ÑS�P“Q •S—ÔÕUWÓ“Ó‘JNˆœ™XZ΂ˆØ\ÙH•S—ÑT—ÖÔ’QÒ‚ˆ�[—ÝžWÜ�[œÝÜØÚXÚÊXÝ[™×Ù[�]K[Ý™^ [Ý™^‹�[›š[™×Þ �[›š[™×Þ‹XÝ[™×Ü�[—ØÛÛ™šY×Ù›YÜË•S—ÐÓÓ‘’Q×ÖÔ’QÒÑTÒÐÓÓSPS‘ •S—ÐÓÓ‘’Q×ÖÔ’QÒÑTÒÑ’VQ •S—ÐÓÓ‘’Q×ÖÔ’QÒÑS�P“Q •S—ÔÕUWÓ“Ó‘JNˆœ™XZ΂ˆØ\ÙH•S—ÑT—ÖÓ“Ó‘N‚ˆœ™XZΈB‚ˆÝÚ]Ú +�[›š[™×ÞŠHˆØ\ÙH•S—ÑT—Ö—ÕT‚ˆ�[—ÝžWÜ�[œÝÜØÚXÚÊXÝ[™×Ù[�]K[Ý™^ [Ý™^‹�[›š[™×Þ �[›š[™×Þ‹XÝ[™×Ü�[—ØÛÛ™šY×Ù›YÜË•S—ÐÓÓ‘’Q×Ö—ÕTÑTÒÐÓÓSPS‘ •S—ÐÓÓ‘’Q×Ö—ÕTÑTÒÑ’VQ •S—ÐÓÓ‘’Q×Ö—ÕTÑS�P“Q •S—ÔÕUWÓ“Ó‘JNˆœ™XZ΂ˆØ\ÙH•S—ÑT—Ö—ÑÕÓŽ‚ˆ�[—ÝžWÜ�[œÝÜØÚXÚÊXÝ[™×Ù[�]K[Ý™^ [Ý™^‹�[›š[™×Þ �[›š[™×Þ‹XÝ[™×Ü�[—ØÛÛ™šY×Ù›YÜË•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑTÒÐÓÓSPS‘ •S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑTÒÑ’VQ •S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑS�P“Q •S—ÔÕUWÓ“Ó‘JNˆœ™XZ΂ˆØ\ÙH•S—ÑT—Ö—Ó“Ó‘N‚ˆœ™XZΈBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLM‚Š‚Šˆ™]\›ˆ�YHÚ[ˆH[�]HX^HŠˆ›ØÙ\ÜÈÜ™[˜\žHYK\Ý]H^Y\ˆŠˆ[œ] ‚Š‹Â˜›ÛÛ^Y\—ØXØÙ\×ÚYWÚ[œ] +ÛÛœÝ[�]H +˜XÝ[™×Ù[�]JHˆˆÛÛœÝר[š[H +˜[š[X][ÛˆHXÝ[™×Ù[�]KO˜[š[X][ێ‚ˆYŠXÝ[™×Ù[�]KOšY[™ÊHˆ™]\›ˆ�YNˆB‚ˆYŠX[š[X][Û‚ˆX[š[X][Û‹OšYBˆ[š[X][Û‹O›�[Yœ˜[Y\ÈH ˆXÝ[™×Ù[�]KO˜[š[\܈�H +Z[� �Ý +X[š[X][Û‹O›�[Yœ˜[Y\ÊHˆ™]\›ˆ˜[ÙNˆB‚ˆ™]\›ˆ[š[X][Û‹OšYVØXÝ[™×Ù[�]KO˜[š[\Ü×HÈ�YHˆ˜[ÙNŸB‚�›ÚY^Y\—Ý[šÊ +BžÂˆ\YYˆ[�[HWÛØØ[ØXÝ[Û—Ù›Y܈ˆPÕSÓ—Ó“Ó‘KˆPÕSÓ—ÕÐSˈPÕSÓ—ÕT ˆPÕSÓ—ÑÕÓ‹ˆPÕSÓ—Ô•S‚ˆHWÛØØ[ØXÝ[Û—Ù›YÜ΂ˆWÛØØ[ØXÝ[Û—Ù›YÜÈXÝ[ÛˆH ˆ›ÛÛ˜XÚ×ÝØ[ÈH˜[ÙNÈ ËØ˜XÚÝØ[ˆˆ[�]H +›Ý\ˆH•Sˆ›Ø][š]X[Ú�[\Ý™[ØÚ]WÞˆH Œ‚ˆ[�]JˆXÝ[™×Ù[�]HHÙ[ŽÂ‚ˆÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙWÛY�ÛY�×HHÑ“Q×ÓSÕ‘SQ• “Q×ÓSÕ‘SQ•NˆÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙWÜšYÚÜšYÚ×HHÑ“Q×ÓSÕ‘T’QÒ “Q×ÓSÕ‘T’QÒNˆÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙWÝ\Ý\×HHÑ“Q×ÓSÕ‘UT “Q×ÓSÕ‘UTNˆÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙWÙÝÛ—ÙÝÛ–×HHÑ“Q×ÓSÕ‘QÕÓ‹“Q×ÓSÕ‘QÕÓŸNȈˆ[�HHXÝ[™×Ù[�]KOœ^Y\š[™^ˆ×Ü^Y\ˆ +˜XÝ[™×Ü^Y\ˆH^Y\ˆ +ÈN‚ˆYŠXÝ[™×Ü^Y\‹O™[�OHXÝ[™×Ù[�]HXÝ[™×Ù[�]KO™X]ÜÝ]H ˆPUÔÕUWÑPQ +Bˆˆ™]\›ŽÂˆB‚ˆ Ê‚ˆ +ˆ\™HÙHÝXÚ[™ÈH[™]™[[�]Oˆ +‹ÂˆYŠ +Ý\ˆHš[™Ù[�Ú\™JXÝ[™×Ù[�]KXÝ[™×Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž‹TWÑS‘U‘S •S +JHˆ ‰ˆY™ŠXÝ[™×Ù[�]KOœÜÚ][Û‹žKÝ\‹OœÜÚ][Û‹žJHH ŒJH‚ˆ›ÛÛ›×Ü^Y\—Ü™XXÚYH˜[ÙNˆZ[� �ÝÝ[WÛ›ÝÜ™XXÚYH ˆZ[� �ÝÝ[WÜ™XXÚYH ˆZ[� �ÝNˆˆ›Üˆ +HH ÈHPVÔVQT”ÎÈJÊÊHˆYˆ +\™XXÚYÚWJ^ˆÝ[WÛ›ÝÜ™XXÚY +ÊΈBˆBˆ›×Ü^Y\—Ü™XXÚYH +Ý[WÛ›ÝÜ™XXÚY�HPVÔVQT”ÊHÈ�YHˆ˜[ÙN‚ˆYŠ›×Ü^Y\—Ü™XXÚY +HˆYØÛÜ™JKÝ\‹O›[Ù[]KœØÛÜ™JNˆBˆ™XXÚYÜWHH�YN‚ˆ›Üˆ +HH ÈHPVÔVQT”ÎÈJÊÊHˆÝ[WÜ™XXÚY +ÏH™XXÚYÚWNˆB‚ˆYˆ +[Ý\‹O›[Ù[]KœÝX�\H +Ý\‹O›[Ù[]KœÝX�\HOHÕP•TWГÕ ‰ˆÝ[WÜ™XXÚY�H +ÛÝ[�Ù[�ÊTWÔVQTŠJJJHˆ]™[ØÛÛ\]YH N‚ˆYŠÝ\‹O›[Ù[]K˜œ˜[˜Ú +HˆÝ›˜ÜJœ˜[˜ÚÛ˜[YKÝ\‹O›[Ù[]K˜œ˜[˜Ú PVÓ�SQWÓSŠNÈ ËÛ›ÝË[ÝHØ[ˆœ˜[˜ÚÈ[›Ý\ˆ]™[ˆBˆ™]\›ŽÂˆBˆB‚ˆ Ê‚ˆ +ˆ™\Ù]ÛÛX›ÈÛÝ[�Yˆ[YH\È^\™Y ‚ˆ +‹ÂˆYŠÝ[YHˆXÝ[™×Ù[�]KOœ�\Ú �[YJHˆXÝ[™×Ù[�]KOœ�\Ú ˜ÛÝ[�H ˆXÝ[™×Ù[�]KOœ�\Ú �[YHH ˆB‚ˆYŠ^Y\—Ü™Z[œ] + +JHˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ù[�]KO˜Ú\™Ú[™ÊHˆ^Y\—ØÚ\™ÙWØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ù[�]KOš[œZ[ˆ ˆ’S—ÔRS—Ó“Ó‘H +XÝ[™×Ù[�]KO›[šÈ ‰ˆXXÝ[™×Ù[�]KO™Ü˜X˜š[™ÊJHˆ^Y\—ÜZ[—ØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ ËȘ[[™ÏÈÚXÚț܈[™[™ÂˆYŠXÝ[™×Ù[�]KOœ›Ú™XÝ[H ˆ“TÕÕÔÔÊHˆ^Y\—Ù˜[ØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ ËÈܘXˆÙXÝ[Û‹Û�[Ý™HYˆÝ[[š[X][™ÂˆYŠXÝ[™×Ù[�]KO™Ü˜X˜š[™È ‰ˆXÝ[™×Ù[�]KO˜]XÚÚ[™ÈOHUPÒÒS‘×Ó“Ó‘H ‰ˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆOHÛÛ[[Û—Ý›Ý×ÝØZ] +Hˆ^Y\—ÙܘX—ØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ ËÈ�[\ÙXÝ[Û‚ˆYŠXÝ[™×Ù[�]KOš�[\[™ÊHˆ^Y\—Ú�[\ØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ù[�]KO˜[š[[�[HOHS’WÕÐSÓÑ‘ŠHˆ^Y\—ÝØ[ÛÙ™—ØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ù[�]KO™›Ü ‰ˆXÝ[™×Ù[�]KOœÜÚ][Û‹žHOHXÝ[™×Ù[�]KO˜˜\ÙH ‰ˆXXÝ[™×Ù[�]KO�™[ØÚ]KžJHˆ^Y\—ÛYWØÚXÚÊ +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ Ê‚ˆ +ˆÚXÚÈYˆ^Y\ˆ\È[ˆHÝ]H][Ý܈ +ˆÜ™[˜\žHYK\Ý]H[œ]›ØÙ\ÜÚ[™ËˆYˆ›Ý ˆ +ˆÚÚ\H™\ÝÙˆH[œ]ÚXÚÜË‚ˆ +‹ÂˆYŠ\^Y\—ØXØÙ\×ÚYWÚ[œ] +XÝ[™×Ù[�]JJHˆÛÝÈ[™[šØÚXÚΈB‚ˆ ËÈÚXÚÈYˆ[�]H\È[™\ˆH]›Ü›Bˆ ÊšYŠXÝ[™×Ù[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÔU“Ô“H ‰ˆ +ZYÚ˜\ˆHXÝ[™×Ù[�]KO˜[š[X][Û‹OœÚ^™KžHÈXÝ[™×Ù[�]KO˜[š[X][Û‹OœÚ^™KžHˆXÝ[™×Ù[�]KO›[Ù[]KœÚ^™KžJH ‰‚ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÑPÒÊH ‰ˆÚXÚ×Ü]›Ü›WØ™]ÙY[ŠXÝ[™×Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]KOœÜÚ][Û‹žKXÝ[™×Ù[�]KOœÜÚ][Û‹žH +ÈZYÚ˜\‹XÝ[™×Ù[�]JJBˆˆXÝ[™×Ù[�]KOšY[™ÈHQS‘×Ó“Ó‘NˆXÝ[™×Ù[�]KO™XÚÚ[™ÈHPÒ×ÐPÕU‘NˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÜÝXÚ×Ý[™\›™X]ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑPÒË +NˆÛÝÈ[™[šØÚXÚΈJ‹Â‚ˆÛۜݛØ][Y™ˆHY™ŠXÝ[™×Ù[�]KOœÜÚ][Û‹žKXÝ[™×Ù[�]KO˜˜\ÙJNˆÛۜݛÛÛ›Ý[˜Z\ˆH +XÝ[™×Ù[�]KO›[™YÛÛ—Ü]›Ü›HÈ[Y™ˆ Hˆ[Y™ˆ ŠN‚ˆYŠXÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×ÓSÕ‘UT +H‚ˆÛۜݛÛÛÛÛ[X[™ÛX]ÚH +›Ý[˜Z\ˆ ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÝ\Ý\ XÝ[™×Ü^Y\‹ ŠJN‚ˆYŠÛÛ[X[™ÛX]Ú ‰ˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ +•S—ÐÓÓ‘’Q×Ö—ÕTÑS�P“Q•S—ÐÓÓ‘’Q×Ö—ÕTÒS’UPS +JHOH +•S—ÐÓÓ‘’Q×Ö—ÕTÑS�P“Q•S—ÐÓÓ‘’Q×Ö—ÕTÒS’UPS +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•SŠJHˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘UTˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÔÕT•ÖÈ ËÈ^Y\ˆ™YÚ[œÈÈ�[‚ˆˆH[ÙHYŠÛÛ[X[™ÛX]Ú ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒÕT +JH‚ˆ ËÈ™]ÈHHÛÛX›È]XÚˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘UTˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐUPÒÕT  +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNÈ ËÈ\ÈÛÜšØ\›Ý[™X[ÈY˜][œ™Y\ÜXÚX[ ‚ˆÛÝÈ[™[šØÚXÚΈˆH[ÙHYŠÛÛ[X[™ÛX]Ú ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÑÑÑJJHˆ ËÈ™]ÈÙÙH[Ý™HZÙHÛˆÓԌˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘UTˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙÙÙNˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOšY[™ÈHQS‘×Ó“Ó‘NˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH XXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž +ˆ K�ÍNˆXÝ[™×Ù[�]KO�™[ØÚ]KžH ËËÈÒÈ[ÝHØ[ˆ\ÙH�[\œ˜[YHÈ[ÙYžH\È[ž]Ø^Bˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑÑÑK +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆYŠXÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠHˆÛۜݛÛÛÛÛ[X[™ÛX]ÚH +›Ý[˜Z\ˆ ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÙÝÛ—ÙÝÛ‹XÝ[™×Ü^Y\‹ ŠJN‚ˆYŠÛÛ[X[™ÛX]Ú ‰ˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ +•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑS�P“Q•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÒS’UPS +JHOH +•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑS�P“Q•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÒS’UPS +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•SŠJHˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘QÕӎˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÔÕT•ÖŽÈ ËÈ^Y\ˆ™YÚ[œÈÈ�[‚ˆˆH[ÙHYŠÛÛ[X[™ÛX]Ú ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒÑÕÓŠJHˆ ËÈ™]ÈÛÛX›È]XÚˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘QÕӎˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐUPÒÑÕÓ‹ +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆÛÝÈ[™[šØÚXÚΈˆH[ÙHYŠÛÛ[X[™ÛX]Ú ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÑÑÑJJHˆ ËÈ™]ÈÙÙH[Ý™HZÙHÛˆÓԌˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÓSÕ‘QÕӎˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙÙÙNˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOšY[™ÈHQS‘×Ó“Ó‘NˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆHXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž +ˆ K�ÍNˆXÝ[™×Ù[�]KO�™[ØÚ]KžH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑÑÑK +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆYŠ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +JJHˆˆÛۜݛÛÛÛÛ[X[™ÛX]ÚÛY�H +›Ý[˜Z\ˆ ‰ˆ +XÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÛY�ÛY� XÝ[™×Ü^Y\‹ ŠJJNˆÛۜݛÛÛÛÛ[X[™ÛX]ÚÜšYÚH +›Ý[˜Z\ˆ ‰ˆ +XÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÜšYÚÜšYÚ XÝ[™×Ü^Y\‹ ŠJJNˆÛۜݛÛÛÛÛ[X[™ÛX]ÚÙ›Ü�Ø\™HÛÛ[X[™ÛX]ÚÛY�ÛÛ[X[™ÛX]ÚÜšYÚˆÛۜݛÛÛÛÛ[X[™ÛX]ÚؘXÚÈH›Ý[˜Z\‚ˆ ‰ˆXÝ[™×Ù[�]KO›[Ù[]K™˜XÚ[™Âˆ ‰ˆ + +XÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÛY�ÛY� XÝ[™×Ü^Y\‹ ŠJBˆ +XÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWÜšYÚÜšYÚ XÝ[™×Ü^Y\‹ ŠJJNȈˆYˆ +ÛÛ[X[™ÛX]ÚÛY� ‰ˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ +•S—ÐÓÓ‘’Q×ÖÓQ•ÑS�P“Q•S—ÐÓÓ‘’Q×ÖÓQ•ÒS’UPS +JHOH +•S—ÐÓÓ‘’Q×ÖÓQ•ÑS�P“Q•S—ÐÓÓ‘’Q×ÖÓQ•ÒS’UPS +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•SŠJH‚ˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HŠ“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +NÈ ËÈ\ÝX[HY� +ÈšYÚ\È›ÝXØÙ\X›KÛÈ]\ÈÒÈÈ�[›ÝˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÔÕT•ÖÈ ËÈ^Y\ˆ™YÚ[œÈÈ�[‚ˆˆH[ÙHYŠÛÛ[X[™ÛX]ÚÜšYÚ ‰ˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ +•S—ÐÓÓ‘’Q×ÖÔ’QÒÑS�P“Q•S—ÐÓÓ‘’Q×ÖÔ’QÒÒS’UPS +JHOH +•S—ÐÓÓ‘’Q×ÖÔ’QÒÑS�P“Q•S—ÐÓÓ‘’Q×ÖÔ’QÒÒS’UPS +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•SŠJHˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HŠ“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +NÈ ËÈ\ÝX[HY� +ÈšYÚ\È›ÝXØÙ\X›KÛÈ]\ÈÒÈÈ�[›ÝˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÔÕT•ÖÈ ËÈ^Y\ˆ™YÚ[œÈÈ�[‚ˆˆH[ÙHYŠÛÛ[X[™ÛX]ÚؘXÚÈ ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐ�PÒÔ•SŠJHˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HŠ“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +NÈ ËÈ\ÝX[HY� +ÈšYÚ\È›ÝXØÙ\X›KÛÈ]\ÈÒÈÈ�[›ÝˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÔÕT•ÖÈ ËÈ^Y\ˆ™YÚ[œÈÈ�[‚ˆˆH[ÙHYŠÛÛ[X[™ÛX]ÚÙ›Ü�Ø\™ ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒѓԕÐT‘ +JHˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HŠ“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +NˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐUPÒѓԕÐT‘  +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWØÛÛœÝ[YWÛ]\ÝÜ™\ÜÊXÝ[™×Ü^Y\ŠNˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆ Ê‚ˆ +ˆ]XÚÈ›Ý ˆ]XÚÈ +ÈÙ^HX\Yˆ +ˆžHZœÜXÚX[ ‚ˆ +‹Â‚ˆYŠ +Ûؘ[ØÛÛ™šY˘ZœÜXÚX[OHR”ÔPÒPSÒÑVWÔÔPÒPS ‰ˆ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒГÕ +J_ˆ +Ûؘ[ØÛÛ™šY˘ZœÜXÚX[OHR”ÔPÒPSÒÑVWÐUPÒ̈ ‰ˆ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒГÕ +J_ˆ +Ûؘ[ØÛÛ™šY˘ZœÜXÚX[OHR”ÔPÒPSÒÑVWÐUPÒÌÈ ‰ˆ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒГÕ +J_ˆ +Ûؘ[ØÛÛ™šY˘ZœÜXÚX[OHR”ÔPÒPSÒÑVWÐUPÒÍ ‰ˆ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒГÕ +JJBˆˆYŠ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÐUPÒÊH ‰ˆ›Ý[˜Z\ŠBˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×Ò•STˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOœÝ[[YHH È ËÈYˆ]XÚÈ\È™\ÜÙY Û[™ÈÝÛˆ]XÚÈÈ^XÝ]H]XÚÌÈ\È›ÈÛ™Ù\ˆ˜[Yˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐUPÒГÕ  +NˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆ Ê‚ˆ +ˆÛÛ[X[™TÚ\™ÙK‚ˆ +‹Â‚ˆYŠ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST +H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑJJBˆˆYŠ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÔÔPÒPS +H ‰ˆ›Ý[˜Z\ŠBˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×Ò•STˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ØÚ\™ÙNˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KOœÝ[[YHH ˆÙ]ØÚ\™Ú[™ÊXÝ[™×Ù[�]JNˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑK +NˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆ Ê‚ˆ +ˆ[™HÜXÚX[Ù^KˆÚXÚț܈\�ÙˆHˆ +ˆœ™Y\ÜXÚX[ÛÛ[X[™ [™[ˆ›ØÚÚ[™Ë‚ˆ +‹Â‚ˆYŠXÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×ÔÔPÒPS +H ËÈHÜXÚX[�]ÛˆØ[ˆ›ÝÈ™H\ÙY›Üˆœ™Y\ÜXÚX[ˆˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÔÔPÒPS ŠH ‰ˆ›Ý[˜Z\ˆ ‰‚ˆ +XÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ•ˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• +H‚ˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JH +BˆˆYŠÚXÚרÛÜÝ[Ý™JS’WÔÔPÒPS ‹  +JBˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÔÔPÒPSˆÛÝÈ[™[šØÚXÚΈBˆB‚‚BKËÈ›ØÚÚ[™Ë‚ˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WГÐÒÊH ‰ˆ›Ý[˜Z\ˆ ‰ˆJXÝ[™×Ù[�]KO›[Ù[]K˜›ØÚרÛÛ™šY×Ù›YÜÈ ˆ“ÐÒ×ÐÓÓ‘’Q×ÑTÐP“Q +JBˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÔÔPÒPS‚‚BBKËÈÙ]\›YÜËXÝ[Û‹[™›ØÚÈ[š[X][ۜ˂‚BBYרXÝ]™WØ›ØÚÊXÝ[™×Ù[�]JN‚‚BBYÛÝÈ[™[šØÚXÚΈBˆB‚ˆ Ê‚ˆ +ˆœ™XZÛÝ]ÜXÚX[ ‚ˆ +‹Â‚ˆYŠ›Ý[˜Z\ˆ ‰ˆ^Y\—ØÚXÚ×ÜÜXÚX[ + +JBˆˆÛÝÈ[™[šØÚXÚÎÈ ËÈÛÈ[ÝHÛ‰Ý\™›Ü›HÜXÚX[Ș[[™ÈÙ™ˆHYÙBˆB‚ˆ Ê‚ˆ +ˆÚ\™ÙH]XÚÈ +Û]XÚÈ ˆ™[X\ÙJK‚ˆ +‹Â‚ˆYŠ +XÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\È ˆ“Q×ÐUPÒÊJBˆˆYŠXÝ[™×Ù[�]KOœÝ[[YH ‰ˆ›Ý[˜Z\ˆ ‰‚ˆ + +˜[Y[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑPUPÒÊH ‰ˆXÝ[™×Ù[�]KOœÝ[[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆXÝ[™×Ù[�]KO›[Ù[]K˜[š[X][Û–ÐS’WÐÒT‘ÑPUPÒ×KO˜Ú\™ÙWÝ[YJHÝ[YJHˆ +]˜[Y[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑPUPÒÊH ‰ˆ˜[Y[š[JXÝ[™×Ù[�]K[š[X]XÚÜÖØXÝ[™×Ù[�]KO›[Ù[]K˜]ÚZ[–ØXÝ[™×Ù[�]KO›[Ù[]K˜ÚZ[›[™Ý H WH H WJBˆ ‰ˆXÝ[™×Ù[�]KO›[Ù[]K˜ÚZ[›[™Ýˆ  ‰ˆXÝ[™×Ù[�]KOœÝ[[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆXÝ[™×Ù[�]KO›[Ù[]K˜[š[X][Û–Ø[š[X]XÚÜÖØXÝ[™×Ù[�]KO›[Ù[]K˜]ÚZ[–ØXÝ[™×Ù[�]KO›[Ù[]K˜ÚZ[›[™Ý H WH H WWKO˜Ú\™ÙWÝ[YJHÝ[YJJJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ‚ˆXÝ[™×Ù[�]KOœÝ[[YHH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý œ[˜Ú�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý œ[˜Ú  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑPUPÒÊJBˆˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐÒT‘ÑPUPÒË +NˆBˆ[ÙHYŠ˜[Y[š[JXÝ[™×Ù[�]K[š[X]XÚÜÖØXÝ[™×Ù[�]KO›[Ù[]K˜]ÚZ[–ØXÝ[™×Ù[�]KO›[Ù[]K˜ÚZ[›[™Ý H WH H WJJBˆˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]K[š[X]XÚÜÖØXÝ[™×Ù[�]KO›[Ù[]K˜]ÚZ[–ØXÝ[™×Ù[�]KO›[Ù[]K˜ÚZ[›[™Ý H WH H WK +NˆBˆÛÝÈ[™[šØÚXÚΈBˆXÝ[™×Ù[�]KOœÝ[[YHH ˆB‚ˆ Ê‚ˆ +ˆ]XÚÈ�]Û‹ˆ[™H˜\ÚXÈ]XÚȈ +ˆ�]ÛˆXÝ[ÛœÈ +]XÚËÙ] ]ËŠK‚ˆ +‹Â‚ˆYŠ +XÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×ÐUPÒÊH ‰ˆ›Ý[˜Z\ŠBˆˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×ÐUPÒΈXÝ[™×Ù[�]KOœÝ[[YHH È ËÈ\ØX›HH]XÚÌÈÝ[[YB‚ˆYŠ +XÝ[™×Ù[�]KO™XÚÚ[™È ˆPÒ×ÐPÕU‘JH ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÑPÒÐUPÒÊH ‰ˆVQT—ÓRS—ÖˆOHVQT—ÓPVÖŠH ËØXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓ‚ˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑPÒÐUPÒË +NˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ù[�]KOœ�[›š[™È ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•S�UPÒÊJH ËÈ™]È�[ˆ]XÚÈÛÙHÙXÝ[Û‚ˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘Nˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÔ•S�UPÒË +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ Ê‚ˆ +ˆ˜XÚÈ]XÚˈYˆ^Y\‰ÜÈÛÛ[X[™�Y™™\ˆX]Ú\Ȉ +ˆH˜XÚÈ]XÚÈÙ\]Y[˜ÙKÙIÛ][\ÈȈ +ˆH˜XÚÈ]XÚË‚ˆ +‹ÂˆÛÛœÝÙ^WÛX\Ú×ÝÙ\]Y[˜ÙWؘXÚר]XÚÖ×HHÑ“Q×Ð�PÒÕÐT‘ “Q×ÐUPÒßN‚ˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÐUPÒÐ�PÒÕÐT‘ +H ‰ˆX]ÚØÛÛX›ÊÙ\]Y[˜ÙWؘXÚר]XÚËXÝ[™×Ü^Y\‹ ŠJHˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ]XÚ×Ú[œ]Ù]™[�ˆÛÛœÝרÛÛ[X[™Ú[œ]Ù]™[� +ˆ˜XÚÝØ\™Ú[œ]Ù]™[�‚ˆZ[� �Ý\ÝÜžWÚ[™^BˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^‚ˆZ[� �Ý™[XZ[š[™×Ù]™[�ÈBˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�‚ˆ Ê‚ˆ +ˆÙ]H\ÝÛÈ™\ÜÈ]™[�ˈ™XY[™È›ÝYÚˆ +ˆHÛÛ\]Xš[]H[\ˆ™]™[�È�]\™H™[X\ÙBˆ +ˆ[™[YYÛ]™[�Èœ›ÛH\Ý\˜š[™È˜XÚÈ]XÚË‚ˆ +‹Âˆ]XÚ×Ú[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×Ü™\ÜʈXÝ[™×Ü^Y\‹ˆ š\ÝÜžWÚ[™^ ˆ œ™[XZ[š[™×Ù]™[�ˆ +N‚ˆ˜XÚÝØ\™Ú[œ]Ù]™[�HÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ™]š[Ý\×Ü™\ÜʈXÝ[™×Ü^Y\‹ˆ š\ÝÜžWÚ[™^ ˆ œ™[XZ[š[™×Ù]™[�ˆ +N‚ˆ Ê‚ˆ +ˆY˜XÚÈ]XÚÈ[œ]ÈÛÛYHÚ][ˆBˆ +ˆ[YHÚ[™ÝÏÈYˆÛËÙIÛÈH˜XÚÈ]XÚË‚ˆ +‹ÂˆYŠ]XÚ×Ú[œ]Ù]™[�ˆ ‰ˆ˜XÚÝØ\™Ú[œ]Ù]™[�ˆ ‰ˆ]XÚ×Ú[œ]Ù]™[� O�[YBˆ H˜XÚÝØ\™Ú[œ]Ù]™[� O�[YBˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY È L +H‚ˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžH ˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ‚ˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ•ˆ ‰ˆ +˜XÚÝØ\™Ú[œ]Ù]™[� Oœ™\ÜÈ ˆ“Q×ÓSÕ‘SQ• +JHˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆˆH[ÙHYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒˆ ‰ˆ +˜XÚÝØ\™Ú[œ]Ù]™[� Oœ™\ÜÈ ˆ“Q×ÓSÕ‘T’QÒ +JHˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆB‚ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐUPÒÐ�PÒÕÐT‘  +NˆÛÝÈ[™[šØÚXÚΈBˆB‚ˆ Ê‚ˆ +ˆÙ]][KˆYˆ^Y\ˆ\ÈÝ[™[™ÈÛˆ[ˆ][Bˆ +ˆ[™HÙ][š[X][Ûˆ\Ș[Y [‚ˆ +ˆÙIÛXÚÈ]\[™�[ˆHÙ][š[X][Û‹‚ˆ +‹ÂˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÑÑU +Hˆ ‰ˆ +Ý\ˆHš[™Ù[�Ú\™JXÝ[™×Ù[�]KXÝ[™×Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž‹TWÒUSK^Y\—Ý\ÝÜXÚØX›JJJH‚ˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆÙ]ÙÙ][™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÙÙ]ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑÑU  +N‚ˆ Ê‚ˆ +ˆ][H˜]XÚÜȈÛÛXÝ܈ÈXZÙH]ˆ +ˆX\ÞHÈØÜš\XÝ[ÛœÈÛˆ][HXÚÈ\ ˆˆ +‹Âˆ×Ú][WÜØÜš\ +XÝ[™×Ù[�]KÝ\ŠN‚ˆYš[™Ú][JÝ\ŠNˆÛÝÈ[™[šØÚXÚΈB‚ˆ ËÈ\ÙHÝ[[YHÈÚ\™ÙH[™ [[Ý™BˆXÝ[™×Ù[�]KOœÝ[[YHHÝ[YNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ‚ˆYŠXÝ[™×Ù[�]KO�ÙX\[� ‰‚ˆXÝ[™×Ù[�]KO�ÙX\[� O›[Ù[]KœÝX�\HOHÕP•TWÔ“Ò‘PÕSH ‰‚ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÕ“ÕÐUPÒÊH +BˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕ“ÕÐUPÒË +NˆÛÝÈ[™[šØÚXÚΈBˆ[ÙHYŠ\™›Ü›WØ]ÚZ[Š +JBˆˆYŠÛؘ[ÜØ[\WÛ\Ý œ[˜Ú�H  ‰ˆXÝ[™×Ù[�]KO˜]XÚÚ[™ÈOHUPÒÒS‘×Ó“Ó‘JBˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý œ[˜Ú  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆÛÝÈ[™[šØÚXÚΈB‚ˆBˆˆ Ê‚ˆ +ˆ�[\[™ÈÛÛ�Ü› ‚ˆ +‹Â‚ˆYŠXÝ[™×Ü^Y\‹Oœ^ZÙ^\È ˆ“Q×Ò•ST ‰ˆ›Ý[˜Z\ŠBˆˆ ËÈYYZ[˜Z\ŠXÝ[™×Ù[�]JHÛÈ^Y\œÈØ[‰Ý�[\Ú[ˆ˜[[™È[�ÈÛ\ˆXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H‘“Q×Ò•ST‚ˆ Ê‚ˆ +ˆˆ^\ÈÛÛ�›Û ‚ˆ +‚ˆ +ˆYˆ^Y\ˆØ[ˆ[š]X[^™HHˆ�[\ˆ +ˆ[™\܈ÝÛˆÙ^\È\™HXÝ]™HÙIÛˆ +ˆÙ]HÜ�[ÛˆÙˆZ\ˆ�[\ÜYY\ˆ +ˆHˆ™[ØÚ]KˆÙIÛ\ÙH\Ș[YH\ˆ +ˆHˆ\˜[Y]\ˆ›Üˆ[ÝۜݙX[Bˆ +ˆ�[\�[˜Ý[ÛˆØ[Ë‚ˆ +‹Â‚ˆYˆ +XÝ[™×Ù[�]KO›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÖ—ÒS’UPS +BˆˆYˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ[š]X[Ú�[\Ý™[ØÚ]WÞˆH XXÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY +ˆ �NˆBˆ[ÙHYˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ[š]X[Ú�[\Ý™[ØÚ]WÞˆHXÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY +ˆ �NˆBˆBˆ[ÙBˆˆ[š]X[Ú�[\Ý™[ØÚ]WÞˆH ŒˆB‚ˆYŠXÝ[™×Ù[�]KOœ�[›š[™ÊBˆˆ ËÔÛYBˆYŠ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•S”ÓQJJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘Nˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÔ•S”ÓQK +NˆÛÝÈ[™[šØÚXÚΈH‚ˆ ʈ�[\[™È[ÝÙYÈ +‹ÂˆYˆ +JXÝ[™×Ù[�]KO›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÑTÐP“JJBˆˆYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WÔ•S’•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\ZYÚ XÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY +ˆXÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\\Ý [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WÔ•S’•ST +NˆBˆ[ÙHYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WѓԕÐT‘•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\ZYÚ XÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY +ˆXÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\\Ý [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WѓԕÐT‘•ST +NˆBˆ[ÙHYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WÒ•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\ZYÚ XÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY +ˆXÝ[™×Ù[�]KO›[Ù[]Kœ�[š�[\\Ý [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WÒ•ST +NˆBˆBˆBˆ[ÙBˆˆ ËÔÛYBˆYŠ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÔÓQJJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ø]XÚ×Ü›ØÎˆÙ]Ø]XÚÚ[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆXÝ[™×Ù[�]KO˜ÛÛX›ÜÝ\ÌHH ˆXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘Nˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÔÓQK +NˆÛÝÈ[™[šØÚXÚΈB‚ˆ ʈ�[\[™È[ÝÙYÈ +‹ÂˆYˆ +JXÝ[™×Ù[�]KO›[Ù[]K˜Z\—ØÛÛ�›Û ˆRT—ÐÓÓ•“ÓÒ•STÑTÐP“JJBˆ‚ˆ Ê‚ˆ +ˆ[™HY� ÜšYÚ\™XÝ[ÛˆÛÛ[X[™ ‚ˆ +‚ˆ +ˆYˆY�܈šYÚÙ^H\ÈXÝ]™Kˆ +ˆ[ˆÝÚ]Ú˜XÚ[™ÈXØÛÜ™[™ÛH[™ˆ +ˆÛÛ�[�YHÛˆÈ[Ýš[™È�[\ÙÚXË‚ˆ +‚ˆ +ˆÝ\�Ú\ÙH\™›Ü›HH�[\Ú]›Âˆ +ˆÜš^›Û�[™[ØÚ]K‚ˆ +‹Â‚ˆYˆ +JXÝ[™×Ü^Y\‹OšÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +JH ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÒ•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kš�[\ZYÚ  [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WÒ•ST +NˆÛÝÈ[™[šØÚXÚΈBˆ[ÙHYˆ + +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[ÙHYˆ + +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆB‚ˆ Ê‚ˆ +ˆÜš^›Û�[[Ýš[™È�[\ ‚ˆ +‹Â‚ˆYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WѓԕÐT‘•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kš�[\ZYÚ XÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WѓԕÐT‘•ST +NˆBˆ[ÙHYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WÒ•ST +JBˆˆžZ�[\ +XÝ[™×Ù[�]KO›[Ù[]Kš�[\ZYÚ XÝ[™×Ù[�]KO›[Ù[]Kš�[\ÜYY [š]X[Ú�[\Ý™[ØÚ]WÞ‹S’WÒ•ST +NˆBˆBˆBˆ™]\›ŽÂˆB‚ˆ Ê‚ˆ +ˆ�[ˆÝÜ ‚ˆ +‹Âˆ�[—ÝžWÜ�[œÝÜÜ^Y\ŠXÝ[™×Ù[�]KXÝ[™×Ü^Y\ŠN‚ˆ Ê‚ˆ +‹Â‚ˆYŠVQT—ÓRS—ÖˆOHVQT—ÓPVÖˆ ‰ˆXÝ[™×Ù[�]KO™XÚÚ[™ÈOHPÒ×Ó“Ó‘JBˆˆ ËÈ[Ü™HÙˆH]›Ü›H™Y[ˆYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘UT +BˆÈˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÕT +H ‰ˆXÝ[™×Ù[�]KOœ�[›š[™ÈOH•S—ÔÕUWÓ“Ó‘JBˆˆXÝ[ÛˆHPÕSÓ—ÕTˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH XXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž È ŽÈ ËÈ\ÙY›Üˆ\[š[X][Û‚ˆBˆ[ÙHYŠXÝ[™×Ù[�]KOœ�[›š[™È ˆ•S—ÔÕUWÔÕT•Ö +BˆˆXÝ[ÛˆHPÕSÓ—Ô•SŽÂ‚ˆYˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ•S—ÐÓÓ‘’Q×ÖÔ’QÒÑTÒÑ’VQˆ ‰ˆJXÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ•S—ÐÓÓ‘’Q×Ö—ÕTÑS�P“Q +JHˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ŒˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH XXÝ[™×Ù[�]KO›[Ù[]Kœ�[œÜYY È ŽÈ ËÈ[Ý™\È\]H˜\Ý\ˆ˜]H�[›š[™ÂˆBˆBˆ[ÙBˆˆXÝ[ÛˆHPÕSÓ—ÕÐSΈXÝ[™×Ù[�]KO�™[ØÚ]KžˆH XXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž È ŽÂˆBˆBˆ[ÙHYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆÈˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÑÕÓŠH ‰ˆXÝ[™×Ù[�]KOœ�[›š[™ÈOH•S—ÔÕUWÓ“Ó‘JBˆˆXÝ[ÛˆHPÕSÓ—ÑÕӎˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆHXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž È ŽÈ ËÈ\ÙY›ÜˆÝÛˆ[š[X][Û‚ˆBˆ[ÙHYŠXÝ[™×Ù[�]KOœ�[›š[™È ˆ•S—ÔÕUWÔÕT•Ö +BˆˆXÝ[ÛˆHPÕSÓ—Ô•SŽÂ‚ˆYˆ +XÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ•S—ÐÓÓ‘’Q×ÖÔ’QÒÑTÒÑ’VQˆ ‰ˆJXÝ[™×Ù[�]KO›[Ù[]Kœ�[—ØÛÛ™šY×Ù›YÜÈ ˆ•S—ÐÓÓ‘’Q×Ö—ÑÕÓ—ÑS�P“Q +JHˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ŒˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆHXÝ[™×Ù[�]KO›[Ù[]Kœ�[œÜYY È ŽÈ ËÈ[Ý™\È\]H˜\Ý\ˆ˜]H�[›š[™ÂˆBˆBˆ[ÙBˆˆXÝ[ÛˆHPÕSÓ—ÕÐSΈXÝ[™×Ù[�]KO�™[ØÚ]KžˆHXÝ[™×Ù[�]KO›[Ù[]KœÜYY ž È ŽÂˆBˆBˆ[ÙHYŠJXÝ[™×Ü^Y\‹OšÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓŠJJBˆˆXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆBˆBˆ[ÙHYŠXÝ[™×Ù[�]KO™XÚÚ[™ÈOHPÒ×Ó“Ó‘H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÑPÒÊH ‰ˆXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓˆ ‰ˆ›Ý[˜Z\ŠBˆˆžYXÚÊXÝ[™×Ù[�]JNˆÛÝÈ[™[šØÚXÚΈB‚ˆYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• ‰ˆXÝ[™×Ù[�]KO™XÚÚ[™ÈOHPÒ×Ó“Ó‘JBˆˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +Bˆˆ ËØXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NÈ ËÈ]Z]È�[›š[™ÈYˆ^Y\ˆÚ[™Ù\È\™XÝ[Û‚ˆYŠXÝ[™×Ù[�]KO›[Ù[]K�\›™[^H ‰ˆXXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO�\›�[YHHÝ[YH +ÈXÝ[™×Ù[�]KO›[Ù[]K�\›™[^NˆBˆ[ÙHYŠXÝ[™×Ù[�]KO�\›�[YH ‰ˆÝ[YH�HXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO�\›�[YHH ˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÕT“ŠJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ý\›ŽÂˆÙ]Ý\›š[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕT“‹ +NˆÛÝÈ[™[šØÚXÚΈBˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆ[ÙHYŠXXÝ[™×Ù[�]KO›[Ù[]K�\›™[^H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÕT“ŠJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ý\›ŽÂˆÙ]Ý\›š[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕT“‹ +NˆÛÝÈ[™[šØÚXÚΈBˆ[ÙHYŠXXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�\›�[YHH ˆB‚ˆYŠXÝ[™×Ù[�]KOœ�[›š[™ÊBˆˆXÝ[ÛˆHPÕSÓ—Ô•SŽÂˆXÝ[™×Ù[�]KO�™[ØÚ]KžH XXÝ[™×Ù[�]KO›[Ù[]Kœ�[œÜYYÈ ËÈYˆ�[›š[™Ë^Y\ˆ[Ý™\È]H˜\Ý\ˆ˜]BˆBˆ[ÙHYŠXÝ[ÛˆOHPÕSÓ—ÕT ‰ˆXÝ[ÛˆOHPÕSÓ—ÑÕÓŠBˆˆXÝ[ÛˆHPÕSÓ—ÕÐSΈXÝ[™×Ù[�]KO�™[ØÚ]KžH XXÝ[™×Ù[�]KO›[Ù[]KœÜYY žˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�™[ØÚ]KžH XXÝ[™×Ù[�]KO›[Ù[]KœÜYY žˆBˆBˆ[ÙHYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ ‰ˆXÝ[™×Ù[�]KO™XÚÚ[™ÈOHPÒ×Ó“Ó‘JBˆˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +Bˆˆ ËØXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NÈ ËÈ]Z]È�[›š[™ÈYˆ^Y\ˆÚ[™Ù\È\™XÝ[Û‚ˆYŠXÝ[™×Ù[�]KO›[Ù[]K�\›™[^H ‰ˆXXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO�\›�[YHHÝ[YH +ÈXÝ[™×Ù[�]KO›[Ù[]K�\›™[^NˆBˆ[ÙHYŠXÝ[™×Ù[�]KO�\›�[YH ‰ˆÝ[YH�HXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO�\›�[YHH ˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÕT“ŠJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ý\›ŽÂˆÙ]Ý\›š[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕT“‹ +NˆÛÝÈ[™[šØÚXÚΈBˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆ[ÙHYŠXXÝ[™×Ù[�]KO›[Ù[]K�\›™[^H ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÕT“ŠJBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ý\›ŽÂˆÙ]Ý\›š[™ÊXÝ[™×Ù[�]JNˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO�™[ØÚ]KžˆH ˆ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕT“‹ +NˆÛÝÈ[™[šØÚXÚΈBˆ[ÙHYŠXXÝ[™×Ù[�]KO�\›�[YJBˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�\›�[YHH ˆB‚ˆYŠXÝ[™×Ù[�]KOœ�[›š[™ÊBˆˆXÝ[ÛˆHPÕSÓ—Ô•SŽÂˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO›[Ù[]Kœ�[œÜYYÈ ËÈYˆ�[›š[™Ë^Y\ˆ[Ý™\È]H˜\Ý\ˆ˜]BˆBˆ[ÙHYŠXÝ[ÛˆOHPÕSÓ—ÕT ‰ˆXÝ[ÛˆOHPÕSÓ—ÑÕÓŠBˆˆXÝ[ÛˆHPÕSÓ—ÕÐSΈXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO›[Ù[]KœÜYY žˆBˆ[ÙBˆˆXÝ[™×Ù[�]KO�™[ØÚ]KžHXÝ[™×Ù[�]KO›[Ù[]KœÜYY žˆBˆBˆ[ÙHYŠJ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• +Hˆ +XÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JH +Bˆˆ ËØXÝ[™×Ù[�]KOœ�[›š[™ÈH•S—ÔÕUWÓ“Ó‘NÈ ËÈ^Y\ˆ]ÛÈÙˆY� ÜšYÚ[™ÛÈ]Z]È�[›š[™ÂˆXÝ[™×Ù[�]KO�™[ØÚ]KžH ˆXÝ[™×Ù[�]KO�\›�[YHH ˆB‚ˆYŠ +Ý\ˆHš[™Ù[�Ú\™JXÝ[™×Ù[�]KXÝ[™×Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž‹TWÒUSK^Y\—Ý\ÝÝÝXÚ +JH +Bˆˆ×Ú][WÜØÜš\ +XÝ[™×Ù[�]KÝ\ŠNˆYš[™Ú][JÝ\ŠNÈ ËÈYY�[˜Ý[ÛˆÈÛX[ˆÛÙH\Hš]ˆB‚ˆYˆ +XÝ[™×Ù[�]KO™XÚÚ[™È ˆPÒ×ÐPÕU‘JBˆˆYˆ +JXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠJBˆˆžYXÚÜš\ÙJXÝ[™×Ù[�]JNˆÛÝÈ[™[šØÚXÚΈBˆYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘SQ• +BˆˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—ÓQ•ˆBˆBˆ[ÙHYŠXÝ[™×Ü^Y\‹OšÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +BˆˆYŠXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +BˆˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒˆBˆBˆBˆYˆ +XÝ[™×Ù[�]KO™XÚÚ[™ÊBˆˆÛÝÈ[™[šØÚXÚΈB‚‚ˆ ËÕÚ]H˜YÛÛŽˆ™\\™H›ÜˆY[™È[š[X][ۜˋ‹‚ˆYŠXÝ[ÛŠBˆˆXÝ[™×Ù[�]KO�ZÙXXÝ[ÛˆH•SˆXÝ[™×Ù[�]KOšY[™ÈHQS‘×Ô‘TT‘QˆB‚ˆÝÚ]Ú +XÝ[ÛŠBˆˆØ\ÙHPÕSÓ—ÕÐS΂ˆ ËȘXÚÈØ[È™X]\™BˆYŠ]™[ ‰ˆ˜[Y[š[JXÝ[™×Ù[�]KS’WÐ�PÒÕÐSÊJH‚ˆYŠXÝ[™×Ù[�]KO›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÔ’QÒ]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÔ’QÒ +H‚ˆ˜XÚ×ÝØ[ÈHXXÝ[™×Ù[�]KO™\™XÝ[ێ‚ˆH[ÙHYŠXÝ[™×Ù[�]KO›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓQ•]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓQ• +H‚ˆ˜XÚ×ÝØ[ÈHXÝ[™×Ù[�]KO™\™XÝ[ێ‚ˆH[ÙHYŠ +XÝ[™×Ù[�]KO›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S +H ‰ˆ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +H ‰ˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +H‚ˆ˜XÚ×ÝØ[ÈH�YN‚ˆH[ÙHYŠ +XÝ[™×Ù[�]KO›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S +H ‰ˆ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÔ’QÒ +H ‰ˆXÝ[™×Ù[�]KO™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +H‚ˆ˜XÚ×ÝØ[ÈH�YN‚ˆH[ÙHYŠXÝ[™×Ù[�]KO�\›�[YH ‰ˆXÝ[™×Ù[�]KO›[Ù[]K�\›™[^JH‚ˆ˜XÚ×ÝØ[ÈH�YNˆB‚ˆYŠ˜XÚ×ÝØ[ÊHˆÛÛ[[ؘۗXÚÝØ[ר[š[JXÝ[™×Ù[�]JNȈH[ÙHˆÛÛ[[Û—ÝØ[ר[š[JXÝ[™×Ù[�]JNˆBˆˆH[ÙHˆÛÛ[[Û—ÝØ[ר[š[JXÝ[™×Ù[�]JNȈBˆœ™XZΈØ\ÙHPÕSÓ—ÕT‚ˆÛÛ[[Û—Ý\Ø[š[JXÝ[™×Ù[�]JNÈ ËÙ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÕT  +NÈ ËÈÙ]È\[š[X][ÛˆYˆ^\݈œ™XZΈØ\ÙHPÕSÓ—ÑÕÓŽ‚ˆÛÛ[[Û—ÙÝÛ—Ø[š[JXÝ[™×Ù[�]JNÈ ËÙ[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÑÕÓ‹ +NÈ ËÈÙ]ÈÝÛˆ[š[X][ÛˆYˆ^\݈œ™XZΈØ\ÙHPÕSÓ—Ô•SŽ‚ˆYˆ +˜[Y[š[JXÝ[™×Ù[�]KS’WÐ�PÒÔ•SŠJBˆˆYˆ +\×Ú[—ؘXÚÜ�[ŠXÝ[™×Ù[�]JJH[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÐ�PÒÔ•S‹ +Nˆ[ÙH[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÔ•S‹ +NˆBˆ[ÙH[�ÜÙ]Ø[š[JXÝ[™×Ù[�]KS’WÔ•S‹ +NÈ ËÈÙ]È�[ˆ[š[X][ÛˆYˆ^\Ý‚ˆœ™XZΈY˜][‚‚ˆYŠXÝ[™×Ù[�]KOšY[™ÊBˆˆÛÛ[[Û—ÚYWØ[š[JXÝ[™×Ù[�]JNˆBˆœ™XZΈB‚‚™[™[šØÚXÚ΂ˆ ËÚ[œÙ\�ÚXÚÈ\™Bˆ™]\›ŽÂŸB‚š[�\×Ú[—ؘXÚÜ�[Š[�]JˆÙ[ŠBžÂˆYˆ + + +Ù[‹O›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÔ’QÒ]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÔ’QÒ +H ‰ˆÙ[‹O�™[ØÚ]Kž +Hˆ + +Ù[‹O›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓQ•]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓQ• +H ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Hˆ + + +Ù[‹O›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S +H ‰ˆ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÔ’QÒ +JH ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Hˆ + + +Ù[‹O›[Ù[]K™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S]™[ O™˜XÚ[™ÈOH�PÒS‘×ÐQ•TÕÓU‘S +H ‰ˆ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +JH ‰ˆÙ[‹O�™[ØÚ]Kžˆ +Bˆ +H™]\›ˆ Nˆ[ÙH™]\›ˆ ŸB‚‹ËØ[[[ÈÛÝ[�ÛÙ\ÈÝÛ‚�›ÚYÝX�˜XÝÜÚÝ + +BžÂˆYŠÙ[‹O�ÙX\[� ‰ˆÙ[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØÛÝ[� +BˆˆÙ[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØÛÝ[� KN‚ˆ Ê‚ˆ +ˆÝ]Ùˆ\Ù\ÏÈ›ÜHÙX\Û‹‚ˆ +‹Â‚ˆYŠ\Ù[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�\ÙWØÛÝ[� +BˆˆÙ[‹O�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜרÛÝ[�H ˆ›ÜÙX\ÛŠÙ[‹ +NˆBˆBŸB‚‚�›ÚY›ÜÙX\ÛŠ[�]JˆXÝ[™×Ù[�]K[�›YÊBžÂˆ[�Ø[H ˆ[�]H +›Ý\ˆH•Sˆ[�]JˆÙX\Û—Ù[�]HH•Sˆ×ÝÙX\ÛŠˆÙX\Û—Ü›Ü\�Y\ÈH•S‚‚KËÈYˆÙH[™XYH]™HHÙX\Û‹ÙIÛ™YYÈ\ØØ\™] ‚ˆYŠXÝ[™×Ù[�]KO�ÙX\[� +Bˆˆ Ê‚ˆ +ˆ[\Ú[�\œÈÈÙ[‰ÜÈÙX\Ûˆ[�]H[™Hˆ +ˆÙX\Ûˆ[�]IÜÈ[Ù[]HÙX\Ûˆ›Ü\�Y\Ȉ +ˆ[�ÈØØ[˜\šXX›\ˈ\È\È�\ݛ܈XZ\Ù\ˆˆ +ˆ™XY[™ÈÝۜݙX[K‚ˆ +‹Â‚ˆÙX\Û—Ù[�]HHXÝ[™×Ù[�]KO�ÙX\[�ˆÙX\Û—Ü›Ü\�Y\ÈH ˜XÝ[™×Ù[�]KO�ÙX\[� O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\΂‚BKËÈ Œ NKLKLŽH H›ÝÝ\™HX›Ý]\ÈÙÚXˈ]\X\œÈ]Û›H\HÚÝ‚BKËÈÙX\ÛœÈ܈ÙX\ÛœÈÚ]ÚÝ[[[È\™H›ÜY ˆ[ž][™È[ÙH\ÈÚ[\H\ØØ\™Y ‚‚BKËÈ™YYÈ]˜[X]H[ÙX\ÛˆÙÚXÈÈÙ]HÛÜšÙ›ÝË‚ˆYŠÙX\Û—Ü›Ü\�Y\ËO�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÓSRUQÕTÑH +JÙX\Û—Ü›Ü\�Y\ËO�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÓSRUQÕTÑJH ‰ˆÙX\Û—Ü›Ü\�Y\ËO�\ÙWØÛÝ[� +JBˆÈ‚BBKËÈYˆH›YÈ\È ˆ܈™[ÝËÙHÝX�˜XÝH›YÉÜ‚BBKËȘ[YHœ›ÛHÙX\ÛˆÛÝ[�\‹‚‚BBZYŠ›YÈ ŠBˆˆÙX\Û—Ü›Ü\�Y\ËO›ÜÜרÛÝ[� OH›YΈBˆ‚BBKËÈÙIÜ™HÛÚ[™ÈÈ\ÙHÝ\ˆÝÛˆÜÚ][Ûˆ›ÜˆHÙX\Û‹‚ˆÙX\Û—Ù[�]KO™\™XÝ[ÛˆHXÝ[™×Ù[�]KO™\™XÝ[ێˆÙX\Û—Ù[�]KOœÜÚ][Û‹žˆHXÝ[™×Ù[�]KOœÜÚ][Û‹žŽÂˆÙX\Û—Ù[�]KOœÜÚ][Û‹žHXÝ[™×Ù[�]KOœÜÚ][Û‹žˆÙX\Û—Ù[�]KOœÜÚ][Û‹žHHXÝ[™×Ù[�]KOœÜÚ][Û‹žN‚‚BBKËÈÙ][žHØ[È[™]›Ü›\Ë‚ˆÝ\ˆHÚXÚ×Ü]›Ü›JÙX\Û—Ù[�]KOœÜÚ][Û‹ž ÙX\Û—Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]JNˆØ[HÚXÚÝØ[Ú[™^ +ÙX\Û—Ù[�]KOœÜÚ][Û‹ž ÙX\Û—Ù[�]KOœÜÚ][Û‹žŠN‚‚BBKËÈXÙHÛ�ÈØ[܈]›Ü›K‚ˆYŠÝ\ˆ ‰ˆÝ\ˆOHÙX\Û—Ù[�]JBˆˆÙX\Û—Ù[�]KO˜˜\ÙH +ÏHÝ\‹OœÜÚ][Û‹žH +ÈÝ\‹O˜[š[X][Û‹Oœ]›Ü›VÛÝ\‹O˜[š[\Ü×VÔU“Ô“WÒRQÒNˆBˆ[ÙHYŠØ[�H +BˆˆÙX\Û—Ù[�]KO˜˜\ÙH +ÏH]™[ O�Ø[ÖÝØ[KšZYÚˆB‚‚BBKËÈ\ÙHHÙX\Û‰ÜÈ‘TÔUÓˆ܈ÔUÓˆ[š[X][ÛœÈYˆ]˜Z[X›KÝ\�Ú\ÙB‚BBKËÈÛÈšYÚÈYK‚ˆYŠ˜[Y[š[JÙX\Û—Ù[�]KS’WÔ‘TÔUÓŠJBˆˆ[�ÜÙ]Ø[š[JÙX\Û—Ù[�]KS’WÔ‘TÔUÓ‹ JNˆBˆ[ÙHYŠ˜[Y[š[JÙX\Û—Ù[�]KS’WÔÔUÓŠJBˆˆ[�ÜÙ]Ø[š[JÙX\Û—Ù[�]KS’WÔÔUÓ‹ JNˆBˆ[ÙBˆˆYŠ˜[Y[š[JÙX\Û—Ù[�]KS’WÒQJJH[�ÜÙ]Ø[š[JÙX\Û—Ù[�]KS’WÒQK JNˆB‚‚BBKËÈYˆHÙX\Û‰ÜÈÛÝ[�\ˆ\È\]Y [ˆÙX\Ûˆ\ÈÜݛ܈ÛÛÙ ‚‚BBKËÈYˆ]\È[ˆ˜[š[X[‹[ˆÙH\HH[š[X[�[›š[™È]Ø^HÙÚXË‚‚BBKËÈÝ\�Ú\ÙHHÙX\Ûˆ›[šÜÈÝ] ‚ˆYŠ]ÙX\Û—Ü›Ü\�Y\ËO›ÜÜרÛÝ[� +BˆˆYŠJXÝ[™×Ù[�]KO›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—ÜÝ]H ˆÑPTÓ—ÔÕUWÐS’SPS +JBˆˆÙX\Û—Ù[�]KO˜›[šÈH NˆÙX\Û—Ù[�]KO�ZÙXXÝ[ÛˆHÛÛ[[Û—ÛYNˆBˆ[ÙBˆˆÙX\Û—Ù[�]KO›[Ù[]K�\HHTWÓ“Ó‘NˆÙX\Û—Ù[�]KO�[šÈH�[˜[š[X[ˆBˆBˆÙX\Û—Ù[�]KO›™^[šÈHÝ[YH +È NˆB‚‚BKËÈÛX\ˆÝ\ˆ˜XÚÚ[™È˜\šXX›H]ÙY\ÈHÙX\Ûˆ[�]HÚ[�\‹‚ˆXÝ[™×Ù[�]KO�ÙX\[�H•SˆB‚‚KËÈ›YÈ ˆYX[œÈÙIÜ™H›Ø˜X›HÙ][™ÈHÙX\Ûˆ\™XÝH +^ˆÙ]ÙX\ÛˆÛÛ[X[™ +Kˆ‚KËÈ[ˆ]Ø\ÙHÙHÛ‰ÝÛÜœžHX›Ý]HÙX\Ûˆ[�]Kˆ�\ÝÝÚ]ÚÝ\œÙ[™\ÈÝ™\‚‚KËÈÈHÙX\Ûˆ[Ù[ ‚ˆYŠ›YÈ ŠBˆˆYŠXÝ[™×Ù[�]KO›[Ù[]K�\H ˆTWÔVQTŠBˆˆYŠ^Y\–ØXÝ[™×Ù[�]KOœ^Y\š[™^K�ÙX\�[JBˆˆÙ]ÝÙX\ÛŠXÝ[™×Ù[�]K^Y\–ØXÝ[™×Ù[�]KOœ^Y\š[™^K�ÙX\�[K +NˆBˆ[ÙBˆˆÙ]ÝÙX\ÛŠXÝ[™×Ù[�]K]™[ OœÙ]ÙX\  +NˆBˆBˆ[ÙBˆˆÙ]ÝÙX\ÛŠXÝ[™×Ù[�]K  +NˆBˆB‚‚KËÈ[Ù[Ý™\œšYKˆYˆ\È\ÈÜ[]Y ÙH\ÙH]Ș[YB‚KËÈÈØØ]HH[Ù[žH[™^[™™]™\�È][œÝXY‚KËÈÙˆHY˜][[Ù[Ú[ˆHÙX\Ûˆ\ÈÜÝ ‚ˆYŠXÝ[™×Ù[�]KO›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜ×Ú[™^OHSÑSÒS‘VÓ“Ó‘JBˆˆÙ]ÝÙX\ÛŠXÝ[™×Ù[�]KXÝ[™×Ù[�]KO›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜ×Ú[™^  +NˆBŸB‚‚š[�^Y\—ÝZÙY[XYÙJ[�]Jˆ\™Ù]Ù[�]K[�]Jˆ]XÚÚ[™×Ù[�]Kר]XÚʈ]XÚ×ÛØš™XÝ [�˜[Ù›YËÛÛœÝ×ÙY™[œÙJˆY™[œÙWÛØš™XÝ +BžÂˆר]XÚÈ]ÈH +˜]XÚ×ÛØš™X݈ ËÜš[�Š™[XYÙYžNˆ É\ÉÈ Yˆ‹Ý\‹O›˜[YK]XÚËO˜]XÚ×ٛܘÙJN‚‚KËÈܘ]\È + L LŒ ŒJH›ÝÈHš[™š[š]HX[ÚX]ˆÚ[ÚXÚÈH[XYÙHÛÝ\˜ÙK]Ú[]›ÚYÛÛYHœÜXÚX[ˆ[XYÙHÛÝ\˜Ù\‚‚KËÈ[XYÙHÛÛY\Èœ›ÛHH›Ü›X[ÛÝ\˜ÙO‚XÛۜݛÛۛܛX[Ù[XYÙHH +Z\ר]XÚ×Ý\WÜÜXÚX[ +]˘]XÚ×Ý\JJHÈ�YHˆ˜[ÙN‚ˆYŠ +Ûؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÒPSÐPÕU‘H ‰ˆ›Ü›X[Ù[XYÙJBˆ +]™[ O››Ú\�OHSPQÑWÑ”“ÓWÑS‘SVWÓÑ‘ˆ ‰ˆ +]XÚÚ[™×Ù[�]KO›[Ù[]K�\H ˆTWÑS‘SVJJJBˆˆ]˘]XÚ×ٛܘÙHH ˆBˆˆ™]\›ˆÛÛ[[Û—ÝZÙY[XYÙJ\™Ù]Ù[�]K]XÚÚ[™×Ù[�]K ˜]˘[Ù›YËY™[œÙWÛØš™XÝ +NŸB‚‹ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË‚‹ËÈØ[YÚ[ˆ^Y\ˆ™KY[�\œÈHØ[YK‚‹ËÈ›Ü[[™[ZY\ÈVÑT›ÜˆH[šÙY Ùœ›Þ™[ˆÛ™\Ë‚�›ÚY›ÜØ[Ù[™[ZY\Ê +BžÂˆ[�Nˆ[�]H +�ÙX\Ù[ˆHÙ[ŽÂˆר]XÚÈ]XÚÈH[\X]XÚ΂ˆ›ÜŠHH ÈH[�ÛX^ÈJÊÊBˆˆYŠ[�Û\ÝÚWKO™^\ÝÈ ‰‚ˆ[�Û\ÝÚWKO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ  ‰‚ˆ +[�Û\ÝÚWKO›[Ù[]K�\H ˆTWÑS‘SVJH ‰‚ˆY[�Û\ÝÚWKO›ÝÛ™\ˆ ‰ˆ ËÈÛ‰ÝØ[�ÈÛ›ØÚÈÝÛˆH›Ú™XÝ[BˆY[�Û\ÝÚWKO™œ›Þ™[ˆ ‰ˆ ËÈÛ‰ÝØ[�È[™œ™Y^™HHœ›Þ™[ˆ[™[^BˆJ[�Û\ÝÚWKO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×Ó“×ÓSÕ‘JH ‰‚ˆJ[�Û\ÝÚWKO›[Ù[]KœZ[—ØÛÛ™šY×Ù›YÜÈ ˆRS—ÐÓÓ‘’Q×Ñ�SÑTÐP“JH ‰‚ˆ˜[Y[š[J[�Û\ÝÚWKS’WÑ�S +H +Bˆˆ[�Û\ÝÚWKO˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘Nˆ[�Û\ÝÚWKOœ›Ú™XÝ[HH“TÕÓ“Ó‘Nˆ[�Û\ÝÚWKO�ZÙXXÝ[ÛˆHÛÛ[[Û—Ù˜[ËËÙ[™[^WÙ˜[ˆ[�Û\ÝÚWKO™[XYÙWÛÛ—Û[™[™Ë˜]XÚ×ٛܘÙHH ˆ[�Û\ÝÚWKO™[XYÙWÛÛ—Û[™[™Ë˜]XÚ×Ý\HHU×Ó“Ó‘NˆÙ[ˆH[�Û\ÝÚWNˆ[�Ý[›[šÊÙ[ŠNˆ[�Û\ÝÚWKO�™[ØÚ]KžH +Ù[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +HÈ + LKŒŠHˆ KŒŽÂˆˆYŠ[�Û\ÝÚWKO›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë›ÜÜרÛÛ™][Ûˆ ˆÑPTÓ—ÓÔÔ×ÐÓÓ‘USÓ—ÔÕQÑJBˆˆ›ÜÙX\ÛŠÙ[‹ JNˆB‚ˆÜÜÊ[�Û\ÝÚWK ‹�H +Ș[™Š JJNˆ[�Û\ÝÚWKOšÛ›ØÚÙÝÛ˜ÛÝ[�H[�Û\ÝÚWKO›[Ù[]KšÛ›ØÚÙÝÛ˜ÛÝ[�‚ˆ[�Û\ÝÚWKOšÛ›ØÚÙÝÛ�[YHH ‚ˆÙ]Ù˜[ +[�Û\ÝÚWKÙ[‹ ˜]XÚË JNˆBˆBˆÙ[ˆHÙX\Ù[ŽÂŸB‚‚‚‹ÊˆØ[YÚ[ˆ›ÜÜÈY\ˈ +‹Â�›ÚYÚ[Ø[Ù[™[ZY\Ê +BžÂˆ[�Nˆר]XÚÈ]XÚÈH[\X]XÚΈ[�]H +�\Ù[ˆH•S‚‚X]XÚ˘]XÚ×Ý\HHU×ГÔÔ×ÑPU‚X]XÚË™›ÜˆHY˜][Û[Ù[ٛ܎‚ˆ ʈˆ +ˆÝۜݙX[H[XYÙH�[˜Ý[ÛœÈ\ÙHˆ +ˆÙ[ˆÛؘ[ ÛÈÙHÜ[]H]Ú]ˆ +ˆ[�]HÝ\œÛ܈[ˆXXÚ]\˜][ÛˆÙˆˆ +ˆÛÜ™[ÝˈÙY\Ý\œ™[�˜[YH\™Hˆ +ˆÛÈÙHØ[ˆ™\ÝÜ™HÚ[ˆÛÜ\Èš[š\ÚY ˆˆ +‹Âˆ\Ù[ˆHÙ[ŽÂ‚ˆ ʈˆ +ˆ]™\žH˜[Y[™[^H\HÚ]HZÙY[XYÙBˆ +ˆ�[˜Ý[ÛˆZÙ\È]ÈÝ\œ™[�X[[ˆ[XYÙK‚ˆ +‹Âˆ›ÜŠHH ÈH[�ÛX^ÈJÊÊBˆˆYŠ[�Û\ÝÚWKO™^\݈ ‰ˆ[�Û\ÝÚWKO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ ˆ ‰ˆ +[�Û\ÝÚWKO›[Ù[]K�\H ˆTWÑS‘SVJBˆ ‰ˆ[�Û\ÝÚWKO�ZÙY[XYÙJBˆˆÙ[ˆH[�Û\ÝÚWN‚ˆ]XÚ˘]XÚ×ٛܘÙHHÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆÙ[‹O�ZÙY[XYÙJÙ[‹Ù[‹ ˜]XÚË Ù[‹O™Y™[œÙJNˆBˆB‚ˆÙ[ˆH\Ù[ŽÈŸB‚‚‚�›ÚYÛX\�Ø›ÛXŠ[�]H +™Kר]XÚÈ +˜]XÚÊHÈ ËÈ™]ÈY]ٛ܈ÛX\�›ÛXœÂ‚ˆ[�K]H ˆ[�]H +�\Ù[ˆH•S‚ˆ\Ù[ˆHÙ[ŽÂˆ›ÜŠHH ÈH[�ÛX^ÈJÊÊH‚ˆYŠ[�Û\ÝÚWKO™^\݈ ‰ˆ[�Û\ÝÚWHOHBˆ ‰ˆ[�Û\ÝÚWKO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ ˆ ‰ˆ˜XÝ[Û—ØÚXÚ×Ú\×ÚÜÝ[JK[�Û\ÝÚWJJHˆˆÙ[ˆH[�Û\ÝÚWNˆ]H NÈ Ëț܈›ØÛÜÝ YˆH›ÛXˆÙ\Û‰Ý] ]ÛÛ‰ÝÛÜÝ[™\™ÞB‚ˆ\Ý] ˜]XÚÈH]XÚΈ\Ý] ˜]XÚÙ\ˆHNˆ\Ý] ˜ÛÛ\Ú[Û—Ø]XÚÈH•Sˆ\Ý] ˜ÛÛ™š\›HH Nˆ\Ý] ™]XÝØ›ÙHH•Sˆ\Ý] ™]XÝØÛÛ\Ú[Û—Ø]XÚÈH•Sˆ\Ý] ™]XÝØÛÛ\Ú[Û—Ø›ÙHH•Sˆ\Ý] œÜÚ][Û‹žHÙ[‹OœÜÚ][Û‹žˆ\Ý] œÜÚ][Û‹žHHÙ[‹OœÜÚ][Û‹žNˆ\Ý] œÜÚ][Û‹žˆHÙ[‹OœÜÚ][Û‹žŽÂˆ\Ý] �\™Ù]HÙ[ŽÂ‚ˆYŠÙ[‹O�ZÙY[XYÙJH‚ˆÛÛœÝ×ÙY™[œÙJˆY™[œÙWÛØš™XÝHY™[œÙWÙš[™ØÝ\œ™[�ÛØš™XÝ +Ù[‹•S ]XÚËO˜]XÚ×Ý\JNˆˆ ËØ]XÚ˘]XÚ×Ù›ÜHÙ[‹O›[Ù[]KšÛ›ØÚÙÝÛ˜ÛÝ[� +ÌNˆÙ[‹O�ZÙY[XYÙJÙ[‹K]XÚË Y™[œÙWÛØš™XÝ +NˆˆH[ÙHˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OH]XÚËO˜]XÚ×ٛܘÙNˆˆYŠÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H +HˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÔÓPT•“ÓPŠNˆBˆB‚ˆÜ]Û—Ø]XÚ×Ù›\Ú +Ù[‹]XÚË]XÚËO™›\Ú ›[Ù[Ú] Ù[‹O›[Ù[]K™›\Ú ›[Ù[Ø›ØÚÊNˆˆBˆB‚ˆYŠ›ØÛÜÝ ‰ˆ] ‰ˆÛX\�›ÛX™\ŠHÈ ËÈÛ‰Ý\ÙHK™XØ]\ÙH\ÈØ[ˆ™H[ˆ][KX›ÛX‚ˆÙ[ˆHÛX\�›ÛX™\ŽÂˆˆYŠÚXÚ×Ù[™\™ÞJS‘T‘ÖWÕTWÓT S’WÔÔPÒPS +JHˆÙ[‹O™[™\™ÞWÜÝ]K›\ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈H[ÙHˆÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OHÙ[‹O›[Ù[]K˜[š[X][Û–ÐS’WÔÔPÒPSKO™[™\™ÞWØÛÜÝ ˜ÛÜ݈BˆˆB‚ˆÙ[ˆH\Ù[ŽÂ‚ŸB‚‚‹ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË‚�›ÚY[ž][™×ÝØ[Ê +BžÂˆYŠÙ[‹OœÜÚ][Û‹žY˜[˜Ù^ H Ù[‹OœÜÚ][Û‹žˆY˜[˜Ù^ +È +šY[Û[Ù\Ëš™\È +È +JBˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÕÐS×ÓÕUÓїГÕS‘ÊNˆ™]\›ŽÂˆBˆ ËÜÙ[‹OœÜÚ][Û‹ž +ÏHÙ[‹O�™[ØÚ]KžŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ NKLL‹LN‹Ë‹ËÈ\HÛÛ܈Ù]Y�\ÝY[�È[�]KÜÜÚX›B‹ËȘ\ÙYÛˆH\™[� ÛÝÛ™\ˆ\[™[™ÈÛˆÛÛ܈Ù]‹ËÈY�\ÝY[�Ù][™Ë‚�›ÚY\WØÛÛÜ—ÜÙ]ØY�\Ý +[�]Jˆ[� [�]Jˆ\™[� WØÛÛÜ—ØY�\ÝY�\ÝY[� +BžÂ‚Z[�HH È ËÈÛÜÝ\œÛÜ‹‚‚‚KËÈ\HÛÛ܈Ù][™Ë‚‚\ÝÚ]Ú +Y�\ÝY[� +B‚^‚YY˜][‚‚B‚BKËÈ\ÙHY�\ÝY[�˜[YH\ÈÛÛ܈Ù][™^ ‚‚BY[�ÜÙ]ØÛÛÝ\›X\ +[� Y�\ÝY[� +N‚BXœ™XZ΂B‚XØ\ÙHÓÓÔ”ÑUÐQ•TÕÓ“Ó‘N‚‚BB‚BKËÈÈ›Ý[™Ë‚BB‚BXœ™XZ΂B‚XØ\ÙHÓÓÔ”ÑUÐQ•TÕÔT‘S•ÒS‘V‚‚‚BKËÈØØ]H\™[� ÜÈÝ\œ™[�ÛÛ܈Ù][™^ ˆ[‚‚BKËÈÙ]Ý\ˆÛÛ܈Ù]žH][™^ ‚‚‚BY›Üˆ +HH ÈH\™[� O›[Ù[]K›X\×ÛØYYÈJÊÊB‚B^‚BBZYˆ +\™[� O˜ÛÛÝ\›X\OH\™[� O›[Ù[]K˜ÛÛÝ\›X\ÚWJB‚BB^‚BBBY[�ÜÙ]ØÛÛÝ\›X\ +[� JN‚BBBXœ™XZ΂BB_B‚B_B‚BXœ™XZ΂‚XØ\ÙHÓÓÔ”ÑUÐQ•TÕÔT‘S•ÕP“N‚‚BB‚BKËÈ\ÙH\™[� ÜÈÛÛ܈X›K‚‚‚BY[� O˜ÛÛÝ\›X\H\™[� O˜ÛÛÝ\›X\‚BXœ™XZ΂‚_BŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Š‚Šˆ Œ NKLL‹LŒ‚ŠˆÛÜHH˜XÝ[ÛˆÙ][™ÜÈœ›ÛHHŠˆÛÝ\˜ÙH[�]K‚Š‹È�›ÚY˜XÝ[Û—ØÛÜWØ[ +[�]Jˆ\Ý [�]JˆÛÝ\˜ÙJBžÂˆ˜XÝ[Û—ØÛÜWÙ]J ™\Ý O›[Ù[]K™˜XÝ[Û‹ œÛÝ\˜ÙKO™˜XÝ[ÛŠNˆ˜XÝ[Û—ØÛÜWÙ]J ™\Ý O™˜XÝ[Û‹ œÛÝ\˜ÙKO™˜XÝ[ÛŠNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËL ‹LŽŠˆŠˆÛÜH˜XÝ[Ûˆ›Ü\�Y\ÈYˆŠˆÛÛ™][ÛœÈ\ÜË‚Š‹Â�›ÚY˜XÝ[Û—ØÛÜWÙ]J×Ù˜XÝ[ÛŠˆ\Ý ×Ù˜XÝ[ÛŠˆÛÝ\˜ÙJH‚ˆ Ê‚ˆ +ˆH\Ý[˜][Ûˆ\È[Ø^\ÈH˜XÝ[Û‚ˆ +ˆØš™XÝ ™YØ\™\ÜÈÙˆÚXÚ˜XÝ[Û‚ˆ +ˆ›Ü\�Y\È]X[YžH›ÜˆÛÜZ[™Ë‚ˆ +‹Âˆ\Ý O›Øš™XÝÝ\HHÐ’‘PÕÕTWÑ�PÕSӎ‚ˆ Ê‚ˆ +ˆ˜XÝ[ۈܛÝ\ˈÛ›HÛÜHYˆÛÝ\˜ÙH܈ˆ +ˆ\Ý[˜][Ûˆ\ÈH˜[YH[™Ù\ț݈ +ˆ]™HH›ÈÛÜH›YË‚ˆ +ˆˆ +ˆIÙ˜]\ˆ™HX›HÈÛÜH[\H˜[Y\Ȉ +ˆ\ÈÙ[ �]]™\]Z\™\È[œÙ\�[™Èˆ +ˆY˜][˜[Y\È[ˆÙ]™\˜[Y™™\›�ˆ +ˆØØ][ÛœÈ\›Ý[™HÛÙKˆ™]\ˆˆ +ˆÙY\]\™H[™XZ[�Z[˜X›Kˆˆ +‹Â‚ˆYˆ +ÛÝ\˜ÙKO™[XYÙWÙ\™XÝOH�PÕSÓ—ÑÔ“ÕTÓ“Ó‘Hˆ ‰ˆJÛÝ\˜ÙKO™[XYÙWÙ\™XÝ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O™[XYÙWÙ\™XÝ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJJHˆ\Ý O™[XYÙWÙ\™XÝHÛÝ\˜ÙKO™[XYÙWÙ\™XÝȈB‚ˆYˆ +ÛÝ\˜ÙKO™[XYÙWÚ[™\™XÝOH�PÕSÓ—ÑÔ“ÕTÓ“Ó‘Hˆ ‰ˆJÛÝ\˜ÙKO™[XYÙWÚ[™\™XÝ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O™[XYÙWÚ[™\™XÝ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJJHˆ\Ý O™[XYÙWÚ[™\™XÝHÛÝ\˜ÙKO™[XYÙWÚ[™\™XÝȈBˆˆYˆ +ÛÝ\˜ÙKOšÜÝ[HOH�PÕSÓ—ÑÔ“ÕTÓ“Ó‘Hˆ ‰ˆJÛÝ\˜ÙKOšÜÝ[H ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJHˆ ‰ˆJ\Ý OšÜÝ[H ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJJHˆ\Ý OšÜÝ[HHÛÝ\˜ÙKOšÜÝ[NȈBˆˆYˆ +ÛÝ\˜ÙKO›Y[X™\ˆOH�PÕSÓ—ÑÔ“ÕTÓ“Ó‘Hˆ ‰ˆJÛÝ\˜ÙKO›Y[X™\ˆ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O›Y[X™\ˆ ˆ�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔJJHˆ\Ý O›Y[X™\ˆHÛÝ\˜ÙKO›Y[X™\ŽÈˆB‚ˆ Ê‚ˆ +ˆ\\ˈØ[YH�[H\ȘXÝ[ۈܛÝ\Ë‚ˆ +‹Â‚ˆYˆ +ÛÝ\˜ÙKO�\WÙ[XYÙWÙ\™XÝOHTWÕS‘PÓT‘Qˆ ‰ˆJÛÝ\˜ÙKO�\WÙ[XYÙWÙ\™XÝ ˆTWÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O�\WÙ[XYÙWÙ\™XÝ ˆTWÓ“×ÐÓÔJJHˆˆ\Ý O�\WÙ[XYÙWÙ\™XÝHÛÝ\˜ÙKO�\WÙ[XYÙWÙ\™XÝȈB‚ˆYˆ +ÛÝ\˜ÙKO�\WÙ[XYÙWÚ[™\™XÝOHTWÕS‘PÓT‘Qˆ ‰ˆJÛÝ\˜ÙKO�\WÙ[XYÙWÚ[™\™XÝ ˆTWÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O�\WÙ[XYÙWÚ[™\™XÝ ˆTWÓ“×ÐÓÔJJHˆ\Ý O�\WÙ[XYÙWÚ[™\™XÝHÛÝ\˜ÙKO�\WÙ[XYÙWÚ[™\™XÝȈB‚ˆYˆ +ÛÝ\˜ÙKO�\WÚÜÝ[HOHTWÕS‘PÓT‘Qˆ ‰ˆJÛÝ\˜ÙKO�\WÚÜÝ[H ˆTWÓ“×ÐÓÔJHˆ ‰ˆJ\Ý O�\WÚÜÝ[H ˆTWÓ“×ÐÓÔJJHˆ\Ý O�\WÚÜÝ[HHÛÝ\˜ÙKO�\WÚÜÝ[NȈHŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ Œ‹L KL�Š‚Šˆ™XYH^\™Ý[Y[�›Üˆ[Ù[ÛÜH›YŠˆ[™Ý]]\›ÜšX]HÛÛœÝ[� ‚Š‹Â™˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ݘXÝ[Û—ÙÙ]Ù›Y×Ùœ›ÛWÜÝš[™ÊÛÛœÝÚ\Šˆ˜[YJH‚ˆÛÛœÝÝ�X݈ÛÛœÝÚ\Šˆ^Û˜[YNˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×Ý›Y΂ˆH›Y×ÛÛÚÝ\ÝX›V×HHˆÈ››Û™H‹�PÕSÓ—ÑÔ“ÕTÓ“Ó‘HKˆÈ˜[‹�PÕSÓ—ÑÔ“ÕTÐSÓ“Ô“PSKˆȘ[ ‹�PÕSÓ—ÑÔ“ÕTÐSÓ“Ô“PSÌKˆȘ[ H‹�PÕSÓ—ÑÔ“ÕTÐSÓ“Ô“PSÌHKˆÈ›™]]˜[‹�PÕSÓ—ÑÔ“ÕTÓ‘UU�SKˆÈ››×ØÛÜH‹�PÕSÓ—ÑÔ“ÕTÓ“×ÐÓÔHKˆÈœ^Y\—Ý™\œÙ\È‹�PÕSÓ—ÑÔ“ÕTÔVQT—Õ‘T”ÑTÈKˆÈ�\WÙ^Û\Ú]™H‹�PÕSÓ—ÑÔ“ÕTÕTWÑVÓTÒU‘HKˆÈ�\WÚ[˜Û\Ú]™H‹�PÕSÓ—ÑÔ“ÕTÕTWÒS�ÓTÒU‘HKˆÈ˜H‹�PÕSÓ—ÑÔ“ÕTÐHKˆÈ˜ˆ‹�PÕSÓ—ÑÔ“ÕTЈKˆÈ˜È‹�PÕSÓ—ÑÔ“ÕTÐÈKˆÈ™‹�PÕSÓ—ÑÔ“ÕTÑKˆÈ™H‹�PÕSÓ—ÑÔ“ÕTÑHKˆÈ™ˆ‹�PÕSÓ—ÑÔ“ÕTшKˆÈ™È‹�PÕSÓ—ÑÔ“ÕTÑÈKˆÈš‹�PÕSÓ—ÑÔ“ÕTÒKˆÈšH‹�PÕSÓ—ÑÔ“ÕTÒHKˆÈšˆ‹�PÕSÓ—ÑÔ“ÕTÒˆKˆÈšÈ‹�PÕSÓ—ÑÔ“ÕTÒÈKˆÈ›‹�PÕSÓ—ÑÔ“ÕTÓKˆÈ›H‹�PÕSÓ—ÑÔ“ÕTÓHKˆÈ›ˆ‹�PÕSÓ—ÑÔ“ÕTÓˆKˆÈ›È‹�PÕSÓ—ÑÔ“ÕTÓÈKˆÈœ‹�PÕSÓ—ÑÔ“ÕTÔKˆÈœH‹�PÕSÓ—ÑÔ“ÕTÔHKˆÈœˆ‹�PÕSÓ—ÑÔ“ÕTÔˆKˆÈœÈ‹�PÕSÓ—ÑÔ“ÕTÔÈKˆÈ�‹�PÕSÓ—ÑÔ“ÕTÕKˆÈ�H‹�PÕSÓ—ÑÔ“ÕTÕHKˆÈ�ˆ‹�PÕSÓ—ÑÔ“ÕTÕˆKˆÈ�È‹�PÕSÓ—ÑÔ“ÕTÕÈKˆÈž‹�PÕSÓ—ÑÔ“ÕTÖKˆÈžH‹�PÕSÓ—ÑÔ“ÕTÖHKˆÈžˆ‹�PÕSÓ—ÑÔ“ÕTÖˆKˆÈ˜LH‹�PÕSÓ—ÑÔ“ÕTÐLHKˆÈ˜ŒH‹�PÕSÓ—ÑÔ“ÕTÐŒHKˆÈ˜ÌH‹�PÕSÓ—ÑÔ“ÕTÐÌHKˆÈ™ H‹�PÕSÓ—ÑÔ“ÕTÑ HKˆÈ™LH‹�PÕSÓ—ÑÔ“ÕTÑLHKˆÈ™ŒH‹�PÕSÓ—ÑÔ“ÕTÑŒHKˆÈ™ÌH‹�PÕSÓ—ÑÔ“ÕTÑÌHKˆÈš H‹�PÕSÓ—ÑÔ“ÕTÒ HKˆÈšLH‹�PÕSÓ—ÑÔ“ÕTÒLHKˆÈšŒH‹�PÕSÓ—ÑÔ“ÕTÒŒHKˆÈšÌH‹�PÕSÓ—ÑÔ“ÕTÒÌHKˆÈ› H‹�PÕSÓ—ÑÔ“ÕTÓ HKˆÈ›LH‹�PÕSÓ—ÑÔ“ÕTÓLHKˆÈ›ŒH‹�PÕSÓ—ÑÔ“ÕTÓŒHKˆÈ›ÌH‹�PÕSÓ—ÑÔ“ÕTÓÌHKˆÈœ H‹�PÕSÓ—ÑÔ“ÕTÔ HKˆÈœLH‹�PÕSÓ—ÑÔ“ÕTÔLHKˆÈœŒH‹�PÕSÓ—ÑÔ“ÕTÔŒHKˆÈœÌH‹�PÕSÓ—ÑÔ“ÕTÔÌHKˆÈ� H‹�PÕSÓ—ÑÔ“ÕTÕ HKˆÈ�LH‹�PÕSÓ—ÑÔ“ÕTÕLHKˆÈ�ŒH‹�PÕSÓ—ÑÔ“ÕTÕŒHKˆÈ�ÌH‹�PÕSÓ—ÑÔ“ÕTÕÌHKˆÈž H‹�PÕSÓ—ÑÔ“ÕTÖ HKˆÈžLH‹�PÕSÓ—ÑÔ“ÕTÖLHKˆÈžŒH‹�PÕSÓ—ÑÔ“ÕTÖŒHBˆN‚ˆÛÛœÝÚ^™WÝ\ÝØÛÝ[�HÚ^™[ÙŠ›Y×ÛÛÚÝ\ÝX›JH ÈÚ^™[ÙŠ +™›Y×ÛÛÚÝ\ÝX›JN‚ˆ›Üˆ +Ú^™WÝHH ÈH\ÝØÛÝ[�ÈJÊÊHˆYˆ +ÝšXÛ\ +˜[YK›Y×ÛÛÚÝ\ÝX›VÚWK�^Û˜[YJHOH +Hˆ™]\›ˆ›Y×ÛÛÚÝ\ÝX›VÚWK™›YΈBˆB‚ˆ Ê‚ˆ +ˆÛÝ[‰Ýš[™HX]Ú[ˆHÛÚÝ\ˆ +ˆX›KˆÙ[™[\�ÈÙÈ[™™]\›‚ˆ +ˆ›Û™H›YË‚ˆ +‹Â‚ˆš[�Š——ˆ[šÛ›ÝÛˆ˜XÝ[Ûˆ + \ÊKˆˆ‹˜[YJNˆ™]\›ˆ�PÕSÓ—ÑÔ“ÕTÓ“Ó‘NŸB‚‹Ê‚‹HØ\ÚÙ^K[[Ûˆ‹‚‹H Œ �‹L LLB‹B‹H™XY˜XÝ[Ûˆ\™Ý[Y[�È\™XÝHœ›ÛHHÛÝ\˜ÙH[™H[™ˆÛÛXš[™HZ\ˆÛÜœ™\ÜÛ™[™ÈÜ›Ý\›YÜË‚Š‹Â™˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ݘXÝ[Û—ÙÙ]Ù›YÜ×Ùœ›ÛWØÛÛ[X[™Û[™JˆÛÛœÝÚ\ŠˆÛÛ[X[™Û[™BŠBžÂˆÛÛœÝÚ\Šˆ˜[YNˆרÛÛ[X[™Ø\™Ý[Y[�Ü™XY\ˆ™XY\ŽÂˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×Ý™\Ý[H�PÕSÓ—ÑÔ“ÕTÓ“Ó‘N‚ˆÛÛ[X[™Ø\™Ý[Y[�Ü™XY\—Ú[š]X[^™J œ™XY\‹ÛÛ[X[™Û[™K JN‚ˆÚ[JÛÛ[X[™Ø\™Ý[Y[�Ü™XY\—Û™^ + œ™XY\‹ �˜[YJJHˆ™\Ý[H˜XÝ[Û—ÙÙ]Ù›Y×Ùœ›ÛWÜÝš[™Ê˜[YJNˆB‚ˆ™]\›ˆ™\Ý[ŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËL ‹L�‚Š‚Šˆ™]\›ˆ�YHYˆXÝ[™È[�]HØ[ˆŠˆ]\™Ù][�]HÚ]]XÚÜË‚Š‹Â˜›ÛÛ˜XÝ[Û—ØÚXÚרØ[—Ù[XYÙJ[�]JˆXÝ[™×Ù[�]K[�]Jˆ\™Ù]Ù[�]KÛۜݛÛÛ[™\™XÝ +H‚ˆWÙ[�]WÝ\HXÝ[™×Ý\NˆWÙ[�]WÝ\H\™Ù]Ý\Nˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ÝXÝ[™×Ù˜XÝ[ێˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ÝXÝ[™×Ù˜XÝ[Û—Ùš[\™Yˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×Ý\™Ù]Ù˜XÝ[ێ‚ˆYˆ +XXÝ[™×Ù[�]H]\™Ù]Ù[�]JHˆ™]\›ˆ˜[ÙNˆB‚ˆ Ê‚ˆ +ˆÙHÚ[\ÙHY™™\™[�XÝ[™È˜XÝ[Ûˆ›Ü\�Bˆ +ˆ[™\HYˆH[™\™XÝ›YÈ\ÈÙ] ‚ˆ +‹Â‚ˆYˆ +[™\™XÝ +HˆXÝ[™×Ù˜XÝ[ÛˆHXÝ[™×Ù[�]KO™˜XÝ[Û‹™[XYÙWÚ[™\™X݈XÝ[™×Ý\HHXÝ[™×Ù[�]KO™˜XÝ[Û‹�\WÙ[XYÙWÚ[™\™X݈ˆH[ÙHˆXÝ[™×Ù˜XÝ[ÛˆHXÝ[™×Ù[�]KO™˜XÝ[Û‹™[XYÙWÙ\™X݈XÝ[™×Ý\HHXÝ[™×Ù[�]KO™˜XÝ[Û‹�\WÙ[XYÙWÙ\™X݈B‚ˆXÝ[™×Ù˜XÝ[Û—Ùš[\™YHXÝ[™×Ù˜XÝ[ێ‚ˆ Ê‚ˆ +ˆ™[[Ý™HÜXÚX[\\Ë‚ˆ +‹Â‚ˆXÝ[™×Ù˜XÝ[Û—Ùš[\™Y �H‘�PÕSÓ—ÑÔ“ÕTÓ“×ÐÒPÒΈXÝ[™×Ý\H �H•TWÓ“×ÐÒPÒ΂ˆ Ê‚ˆ +ˆÚXÚÈ^Y\ˆ[�\˜XÝ[Û‹‚ˆ +‹Â‚ˆYˆ +˜XÝ[Û—ØÚXÚ×Ü^Y\—Ý™\œÙ\ÊXÝ[™×Ù[�]K\™Ù]Ù[�]KXÝ[™×Ù˜XÝ[ÛŠJHˆ™]\›ˆ˜[ÙNˆB‚ˆ\™Ù]Ý\HH\™Ù]Ù[�]KO›[Ù[]K�\N‚ˆ Ê‚ˆ +ˆYˆÛ™HÙˆHXÝ[™È˜XÝ[ÛœÈ\ÈBˆ +ˆ\H^Û\Ú]™HÜ›Ý\ [ˆÙHÛ›Bˆ +ˆÚXÚÈXÝ[™È\\Ȝˈ\™Ù]\Bˆ +ˆ[™YۛܙHÝ\ˆ˜XÝ[ۜ˂ˆ +‹Â‚ˆYˆ +XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÑVÓTÒU‘JHˆˆYˆ +XÝ[™×Ý\H ˆ\™Ù]Ý\JHˆ™]\›ˆ�YNˆH[ÙHˆ™]\›ˆ˜[ÙNˆBˆB‚ˆ Ê‚ˆ +ˆ›ÝÈÙHÛÛ\\™HÝ\ˆXÝ[™È˜XÝ[ÛŠÊHÈBˆ +ˆ˜XÝ[ÛŠÊH\™Ù]\ÈHY[X™\ˆÙˆ›Üˆ[žHX]Ú ‚ˆ +‹Â‚ˆ\™Ù]Ù˜XÝ[ÛˆH\™Ù]Ù[�]KO™˜XÝ[Û‹›Y[X™\ŽÂ‚ˆYˆ +XÝ[™×Ù˜XÝ[Û—Ùš[\™Y ˆ\™Ù]Ù˜XÝ[ÛŠHˆ Ê‚ˆ +ˆYˆÛ™HÙˆHXÝ[™È˜XÝ[ÛœÈ\ˆ +ˆHYH[˜Û\Ú[™ÈÜ›Ý\ [ˆÙBˆ +ˆ[ÛÈÚXÚÈXÝ[™È\\ÈœÈBˆ +ˆ\™Ù] ÜÈ\K‚ˆ +‹Â‚ˆYˆ +XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÒS�ÓTÒU‘JHˆˆYˆ +XÝ[™×Ý\H ˆ\™Ù]Ý\JHˆ™]\›ˆ�YNˆˆH[ÙHˆ™]\›ˆ˜[ÙNˆBˆB‚ˆ™]\›ˆ�YNˆB‚ˆ™]\›ˆ˜[ÙNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËL ‹L�‚ŠˆŠˆ™]\›ˆ�YHYˆXÝ[™È[�]H\ŠˆÜÝ[HÝØ\™\™Ù][�]K‚Š‹Âš[�˜XÝ[Û—ØÚXÚ×Ú\×ÚÜÝ[J[�]JˆXÝ[™×Ù[�]K[�]Jˆ\™Ù]Ù[�]JBžÂˆ ËÜš[�Š——ˆ˜XÝ[Û—ØÚXÚ×Ú\×ÚÜÝ[J \  \ +H‹XÝ[™×Ù[�]K\™Ù]Ù[�]JN‚ˆWÙ[�]WÝ\HXÝ[™×Ý\NˆWÙ[�]WÝ\H\™Ù]Ý\Nˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ÝXÝ[™×Ù˜XÝ[ێˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×Ýš[\™YÙ˜XÝ[ێˆ˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×Ý\™Ù]Ù˜XÝ[ێ‚ˆYˆ +XXÝ[™×Ù[�]H]\™Ù]Ù[�]JBˆˆ™]\›ˆ ˆB‚ˆ ËÜš[�Š——XÝ[™×Ù[�]KO›˜[YNˆ \Ë\™Ù]Ù[�]KO›˜[YNˆ \È‹XÝ[™×Ù[�]KO›˜[YK\™Ù]Ù[�]KO›˜[YJN‚ˆXÝ[™×Ù˜XÝ[ÛˆHXÝ[™×Ù[�]KO™˜XÝ[Û‹šÜÝ[Nˆš[\™YÙ˜XÝ[ÛˆHXÝ[™×Ù˜XÝ[ێˆXÝ[™×Ý\HHXÝ[™×Ù[�]KO™˜XÝ[Û‹�\WÚÜÝ[Nˆ\™Ù]Ý\HH\™Ù]Ù[�]KO›[Ù[]K�\N‚ˆ ËÜš[�Š——XÝ[™×Ù˜XÝ[ÛŽˆ Y‹XÝ[™×Ù˜XÝ[ÛŠNˆ ËÜš[�Š——XÝ[™×Ý\Nˆ Y‹XÝ[™×Ý\JNˆ ËÜš[�Š——\™Ù]Ý\Nˆ Y‹\™Ù]Ý\JN‚ˆ Ê‚ˆ +ˆ™[[Ý™HÜXÚX[\\Ë‚ˆ +‹Â‚ˆš[\™YÙ˜XÝ[Ûˆ �H‘�PÕSÓ—ÑÔ“ÕTÓ“×ÐÒPÒΈXÝ[™×Ý\H �H•TWÓ“×ÐÒPÒ΂ˆ ËÜš[�Š——XÝ[™×Ù˜XÝ[ÛŽˆ Y‹XÝ[™×Ù˜XÝ[ÛŠNˆ ËÜš[�Š——XÝ[™×Ý\Nˆ Y‹XÝ[™×Ý\JN‚ˆ Ê‚ˆ +ˆÚXÚÈ^Y\ˆ[�\˜XÝ[Û‹ˆˆ +‹Â‚ˆYˆ +˜XÝ[Û—ØÚXÚ×Ü^Y\—Ý™\œÙ\ÊXÝ[™×Ù[�]K\™Ù]Ù[�]KXÝ[™×Ù˜XÝ[ÛŠJBˆˆ ËÜš[�Š——^Y\ˆœËˆ™]\›ˆ ŠN‚ˆ™]\›ˆ ˆB‚ˆ Ê‚ˆ +ˆYˆÛ™HÙˆHXÝ[™È˜XÝ[ÛœÈ\ÈBˆ +ˆ\H^Û\Ú]™HÜ›Ý\ [ˆÙHÛ›Bˆ +ˆÚXÚÈXÝ[™È\\Ȝˈ\™Ù]\Bˆ +ˆ[™YۛܙHÝ\ˆ˜XÝ[ۜ˂ˆ +‹Â‚ˆYˆ +XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÑVÓTÒU‘JBˆˆ ËÜš[�Š——XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÑVÓTÒU‘Nˆ Y‹XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÑVÓTÒU‘JN‚ˆYˆ +XÝ[™×Ý\H ˆ\™Ù]Ý\JBˆˆ ËÜš[�Š——XÝ[™×Ý\H ˆ\™Ù]Ý\Nˆ Y +Y\ÊH‹XÝ[™×Ý\H ˆ\™Ù]Ý\JN‚ˆ™]\›ˆ NˆBˆ[ÙBˆˆš[�Š——XÝ[™×Ý\H ˆ\™Ù]Ý\Nˆ Y +›ÊH‹XÝ[™×Ý\H ˆ\™Ù]Ý\JN‚ˆ™]\›ˆ ˆBˆB‚ˆ Ê‚ˆ +ˆ›ÝÈÙHÛÛ\\™HÝ\ˆXÝ[™È˜XÝ[ÛŠÊHÈBˆ +ˆ˜XÝ[ÛŠÊH\™Ù]\ÈHY[X™\ˆÙˆ›Üˆ[žHX]Ú ‚ˆ +‹Â‚ˆ\™Ù]Ù˜XÝ[ÛˆH\™Ù]Ù[�]KO™˜XÝ[Û‹›Y[X™\ŽÂ‚ˆYˆ +š[\™YÙ˜XÝ[Ûˆ ˆ\™Ù]Ù˜XÝ[ÛŠBˆˆ Ê‚ˆ +ˆYˆÛ™HÙˆHXÝ[™È˜XÝ[ÛœÈ\ˆ +ˆHYH[˜Û\Ú[™ÈÜ›Ý\ [ˆÙBˆ +ˆ[ÛÈÚXÚÈXÝ[™È\\ÈœÈBˆ +ˆ\™Ù] ÜÈ\K‚ˆ +‹Â‚ˆYˆ +XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÒS�ÓTÒU‘JBˆˆ ËÜš[�Š——XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÒS�ÓTÒU‘Nˆ Y‹XÝ[™×Ù˜XÝ[Ûˆ ˆ�PÕSÓ—ÑÔ“ÕTÕTWÒS�ÓTÒU‘JN‚ˆYˆ +XÝ[™×Ý\H ˆ\™Ù]Ý\JBˆˆ ËÜš[�Š——XÝ[™×Ý\H ˆ\™Ù]Ý\Nˆ Y +Y\ÊH‹XÝ[™×Ý\H ˆ\™Ù]Ý\JN‚ˆ™]\›ˆ NˆBˆ[ÙBˆˆ ËÜš[�Š——XÝ[™×Ý\H ˆ\™Ù]Ý\Nˆ Y +›ÊH‹XÝ[™×Ý\H ˆ\™Ù]Ý\JN‚ˆ™]\›ˆ ˆBˆB‚ˆ™]\›ˆ NˆB‚ˆ ËÜš[�Š——›ÈX]Ú ˆŠN‚ˆ™]\›ˆ ŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ ŒËL ‹LŽŠˆŠˆ™]\œÈ HYˆ^Y\œÈ\™H›Ý[ÝÙYŠˆœËˆ[�\˜XÝ[ÛˆÛˆHÚ]™[ˆ˜XÝ[ÛˆŠˆ›Ü\�Kˆ^ ˆÜÝ[K\™XÝ[XYÙKŠˆ[™\™XÝ[XYÙK‚Š‹Âš[�˜XÝ[Û—ØÚXÚ×Ü^Y\—Ý™\œÙ\Ê[�]JˆXÝ[™×Ù[�]K[�]Jˆ\™Ù]Ù[�]K˜XÝ[Û—ÙÜ›Ý\ÛX\Ú×ݘXÝ[Û—Ü›Ü\�JBžÂˆYˆ +XXÝ[™×Ù[�]H]\™Ù]Ù[�]JBˆˆ™]\›ˆ ˆB‚ˆ Ê‚ˆ +ˆ›Ý[�]\È]\Ý™H^Y\œË‚ˆ +‹Â‚ˆYˆ +JXÝ[™×Ù[�]KO›[Ù[]K�\H ˆTWÔVQTŠJBˆˆ™]\›ˆ ˆB‚ˆYˆ +J\™Ù]Ù[�]KO›[Ù[]K�\H ˆTWÔVQTŠJBˆˆ™]\›ˆ ˆB‚ˆ Ê‚ˆ +ˆ[ˆ˜XÝ[ۈܛÝ\ÈÝ™\œšYHœšY[™Bˆ +ˆš\™HÙ][™Üψ +‹Â‚ˆYˆ +˜XÝ[Û—Ü›Ü\�H ˆ�PÕSÓ—ÑÔ“ÕTÔVQT—Õ‘T”ÑTÊBˆˆ™]\›ˆ ˆB‚ˆ Ê‚ˆ +ˆYˆ”ˈ[ÙH\›™YÙ™ˆ[ˆÜ[ۜˆ +ˆ܈]™[›Ú]\È[˜X›Y [‚ˆ +ˆÙH\™H™œšY[™HˆÝØ\™\™Ù] ‚ˆ +‹Â‚ˆYˆ +Ø]™Y]K›[ÙJBˆˆ™]\›ˆ NȈB‚ˆYˆ +]™[ ‰ˆ]™[ O››Ú]OHSPQÑWÑ”“ÓWÔVQT—ÓÑ‘ŠBˆˆ™]\›ˆ NˆB‚ˆ™]\›ˆ ŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ NKLL‹LN +™Y˜XÝÜŠBŠ‚ŠˆÜšYÚ[˜[]]܈[šÛ›ÝÛˆ +Z[ÏÊKˆ™Y˜XÝÜ™YÈ™[[Ý™HH]™\‹YÜ›ÝÚ[™È\˜[Y]\ˆ\ÝŠˆ[™ÛÛœÛÛY]H›Ú™XÝ[HÜ]ÛˆÙÚXˈÜ]ÛœÈ[ˆ[�]H[™š\™\È]\ÈH›Ú™XÝ[KˆŠˆ[Ù[\ÙY›ÜˆÜ]Ûˆ\È]\›Z[™YžHHY\˜\˜ÚHÙˆYØXÞH\˜[Y]\œÈ +ÙYH]Z[YŠˆÛÛ[Y[�È[ˆ�[˜Ý[ÛŠK‚Š‚Šˆ™]\›œÈÚ[�\ˆÙˆÜ]Û™Y›Ú™XÝ[K܈•SÛˆ˜Z[ ‚Š‹Â™[�]H +šÛšY™WÜÜ]ÛŠ[�]H +œ\™[� ×ܛڙXÝ[H +œ›Ú™XÝ[JBžÂˆ[�]H +œ›Ú™XÝ[WÙ[�]HH•S‚‚\ר^\×Üš[˜Ú\[Ù›Ø]ÜÚ][ێ‚YWÙ\™XÝ[Ûˆ\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒ‚YWܛڙXÝ[WÜš[YH›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓ“Ó‘N‚B‚KʈYˆ\™IÜțțڙXÝ[H܈\™[�Ù][™Ë^]›Ýˈ +‹Â‚ZYˆ +\›Ú™XÝ[H\\™[� +B‚^‚B\™]\›ˆ•S‚_B‚ˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž‚\ÜÚ][Û‹žHH\™[� OœÜÚ][Û‹žH +țڙXÝ[KOœÜÚ][Û‹žN‚\ÜÚ][Û‹žˆH\™[� OœÜÚ][Û‹žˆ +țڙXÝ[KOœÜÚ][Û‹žŽÂ‚ˆ Ê‚‚Jˆ›ÝÈÙH™YYÈÜ]ÛˆH›Ú™XÝ[H[�]Kˆ\™H\™HX[žH\^˜\™YØXÞH‚JˆY][ÛœÈÈÚY�›ÝYÚ ÛÈÙH™YYÈš[Üš]^™HÚXÚ[Ù[ÈÜ]Û‹ˆ‚Jˆ[ˆÙ[™\˜[ ÙHÛܚȘXÚÈœ›ÛH[ÜÝܘ[�[\ˆÈ[ÜÝÛؘ[ ‚‚J‚‚Jˆœ›ÛHYÚ\ÝÈÝÙ\Ýš[Üš]N‚‚Jˆ‚Jˆ Kˆ›Ú™XÝ[HÛšY™H›Ü\�K‚‚Jˆ ‹ˆ›Ú™XÝ[H›\Ú›Ü\�K‚‚Jˆ ˈ\Ú[™ÈÙX\ÛˆÚ][Ù[›Ú™XÝ›Ü\�K‚‚Jˆ ˆ[Ù[ÛšY™H›Ü\�K‚‚Jˆ Kˆ[Ù[ÚݛțÜ\�K‚‚Jˆ ‹ˆÛؘ[\™ÛÙH[Ù[˜[YK’ÛšY™H‹‚‚Jˆ ˈÛؘ[\™ÛÙH[Ù[˜[YK”ÚÝ‹‚‚J‹ÂˆYˆ +›Ú™XÝ[KOšÛšY™H�H +B‚^ˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S ›Ú™XÝ[KOšÛšY™K•S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÖN‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÔ“Ò—ÒÓ’Q‘N‚_B‚Y[ÙHYˆ +›Ú™XÝ[KO™›\Ú�H +B‚^ˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S ›Ú™XÝ[KO™›\Ú •S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÑ“ÓԎ‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÔÕUSÓ�T–N‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÔ“Ò—Ñ“TÒ‚_B‚Y[ÙHYˆ +\™[� O�ÙX\[� ‰ˆ\™[� O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ�H +B‚^ˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S \™[� O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ •S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÖN‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÕÑPTÓ—Ô“Ò‘PÕSN‚_B‚Y[ÙHYˆ +\™[� O›[Ù[]KšÛšY™H�H +B‚^ˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S \™[� O›[Ù[]KšÛšY™K•S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÖN‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÓSÑSÒÓ’Q‘N‚_B‚Y[ÙHYˆ +\™[� O›[Ù[]KœÚÝ›È�H +B‚^ˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S \™[� O›[Ù[]KœÚݛ˕S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÑ“ÓԎ‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÔÕUSÓ�T–N‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÓSÑSÔÒÕ“΂_B‚Y[ÙB‚^ˆ Ê‚‚BJˆ›È[Ù[[™^\ÈÙ] ÛÈ] ÜȘ[˜XÚÈ‚BJˆHYØXÞH\™ÛÙH[Ù[˜[Y\Ë‚ˆ +‚‚BJˆžH\™ÛÙHšÛšY™Hˆš\œÝ ˆYˆ]˜Z[ËÙIÛžB‚BJˆœÚ݈™^ ‚ˆ +‹Âˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹’ÛšY™H‹SÑSÒS‘VÓ“Ó‘K•S +N‚BB‚BZYˆ +›Ú™XÝ[WÙ[�]JB‚B^ˆ Ê‚‚BBJˆ\™ÛÙHÛšY™HÜ]ÛˆÝXØÙ\ÜÙ�[ ˆX\šÈ\ÈYØXÞHÛšY™B‚BBJˆ[™ÛÛ�[�YK‚ˆ +‹È‚BB\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÑÓÐ�SÒÓ’Q‘N‚B_B‚BY[ÙH‚B^‚BBKʈžHœÚÝ‹ˆ +‹Âˆ›Ú™XÝ[WÙ[�]HHÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹”ÚÝ‹SÑSÒS‘VÓ“Ó‘K•S +N‚‚BB\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÑÓÐ�SÔÒÕ‚B_B‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÖN‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂_B‚‚KʈYˆÙH™]™\ˆÝXØÙ\ÜÙ�[HÜ]Û™YH›Ú™XÝ[H[�]K^] ˆ +‹ÂˆYŠ\›Ú™XÝ[WÙ[�]JBˆˆ™]\›ˆ•SˆB‚ˆ Ê‚ˆ +ˆÙ]™\Ý[Ùˆ\™XÝ[ÛˆY�\ÝY[� ˆÙH™YY\È™Y›Ü™HÙHØ[ˆ[™Bˆ +ˆÜÚ][Ûš[™ÈÛˆ^\Ë‚ˆ +‹Âˆ\™XÝ[ÛˆH\™XÝ[Û—ÙÙ]ØY�\ÝY[�Ü™\Ý[ +›Ú™XÝ[WÙ[�]K\™[� ›Ú™XÝ[KO™\™XÝ[Û—ØY�\Ý +N‚ˆ Ê‚ˆ +ˆ] ÜÈÙ]\HÜ]ÛˆÜÚ][Û‹ˆ™]™\œÙHÚ[‚ˆ +ˆ\™[�˜XÙ\ÈY� ‚ˆ +‚ˆ +ˆ\HY˜][ÜÚ][ÛˆYˆÜ™X]܈Y›ÝÚ]™Bˆ +ˆ\ÈH˜[YK‚ˆ +‹Â‚ˆYˆ +›Ú™XÝ[KOœÜÚ][Û‹žOH“Ò‘PÕSWÓQÐPÖWÐÓÓTUP’SUWÔÔÒUSÓ—Ö +Bˆˆ›Ú™XÝ[KOœÜÚ][Û‹žH“Ò‘PÕSWÑQ�USÔÔÒUSÓ—ÖˆB‚ˆYˆ +\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž +țڙXÝ[KOœÜÚ][Û‹žˆBˆ[ÙBˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž H›Ú™XÝ[KOœÜÚ][Û‹žˆB‚ˆ›Ú™XÝ[WÙ[�]KO™\™XÝ[ÛˆH\™XÝ[ێˆ›Ú™XÝ[WÙ[�]KOœÜÚ][Û‹žHÜÚ][Û‹žˆˆ ʈˆ +ˆ^Y\ˆ›Ú™XÝ[\È\™H[Ø^\È\HœÚÝ‹[›\ÜȈ +ˆ\Ú[™ÈHÝ\œ™[�“Ò‘PÕSH\K‚ˆ +‹ÂˆYˆ +J›Ú™XÝ[WÙ[�]KO›[Ù[]K�\H ˆTWÔ“Ò‘PÕSJJBˆˆYˆ +\™[� O›[Ù[]K�\H ˆTWÔVQTŠBˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K�\HHTWÔÒÕˆBˆ[ÙBˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K�\HH\™[� O›[Ù[]K�\NˆBˆB‚‚Kʈ\H›Ú™XÝ[Hš[YH›YÜˈ +‹Âˆ›Ú™XÝ[WÙ[�]KOœ›Ú™XÝ[WÜš[YHH›Ú™XÝ[WÜš[YN‚ˆ Ê‚‚JˆÛÜHÙ™™[œÙH˜[Y\Èœ›ÛH\™[�Ù™™[œÙHÙ][™ÜÈ‚JˆÈ›Ú™XÝ[H[š]HYˆ™\]Y\ÝY ‚‚J‹ÂˆYˆ +›Ú™XÝ[KO›Ù™™[œÙHOH“Ò‘PÕSWÓÑ‘‘S”ÑWÔT‘S• +B‚^‚B[Y[XÜJ›Ú™XÝ[WÙ[�]KO›Ù™™[œÙK\™[� O›Ù™™[œÙKÚ^™[ÙŠ +œ›Ú™XÝ[WÙ[�]KO›Ù™™[œÙJH +ˆX^Ø]XÚ×Ý\\ÊN‚_B‚‚Kʈ\HÛÛ܈Y�\ÝY[� ˆ +‹Â‚X\WØÛÛÜ—ÜÙ]ØY�\Ý +›Ú™XÝ[WÙ[�]K\™[� ›Ú™XÝ[KO˜ÛÛÜ—ÜÙ]ØY�\Ý +N‚BB‚ˆ Ê‚‚JˆYˆ›È[Ý™K[ˆ[ÜYY\È ˆÝ\�Ú\ÙHÚXÚț܈\ÙHÙ‚‚Jˆ›Ú™XÝ[H™[ØÚ]KˆYˆ^Y\ˆÝ\YY[žH˜[YHÝ\ˆ‚Jˆ[ˆSÑSÔÔQQÓ“Ó‘KÙH\ÙH^Y\‰ÜȘ[YKˆYˆ›Ý ˜[‚Jˆ˜XÚÈÈY˜][˜[Y\ˈ\È\ÈHš]Ý™\˜ÛÛ\XØ]Y �]‚Jˆ[ÝÜÈ^Y\œÈÈÝ\HH ™[ØÚ]H˜[YHÛˆ[žH^\Ë‚‚J‹ÂˆYˆ +›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×Ó“×ÓSÕ‘JB‚^ˆ›Ú™XÝ[WÙ[�]KO›[Ù[]KœÜYY žH ˆ›Ú™XÝ[WÙ[�]KO›[Ù[]KœÜYY žHH ˆ›Ú™XÝ[WÙ[�]KO›[Ù[]KœÜYY žˆH ‚_B‚Y[ÙB‚^ÂB‚BKʈÛÜHÜYY˜[Y\Èœ›ÛH[š[X][Ûˆ›Ú™XÝ[HÙ][™ÜÈÈ[Ù[ ˆ +‹Âˆ›Ú™XÝ[KO�™[ØÚ]HH›Ú™XÝ[WÙ[�]KO›[Ù[]KœÜYY‚_B‚‚KʈÙ]\™Z]š[܈›YÜˈ +‹Âˆ›Ú™XÝ[WÙ[�]KOœÜ]Û�\HHÔUÓ—ÕTWÔ“Ò‘PÕSWÓ“Ô“PSˆ›Ú™XÝ[WÙ[�]KO›ÝÛ™\ˆH\™[�ˆ›Ú™XÝ[WÙ[�]KO››ÙܘXˆH Nˆ›Ú™XÝ[WÙ[�]KO˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘Nˆ›Ú™XÝ[WÙ[�]KO�[šÈHÛÛ[[Û—Ý[šÎˆ›Ú™XÝ[WÙ[�]KO›™^[šÈHÝ[YH +È Nˆ›Ú™XÝ[WÙ[�]KO�ž[[Ý™HH•Sˆ›Ú™XÝ[WÙ[�]KO�ZÙY[XYÙHH\œ›Ý×ÝZÙY[XYÙNˆ›Ú™XÝ[WÙ[�]KO�ZÙXXÝ[ÛˆH•Sˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K˜Z[[Ý™HHRSSÕ‘LWÐT”“ÕΈ›Ú™XÝ[WÙ[�]KOœÜYY][H ŽÂˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K˜ZX]XÚÈHRPUPÒÌWÓ“ÐUPÒΈˆYŠ\›Ú™XÝ[WÙ[�]KO›[Ù[]K›Ù™œØÜ™Y[šÚ[ +Bˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K›Ù™œØÜ™Y[šÚ[H Œ È ËÙY˜][˜[YBˆBBˆ‚KʈÚ[Ù[ˆÚ[ˆÙH] ˆ +‹Â‚ZYˆ +›Ú™XÝ[WÙ[�]KO›[Ù[]Kœ™[[Ý™WØÛÛ™šYÈ ˆ‘SSÕ‘WÐÓÓ‘’Q×ÒU +B‚^ˆ›Ú™XÝ[WÙ[�]KO˜]]ÚÚ[HUUÒÒSÐUPÒ×ÒU‚_B‚Bˆ ʈÚ[Ù[ˆÚ[ˆÙHš[š\Ú[š[X][Û‹ˆ +‹Â‚ZYˆ +›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×Ó“×ÓSÕ‘JB‚^ˆ›Ú™XÝ[WÙ[�]KO˜]]ÚÚ[HUUÒÒSÐS’SPUSÓ—ÐÓÓTUN‚_B‚B‚Kʈ\È\ÈH›Û܈܈›Z[™È›Ú™XÝ[HÈÙ]˜\ÙHXØÛÜ™[™ÛKˆ +‹ÂˆYŠ›Ú™XÝ[WÙ[�]KOœ›Ú™XÝ[WÜš[YH ˆ“Ò‘PÕSWÔ’SQWÐ�TÑWÑ“ÓÔŠBˆˆ›Ú™XÝ[WÙ[�]KO˜˜\ÙHH ˆBˆ[ÙBˆˆ›Ú™XÝ[WÙ[�]KO˜˜\ÙHHÜÚ][Û‹žNˆB‚ˆ Ê‚‚JˆÛÜH˜XÝ[Ûˆ]Hœ›ÛH\™[� ‚‚J‹Â‚ˆ˜XÝ[Û—ØÛÜWØ[ +›Ú™XÝ[WÙ[�]K\™[� +N‚ˆ Ê‚‚JˆYˆ^Y\ˆ[XYÙH\›™YÙ™‹™[[Ý™H^Y\ˆ\Hœ›ÛB‚JˆÜÝ[H +ÛÈÛZ[™È›Ú™XÝ[\ÈX]™H^Y\œÈ[Û™JH[™‚Jˆœ›ÛHØ[™[XYÙK‚ˆ +‹ÂˆYŠ +\™[� O›[Ù[]K�\H ˆTWÔVQTŠH ‰ˆ + +]™[ ‰ˆ]™[ O››Ú]OHSPQÑWÑ”“ÓWÔVQT—ÓÑ‘ŠHØ]™Y]K›[ÙJJBˆˆ›Ú™XÝ[WÙ[�]KO™˜XÝ[Û‹�\WÚÜÝ[H �H•TWÔVQTŽÂˆ›Ú™XÝ[WÙ[�]KO™˜XÝ[Û‹�\WÙ[XYÙWÙ\™XÝ �H•TWÔVQTŽÂˆB‚‚KÊ‚ˆ +ˆÙ]\œ˜Z[ˆ[™[Ý™[Y[�™Z]š[܈›YÜˈYØXÞHˆ +ˆ™Z]š[܈ÛÝ[‰Ý[ÝÈ[Ý™[Y[�[Û™ÈH^\ˆ +ˆÚ]Ý][ˆ\˜Ë�]ÙHØ[‰Ýš^\ÈÚ]Ý]ˆ +ˆœ™XZÚ[™ÈÛÛ\]Xš[]KÛÈÙIÛ™YYHY™™\™[�ˆ +ˆÙ]\\[™[™ÈÛˆÚ]�[˜Ý[ۈܙX]܈\ÙY ‚ˆ +‹Âˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈH +SÕ‘WÐÓÓ‘’Q×Ô“Ò‘PÕSWÐ�TÑWÑQHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÒÓHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÔU“Ô“HSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÕÐSSÕ‘WÐÓÓ‘’Q×Ô“Ò‘PÕSWÕÐSГÕS�ÑJNˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ �H“SÕ‘WÐÓÓ‘’Q×Ó“×ÐQ•TÕÐ�TÑN‚ˆYˆ +›Ú™XÝ[WÙ[�]KOœ›Ú™XÝ[WÜš[YH ˆ“Ò‘PÕSWÔ’SQWÒS’UPSV‘WÓQÐPÖWÔ“Ò‘PÕSWÑ•S�ÕSÓŠBˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÑÔ�U’UNˆBˆ[ÙBˆˆ›Ú™XÝ[WÙ[�]KO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ �H“SÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÑÔ�U’UNˆBˆ‚Kʈ^XÝ]HH›Ú™XÝ[IÜÈÛˆÜ]Ûˆ]™[� ˆ +‹Â‚Y^XÝ]WÛÛœÜ]Û—ÜØÜš\ +›Ú™XÝ[WÙ[�]JN‚B‚\™]\›ˆ›Ú™XÝ[WÙ[�]NŸB‚�›ÚY›ÛX—Ù^ÙJ +BžÂˆYŠÙ[‹O˜[š[X][™ÊBˆˆ™]\›ŽÂˆBˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ГÓP—ÑVÑWÐS’SPUSÓ—ÐÓÓTUJNŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ NKLL‹LŒˆ +™Y˜XÝÜŠBŠ‚ŠˆÜšYÚ[˜[]]܈[šÛ›ÝÛˆ +Z[ÏÊKˆ™Y˜XÝÜ™YÈ™[[Ý™HH]™\‹YÜ›ÝÚ[™È\˜[Y]\ˆ\ÝŠˆ[™ÛÛœÛÛY]H›Ú™XÝ[HÜ]ÛˆÙÚXˈÜ]ÛœÈ[ˆ[�]H[™š\™\È]\ÈH›ÛXˆ›Ú™XÝ[KˆŠˆ[Ù[\ÙY›ÜˆÜ]Ûˆ\È]\›Z[™YžHHY\˜\˜ÚHÙˆYØXÞH\˜[Y]\œÈ +ÙYH]Z[YŠˆÛÛ[Y[�È[ˆ�[˜Ý[ÛŠK‚Š‚Šˆ™]\›œÈÚ[�\ˆÙˆÜ]Û™Y›Ú™XÝ[K܈•SÛˆ˜Z[ ‚Š‹Â™[�]H +˜›ÛX—ÜÜ]ÛŠ[�]H +œ\™[� ×ܛڙXÝ[H +œ›Ú™XÝ[JBžÂ‚Y[�]Jˆ[�H•S‚\ר^\×Üš[˜Ú\[Ù›Ø]ÜÚ][ێ‚YWÙ\™XÝ[Ûˆ\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒ‚YWܛڙXÝ[WÜš[YH›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓ“Ó‘N‚‚KËÈYˆ\™IÜțțڙXÝ[H܈\™[�Ù][™Ë^]›ÝË‚‚ZYˆ +\›Ú™XÝ[H\\™[� +B‚^‚B\™]\›ˆ•S‚_BˆBˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž‚\ÜÚ][Û‹žHH\™[� OœÜÚ][Û‹žH +țڙXÝ[KOœÜÚ][Û‹žN‚\ÜÚ][Û‹žˆH\™[� OœÜÚ][Û‹žˆ +țڙXÝ[KOœÜÚ][Û‹žŽÂ‚ˆ Ê‚‚Jˆ›ÝÈÙH™YYÈÜ]ÛˆH›Ú™XÝ[H[�]Kˆ\™H\™HX[žH\^˜\™YØXÞH‚JˆY][ÛœÈÈÚY�›ÝYÚ ÛÈÙH™YYÈš[Üš]^™HÚXÚ[Ù[ÈÜ]Û‹ˆ‚Jˆ[ˆÙ[™\˜[ ÙHÛܚȘXÚÈœ›ÛH[ÜÝܘ[�[\ˆÈ[ÜÝÛؘ[ ‚‚J‚‚Jˆœ›ÛHYÚ\ÝÈÝÙ\Ýš[Üš]N‚‚Jˆ‚Jˆ Kˆ›Ú™XÝ[H›ÛXˆ›Ü\�K‚‚Jˆ ‹ˆ\Ú[™ÈÙX\ÛˆÚ][Ù[›ÛXˆ›Ü\�K‚‚Jˆ ˈ[Ù[›ÛXˆ›Ü\�K‚‚J‹Â‚ˆYŠ›Ú™XÝ[KO˜›ÛXˆ�H +Bˆˆ[�HÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S ›Ú™XÝ[KO˜›ÛX‹•S +N‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÔ“җГÓPŽÂ‚_B‚Y[ÙHYˆ +Ù[‹O�ÙX\[� ‰ˆÙ[‹O�ÙX\[� O›[Ù[]KœÝX�\HOHÕP•TWÔ“Ò‘PÕSH ‰ˆÙ[‹O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ�H +B‚^‚BY[�HÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S Ù[‹O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ •S +N‚BB‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÕÑPTÓ—Ô“Ò‘PÕSN‚_Bˆ[ÙHYŠÙ[‹O›[Ù[]K˜›ÛXˆ�H +Bˆˆ[�HÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S Ù[‹O›[Ù[]K˜›ÛX‹•S +N‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÓSÑSГÓPŽÂ‚_B‚B‚\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÑ“ÓԎ‚\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂B‚KËÈYˆÙH™]™\ˆÝXØÙ\ÜÙ�[HÜ]Û™YH›Ú™XÝ[H[�]K^] ‚ˆYŠY[� +Bˆˆ™]\›ˆ•SˆB‚ˆ Ê‚ˆ +ˆÙ]™\Ý[Ùˆ\™XÝ[ÛˆY�\ÝY[� ˆÙH™YY\È™Y›Ü™HÙHØ[ˆ[™Bˆ +ˆÜÚ][Ûš[™ÈÛˆ^\Ë‚ˆ +‹Âˆ\™XÝ[ÛˆH\™XÝ[Û—ÙÙ]ØY�\ÝY[�Ü™\Ý[ +[� \™[� ›Ú™XÝ[KO™\™XÝ[Û—ØY�\Ý +N‚ˆ Ê‚ˆ +ˆ] ÜÈÙ]\HÜ]ÛˆÜÚ][Û‹ˆ™]™\œÙHÚ[‚ˆ +ˆ\™[�˜XÙ\ÈY� ‚ˆ +‚ˆ +ˆ\HY˜][ÜÚ][ÛˆYˆÜ™X]܈Y›ÝÚ]™Bˆ +ˆ\ÈH˜[YK‚ˆ +‹Â‚ˆYˆ +›Ú™XÝ[KOœÜÚ][Û‹žOH“Ò‘PÕSWÓQÐPÖWÐÓÓTUP’SUWÔÔÒUSÓ—Ö +Bˆˆ›Ú™XÝ[KOœÜÚ][Û‹žH“Ò‘PÕSWÑQ�USÔÔÒUSÓ—ÖˆB‚ˆYˆ +\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž +țڙXÝ[KOœÜÚ][Û‹žˆBˆ[ÙBˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž H›Ú™XÝ[KOœÜÚ][Û‹žˆB‚ˆ[� O™\™XÝ[ÛˆH\™XÝ[ێˆ[� OœÜÚ][Û‹žHÜÚ][Û‹ž‚‚‚Y[� Oœ›Ú™XÝ[WÜš[YHH›Ú™XÝ[WÜš[YN‚ˆ Ê‚ˆ +ˆYˆ›È[Ý™K[ˆ[ÜYY\È ˆÝ\�Ú\ÙHÚXÚț܈\ÙHÙ‚‚Jˆ›Ú™XÝ[H™[ØÚ]KˆYˆ^Y\ˆÝ\YY[žH˜[YHÝ\ˆ‚Jˆ[ˆSÑSÔÔQQÓ“Ó‘KÙH\ÙH^Y\‰ÜȘ[YKˆYˆ›Ý ˜[‚Jˆ˜XÚÈÈY˜][˜[Y\ˈ\È\ÈHš]Ý™\˜ÛÛ\XØ]Y �]‚Jˆ[ÝÜÈ^Y\œÈÈÝ\HH ™[ØÚ]H˜[YHÛˆ[žH^\Ë‚ˆ +‹Â‚‚ZYˆ +[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×Ó“×ÓSÕ‘JB‚^‚BY[� O›[Ù[]KœÜYY žH ‚BY[� O›[Ù[]KœÜYY žHH ‚BY[� O›[Ù[]KœÜYY žˆH ‚_B‚Y[ÙB‚^ÂBB‚BKËÈÛÜHÜYY˜[Y\Èœ›ÛH[š[X][Ûˆ›Ú™XÝ[HÙ][™ÜÈÈ[Ù[ ‚‚B\›Ú™XÝ[KO�™[ØÚ]KžH[� O›[Ù[]KœÜYY ž‚_B‚ˆ Ê‚‚JˆÜÜÈH›ÛXˆ[�]H[ˆ[ˆ\˜Ë‚‚J‚‚JˆÙHØ[�È[™HYØXÞH™Z]š[܈ +\ÙH›Ú™XÝ[H�[\ZYÚ‚Jˆ›ÜˆHÜÜÈ™[ØÚ]JK[ÝÈ]]܈È\HH ˜[YH›ÜˆH‚Jˆ™[ØÚ]K[™\ÙHHØ[YH™[ØÚ]HÝ�XÝ\™HY[X™\œÈ›Üˆ›ÛXˆ‚Jˆ[™ÛšY™H›Ú™XÝ[\ˈH\Ý\�\È[ˆ^˜HÚ[[™ÙH™XØ]\ÙH‚JˆHY˜][™[ØÚ]H™YYț܈ۚY™H[™›ÛXˆ\™H›ÝÛÛ\]X›Kˆ‚JˆÈ[™H[Ùˆ\È\ÈÙHÚ[Ù]H™[ØÚ]KžHY[X™\ˆÈ‚JˆSÑSÔÔQQÓ“Ó‘HÜXÙšXØ[HÚ[ˆH›ÛXˆ›Ú™XÝ[H\È™\]Y\ÝY‚JˆžHH›ÝÙœ˜[YHÛÛ[X[™܈˜›ÛXˆˆ\Hœ›ÛHYØXÞHØÜš\�[˜Ý[Ûˆ‚Jˆ›Ú™XÝ[J +KˆYˆH]]܈Ù\È›Ý[ÙYžH\Ș[YKÙHÛ›ÝÈ‚JˆÈ˜[˜XÚÈÈYØXÞH™Z]š[܈[™\ÙHH›Ú™XÝ[H[�]IÜÈ‚Jˆ[Ù[�[\ZYÚ ˆ‚J‚‚JˆYˆH˜[YH\È[ž][™ÈÝ\ˆ[ˆSÑSÔÔQQÓ“Ó‘K[ˆÙHÛ›ÝÈ‚JˆH]]܈™\]Y\ÝYHÜXÚYšXÈ™[ØÚ]H +[˜ÛY[™È +H[™Ú[‚Jˆ\ÙH]]܈˜[YH[œÝXYÙˆ[Ù[�[\ZYÚ ‚‚J‹Â‚‚ZYˆ +›Ú™XÝ[KO�™[ØÚ]KžHOHSÑSÔÔQQÓ“Ó‘JB‚^‚B]ÜÜÊ[� [� O›[Ù[]Kš�[\ZYÚ +N‚_B‚Y[ÙB‚^‚B]ÜÜÊ[� ›Ú™XÝ[KO�™[ØÚ]KžJN‚_B‚B‚Kʈ\HÛÛ܈Y�\ÝY[� ˆ +‹Â‚X\WØÛÛÜ—ÜÙ]ØY�\Ý +[� \™[� ›Ú™XÝ[KO˜ÛÛÜ—ÜÙ]ØY�\Ý +N‚ˆ[� OœÜ]Û�\HHÔUÓ—ÕTWÔ“Ò‘PÕSWГÓPŽÂˆ[� O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘Nˆ[� O›ÝÛ™\ˆH\™[�Ȉ[� O››ÙܘXˆH NȈ[� O�Ù^ÙHH +VÑWÔ‘TT‘WÕÕPÒVÑWÔ‘TT‘WÑÔ“ÕS‘ +NȈˆ[� O�[šÈHÛÛ[[Û—Ý[šÎˆ[� O›™^[šÈHÝ[YH +È Nˆ[� O�ž[[Ý™HH•Sˆ[� O�ZÙXXÝ[ÛˆH•Sˆ[� O›[Ù[]K˜Z[[Ý™HHRSSÕ‘LWГÓPŽÂˆ[� O›[Ù[]K˜ZX]XÚÈHRPUPÒÌWÓ“ÐUPÒΈ[� O�ZÙY[XYÙHHÛÛ[[Û—ÝZÙY[XYÙN‚Y[� O˜]]ÚÚ[ �H�UUÒÒSÐUPÒ×ÒUÈ‚‚ZYˆ +[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ ˆSÕ‘WÐÓÓ‘’Q×Ó“×ÓSÕ‘JB‚^‚BY[� O˜]]ÚÚ[HUUÒÒSÐS’SPUSÓ—ÐÓÓTUN‚_B‚Bˆ[� OœÜYY][H ŽÂ‚‚KÊ‚ˆ +ˆÛÜH˜XÝ[Ûˆ]K‚ˆ +‹Â‚‚Y˜XÝ[Û—ØÛÜWØ[ +[� \™[� +Nˆ‚Y[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ �H“SÕ‘WÐÓÓ‘’Q×Ó“×ÐQ•TÕÐ�TÑN‚Y[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈH +SÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×Ð�TÑSPTSÕ‘WÐÓÓ‘’Q×Ô“Ò‘PÕSWÐ�TÑWÑQHSÕ‘WÐÓÓ‘’Q×Ô“Ò‘PÕSWÕÐSГÕS�ÑHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÑÔ�U’UHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÒÓHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÔU“Ô“HSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÕÐS +N‚B‚KËÈ^XÝ]HH›Ú™XÝ[IÜÈÛˆÜ]Ûˆ]™[� ‚‚Y^XÝ]WÛÛœÜ]Û—ÜØÜš\ +[� +N‚B‚\™]\›ˆ[�ŸB‚‹ËÈÜ]Ûˆ ÈÝ\œÂ‹Ë‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ NKLL‹LM‹Ë‹ËÈÜ]Ûˆ™YHœÝ\ˆˆ›Ú™XÝ[\ˈYX[�›ÜˆZZšH[™[ZY\È[ˆ‹ËÈÜšYÚ[˜[™X]ÈÙˆ˜YÙKÚÈÛÝ[�[\[™›ÝÈ™YHÝ\ˆ‹ËÈÚ\šZÙ[ˆXYÛÛ˜[HÝÛ�Ø\™]^Y\œËˆÜšYÚ[˜[]]܈‹ËÈ›Ù[ �][ÙYšYYÙ]™\˜[[Y\ÈžH[šÛ›ÝÛˆ\�Y\ˈ™Y˜XÝÜ™Y‹ËÈžHÈ Œ NKLL‹LMÈÈÛÜšÈÚ]Ý\œ™[�›Ú™XÝ[HÞ\Ý[Kˆ‹ËÈØ�š[Ý\ÛKÙH™YY\ț܈˜XÚÝØ\™ÛÛ\]Xš[]HÚ]YØXÞH‹ËÈ[Ù[\Ë�]Ý\�Ú\ÙHØÜš\\ÈH™\ÝÚÚXÙHÈ[™H‹ËÈ][\H›Ú™XÝ[\È܈[žHÝ\ˆÛÜ�ÙˆÜXÚX[^™Y‹ËțڙXÝ[HÜ]ۜ˂‹Ë‹ËÈ™]\›ˆ•QHYˆÝ\œÈÜ]Û™Y �SÑHÛˆ˜Z[ ‚š[�Ý\—ÜÜ]ÛŠ[�]H +œ\™[� ×ܛڙXÝ[H +œ›Ú™XÝ[JBžÂˆÛÛœÝ[�PVÔÕT”ÈH ΂ˆ[�]H +™[�H•S‚Z[�HH ‚Z[�[™^HSÑSÒS‘VÓ“Ó‘Nˆ[�š\œÝÜÛÜ�YH ‚‚\ר^\×Üš[˜Ú\[Ù›Ø]ÜÚ][ێ‚YWÙ\™XÝ[Ûˆ\™XÝ[ÛˆHT‘PÕSÓ—Ô’QÒ‚YWܛڙXÝ[WÜš[YH›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓ“Ó‘N‚‚KËÈYˆ\™IÜțțڙXÝ[H܈\™[�Ù][™Ë^]›ÝË‚‚ZYˆ +\›Ú™XÝ[H\\™[� +B‚^‚B\™]\›ˆ�SÑN‚_B‚BˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž‚\ÜÚ][Û‹žHH\™[� OœÜÚ][Û‹žH +țڙXÝ[KOœÜÚ][Û‹žN‚\ÜÚ][Û‹žˆH\™[� OœÜÚ][Û‹žˆ +țڙXÝ[KOœÜÚ][Û‹žŽÂ‚ˆ ËÈØ[YHÛÛ˜Ù\\ÈÛšY™HÜ]Û‹ˆÛÚț܈[Ù[ÈÜ]Û‹‚‚KËÈ Kˆ[š[X][Ûˆ›Ú™XÝ[K‚‚KËÈ ‹ˆÙX\Ûˆ[Ù[›Ú™XÝ[K‚‚KËÈ Ëˆ˜\ÙH[Ù[›Ú™XÝ[K‚‚KËÈ ˆYØXÞHY˜][ ‚ˆYŠ›Ú™XÝ[KOœÝ\ˆ�H +Bˆˆ[™^H›Ú™XÝ[KOœÝ\ŽÂ‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÔ“Ò—ÔÕTŽÂˆB‚Y[ÙHYˆ +\™[� O�ÙX\[� ‰ˆ\™[� O�ÙX\[� O›[Ù[]KœÝX�\HOHÕP•TWÔ“Ò‘PÕSH ‰ˆ\™[� O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ�H +B‚^‚BZ[™^H\™[� O�ÙX\[� O›[Ù[]Kœ›Ú™XÝ‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÕÑPTÓ—Ô“Ò‘PÕSN‚_Bˆ[ÙHYŠ\™[� O›[Ù[]KœÝ\ˆ�H +Bˆˆ[™^H\™[� O›[Ù[]KœÝ\ŽÂ‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÓSÑSÔÕTŽÂˆBˆ[ÙBˆˆ[™^HÙ]ØØXÚYÛ[Ù[Ú[™^ +”Ý\ˆŠNÈ‚‚B\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÔÓÕT�ÑWÑÓÐ�SÔÕTŽÂˆB‚‚\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÐ�TÑWÖN‚\›Ú™XÝ[WÜš[YHH“Ò‘PÕSWÔ’SQWÓUS�ÒÓSÕ’S‘΂‚KËÈÛÜÈX^Ý\ˆÛÝ[� ‚ˆ›ÜŠHH ÈHPVÔÕT”ÎÈJÊÊBˆ‚BKËÈÜ]ÛˆHÝ\ˆ[�]KˆYˆÙH˜Z[ ^][™™]\›ˆ˜[ÙK‚ˆ[�HÜ]ÛŠÜÚ][Û‹ž ÜÚ][Û‹ž‹ÜÚ][Û‹žK\™XÝ[Û‹•S [™^ •S +NˆYŠ[�OH•S +Bˆˆ™]\›ˆ ˆB‚ˆ ËÈÙ]™\Ý[Ùˆ\™XÝ[ÛˆY�\ÝY[� ˆÙH™YY\È™Y›Ü™HÙHØ[ˆ[™Bˆ ËÈÜÚ][Ûš[™ÈÛˆ^\Ë‚ˆ\™XÝ[ÛˆH\™XÝ[Û—ÙÙ]ØY�\ÝY[�Ü™\Ý[ +[� \™[� ›Ú™XÝ[KO™\™XÝ[Û—ØY�\Ý +N‚ˆ Ê‚ˆ +ˆ\HY˜][ÜÚ][ÛˆY‚ˆ +ˆÜ™X]܈Y›ÝÚ]™H\ÈH˜[YK‚ˆ +‹Â‚ˆYˆ +›Ú™XÝ[KOœÜÚ][Û‹žOH“Ò‘PÕSWÓQÐPÖWÐÓÓTUP’SUWÔÔÒUSÓ—Ö +Bˆˆ›Ú™XÝ[KOœÜÚ][Û‹žH“Ò‘PÕSWÑQ�USÔÕT—ÔÔÒUSÓ—ÖˆB‚ˆ ËÈ™]™\œÙHÚ[ˆ\™[�˜XÙ\ÈY� ‚ˆYˆ +\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž +țڙXÝ[KOœÜÚ][Û‹žˆBˆ[ÙBˆˆÜÚ][Û‹žH\™[� OœÜÚ][Û‹ž H›Ú™XÝ[KOœÜÚ][Û‹žˆB‚ˆ[� OœÜÚ][Û‹žHÜÚ][Û‹žˆ[� O™\™XÝ[ÛˆH\™XÝ[ێ‚‚BKËÈ Œ NKLL‹LMÈÈ H›ÝÝ\™HÚHÙHÙ]]XÚÚ[™ÈÙ™‹�]‚BKËÈX]š[™È]\™H›ÜˆYØXÞH™Z]š[Ü‹‚ˆ\™[� O˜]XÚÚ[™ÈHUPÒÒS‘×Ó“Ó‘N‚‚BKËÈš\œÝÝ\ˆÜ]Û™YÛÜ�YÙ\�™\È\ÈH˜\ÙH›ÜˆÛÜ�[™Ëˆ‚BKËÈ[ˆH™^Ý\‰ÜÈÛÜ�\ÈH˜\ÙH HÛÜ[™^ ˆXXÚ‚BKËÈÝXœÙ\]Y[�Ý\ˆ\X\œÈÛ™HÝ\�\�\ˆ™Z[™[‚‚BKËÈÛÜ�[™ÈÜ™\‹ˆ‚BKË‚BKËÈ^ˆ˜\ÙH +š\œÝÝ\ŠHH Œ  Œ H HH NK Œ H ˆH N ‚‚BZYˆ +HH +B‚B^‚BBYš\œÝÜÛÜ�YH[� OœÛÜ�Y‚B_B‚ˆ[� OœÛÜ�YHš\œÝÜÛÜ�Y HN‚ˆ[� O�ZÙY[XYÙHH\œ›Ý×ÝZÙY[XYÙNˆ[� O›ÝÛ™\ˆH\™[�ˆ[� O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘Nˆ[� O››ÙܘXˆH Nˆ‚BKËÈÙ]HÝ\ˆ™[ØÚ]HÙ][™Èœ›ÛH[š[X][Û‹‚‚BY[� O�™[ØÚ]KžH›Ú™XÝ[KOœÝ\—Ý™[ØÚ]VÚWN‚‚BKËÈ™]™\œÙH™[ØÚ]HYˆ\™XÝ[Ûˆ\ÈY� ‚‚BZYˆ +\™XÝ[ÛˆOHT‘PÕSÓ—ÓQ• +B‚B^‚BBY[� O�™[ØÚ]KžH Y[� O�™[ØÚ]Kž‚B_B‚BB‚BY[� O�[šÈHÛÛ[[Û—Ý[šÎˆ[� O›™^[šÈHÝ[YH +È Nˆ[� O�ž[[Ý™HH•Sˆ[� O�ZÙXXÝ[ÛˆH•Sˆ[� O›[Ù[]K˜Z[[Ý™HHRSSÕ‘LWÔÕTŽÂˆ[� O›[Ù[]K˜ZX]XÚÈHRPUPÒÌWÓ“ÐUPÒΈ‚BKËÈ™[[Ý™HÝ\ˆÛˆÛÛ�XÝ ‚‚BZYˆ +[� O›[Ù[]Kœ™[[Ý™WØÛÛ™šYÈ ˆ‘SSÕ‘WÐÓÓ‘’Q×ÒU +B‚B^‚BBY[� O˜]]ÚÚ[HUUÒÒSÐUPÒ×ÒU‚B_B‚BBBB‚BY[� OœÜÚ][Û‹žHHÜÚ][Û‹žN‚BY[� O˜˜\ÙHHÜÚ][Û‹žNˆ[� OœÜYY][H ŽÂˆˆ Ê‚ˆ +ˆÛÜH˜XÝ[Ûˆ]K‚ˆ +‹Âˆˆ˜XÝ[Û—ØÛÜWØ[ +[� \™[� +N‚‚BKËȘ\ÚXÈ\œšX[ˆ›Ü\�HÙ]\ ‚‚BY[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈH +SÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×Ð�TÑSPTSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÑÔ�U’UHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÒÓHSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÔU“Ô“HSÕ‘WÐÓÓ‘’Q×ÔÕP’‘PÕÕ×ÕÐS +N‚BY[� O›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈ �H“SÕ‘WÐÓÓ‘’Q×Ó“×ÐQ•TÕÐ�TÑN‚ˆ[� OœÜ]Û�\HHÔUÓ—ÕTWÔ“Ò‘PÕSWÔÕTŽÂ‚BY[� Oœ›Ú™XÝ[WÜš[YHH›Ú™XÝ[WÜš[YN‚‚BKËÈ^XÝ]HH›Ú™XÝ[IÜÈÛˆÜ]Ûˆ]™[� ‚‚BY^XÝ]WÛÛœÜ]Û—ÜØÜš\ +[� +NˆBˆ™]\›ˆ•QNŸB‚‚‚�›ÚYÝX[WÝ[šÊ +BžÂˆYŠ\Ù[‹O˜[š[X][™ÊBˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÔÕPSWÐS’SPUSÓ—ÐÓÓTUJNˆ™]\›ŽÂˆB‚ˆÙ[‹O˜˜\ÙH +ÏH NˆÙ[‹OœÜÚ][Û‹žHHÙ[‹O˜˜\ÙNŸB‚‚‚‹Ëț܈H�˜\ˆ\H ËLKLŒ H˜\Ý\��›ÚY˜\Ý[šÊ +BžÂˆÙ[‹O˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘NŸB‹ËÈ ËLKLŒ H˜\[™‚‚‚‚�›ÚYÝX[WÜÜ]ÛŠ›Ø] ›Ø]‹›Ø]JBžÂˆ[�]H +™HH•S‚ˆHHÜ]ÛŠ ‹K ”ÝX[H‹ LK•S +N‚ˆYŠHOH•S +Bˆˆ™]\›ŽÂˆB‚ˆKOœÜ]Û�\HHÔUÓ—ÕTWÔÕPSNˆKO˜˜\ÙHHNˆKO›[Ù[]K›[Ý™WØÛÛ™šY×Ù›YÜÈHSÕ‘WÐÓÓ‘’Q×Ó“×ÐQ•TÕÐ�TÑNˆKO�[šÈHÝX[WÝ[šÎ‚‚KËÈ^XÝ]HHÝX[\ÉÜÈÛˆÜ]Ûˆ]™[� ‚‚Y^XÝ]WÛÛœÜ]Û—ÜØÜš\ +JNŸB‚‚‚�›ÚYÝX[Y\—Ý[šÊ +BžÂˆÝX[WÜÜ]ÛŠÙ[‹OœÜÚ][Û‹ž Ù[‹OœÜÚ][Û‹ž‹Ù[‹OœÜÚ][Û‹žJNˆÙ[‹O›™^[šÈHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È L +H +È +˜[™ ÌŠ +H ˆ ÌJNŸB‚‚‚�›ÚY^Ý[šÊ +H ËÈ™]È�[˜Ý[ÛˆÛÈ^Ø[ˆ™H\Ü^YYžÂˆ ËÈØZ]ÈÝZXÚYBˆYŠ\Ù[‹O˜[š[X][™ÊBˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÕVÐS’SPUSÓ—ÐÓÓTUJNˆBŸB‚‹ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËË‚‹ËÚÛZ[™È\œ›ÝÈš[™]È\™Ù]‹ËÈ\Hˆ\™Ù]\B™[�]H +šÛZ[™×Ùš[™Ý\™Ù] +[�]JˆXÝ[™×Ù[�]JBžÂˆ[�Nˆ[�Z[ŽÂˆ[�X^ˆˆ[�]Jˆ\™Ù]Ù[�]HH•Sˆ[�]JˆÝ\œÛÜ—Ù[�]N‚ˆ ËÝ\ÙHHØ[È[š[X][Û‰ÜȘ[™ÙBˆYŠ˜[Y[š[JXÝ[™×Ù[�]KS’WÕÐSÊJBˆˆZ[ˆHXÝ[™×Ù[�]KO›[Ù[]K˜[š[X][Û–ÐS’WÕÐS×KOœ˜[™ÙKž ›Z[ŽÂˆX^HXÝ[™×Ù[�]KO›[Ù[]K˜[š[X][Û–ÐS’WÕÐS×KOœ˜[™ÙKž ›X^ˆBˆ[ÙBˆˆZ[ˆH ˆX^HNNNˆB‚ˆ ËÙš[™H Û™X\™\Ý ÈÛ™Bˆ›ÜŠHH ÈH[�ÛX^ÈJÊÊBˆˆÝ\œÛÜ—Ù[�]HH[�Û\ÝÚWN‚ˆYŠÝ\œÛÜ—Ù[�]KO™^\ÝÈ ‰ˆÝ\œÛÜ—Ù[�]HOHXÝ[™×Ù[�]H ËÈØ[�\™Ù]Ù[‚ˆ ‰ˆÝ\œÛÜ—Ù[�]HOHXÝ[™×Ù[�]KO›ÝÛ™\ˆ ËÈÛ‰ÝÛÈY�\ˆÝÛ™\‹‚ˆ ‰ˆ˜XÝ[Û—ØÚXÚ×Ú\×ÚÜÝ[JXÝ[™×Ù[�]KÝ\œÛÜ—Ù[�]JBˆ ‰ˆY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž +H +ÈY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]KOœÜÚ][Û‹žŠH�HZ[‚ˆ ‰ˆY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž +H +ÈY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]KOœÜÚ][Û‹žŠHHX^ˆ ‰ˆÝ\œÛÜ—Ù[�]KO˜[š[X][Û‹O��[™\˜X›VØÝ\œÛÜ—Ù[�]KO˜[š[\Ü×H +BˆˆYŠ]\™Ù]Ù[�]HY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž +H +ÈY™ŠÝ\œÛÜ—Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]KOœÜÚ][Û‹žŠHY™Š\™Ù]Ù[�]KOœÜÚ][Û‹ž XÝ[™×Ù[�]KOœÜÚ][Û‹ž +H +ÈY™Š\™Ù]Ù[�]KOœÜÚ][Û‹ž‹XÝ[™×Ù[�]KOœÜÚ][Û‹žŠJBˆˆ\™Ù]Ù[�]HHÝ\œÛÜ—Ù[�]NˆBˆBˆBˆˆ™]\›ˆ\™Ù]Ù[�]NŸB‚‚�›ÚYšZÙWØÜ˜\Ú + +BžÂˆ[�NˆYŠÙ[‹O™\™XÝ[ÛˆOHT‘PÕSÓ—Ô’QÒ +BˆˆÙ[‹O�™[ØÚ]KžH ŽÂˆBˆ[ÙBˆˆÙ[‹O�™[ØÚ]KžH LŽÂˆBˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYˆ +Ø]™Y]Kš›Þ\�[X›VÚWJHÛÛ�›ÛÜ�[X›JK K L +NˆBˆ ËÚYŠÙ[‹OœÜÚ][Û‹žY˜[˜Ù^ LL Ù[‹OœÜÚ][Û‹žˆY˜[˜Ù^ +ÊšY[Û[Ù\Ëš™\ÊÌL +JHÚ[Ù[�]JÙ[ŠNŸB‚‚‚š[�šZÙ\—ÝZÙY[XYÙJ[�]Jˆ\™Ù]Ù[�]K[�]Jˆ]XÚÚ[™×Ù[�]Kר]XÚʈ]XÚ×ÛØš™XÝ [�˜[Ù›YËÛÛœÝ×ÙY™[œÙJˆY™[œÙWÛØš™XÝ +BžÂˆ[�]H +™š]™\ˆH•S‚ˆYŠ\™Ù]Ù[�]KO™X]ÜÝ]H ˆPUÔÕUWÑPQ +Bˆˆ™]\›ˆ ˆBˆ ËÈ™[[ˆHÛBˆYŠ\™Ù]Ù[�]KOœÜÚ][Û‹žHUÑT +BˆˆÚ[Ù[�]J\™Ù]Ù[�]KÒSÑS•UWÕ’QÑÑT—ÕRÑWÑSPQÑWÐ’RÑT—ÔU +Nˆ™]\›ˆ ˆBˆYŠ]XÚÚ[™×Ù[�]HOH\™Ù]Ù[�]JBˆˆÙ]ÛÜÛ™[� +]XÚÚ[™×Ù[�]K\™Ù]Ù[�]JNˆB‚ˆYŠ]XÚ×ÛØš™XÝ O››×ÜZ[ŠH ËÈۉݛܚ]™\ˆ[�[]\ÈXY ™XØ]\ÙHH]XÚÈ\È›ÈZ[ˆY™™X݈ˆÚXÚÙ[XYÙJ\™Ù]Ù[�]K]XÚÚ[™×Ù[�]K]XÚ×ÛØš™XÝ Y™[œÙWÛØš™XÝ +NˆYŠ\™Ù]Ù[�]KO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ +Bˆˆ™]\›ˆ NÈ ËÈ›ÝXYY]ˆBˆB‚ˆÚXÚר˜XÚÜZ[Š]XÚÚ[™×Ù[�]K\™Ù]Ù[�]JNˆÙ]ÜZ[Š\™Ù]Ù[�]K\™Ù]Ù[�]KO›\ÝÙ[XYÙWÝ\K JNˆ\™Ù]Ù[�]KO˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘NˆYŠ]\™Ù]Ù[�]KO›[Ù[]K›Ù™œØÜ™Y[šÚ[ +Bˆˆ\™Ù]Ù[�]KO›[Ù[]K›Ù™œØÜ™Y[šÚ[H L ˆBˆ\™Ù]Ù[�]KO�[šÈHšZÙWØÜ˜\Úˆ ËÈÙ[ \È\ÈH™X[[�]KHš]™\ˆÚÈZÙHH[XYÙBˆYŠ +š]™\ˆH›ÜÙš]™\Š\™Ù]Ù[�]JJJBˆˆš]™\‹OœÜÚ][Û‹žHH\™Ù]Ù[�]KOœÜÚ][Û‹žNˆš]™\‹O™›ÜH Nˆš]™\‹O™\™XÝ[ÛˆH\™Ù]Ù[�]KO™\™XÝ[ێˆYŠš]™\‹O�ZÙY[XYÙJBˆˆš]™\‹O�ZÙY[XYÙJš]™\‹]XÚÚ[™×Ù[�]K]XÚ×ÛØš™XÝ ˜[Ù›YËY™[œÙWÛØš™XÝ +NˆBˆ[ÙBˆˆš]™\‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[� OH]XÚ×ÛØš™XÝ O˜]XÚ×ٛܘÙNˆBˆBˆ\™Ù]Ù[�]KO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H ˆÚXÚÙX] +\™Ù]Ù[�]JNˆ™]\›ˆ NŸB‚‚‚�›ÚYØœÝXÛWÙ˜[ + +BžÂˆYŠ[˜Z\ŠÙ[ŠJBˆˆ™]\›ŽÂˆB‚ˆÙ[‹O�™[ØÚ]KžHÙ[‹O�™[ØÚ]KžˆH ˆYŠ +\Ù[‹O˜[š[X][™È ‰ˆ˜[Y[š[JÙ[‹S’WÑQJJH]˜[Y[š[JÙ[‹S’WÑQJJBˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÓДÕPÓWÑ�SÓ“×ÑPUÐS’SPUSÓŠNÈ ËÈš^YÛÈS’WÑQHØ[ˆ™H\ÙYˆBŸB‚‚‚�›ÚYØœÝXÛWÙ›J +H ËÈ›ÝÈØœÝXÛ\ÈØ[ˆ›HÚ[ˆ]ZÙHÛˆÚ[\ÛÛœËÕS•žÂˆ ËÜÙ[‹OœÜÚ][Û‹ž +ÏHÙ[‹O�™[ØÚ]Kž +ˆ È ËÈ\]Z]™[[�ÙˆÜYY ˆYŠÙ[‹OœÜÚ][Û‹žˆY˜[˜Ù^ +È +šY[Û[Ù\Ëš™\È +È Œ +HÙ[‹OœÜÚ][Û‹žY˜[˜Ù^ H Œ +BˆˆÚ[Ù[�]JÙ[‹ÒSÑS•UWÕ’QÑÑT—ÓДÕPÓWÑ“WÓÕUÓїГÕS‘ÊNˆBŸB‚‚‚š[�ØœÝXÛWÝZÙY[XYÙJ[�]Jˆ\™Ù]Ù[�]K[�]Jˆ]XÚÚ[™×Ù[�]Kר]XÚʈ]XÚ×ÛØš™XÝ [�˜[Ù›YËÛÛœÝ×ÙY™[œÙJˆY™[œÙWÛØš™XÝ +BžÂˆYŠ\™Ù]Ù[�]KOœÜÚ][Û‹žHHUÑT +BˆˆÚ[Ù[�]J\™Ù]Ù[�]KÒSÑS•UWÕ’QÑÑT—ÕRÑWÑSPQÑWÓДÕPÓWÔU +Nˆ™]\›ˆ ˆB‚ˆÙ]ÛÜÛ™[� +]XÚÚ[™×Ù[�]K\™Ù]Ù[�]JNˆYŠ\™Ù]Ù[�]KO›ÜÛ™[� ‰ˆ +\™Ù]Ù[�]KO›ÜÛ™[� O›[Ù[]K�\H ˆTWÔVQTŠJBˆˆYˆ +Ø]™Y]Kš›Þ\�[X›VÝ\™Ù]Ù[�]KO›ÜÛ™[� Oœ^Y\š[™^JHÛÛ�›ÛÜ�[X›J\™Ù]Ù[�]KO›ÜÛ™[� Oœ^Y\š[™^  K ÍJNˆBˆˆ ʈØ[Ý[]H[™\H[XYÙKˆ +‹ÂˆÚXÚÙ[XYÙJ\™Ù]Ù[�]K]XÚÚ[™×Ù[�]K]XÚ×ÛØš™XÝ Y™[œÙWÛØš™XÝ +N‚ˆ\™Ù]Ù[�]KOœ^Y\š[™^H]XÚÚ[™×Ù[�]KOœ^Y\š[™^È ËÈYYÛÈÚ[�ÈÛÈÈHÛÜœ™XÝ^Y\‚ˆYØÛÜ™J]XÚÚ[™×Ù[�]KOœ^Y\š[™^ ]XÚ×ÛØš™XÝ O˜]XÚ×ٛܘÙH +ˆ\™Ù]Ù[�]KO›[Ù[]K›][\JNÈ ËÈÚ[�ÈØ[ˆ›ÝÈ™HÚ]™[ˆ›Üˆ][™È[ˆØœÝXÛB‚ˆYŠ\™Ù]Ù[�]KO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H +Bˆ‚ˆÚXÚÙX] +\™Ù]Ù[�]JN‚ˆYŠ]XÚÚ[™×Ù[�]KOœÜÚ][Û‹ž\™Ù]Ù[�]KOœÜÚ][Û‹ž +Bˆˆ\™Ù]Ù[�]KO�™[ØÚ]KžH NˆBˆ[ÙBˆˆ\™Ù]Ù[�]KO�™[ØÚ]KžH LNˆB‚ˆ\™Ù]Ù[�]KO˜]XÚÚ[™ÈHUPÒÒS‘×ÐPÕU‘NÈ ËÈÛÈØœÝXÛ\ÈØ[ˆ^ÙH[™\�^Y\œËÙ[™[ZY\‚ˆYŠ\™Ù]Ù[�]KO›[Ù[]KœÝX�\HOHÕP•TWÑ“QQJH ËÈ›ÝÈØœÝXÛ\ÈØ[ˆ›HZÙHÛˆÚ[\ÛÛœËÕS•ˆˆ\™Ù]Ù[�]KO�™[ØÚ]Kž +�H ˆ\™Ù]Ù[�]KO�[šÈHØœÝXÛWÙ›Nˆ[�ÜÙ]Ø[š[J\™Ù]Ù[�]KS’WÑ�S  +NˆBˆ[ÙBˆˆ\™Ù]Ù[�]KO�[šÈHØœÝXÛWÙ˜[‚ˆYŠ˜[Y[š[J\™Ù]Ù[�]KS’WÑQJJBˆˆ[�ÜÙ]Ø[š[J\™Ù]Ù[�]KS’WÑQK +NÈ ËȈ KLLËL HYH™Y›Ü™HÜ܈Bˆ[ÙBˆˆÜÜÊ\™Ù]Ù[�]K\™Ù]Ù[�]KO›[Ù[]Kš�[\ZYÚ È KŒÌÌÊNˆ[�ÜÙ]Ø[š[J\™Ù]Ù[�]KS’WÑ�S  +NˆB‚ˆYŠ\™Ù]Ù[�]KO›[Ù[]K™X]ØÛÛ™šY×Ù›YÜÈ ˆPUÐÓÓ‘’Q×ÓPPÔ“×ГS’ÊBˆˆ\™Ù]Ù[�]KO˜›[šÈH NˆBˆBˆB‚ˆ\™Ù]Ù[�]KO›™^[šÈHÝ[YH +È Nˆ™]\›ˆ NŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ N L L�‹Ë‹ËÈ[ØØ]HY[[ÜžH[™Ù][�]H›Ü\�Y\È]Ú[™H˜[œÙ™\™Y‹ËÈÈH›ÜY][K‚�›ÚY[š]X[^™WÚ][WØØ\œžJ[�]H +™[� ×ÜÜ]Û—Ù[�žH +œÜ]Û—Ù[�žJBžÂˆ ËÈ] ÜÈÜÜÚX›HÈØ[\Èœ›ÛHØÜš\ ÛÈY‚ˆ ËÈ\™H\È[™XYHY[[ÜžH›Üˆ[ˆ][H[ØØ]Yˆ ËÈ\™KÛX\ˆ]Ý]ÈXZÙHÝ\™HÙHÛ‰Ý[™\ˆ ËÈÚ][žHY[[ÜžHXZÜË‚ˆYŠ[� Oš][WÜ›Ü\�Y\ÊBˆˆœ™YJ[� Oš][WÜ›Ü\�Y\ÊNˆ[� Oš][WÜ›Ü\�Y\ÈH•SˆB‚ˆ ËÈ[ØØ]HY[[ÜžH›ÜˆH][K‚ˆ[� Oš][WÜ›Ü\�Y\ÈHX[ØÊÚ^™[ÙŠ +™[� Oš][WÜ›Ü\�Y\ÊJNˆY[\Ù] +[� Oš][WÜ›Ü\�Y\Ë Ú^™[ÙŠ +™[� Oš][WÜ›Ü\�Y\ÊJN‚ˆYŠÜ]Û—Ù[�žJBˆˆ[� Oš][WÜ›Ü\�Y\ËOš[™^HÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\Ëš[™^‚ˆYŠÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\˘[X\ÖÌJBˆˆÝ˜ÜJ[� Oš][WÜ›Ü\�Y\ËO˜[X\ËÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\˘[X\ÊNˆB‚ˆYŠÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\˘ÛÛÜœÙ] +Bˆˆ[� Oš][WÜ›Ü\�Y\ËO˜ÛÛÜœÙ]HÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\˘ÛÛÜœÙ]ˆB‚ˆYŠÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\ËšX[ +Bˆˆ[� Oš][WÜ›Ü\�Y\ËOšX[HÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\ËšX[ˆBˆ[� Oš][WÜ›Ü\�Y\ËOœ^Y\—ØÛÝ[�HÜ]Û—Ù[�žKOš][WÜ›Ü\�Y\Ëœ^Y\—ØÛÝ[�ˆBŸB‚™[�]H +œÛX\�Ü]ÛŠ×ÜÜ]Û—Ù[�žH +œ›ÜÊH ËÈ ËLKLŒ H[�\™HÙXÝ[Ûˆ™\XÙYÚ]Ü™˜[ÈÛÙBžÂˆ[�]H +™HH•Sˆ[�]H +�ÜH•Sˆ[�^Y\˜ÛÝ[�‚ˆYŠ›ÜÈOH•S ʈˆ +]™[OH•S ‰‚ˆJØÜ™Y[—ÜÝ]\È ˆ +S—ÔÐÔ‘QS—ÔÑSPÕS—ÔÐÔ‘QS—ÕUHS—ÔÐÔ‘QS—ÒSÓÑ—Ñ�SQHS—ÔÐÔ‘QS—ÑÐSQWÓÕ‘TˆS—ÔÐÔ‘QS—ÔÒÕ×ÐÓÓTUHS—ÔÐÔ‘QS—ÑS‘ÒS‘WÐÔ‘QUS—ÔÐÔ‘QS—ÓQS•HS—ÔÐÔ‘QS—ÑÐSQWÔÕT•ÓQS•HS—ÔÐÔ‘QS—Ó‘U×ÑÐSQWÓQS•HS—ÔÐÔ‘QS—ÓÐQÑÐSQWÓQS•HS—ÔÐÔ‘QS—ÓÔSÓ”×ÓQS•HS—ÔÐÔ‘QS—ÐÓÓ•“ÓÓÔSÓ”×ÓQS•HS—ÔÐÔ‘QS—ÔÓÕS‘ÓÔSÓ”×ÓQS•HS—ÔÐÔ‘QS—Õ’QS×ÓÔSÓ”×ÓQS•HS—ÔÐÔ‘QS—ÔÖTÕSWÓÔSÓ”×ÓQS•JJH ‰‚ˆÝ\œ™[�ØÙ[™JJ‹Âˆ +Bˆˆ™]\›ˆ•SˆB‚ˆ ʈÜ]Ûˆ][H˜\ÙYÛˆ�[X™\ˆÙˆXÝ]™H^Y\œËˆ +‹ÂˆYŠ›ÜËOœÜ]Ûœ^Y\—ØÛÝ[��H +^Y\˜ÛÝ[�HPV + KÛÝ[�Ù[�ÊTWÔVQTŠJJJBˆˆYŠ›ÜËO˜›ÜÜÈ ‰ˆ]™[OH•S +Bˆˆ K[]™[ O˜›ÜÜÙ\ØÛÝ[�ˆBˆ™]\›ˆ•SˆB‚ˆYŠ]™[OH•S ‰ˆ + +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÒS•ÐT‘ +H +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓÕUÐT‘ +JH +BˆˆHHÜ]ÛŠ›ÜËOœÜÚ][Û‹ž ›ÜËOœÜÚ][Û‹žˆ +ÈY˜[˜Ù^K›ÜËOœÜÚ][Û‹žK›ÜËO™›\ ›ÜËO›˜[YK›ÜËOš[™^ ›ÜËO›[Ù[ +NˆBˆ[ÙBˆˆHHÜ]ÛŠ›ÜËOœÜÚ][Û‹ž +ÈY˜[˜Ù^ ›ÜËOœÜÚ][Û‹ž‹›ÜËOœÜÚ][Û‹žK›ÜËO™›\ ›ÜËO›˜[YK›ÜËOš[™^ ›ÜËO›[Ù[ +NˆB‚ˆYŠHOH•S +Bˆˆ™]\›ˆ•SˆB‚ˆ ËÜš[�Љ\Ë + Y‹ Y‹ YŠH H + Y‹ Y‹ YŠH‹›ÜËO›˜[YK›ÜËOœÜÚ][Û‹ž ›ÜËOœÜÚ][Û‹ž‹›ÜËOœÜÚ][Û‹žKKOœÜÚ][Û‹ž KOœÜÚ][Û‹ž‹KOœÜÚ][Û‹žJN‚ˆ ËÈ[X\ψYŠ›ÜËO˜[X\ÖÌJBˆˆY[\Ù] +KO›˜[YK Ú^™[ÙŠKO›˜[YJJNˆÝ˜ÜJKO›˜[YK›ÜËO˜[X\ÊNˆB‚ˆ ËÈYˆÙH]™H][H›Ü\�Y\È[ˆÜ]Ûˆ[�žK[ˆ™\\™HHÙ]Ù‚ˆ ËÈ›Ü\�Y\ÈÈ\ÜÈÛˆÈH][HÚ[ˆ]\È›ÜY ‚ˆYŠ›ÜËOš][JBˆˆ[š]X[^™WÚ][WØØ\œžJK›ÜÊNˆBˆˆ˜XÝ[Û—ØÛÜWÙ]J ™KO›[Ù[]K™˜XÝ[Û‹ œ›ÜËO™˜XÝ[ÛŠNˆ˜XÝ[Û—ØÛÜWÙ]J ™KO™˜XÝ[Û‹ œ›ÜËO™˜XÝ[ÛŠN‚ˆYŠ›ÜËOœÜ]Û�\JBˆˆKOœÜ]Û�\HH›ÜËOœÜ]Û�\NÈ ËÌŒ LWÌ ×ÌŒË\ÜÈÜ]Û�\K‚ˆB‚ˆYŠ›ÜËOšX[Ü^Y\˜ÛÝ[� H WHOH +BˆˆKO™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�HKO›[Ù[]KšX[H›ÜËOšX[Ü^Y\˜ÛÝ[� H WNˆB‚ˆYŠ›ÜËO›\OH +BˆˆKO™[™\™ÞWÜÝ]K›\ØÝ\œ™[�HKO›[Ù[]K›\H›ÜËO›\ˆB‚ˆYŠ›ÜËOœØÛÜ™HOH +BˆˆKO›[Ù[]KœØÛÜ™HH›ÜËOœØÛÜ™NÈ ËÈÝ™\�Üš]HØÛÜ™HYˆ^\ÝÈ[ˆH]™[ Üˈš[BˆBˆYŠ›ÜËO›][\HOH +BˆˆKO›[Ù[]K›][\HH›ÜËO›][\NÈ ËÈÝ™\�Üš]H][\HYˆ^\ÝÈ[ˆH]™[ ÜÈ �š[BˆB‚ˆYŠYKO›X\ ‰ˆ›ÜËO˜ÛÛÝ\›X\ +Bˆˆ[�ÜÙ]ØÛÛÝ\›X\ +K›ÜËO˜ÛÛÝ\›X\ +NˆB‚ˆYŠ›ÜËO˜YÙÜ™\ÜÚ[ÛŠBˆˆKO›[Ù[]K˜YÙÜ™\ÜÚ[ÛˆH›ÜËO˜YÙÜ™\ÜÚ[ÛŽÈ ËÈYÙÜ™\ÜÚ[ÛˆØ[ˆ™HÚ[™ÙYÚ]Ü]ÛˆÚ[�ț݈BˆYŠ›ÜËOš][WÜ›Ü\�Y\˘[JBˆˆKOš][WÜ›Ü\�Y\ËO˜[HH›ÜËOš][WÜ›Ü\�Y\˘[NˆBˆYŠ›ÜËO˜[JBˆˆKO›[Ù[]K˜[HH›ÜËO˜[NˆB‚ˆ ËÈ™Xˆ �‹ Œ H HÝÜ™HHÜšYÚ[˜[X\È™HX›HÈ™\ÝÜ™HÚ]Z[™È›\ÚˆYŠ›ÜËO™Z[™ÊBˆˆKO™Z[™ÈH›ÜËO™Z[™ÎÈ ËÈ™Xˆ �‹ Œ H H\ÙYÈYš[™HÚXÚÛÛÝ\›X\\È\ÙY›ÜˆHZ[™È›\ÚˆKOœ\ŒHH›ÜËOœ\ŒNÈ ËÈX\ˆ ŒK Œ H H\ÙYÈÝÜ™HÝ\ÝÛH\˜Ù[�YÙ\ˆKOœ\ŒˆH›ÜËOœ\ŒŽÈ ËÈX\ˆ ŒK Œ H H\ÙYÈÝÜ™HÝ\ÝÛH\˜Ù[�YÙ\ˆKO™Z[™ÌˆH›ÜËO™Z[™ÌŽÈ ËÈXÈ MK Œ Mˆ H\ÙYÈYš[™HÚXÚÛÛÝ\›X\\È\ÙY›ÜˆHZ[™È›\ڛ܈\ŒˆžHÚ]H˜YÛÛ‚ˆB‚ˆYŠ›ÜËO››ÛY™JBˆˆKO›[Ù[]K››ÛY™HH›ÜËO››ÛY™NÈ ËÈÝ™\�Üš]HÚ]\ˆ]™H\Èš\ÚX›H܈›ÝˆBˆKO˜›ÜÜÈH›ÜËO˜›ÜÜ΂ˆYŠ›ÜËO˜›ÜÜÈ ‰ˆ]™[OH•S ‰ˆ]™[ O˜›ÜÜÛ]\ÚXÖÌJBˆˆ]\ÚXÊ]™[ O˜›ÜÜÛ]\ÚXË K]™[ O˜›ÜÜÛ]\ÚX×ÛÙ™œÙ] +NˆB‚ˆ ËÈÚ]™HH[�]HHÙX\Ûˆ][BˆYŠ›ÜËO�ÙX\ÛŠBˆˆÜHÜ]ÛŠKOœÜÚ][Û‹ž USWÒQWÔÔÒUSÓ—Ö‹  ›ÜËO�ÙX\Û‹›ÜËO�ÙX\Ûš[™^ ›ÜËO�ÙX\Û›[Ù[ +NˆYŠÜ +Bˆˆ ËÙ[�ÙY˜][Ú[š] +Ü +NˆÙ]ÝÙX\ÛŠKÜ O›[Ù[]K�ÙX\Û—Ü›Ü\�Y\Ë�ÙX\Û—Ú[™^  +NˆKO�ÙX\[�HÜ‚ˆKO�ÙX\[� OœÜ]Û�\HHÔUÓ—ÕTWÕÑPTӎˆBˆB‚ˆ ËÈÙ][�]H\Nˆ^Y\‹[™[^KœË‹‹‚ˆYŠ›ÜËO™[�]]\JBˆˆKO›[Ù[]K�\HH›ÜËO™[�]]\NˆB‚ˆ ËÈÙ]H\™[�ˆYŠ›ÜËOœ\™[� +H ËËO�˜\›\Ý O�˜\œËO��OH•ÑSTBˆˆKOœ\™[�H +[�]H +Š\›ÜËOœ\™[�ˆB‚ˆ ËÙ[�ÙY˜][Ú[š] +JNˆ^XÝ]WÛÛœÜ]Û—ÜØÜš\ +JNˆ^XÝ]WÜÜ]Û—ÜØÜš\ +›ÜËJNˆ™]\›ˆNŸH ËÈ ËLKLŒ H™\XÙYÙXÝ[Ûˆ[™È\™B‚š[�\×Ú[˜Ø[J›Ø] ›Ø]‹›Ø]K›Ø]™\ÚÛ +BžÂˆYˆ +]™[ +BˆˆYˆ +�HY˜[˜Ù^ +Ý™\ÚÛ ‰ˆHY˜[˜Ù^ +ÝšY[Û[Ù\Ëš™\Ë]™\ÚÛ ‰ˆ‹XH�HY˜[˜Ù^JÝ™\ÚÛ ‰ˆ‹XHHY˜[˜Ù^JÝšY[Û[Ù\Ë�”™\ËM +HˆYˆ +�HØÜ›ÛZ[ž ‰ˆHØÜ›ÛX^ +ÝšY[Û[Ù\Ëš™\È ‰ˆˆ�HVQT—ÓRS—Öˆ ‰ˆˆHVQT—ÓPVÖˆ +Hˆ™]\›ˆ NˆBˆBˆB‚ˆ™]\›ˆ ŸB‚�›ÚYÜ]Ûœ^Y\Š[�[™^ +BžÂˆ×ÜÜ]Û—Ù[�žHˆ ËÜ×Û[Ù[ +ˆ[Ù[H•Sˆ[�Ø[ˆ[�˘˚[™H ˆ[™^ �H ΂‹ËÈ[Ù[Hš[™Û[Ù[ +^Y\–Ú[™^K›˜[YJN‹ËÈYŠ[Ù[OH•S +H™]\›ŽÂ‚ˆY[\Ù] + œ  Ú^™[ÙŠ +JNˆ ›˜[YHH^Y\–Ú[™^K›˜[YNˆ š[™^H LNˆ š][WÜ›Ü\�Y\Ëš[™^H LNˆ �ÙX\Ûš[™^H LNˆ ˜ÛÛÝ\›X\H^Y\–Ú[™^K˜ÛÛÝ\›X\ˆ œÜ]Ûœ^Y\—ØÛÝ[�H LNˆ œÜ]Û�\HHÔUÓ—ÕTWÔVQT—ÓPRSŽÂ‚ˆYŠ]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +BˆˆYŠ]™[ OœÜ]Ûˆ ‰ˆ]™[ OœÜ]Û–Ú[™^Kž +Bˆˆ œÜÚ][Û‹žH +›Ø] +JšY[Û[Ù\Ëš™\È H]™[ OœÜ]Û–Ú[™^Kž +NˆBˆ[ÙBˆˆ œÜÚ][Û‹žH +›Ø] +J +šY[Û[Ù\Ëš™\È H Œ +H H Ì +ˆ[™^ +NˆBˆBˆ[ÙBˆˆYŠ]™[ OœÜ]Ûˆ ‰ˆ]™[ OœÜ]Û–Ú[™^Kž +Bˆˆ œÜÚ][Û‹žH +›Ø] +J]™[ OœÜ]Û–Ú[™^Kž +NˆBˆ[ÙBˆˆ œÜÚ][Û‹žH +›Ø] +J Œ +È Ì +ˆ[™^ +NˆBˆ ™›\H NˆB‚ˆYŠ]™[ OœÜ]Ûˆ ‰ˆ]™[ OœÜ]Û–Ú[™^KžŠBˆˆYŠ]™[ OœØÜ›Û\ˆ ˆ +ÐÔ“ÓÒS•ÐT‘ÐÔ“ÓÓÕUÐT‘ +JBˆˆ œÜÚ][Û‹žˆH +›Ø] +J]™[ OœÜ]Û–Ú[™^KžŠNˆBˆ[ÙBˆˆ œÜÚ][Û‹žˆH +›Ø] +JVQT—ÓRS—Öˆ +È]™[ OœÜ]Û–Ú[™^KžŠNˆBˆBˆ[ÙHYŠVQT—ÓPVÖˆ HVQT—ÓRS—Öˆˆ JBˆˆ œÜÚ][Û‹žˆH +›Ø] +JVQT—ÓRS—Öˆ +È JNˆBˆ[ÙBˆˆ œÜÚ][Û‹žˆH +›Ø] +TVQT—ÓRS—֎ˆB‚ˆYŠ œÜÚ][Û‹žˆVQT—ÓRS—ÖŠBˆˆ œÜÚ][Û‹žˆHVQT—ÓRS—֎ˆBˆ[ÙHYŠ œÜÚ][Û‹žˆˆVQT—ÓPVÖŠBˆˆ œÜÚ][Û‹žˆHVQT—ÓPV֎ˆB‚ˆ ËËËËËËËËËËËËËËËËËØÚXÚÚ[™ÈÛ\ËÈØ[ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËˈ›ÜŠÈH ÈÈšY[Û[Ù\Ëš™\È È ÈÊÊÊBˆˆYŠ œÜÚ][Û‹ž�HšY[Û[Ù\Ëš™\ÊBˆˆ œÜÚ][Û‹ž OHšY[Û[Ù\Ëš™\ΈBˆYŠ œÜÚ][Û‹ž +Bˆˆ œÜÚ][Û‹ž +ÏHšY[Û[Ù\Ëš™\ΈBˆYŠVQT—ÓRS—ÖˆOHVQT—ÓPVÖŠBˆˆØ[HÚXÚÝØ[Ú[™^ +Y˜[˜Ù^ +È œÜÚ][Û‹ž  œÜÚ][Û‹žŠNˆYŠØ[�H  ‰ˆ]™[ O�Ø[ÖÝØ[KšZYÚPVÕÐSÒRQÒ +Bˆˆœ™XZÎÈ ËÙ›Ý[™ˆBˆYŠÚXÚÚÛWÚ[ŠY˜[˜Ù^ +È œÜÚ][Û‹ž  œÜÚ][Û‹ž‹ œÜÚ][Û‹žJH +Ø[�H  ‰ˆ]™[ O�Ø[ÖÝØ[KšZYÚ�HPVÕÐSÒRQÒ +JBˆˆš[™H ˆBˆ[ÙBˆˆœ™XZÎÈ ËÈ›Ý[™ˆBˆBˆ[ÙH›ÜŠ˜ÈH È˜È +VQT—ÓPVÖˆ HVQT—ÓRS—ÖŠH È ÎȘÊÊË œÜÚ][Û‹žˆ +ÏH ÊBˆˆYŠ œÜÚ][Û‹žˆˆVQT—ÓPVÖŠBˆˆ œÜÚ][Û‹žˆ OHVQT—ÓPVÖˆ HVQT—ÓRS—֎ˆBˆYŠ œÜÚ][Û‹žˆVQT—ÓRS—ÖŠBˆˆ œÜÚ][Û‹žˆ +ÏHVQT—ÓPVÖˆ HVQT—ÓRS—֎ˆBˆØ[HÚXÚÝØ[Ú[™^ +Y˜[˜Ù^ +È œÜÚ][Û‹ž  œÜÚ][Û‹žŠNˆYŠØ[�H  ‰ˆ]™[ O�Ø[ÖÝØ[KšZYÚPVÕÐSÒRQÒ +Bˆˆš[™H Nˆœ™XZΈBˆ[ÙHYŠØ[�H  ‰ˆ]™[ O�Ø[ÖÝØ[KšZYÚ�HPVÕÐSÒRQÒ +BˆˆÛÛ�[�YNˆBˆYŠÚXÚÚÛWÚ[ŠY˜[˜Ù^ +È œÜÚ][Û‹ž  œÜÚ][Û‹ž‹ œÜÚ][Û‹žJJBˆˆÛÛ�[�YNˆBˆš[™H Nˆœ™XZΈBˆYŠš[™ +Bˆˆœ™XZΈBˆ œÜÚ][Û‹ž +ÏH +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +HÈ Mˆ ˆBˆ ËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËËˈÝ\œ™[�Ü]Ûœ^Y\ˆH[™^ˆ^Y\–Ú[™^K™[�HÛX\�Ü]ÛŠ œ +N‚ˆYŠ^Y\–Ú[™^K™[�OH•S +Bˆˆ›Ü”Ú]ÝÛŠ K‘˜][ˆ[˜X›HÈÜ]Ûˆ^Y\ˆœ›ÛH É\É׈‹ ›˜[YJNˆB‚ˆ^Y\–Ú[™^K™[� Oœ^Y\š[™^H[™^‚ˆYŠ›ÛX^�\Ú™\Ù]ÍH�H JBˆˆ^Y\–Ú[™^K™[� Oœ�\Ú ›X^H›ÛX^�\Ú™\Ù]Ú[™^NˆBˆ[ÙBˆˆ^Y\–Ú[™^K™[� Oœ�\Ú ›X^H ˆB‚ˆY[\Ù] +ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]Ú\ÝÜžKˆ ˆÚ^™[ÙŠ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]Ú\ÝÜžJBˆ +N‚ˆY[\Ù] +ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YKˆ ˆÚ^™[ÙŠ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý[YJBˆ +N‚ˆY[\Ù] +ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—Ý[YKˆ ˆÚ^™[ÙŠ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—Ý[YJBˆ +N‚ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÜÝ\�ݘ[YH ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ݘ[YH ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]ØÛÝ[�H ˆ^Y\–Ú[™^K˜ÛÛ[X[™Ú[œ]Ú[™^H ‚ˆYŠ^Y\–Ú[™^KœÜ]ÛšX[ +Bˆˆ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H^Y\–Ú[™^KœÜ]ÛšX[ +È NˆBˆYŠ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ^Y\–Ú[™^K™[� O›[Ù[]KšX[ +Bˆˆ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H^Y\–Ú[™^K™[� O›[Ù[]KšX[ˆB‚ˆ ËÛ\]H™XÛÜ�™\ˆY�\ˆH]™[žHZ[ˆYŠ^Y\–Ú[™^KœÜ]Û›\ +Bˆˆ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�H^Y\–Ú[™^KœÜ]Û›\ +È ŽÂˆBˆYŠ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�ˆ^Y\–Ú[™^K™[� O›[Ù[]K›\ +Bˆˆ^Y\–Ú[™^K™[� O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�H^Y\–Ú[™^K™[� O›[Ù[]K›\ˆB‚ˆYŠ^Y\–Ú[™^K�ÙX\�[JBˆˆÙ]ÝÙX\ÛŠ^Y\–Ú[™^K™[� ^Y\–Ú[™^K�ÙX\�[K +NˆBˆ[ÙBˆˆÙ]ÝÙX\ÛŠ^Y\–Ú[™^K™[� ]™[ OœÙ]ÙX\  +NˆBŸB‚š[�›×Ü^Y\—Ø[]™WÝ×Ú›Ú[Š +BžÂˆ[�›×Ø[]™WÜ^Y\œÈH ˆ[�Nˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYŠ + +\^Y\–ÚWK™[�^Y\–ÚWK›]™\ÈH  +^Y\–ÚWK›]™\ÈH H ‰ˆ^Y\–ÚWK™[� O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�H +JH ‰‚ˆ + +›ÜÚ\™H ‰ˆ^Y\–ÚWK˜Ü™Y]ÈH +H +[›ÜÚ\™H ‰ˆÜ™Y]ÈH +JJBˆ +Bˆˆ +ÊÛ›×Ø[]™WÜ^Y\œÎˆBˆBˆ›×Ø[]™WÜ^Y\œÈH +›×Ø[]™WÜ^Y\œÈ�HPVÔVQT”ÊHÈ Hˆ ‚ˆ™]\›ˆ›×Ø[]™WÜ^Y\œÎŸB‚�›ÚYÚ[Ø[Ü^Y\œ×ØžWÝ[Y[Ý™\Š +BžÂˆ[�Nˆר]XÚÈ]XÚ×Ý[Y[Ý™\ˆH[\X]XÚΈר]XÚÈ]XÚ×ÛÜÙHH[\X]XÚΈÛÛœÝ×ÙY™[œÙJˆY™[œÙWÛØš™XÝH•S‚ˆ]XÚ×Ý[Y[Ý™\‹˜]XÚ×Ý\HHU×ÕSQSÕ‘TŽÂˆ]XÚ×Ý[Y[Ý™\‹™›Ü‹žHHY˜][Û[Ù[ٛ܋žNˆ]XÚ×Ý[Y[Ý™\‹™›Ü‹žHY˜][Û[Ù[ٛ܋žˆ]XÚ×Ý[Y[Ý™\‹™›Ü‹žˆHY˜][Û[Ù[ٛ܋žŽÂ‚ˆ]XÚ×ÛÜÙK˜]XÚ×Ý\HHU×ÓÔÑNˆ‚ˆ[™Ø[YHH Nˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆ[�]Jˆ\HÙ[ŽÂˆÙ[ˆH^Y\–ÚWK™[�ˆYŠÙ[ˆ ‰ˆ]˜[Y[š[JÙ[‹S’WÓÔÑJJBˆˆ[™Ø[YHH ˆ]XÚ×Ý[Y[Ý™\‹˜]XÚ×ٛܘÙHHÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�‚ˆY™[œÙWÛØš™XÝHY™[œÙWÙš[™ØÝ\œ™[�ÛØš™XÝ +Ù[‹•S ]XÚ×Ý[Y[Ý™\‹˜]XÚ×Ý\JNˆˆÙ[‹O�ZÙY[XYÙJÙ[‹Ù[‹ ˜]XÚ×Ý[Y[Ý™\‹ Y™[œÙWÛØš™XÝ +NˆBˆ[ÙHYŠÙ[ŠBˆˆ[™Ø[YHH ‚ˆ]XÚ×ÛÜÙK˜]XÚ×ٛܘÙHHÙ[‹O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆYˆ +[˜Z\ŠÙ[ŠH ‰ˆ˜[Y[š[JÙ[‹S’WÑ�SÔÑJJBˆˆ]XÚ×ÛÜÙK™›Ü‹žHHY˜][Û[Ù[ٛ܋žNˆ]XÚ×ÛÜÙK™›Ü‹žHY˜][Û[Ù[ٛ܋žˆ]XÚ×ÛÜÙK™›Ü‹žˆHY˜][Û[Ù[ٛ܋žŽÂˆÙ[‹O›[Ù[]K™X]ØÛÛ™šY×Ù›YÜÈHPUÐÓÓ‘’Q×ÓPPÔ“×ÑPUÑ�SÓS‘ˆBˆ[ÙBˆˆÙ[‹O›[Ù[]K™X]ØÛÛ™šY×Ù›YÜÈHPUÐÓÓ‘’Q×ÓPPÔ“×ÑPUˆB‚ˆY™[œÙWÛØš™XÝHY™[œÙWÙš[™ØÝ\œ™[�ÛØš™XÝ +Ù[‹•S ]XÚ×ÛÜÙK˜]XÚ×Ý\JNˆˆÙ[‹O�ZÙY[XYÙJÙ[‹Ù[‹ ˜]XÚ×ÛÜÙK Y™[œÙWÛØš™XÝ +NˆBˆÙ[ˆH\ˆBŸB‚�›ÚY[YWÛÝ™\Š +BžÂˆYŠ]™[ O�\HOH JBˆˆ]™[ØÛÛ\]YH NÈ ËÈ™Xˆ �K Œ H H\ÙY›Üˆ›Û�\È]™[ÈÛÈHY™H\Û‰ÝZÙ[ˆ]Ø^HYˆ[YH^\™\Ë›]™[ O�\HOH HYX[œÈ›Û�\È]™[ [ÙH™YÝ[\‚ˆBˆ[ÙHYŠ[]™[ØÛÛ\]Y +BˆˆÚ[Ø[Ü^Y\œ×ØžWÝ[Y[Ý™\Š +N‚ˆYˆ +Z\×ÝÝ[Ý[Y[Ý™\ŠBˆˆYŠÛؘ[ÜØ[\WÛ\Ý �[YWÛÝ™\ˆ�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý �[YWÛÝ™\‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ[Y[Y�H]™[ OœÙ][YH +ˆÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYYÈ ËÈ™Xˆ �  Œ H H\È[™H[Ý™Y\™HÈÙ]Ý\ÝÛH[YBˆYŠY[™Ø[YJBˆˆÚÝÝ[Y[Ý™\ˆH NˆBˆBˆYˆ +Z\×ÝÝ[Ý[Y[Ý™\ˆ ‰ˆ›×Ü^Y\—Ø[]™WÝ×Ú›Ú[Š +JBˆˆ\×ÝÝ[Ý[Y[Ý™\ˆH Nˆ›Ú›Ú[ˆH NˆBˆBŸB‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKH\]H�[˜Ý[ÛœÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚�›ÚY\]WÜØÜ›Û\Š +BžÂˆ›Ø]ÈH ˆ[�KYØZ[œÝ[™H ˆ[��[\^HH È ËÍ^Y\‚ˆ›Ø]HY˜[˜Ù^ HHY˜[˜Ù^Nˆ›Ø]›HH NNNNKHHNNNNNK›HH NNNNKHHNNNNNNÈ ËÜ^Y\ˆ›Ý[™\žH›ÞˆÝ]XÈ[�ØÜ›ÛYH ˆØÜ›ÛHØÜ›ÛHH ˆ[�Ø[]™HH ‚ˆYŠÝ[YH]™[ O˜Y˜[˜Ù][YHœ™Y^™X[ +Bˆˆ™]\›ŽÈ ËÈYYœ™Y^™X[ÛȘXÚÙÜ›Ý[™ËÜØÜ›Û[™ÈÛ‰Ý\]HYˆ[š[X][ÛœÈ\™Hœ›Þ™[‚ˆB‚ˆ Ê‚ˆKËÛ]™[ O˜Y˜[˜Ù][YHHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY ÌL +NÈ ËÈÚ[™ÙYÛÈØÜ›Û[™ÈÜYYÈ\›Üˆ˜\Ý\ˆ^Y\œÂˆ[]™[ O˜Y˜[˜Ù][YHHÝ[YH BˆBJ +^Y\–ÌK™[� ‰ˆ +^Y\–ÌK™[� O›[Ù[]KœÜYY ž�H Lˆ^Y\–ÌK™[� O›[Ù[]Kœ�[œÜYY�H LŠJHˆBH +^Y\–ÌWK™[� ‰ˆ +^Y\–ÌWK™[� O›[Ù[]KœÜYY ž�H Lˆ^Y\–ÌWK™[� O›[Ù[]Kœ�[œÜYY�H LŠJHˆBH +^Y\–Ì—K™[� ‰ˆ +^Y\–Ì—K™[� O›[Ù[]KœÜYY ž�H Lˆ^Y\–Ì—K™[� O›[Ù[]Kœ�[œÜYY�H LŠJHˆBH +^Y\–Ì×K™[� ‰ˆ +^Y\–Ì×K™[� O›[Ù[]KœÜYY ž�H Lˆ^Y\–Ì×K™[� O›[Ù[]Kœ�[œÜYY�H LŠJH +NÈ ËÈÚ[™ÙYÛÈYˆ[Ý\ˆ^Y\ˆ\Ș\Ý\ˆH˜XÚÙÜ›Ý[™ÈØÜ›Û˜\Ý\Š‹Â‚ˆ]™[ O˜Y˜[˜Ù][YHHÝ[YN‚ˆYŠ]™[ØÛÛ\]Y +Bˆˆ™]\›ŽÂˆB‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +^Y\–ÚWK™[� ‰ˆJ^Y\–ÚWK™[� O™X]ÜÝ]H ˆPUÔÕUWÑPQ +JBˆˆØ[]™HH Nˆœ™XZΈBˆB‚ˆ ËÕÚ]H˜YÛÛŽˆ›È[Ü™H[™[ZY\ÈBˆYŠÝ\œ™[�ÜÜ]Ûˆ�H]™[ O›�[\Ü]ÛœÈ ‰ˆYš[™[� +TWÑS‘SVJH ‰ˆØ[]™JBˆˆYŠYš[™[� +TWÑS‘U‘S +H ‰ˆ + +Yš[™[� +TWÒUSHTWÓДÕPÓJH ‰ˆ]™[ O�\HOH JH]™[ O�\HOH +JH ËÈ™Xˆ �K Œ H HYYÛÈØœÝXÛ\ˆˆ]™[ØÛÛ\]YH NÈ ËÈØ[ˆ™H\ÙY›Üˆ›Û�\È]™[ˆBˆBˆ[ÙHYŠÛÝ[�Ù[�ÊTWÑS‘SVJHÜ›Ý\Z[ŠBˆˆÚ[JÛÝ[�Ù[�ÊTWÑS‘SVJHÜ›Ý\X^ ‰‚ˆÝ\œ™[�ÜÜ]Ûˆ]™[ O›�[\Ü]ÛœÈ ‰‚ˆ]™[ OœÜÈ�H]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K˜]ˆ +BˆˆYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›]\ÚXÙ˜YJBˆˆ]\ÚXÙ˜YVÌHH +›Ø] +[]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›]\ÚXÙ˜YNˆ]\ÚXÙ˜YVÌWHH +›Ø] +\Ø]™Y]K›]\ÚXݛۈBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›]\ÚXÖÌJBˆˆÝ›˜ÜJ]\ÚXÛ˜[YK]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›]\ÚXËPVЕQ‘‘T—ÓSŠNˆ]\ÚXÛÙ™œÙ]H]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›]\ÚXÛÙ™œÙ]ˆ]\ÚXÛÛÜH NˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K�ØZ] +Bˆˆ]™[ O�ØZ][™ÈH NˆÛ×Ý[YHH ˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K™Ü›Ý\Z[ˆ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K™Ü›Ý\X^ +BˆˆÜ›Ý\Z[ˆH]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K™Ü›Ý\Z[ŽÂˆÜ›Ý\X^H]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K™Ü›Ý\X^ˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K››Ú›Ú[ˆOH +Bˆˆ›Ú›Ú[ˆH +]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K››Ú›Ú[ˆOH JNˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛZ[žˆ ˆ  +BˆˆØÜ›ÛZ[žˆH +›Ø] +J]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛZ[žˆ ˆ  Ù™™™™™™ŠNˆØÜ›ÛX^ˆH +›Ø] +[]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛX^ŽÂˆYŠWÝ[YJBˆˆY˜[˜Ù^HHØÜ›ÛZ[žŽÈ ËÈ™\Ù]HYˆÜ]Ûˆ]™\žH™YÚ[›š[™ÂˆBˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛZ[ž ˆ  +BˆˆØÜ›ÛZ[žH +›Ø] +J]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛZ[ž ˆ  Ù™™™™™™ŠNˆØÜ›ÛX^H +›Ø] +[]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœØÜ›ÛX^ˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K˜›ØÚØYJBˆˆ ËÈ\ÜÝ[YH]™[Ü]Ûˆ[�žHÚ[›Ý›Û˜XÚËÛÈ�\ÝÚ[™ÙH]È \™BˆYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K˜›ØÚØYH +Bˆˆ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K˜›ØÚØYHH ˆBˆ›ØÚØYHH +›Ø] +[]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K˜›ØÚØYNˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—Kœ[]HOH +Bˆˆ ËÈ\ÜÝ[YH]™[Ü]Ûˆ[�žHÚ[›Ý›Û˜XÚËÛÈ�\ÝÚ[™ÙH]È \™BˆYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—Kœ[]H +Bˆˆ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—Kœ[]HH ˆBˆÚ[™ÙWÜÞ\Ý[WÜ[]J]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—Kœ[]JNˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›YÚ žJH ËÈÚ[™ÙHYÚ\™XÝ[Ûˆ›ÜˆÙžÚY݈ˆYÚ žH]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›YÚ žˆYÚ žHH]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—K›YÚ žNˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝØÛÛÜŠH ËÈÚ[™ÙHÛÛ܈›ÜˆÙžÚY݈ˆÚYÝØÛÛ܈H]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝØÛÛ܎ˆYŠÚYÝØÛÛ܈OH LJBˆˆÚYÝØÛÛ܈H ˆBˆ[ÙHYŠÚYÝØÛÛ܈OH LŠBˆˆÚYÝØÛÛ܈H LNˆBˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝØ[JH ËÈÚ[™ÙHÛÛ܈›ÜˆÙžÚY݈ˆÚYÝØ[HH]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝØ[NˆYŠÚYÝØ[HOH“S‘ÓSÑWÓSÑS +BˆˆÚYÝØ[HH“S‘ÓSÑWÓ“Ó‘NˆBˆBˆ[ÙHYŠ]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝÛÜXÚ]JH ËÈÚ[™ÙHÛÛ܈›ÜˆÙžÚY݈ˆÚYÝÛÜXÚ]HH]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—KœÚYÝÛÜXÚ]NˆYŠÚYÝÛÜXÚ]HOH LJBˆˆÚYÝÛÜXÚ]HH ˆBˆYŠÚYÝÛÜXÚ]HOH LŠBˆˆÚYÝÛÜXÚ]HH LNˆBˆBˆ[ÙBˆˆÛX\�Ü]ÛŠ ›]™[ OœÜ]ÛœÚ[�ÖØÝ\œ™[�ÜÜ]Û—JNˆBˆ +ÊØÝ\œ™[�ÜÜ]ێˆBˆB‚ˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK™[� +BˆˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žˆ›JBˆˆ›HH^Y\–ÚWK™[� OœÜÚ][Û‹žˆBˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žJBˆˆHH^Y\–ÚWK™[� OœÜÚ][Û‹žˆBˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žˆˆ›JBˆˆ›HH^Y\–ÚWK™[� OœÜÚ][Û‹žŽÂˆBˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žˆJBˆˆHH^Y\–ÚWK™[� OœÜÚ][Û‹žŽÂˆBˆ�[\^JÊΈBˆB‚ˆYŠ]™[ O�ØZ][™ÊBˆˆ ËÈØZ]›Üˆ[[™[ZY\ÈÈ™HY™X]YˆYŠYš[™[� +TWÑS‘SVJJBˆˆ]™[ O�ØZ][™ÈH ˆYŠ]™[ O››Ü™\Ù]H JBˆˆ[Y[Y�H]™[ OœÙ][YH +ˆÛؘ[ØÛÛ™šY˘ÛÝ[�\—ÜÜYYÈ ËÈ™Xˆ �  Œ H H\È[™H[Ý™Y\™HÈÙ]Ý\ÝÛH[YBˆBˆÛ×Ý[YHHÝ[YH +È È +ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYYˆBˆB‚ˆYŠ�[\^HOH +Bˆˆ™]\›ŽÂˆB‚‚‚ˆYŠ[]™[ O�ØZ][™ÈÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÒSTPÐP“WÐPÕU‘JBˆˆYŠ]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÔ’QÒ +Bˆ‚ˆYØZ[œÝ[™H +]™[ O�ÚYHšY[Û[Ù\Ëš™\ÊN‚ˆYŠ›H HHˆšY[Û[Ù\Ëš™\ÊBˆˆÈHY˜[˜Ù^ˆBˆ[ÙBˆˆÈH +H +È›JH È ˆ HšY[Û[Ù\Ëš™\È È ˆ +È]™[ O˜Ø[Y\˜^Ù™œÙ]ˆB‚ˆYŠÈØÜ›ÛZ[ž +BˆˆÈHØÜ›ÛZ[žˆBˆ[ÙHYŠÈˆØÜ›ÛX^ +BˆˆÈHØÜ›ÛX^ˆB‚ˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈ›ØÚØYJBˆˆÈH›ØÚØYNˆB‚ˆYŠÈˆY˜[˜Ù^ +BˆˆYŠÈˆY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HΈBˆ[ÙHYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈY˜[˜Ù^ +BˆˆYŠÈY˜[˜Ù^ H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HΈB‚ˆYŠY˜[˜Ù^ +BˆˆY˜[˜Ù^H ˆBˆYŠY˜[˜Ù^�H]™[ O�ÚY HšY[Û[Ù\Ëš™\ÊBˆˆY˜[˜Ù^H +›Ø] +[]™[ O�ÚY HšY[Û[Ù\Ëš™\ΈYØZ[œÝ[™H NˆB‚ˆYŠYØZ[œÝ[™ +Bˆˆ]™[ OœÜÊÊΈBˆ[ÙBˆˆ]™[ OœÜÈH +[� +XY˜[˜Ù^ˆB‚‚ˆBˆ[ÙHYŠ]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +Bˆ‚ˆYØZ[œÝ[™H +]™[ O�ÚYHšY[Û[Ù\Ëš™\ÊN‚ˆYŠ›H HHˆšY[Û[Ù\Ëš™\ÊBˆˆÈHY˜[˜Ù^ˆBˆ[ÙBˆˆÈH +H +È›JH È ˆ HšY[Û[Ù\Ëš™\È È ˆ +È]™[ O˜Ø[Y\˜^Ù™œÙ]ˆB‚ˆYŠÈØÜ›ÛZ[ž +BˆˆÈHØÜ›ÛZ[žˆBˆ[ÙHYŠÈˆØÜ›ÛX^ +BˆˆÈHØÜ›ÛX^ˆB‚ˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆ]™[ O�ÚY HšY[Û[Ù\Ëš™\È HÈ›ØÚØYJBˆˆÈH]™[ O�ÚY HšY[Û[Ù\Ëš™\È H›ØÚØYNˆB‚ˆYŠÈY˜[˜Ù^ +BˆˆYŠÈY˜[˜Ù^ H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HΈBˆ[ÙHYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈˆY˜[˜Ù^ +BˆˆYŠÈˆY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HΈB‚ˆYŠY˜[˜Ù^ˆ]™[ O�ÚY HšY[Û[Ù\Ëš™\ÊBˆˆY˜[˜Ù^H +›Ø] +[]™[ O�ÚY HšY[Û[Ù\Ëš™\ΈBˆYŠY˜[˜Ù^H +BˆˆY˜[˜Ù^H ˆYØZ[œÝ[™H NˆB‚ˆYŠYØZ[œÝ[™ +Bˆˆ]™[ OœÜÊÊΈBˆ[ÙBˆˆ]™[ OœÜÈH +[� +J +]™[ O�ÚY HšY[Û[Ù\Ëš™\ÊH HY˜[˜Ù^ +NˆBˆBˆ[ÙHYŠ]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓÕUÐT‘ +H ËȈØÜ›ÛÛ›Bˆ‚ˆYŠ›H HHˆšY[Û[Ù\Ë�”™\ÊBˆˆÈHY˜[˜Ù^NˆBˆ[ÙBˆˆÈH +›H +ÈJH È ˆ HšY[Û[Ù\Ë�”™\È È ˆ +È]™[ O˜Ø[Y\˜^›Ù™œÙ]ˆB‚ˆYŠÈØÜ›ÛZ[žŠBˆˆÈHØÜ›ÛZ[žŽÂˆBˆ[ÙHYŠÈˆØÜ›ÛX^ŠBˆˆÈHØÜ›ÛX^ŽÂˆB‚ˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈ›ØÚØYJBˆˆÈH›ØÚØYNˆB‚ˆYŠÈˆY˜[˜Ù^JBˆˆYŠÈˆY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HHΈBˆ[ÙHYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈY˜[˜Ù^JBˆˆYŠÈY˜[˜Ù^H H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HHΈB‚ˆYŠY˜[˜Ù^Hˆ[™[ÚZYÚ HšY[Û[Ù\Ë�”™\ÊBˆˆY˜[˜Ù^HH +›Ø] +\[™[ÚZYÚ HšY[Û[Ù\Ë�”™\ΈYØZ[œÝ[™H NˆBˆYŠY˜[˜Ù^H +BˆˆY˜[˜Ù^HH ˆB‚ˆYŠYØZ[œÝ[™ +Bˆˆ]™[ OœÜÊÊΈBˆ[ÙBˆˆ]™[ OœÜÈH +[� +XY˜[˜Ù^NˆBˆBˆ[ÙHYŠ]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÒS•ÐT‘ +BˆˆYŠ›H HHˆšY[Û[Ù\Ë�”™\ÊBˆˆÈHY˜[˜Ù^NˆBˆ[ÙBˆˆÈH +›H +ÈJH È ˆ HšY[Û[Ù\Ë�”™\È È ˆ +È]™[ O˜Ø[Y\˜^›Ù™œÙ]ˆB‚ˆYŠÈØÜ›ÛZ[žŠBˆˆÈHØÜ›ÛZ[žŽÂˆBˆ[ÙHYŠÈˆØÜ›ÛX^ŠBˆˆÈHØÜ›ÛX^ŽÂˆB‚ˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆ[™[ÚZYÚ HšY[Û[Ù\Ë�”™\È HÈ›ØÚØYJBˆˆÈH[™[ÚZYÚ HšY[Û[Ù\Ë�”™\È H›ØÚØYNˆB‚ˆYŠÈY˜[˜Ù^JBˆˆYŠÈY˜[˜Ù^H H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HHΈBˆ[ÙHYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÐ�PÒÊH ‰ˆÈˆY˜[˜Ù^JBˆˆYŠÈˆY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HHΈB‚ˆYŠY˜[˜Ù^Hˆ[™[ÚZYÚ HšY[Û[Ù\Ë�”™\ÊBˆˆY˜[˜Ù^HH +›Ø] +\[™[ÚZYÚ HšY[Û[Ù\Ë�”™\ΈBˆYŠY˜[˜Ù^HH +BˆˆY˜[˜Ù^HH ˆYØZ[œÝ[™H NˆB‚ˆYŠYØZ[œÝ[™ +Bˆˆ]™[ OœÜÊÊΈBˆ[ÙBˆˆ]™[ OœÜÈH +[� +J +[™[ÚZYÚ HšY[Û[Ù\Ë�”™\ÊH HY˜[˜Ù^JNˆBˆBˆ ËÝ\ÝÛ‹[]˜]܈ÝYÙBˆ[ÙHYŠ]™[ OœØÜ›Û\ˆ ˆ +ÐÔ“ÓÕTÐÔ“ÓÑÕÓŠJBˆˆ ËØY˜[˜Ù^H +ÏH �NˆYŠØÜ›ÛYOH JBˆˆØÜ›ÛYH ˆY˜[˜Ù^JÊΈBˆ[ÙBˆˆØÜ›ÛY +ÊΈBˆ]™[ OœÜÈH +[� +XY˜[˜Ù^NˆBˆKËÚYŠ[]™[ O�ØZ][™ÊB‚ˆ ËȈ]]Ë\ØÜ›ÛˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓQ• +H +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÔ’QÒ +JH ËÈYYØÜ›Û\H›ÝÈÙZ\™[™ÜÈØ[ˆ\[‹�]Û›HYˆH[Ù\ˆ\È^žH[ˆ\Ú[™È›ØÚØY\ËÛˆ‚ˆYŠØ[Y\˜]\HOH JBˆˆ›HH NNNNNˆHHNNNNNNÈ ËÜ™XØ[Ý[]Bˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK™[� +BˆˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žˆ H^Y\–ÚWK™[� OœÜÚ][Û‹žHˆ›JBˆˆ›HH^Y\–ÚWK™[� OœÜÚ][Û‹žˆ H^Y\–ÚWK™[� OœÜÚ][Û‹žNˆBˆYŠ^Y\–ÚWK™[� OœÜÚ][Û‹žˆ H^Y\–ÚWK™[� OœÜÚ][Û‹žHJBˆˆHH^Y\–ÚWK™[� OœÜÚ][Û‹žˆ H^Y\–ÚWK™[� OœÜÚ][Û‹žNˆBˆBˆBˆBˆYŠ›H HHˆšY[Û[Ù\Ë�”™\ÊBˆˆÈHY˜[˜Ù^NˆBˆ[ÙBˆˆÈH +›H +ÈJH È ˆ HšY[Û[Ù\Ë�”™\È È ˆ +È]™[ O˜Ø[Y\˜^›Ù™œÙ]ˆB‚ˆ ËÈ™]ÈØÜ›Û[Z]ˆYŠÈˆØÜ›ÛX^ŠBˆˆÈHØÜ›ÛX^ŽÂˆBˆ[ÙHYŠÈØÜ›ÛZ[žŠBˆˆÈHØÜ›ÛZ[žŽÂˆB‚ˆYŠÈOHY˜[˜Ù^JBˆˆYŠÈˆY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H +È]™[ OœØÜ›ÛÜYYˆBˆ[ÙHYŠÈY˜[˜Ù^H H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^H H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^HH +›Ø] +]ΈB‚ˆYŠY˜[˜Ù^Hˆ[™[ÚZYÚ H +]™[ Oœ›ØÚÚ[™ÈÈ Mˆˆ LŠH HšY[Û[Ù\Ë�”™\ÊBˆˆY˜[˜Ù^HH +›Ø] +J[™[ÚZYÚ H +]™[ Oœ›ØÚÚ[™ÈÈ Mˆˆ LŠH HšY[Û[Ù\Ë�”™\ÊNˆBˆYŠY˜[˜Ù^H +BˆˆY˜[˜Ù^HH ˆBˆBˆ ËÈ›ÝÈ]]ÈØÜ›Ûˆ[ÙHYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÒS•ÐT‘ +H +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÓÕUÐT‘ +JBˆˆYŠ›H HHˆšY[Û[Ù\Ëš™\ÊBˆˆÈHY˜[˜Ù^ˆBˆ[ÙBˆˆÈH +H +È›JH È ˆ HšY[Û[Ù\Ëš™\È È ˆ +È]™[ O˜Ø[Y\˜^Ù™œÙ]ˆB‚ˆ ËÈ™]ÈØÜ›Û[Z]ˆYŠÈˆØÜ›ÛX^ +BˆˆÈHØÜ›ÛX^ˆBˆ[ÙHYŠÈØÜ›ÛZ[ž +BˆˆÈHØÜ›ÛZ[žˆB‚ˆYŠÈOHY˜[˜Ù^ +BˆˆYŠÈˆY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ +È]™[ OœØÜ›ÛÜYYˆBˆ[ÙHYŠÈY˜[˜Ù^ H]™[ OœØÜ›ÛÜYY +BˆˆÈHY˜[˜Ù^ H]™[ OœØÜ›ÛÜYYˆBˆY˜[˜Ù^H +›Ø] +]ΈB‚ˆYŠY˜[˜Ù^ˆ]™[ O�ÚY HšY[Û[Ù\Ëš™\ÊBˆˆY˜[˜Ù^H +›Ø] +J]™[ O�ÚY HšY[Û[Ù\Ëš™\ÊNˆBˆYŠY˜[˜Ù^ +BˆˆY˜[˜Ù^H ˆBˆBˆ ËÙ[™Ùˆˆ]]Ë\ØÜ›Ûˆ ËÈÛؘ[˜[YH›Üˆ\WÜ[™[ˆØÜ›ÛHY˜[˜Ù^ HˆØÜ›ÛHHY˜[˜Ù^H HNŸB‚‚�›ÚY\]WÜØÜ›ÛYØ™Ê +BžÂˆ›Ø]›ØÚݘ]™[ˆ[œÚYÛ™YÚ\ˆ™[ÛœÌÌ—NËËÌÊŽˆÝ]XÈ[�›ØÚÜÜÈH ˆÝ]XÈ[�›ØÚÛÙ™œÜÚ[™VÌÌ—HBˆˆ ‹ ‹ Ë  K ‹ Ë Ëˆ  KKKK  ˆ Ë Ë ‹ K  Ë ‹ ‹ˆ K K     K BˆNÈ ËțܛX[›ØÚˆÝ]XÈ[�›ØÚÛÙ™œÜÚZÙVÌÌ—HBˆˆ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ˆ ‹ ‹   ‹   ‹ˆ ‹ ‹ ‹ ‹ ‹ ‹ ‹ ‹ˆ ‹ ‹   ‹   ‹ˆNÈ ËÈÛÝËÛÛœÝ[�˜\œš[™È›ØÚËZÙHÛˆH˜Z[‚ˆÝ]XÈ[�›ØÚÛÙ™œÜ�[X›VÌÌ—HBˆˆ ‹ ‹ Ë Ë ‹ ‹ Ë Ëˆ ‹ ‹ Ë Ë ‹ Ë ‹ ˈ ‹ ‹ Ë Ë ‹ ‹ Ë Ëˆ ‹ ‹ Ë Ë ‹ Ë ‹ ˈNÈ ËȘ\Ý ÛÛœÝ[��[X›[™ËZÙH[‹ÛÛˆH˜[ˆ܈˜Z[\‚ˆ[�ˆH^[ž]\ÖÊ[� +TVSÌÌ—N‚ˆ ËÈ[YHÈ\]H™[Ûˆ[™ØÜ™Y[ˆ[›YȘ[ÙOˆYŠÝ[YH�H™[Û—Ý[YH ‰ˆYœ™Y^™X[ +BˆˆY[XÜJ™[Ûœ ™[Û�X›H +È LŽ +ˆ‹ +ˆŠNˆY[XÜJ™[Û�X›H +È LŽ +ˆ‹™[Ûœ +È ˆ +ˆ‹ ˆ +ˆŠNˆY[XÜJ™[Û�X›H +È + LŽ +È ŠJœ‹™[Ûœ  ˆ +ˆŠN‚ˆ™[Û—Ý[YHHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È ÊNˆB‚ˆYŠYœ™Y^™X[ +Bˆˆ›ØÚݘ]™[H +]™[ Oœ›ØÚÚ[™ÊHÈ + +Ý[YH H˜]™[[YJH È + +›Ø] +YÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY È Ì +JHˆ È ËÈ›ÈZÙH[ˆ™X[Y™KX^X™BˆYŠ]™[ O˜™ÜÜYY +Bˆˆ›ØÚݘ]™[H \›ØÚݘ]™[ˆBˆ™Ý˜]™[Y +ÏH +Ý[YH H˜]™[[YJH +ˆ]™[ O˜™ÜÜYY È Ì +ˆ  +È›ØÚݘ]™[ˆ˜™Ý˜]™[Y +ÏH +Ý[YH H˜]™[[YJH +ˆ]™[ O�˜™ÜÜYY È Ì +ˆ ˆBˆ[ÙBˆˆ^[YH +ÏHÝ[YH H˜]™[[YNˆB‚ˆ[Y]˜\ˆHÝ[YH H^[YN‚ˆYŠ]™[ Oœ›ØÚÚ[™ÊBˆˆ›ØÚÜÜÈH +[Y]˜\ˆ È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È +JH ˆ ÌNˆYŠ]™[ Oœ›ØÚÚ[™ÈOH JBˆˆÙžÞWÛÙ™œÙ]H]™[ Oœ]XZÙH H  H›ØÚÛÙ™œÜÚ[™VÜ›ØÚÜÜ×NˆBˆ[ÙHYŠ]™[ Oœ›ØÚÚ[™ÈOH ŠBˆˆÙžÞWÛÙ™œÙ]H]™[ Oœ]XZÙH H  H›ØÚÛÙ™œÜÚZÙVÜ›ØÚÜÜ×NˆBˆ[ÙHYŠ]™[ Oœ›ØÚÚ[™ÈOH ÊBˆˆÙžÞWÛÙ™œÙ]H]™[ Oœ]XZÙH H  H›ØÚÛÙ™œÜ�[X›VÜ›ØÚÜÜ×NˆBˆBˆ[ÙBˆˆYŠ]™[ Oœ]XZÙH�H +BˆˆÙžÞWÛÙ™œÙ]H]™[ Oœ]XZÙH H ˆBˆ[ÙBˆˆÙžÞWÛÙ™œÙ]H]™[ Oœ]XZÙH +È ˆBˆB‚ˆ ËÚYŠ]™[ OœØÜ›Û\ˆOTÐÔ“ÓÕT ‰ˆ]™[ OœØÜ›Û\ˆOTÐÔ“ÓÑÕÓŠHÙžÞWÛÙ™œÙ] OHY˜[˜Ù^NˆÙžÞWÛÙ™œÙ] +ÏHÙžÞWÛÙ™œÙ]ØYŽÈ ËÌŒ LWÌ Ì ËΈ\H[Ù\ˆY�\ÝY[� ‚‚ˆ˜]™[[YHHÝ[YN‚ˆYŠÝ[YH�H]™[ Oœ]XZÙ][YJBˆˆ]™[ Oœ]XZÙH ÏH ŽÂˆ]™[ Oœ]XZÙ][YHHÝ[YH +È +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È �JNˆBŸB‚�›ÚY˜]×ÜØÜ›ÛYØ™Ê +BžÂˆ[�[™^H  ‹HH ‹ Nˆ×Û^Y\ˆ +›^Y\ŽÂˆ[�ÚY ZYÚ‚ˆ[�œ œKœËœ‚ˆYŠšY]ÜÜ�Ȉ +BˆˆœHšY]ÜÜ�ˆœHHšY]ÜÜ�NˆœÈHšY]ÜÜ�ΈœHšY]ÜÜ�ˆBˆ[ÙBˆˆœHœHH ˆœÈHšY[Û[Ù\Ëš™\ΈœHšY[Û[Ù\Ë�”™\ΈB‚ˆ ËÚYŠ]™[ +Hš[�ЉY Y Y Yˆ‹œ œKœËœ +N‚ˆ×Ù˜]ÛY]ÙØÜ™Y[›Y]ÙHZ[›Y]Ù‚ˆ Êœ×Ù˜]ÛY]Ù +œØÜ™Y[›Y]ÙH œØÜ™Y[›Y]Ùˆ›ÜŠHH ÈH]™[ O›�[ZÛ\ÎÈJÊÊBˆˆÜš]\WØYÜÜš]J +[� +J]™[ OšÛ\ÖÚWKž HØÜ™Y[ž +ÈÙžÞÛÙ™œÙ] +K +[� +J]™[ OšÛ\ÖÚWKžˆ H]™[ OšÛ\ÖÚWK™\ HØÜ™Y[žH +ÈÙžÞWÛÙ™œÙ] +KÓWÖ‹Û\Üš]KØÜ™Y[›Y]Ù  +NˆJ‹Â‚ˆ›ÜŠ[™^H È[™^]™[ O›�[[^Y\œÜ™YŽÈ[™^ +ÊÊBˆˆ^Y\ˆH]™[ O›^Y\œÜ™Yˆ +È[™^‚ˆØÜ™Y[›Y]ÙH^Y\‹O™˜]ÛY]Ù‚ˆ ËÜš[�Š›^Y\ˆ Y [™N‰]KމYˆ‹[™^ ^Y\‹O™Ùž š[™K^Y\‹OœÜÚ][Û‹žŠN‚‚BKËÈ^Y\ˆ]\Ý™H[˜X›Y[™]™H]X\ÝÛ™H[œÝXÙK܈ÙHۉݘ]È] ‚ˆYŠ\ØÜ™Y[›Y]Ù ž™\X]\ØÜ™Y[›Y]Ù ž\™\X][^Y\‹O™[˜X›Y +BˆˆÛÛ�[�YNˆB‚ˆÚYHØÜ™Y[›Y]Ù žÜ[ˆH^Y\‹OœÚ^™Kž +È^Y\‹OœÜXÚ[™ËžˆZYÚHØÜ™Y[›Y]Ù ž\Ü[ˆH^Y\‹OœÚ^™KžH +È^Y\‹OœÜXÚ[™ËžŽÂ‚ˆH +[� +J^Y\‹O›Ù™œÙ] ž H +Y˜[˜Ù^ +șݘ]™[Y +ˆ^Y\‹O˜™ÜÜYY˜][ÊH +ˆ + KŒ H^Y\‹Oœ˜][Ëž +H +H‚ˆ ËÜš[�Š›^Y\ž˜][È Yˆ Y Y—ˆ‹^Y\‹Ož˜][Ë ^Y\‹O˜™ÜÜYY˜][ÊN‚ˆYŠ +]™[ OœØÜ›Û\ˆ ˆÐÔ“ÓÕT +JBˆˆ ËÞˆH +[� +J^Y\‹O›Ù™œÙ] žˆ +ÈY˜[˜Ù^H +ˆ + KŒ H^Y\‹Oœ˜][ËžŠH +HˆˆH +[� +J^Y\‹O›Ù™œÙ] žˆ H +Y˜[˜Ù^H +Ș™Ý˜]™[Y +ˆ^Y\‹O˜™ÜÜYY˜][ÊH +ˆ + KŒ H^Y\‹Oœ˜][ËžŠH +HˆBˆ[ÙBˆˆ ËÞˆH +[� +J^Y\‹O›Ù™œÙ] žˆ HY˜[˜Ù^H +ˆ + KŒ H^Y\‹Oœ˜][ËžŠH +HˆˆH +[� +J^Y\‹O›Ù™œÙ] žˆ H +Y˜[˜Ù^H +Ș™Ý˜]™[Y +ˆ^Y\‹O˜™ÜÜYY˜][ÊH +ˆ + KŒ H^Y\‹Oœ˜][ËžŠH +HˆB‚ˆYŠ^Y\‹Oœ]XZÙJBˆˆ +ÏHÙžÞÛÙ™œÙ]ˆˆ +ÏHÙžÞWÛÙ™œÙ]ˆ ËÜš[�ЉYH Y Yˆ‹[™^ ÙžÞWÛÙ™œÙ] ŠNˆB‚ˆ OHœˆˆ OHœN‚‚ˆYŠ +BˆˆHH + ^ +H ÈÚYˆ OHÚYˆBˆ[ÙBˆˆHH ˆB‚ˆYŠHˆ  ‰ˆØÜ™Y[›Y]Ù �Ø]\‹�Ø]\›[ÙHOHÐUT—ÓSÑWÔÒPTˆ ‰ˆØÜ™Y[›Y]Ù �Ø]\‹˜[\]YJBˆˆKKNˆ OHÚYˆB‚ˆYŠˆ +BˆˆˆH + ^ŠH ÈZYÚˆˆ OHZYÚˆBˆ[ÙBˆˆˆH ˆBˆ‚BZYŠ^Y\‹O›™[ÛŠBˆˆØÜ™Y[›Y]Ù �X›HH™[Û�X›NˆBˆ[ÙBˆˆYŠÝ\œ™[�Ü[]Hˆ +BˆˆØÜ™Y[›Y]Ù �X›HH]™[ Oœ[]\ÖØÝ\œ™[�Ü[]H H WNˆBˆ[ÙBˆˆØÜ™Y[›Y]Ù �X›HH•SˆBˆB‚ˆØÜ™Y[›Y]Ù �Ø]\‹�Ø]™][YHH +[� +J[Y]˜\ˆ +ˆØÜ™Y[›Y]Ù �Ø]\‹�Ø]™\ÜYY +NˆØÜ™Y[›Y]Ù ž™\X]HØÜ™Y[›Y]Ù ž\™\X]H ˆ›ÜŠHHŽÈˆ^Y\‹O™˜]ÛY]Ù ž\™\X] ‰ˆHœÈH +ÏHZYÚ ŠÊËØÜ™Y[›Y]Ù ž\™\X] +ÊÊNˆ›ÜŠHÈH^Y\‹O™˜]ÛY]Ù ž™\X] ‰ˆœÈ +È +ØÜ™Y[›Y]Ù �Ø]\‹�Ø]\›[ÙHOHÐUT—ÓSÑWÔÒPTˆÈ ˆØÜ™Y[›Y]Ù �Ø]\‹˜[\]YH +ˆ ŠNÈ +ÏHÚY JÊËØÜ™Y[›Y]Ù ž™\X] +ÊÊN‚ˆYŠ^Y\‹O™Ùž œØÜ™Y[‹O›XYÚXÈOHØÜ™Y[—ÛXYÚXÊBˆˆÜš]\WØYÜØÜ™Y[Š +Èœ ˆ +ÈœK^Y\‹Ož‹^Y\‹O™Ùž œØÜ™Y[‹ œØÜ™Y[›Y]Ù [™^ +NˆBˆ[ÙHYŠ^Y\‹O™Ùž œÜš]KO›XYÚXÈOHÜš]WÛXYÚXÊBˆˆÜš]\WØYÙœ˜[YJ +Èœ ˆ +ÈœK^Y\‹Ož‹^Y\‹O™Ùž œÜš]K œØÜ™Y[›Y]Ù [™^ +NˆB‚ˆ ËÜš[�ŠŠŠŠŠŠŠ‰Y Y Y Y Y +ŠŠŠŠ—ˆ‹ +Ýœ ŠÝœK^Y\‹O‹ž‹ØÜ™Y[›Y]Ù ž™\X] ØÜ™Y[›Y]Ù ž\™\X] +NˆB‚‚ŸB‚�L̈Ù][�\�˜[ + +BžÂˆ[�\�˜[H[Y\—ÙÙ][�\�˜[ +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY +NÈ ËÈÛÈ[�\�˜[Ø[ˆ™HÙÙÙY[�È[ÝšYBˆYŠ[�\�˜[ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +Bˆˆ[�\�˜[H NˆBˆYŠ[�\�˜[ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY È +Bˆˆ[�\�˜[HÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY È ˆBˆ™]\›ˆ[�\�˜[ŸB‚‹ËÈØ\ÚÙ^K[[Ûˆ‹‚‹ËÈ Œ NKL LŒ‚‹ËÈ‹ËÈ�[ˆ[œ]ØÜš\ˈÚ[Z[\ˆÈÙ^\Ë�]‹ËÈ^XÝ]H™Y›Ü™H›ØÙ\ÜÚ[™È[žHÛÛ[X[™�[˜Ý[ۜ˂�›ÚY^XÝ]WÚ[œ]ÜØÜš\Ê[�^Y\—Ú[™^ +BžÂ‚\×Ü^Y\ˆ +œ^Y\—ÛØšˆH•S‚BB‚\^Y\—ÛØšˆH^Y\ˆ +È^Y\—Ú[™^‚‚ZYˆ +\^Y\—ÛØšŠB‚^‚B\™]\›ŽÂ‚_B‚B‚ZYˆ +^Y\—ÛØš‹O›™]ÚÙ^\È +Ù^\ØÜš\˜]H ‰ˆ^Y\‹OšÙ^\ÊH^Y\‹Oœ™[X\ÙZÙ^\ÊB‚^‚BKËÈ Œ NKL LŒˆÛ‰Ý^\ÝY]‚BKËÚYˆ +]™[ +B‚BKËÞ‚‚BBKËÙ^XÝ]WÛ]™[ÚÙ^WÜØÜš\ +^Y\—Ú[™^ ^Y\ŠN‚BBKËÙ^XÝ]WÙ[�]WÚÙ^WÜØÜš\ +^Y\‹™[� +N‚BKËßB‚BKËÙ^XÝ]WÚÙ^WÜØÜš\ +^Y\—Ú[™^ ^Y\ŠN‚‚BY^XÝ]WÚ[œ]ÜØÜš\Ø[ +^Y\—Ú[™^ +N‚_BŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMŠ‚ŠˆY\™XÝ[Û‹\™[]]™HÛÛ[X[™›YÜÈÈH\ÚXØ[Šˆ[œ]X\ÚË‚Š‚ŠˆY�[™šYÚ™[XZ[ˆ[ˆH™\Ý[ÛÈ\™ XÛÙYŠˆÛÛ[X[™ÈØ[ˆÛÛ�[�YHÈ[œÜXÝH\ÚXØ[[œ] ‚Š‹ÂœÝ]XÈÙ^WÛX\Ú×ÝÛÛ[X[™Ú[œ]Ü™\ÛÛ™WÙ\™XÝ[ÛŠˆÛÛœÝÙ^WÛX\Ú×Ý[œ]Ù›YÜˈÛÛœÝ[�]JˆXÝ[™×Ù[�]BŠHˆÙ^WÛX\Ú×Ý™\ÛÛ™YÙ›YÜÈH[œ]Ù›YÜ΂ˆYŠXXÝ[™×Ù[�]JHˆ™]\›ˆ™\ÛÛ™YÙ›YÜΈB‚ˆYŠ[œ]Ù›YÜÈ ˆ“Q×ÓSÕ‘SQ• +Hˆ™\ÛÛ™YÙ›YÜÈHXÝ[™×Ù[�]KO™\™XÝ[Û‚ˆÈ“Q×Ð�PÒÕÐT‘ˆˆ“Q×ѓԕÐT‘‚ˆH[ÙHYŠ[œ]Ù›YÜÈ ˆ“Q×ÓSÕ‘T’QÒ +Hˆ™\ÛÛ™YÙ›YÜÈHXÝ[™×Ù[�]KO™\™XÝ[Û‚ˆÈ“Q×ѓԕÐT‘ˆˆ“Q×Ð�PÒÕÐT‘ˆB‚ˆ™]\›ˆ™\ÛÛ™YÙ›YÜΟB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËLMÈ HÜ™Ú[˜[žH][›™[Ë[šÛ›ÝÈ]K‚Š‚Šˆ\]HH[œ]Ý]H›ÜˆXXÚ^Y\‹ˆ\È[˜ÛY\Šˆ\ÚXØ[Ù^\ËÛÛ[X[™[œ]\ÝÜžK[™]]ÛX]XŠˆ[YÙ\ˈ™Y˜XÝÜ™YÈÝ\Ü�\™XÝ[Û‹\™[]]™HŠˆÛÛ[X[™›YÜÈ[™^[œÚX›HÛÛ[X[™Þ\Ý[K‚Š‹Â�›ÚY[œ]™Yœ™\Ú +[�^\™XÛ[ÙJH‚ˆ[�ˆ×Ü^Y\ˆ +˜XÝ[™×Ü^Y\ŽÂ‚ˆÛÛ�›ÛÝ\]J^Y\˜ÛÛ�›ÛÚ[�\œËPVÔVQT”ÊN‚ˆ›ÝÙ^\ÈH ˆ›Ý™]ÚÙ^\ÈH ‚ˆ›ÜŠH ÈPVÔVQT”ÎÈ +ÊÊBˆˆXÝ[™×Ü^Y\ˆH^Y\ˆ +È‚ˆYˆ +^\™XÛ[ÙHOHWÔ‘P×ÔVJH‚ˆXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\ÈH +^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜÈXÝ[™×Ü^Y\‹OšÙ^\ÊH H^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜΈXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\È �H˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹OšÙ^\ÈH^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜÈ ˆ˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹O›™]ÚÙ^\ÈH^Y\˜ÛÛ�›ÛÚ[�\œÖÜKO›™]ÚÙ^Y›YÜÈ ˆ˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\ÈHXÝ[™×Ü^Y\‹O›™]ÚÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HXÝ[™×Ü^Y\‹OšÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈˆH[ÙHˆ ËÈ[ˆ^H[ÙNˆY™\ÜÙYÙ^\ÈÈ™XÈÙ^\ˆXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\ÈH +^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜÈXÝ[™×Ü^Y\‹Oœ™]šÙ^\ÊH H^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜΈXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\È �H˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹OšÙ^\ÈH^Y\˜ÛÛ�›ÛÚ[�\œÖÜKOšÙ^Y›YÜÈ ˆ˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹O›™]ÚÙ^\ÈH^Y\˜ÛÛ�›ÛÚ[�\œÖÜKO›™]ÚÙ^Y›YÜÈ ˆ˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\ÈHXÝ[™×Ü^Y\‹O›™]ÚÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �HXÝ[™×Ü^Y\‹OšÙ^\ΈXÝ[™×Ü^Y\‹Oœ^ZÙ^\È �H˜XÝ[™×Ü^Y\‹O™\ØX›ZÙ^\ΈB‚BBBB‚BY^XÝ]WÚ[œ]ÜØÜš\Ê +NÂBB‚ˆ Ê‚ˆ +ˆ™\Ù]ÛÛ[X[™Ù\]Y[˜ÙHYˆH\ÝÛÛ[X[™Ø\ˆ +ˆÛÈÛ™ÈYÛË‚ˆ +‹ÂˆYŠXÝ[™×Ü^Y\‹O™[� ‰ˆXÝ[™×Ü^Y\‹O™[� O˜ÛÛ[X[™Ý[YHÝ[YJHˆY[\Ù] +ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžKˆ ˆÚ^™[ÙŠXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú\ÝÜžJBˆ +N‚ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]ØÛÝ[�H ˆXÝ[™×Ü^Y\‹O˜ÛÛ[X[™Ú[œ]Ú[™^H ˆB‚ˆ Ê‚ˆ +ˆ�Z[Û™H]™[�]™\žH™Yœ™\ÚÛÈ]]ÛX]XÈ[ˆ +ˆ™\ÚÛÈØ[ˆÜ™X]H[ˆYÙHÚ]Ý]H\ÚXØ[ˆ +ˆ�]ÛˆÚ[™ÙKˆÝÜ™H]Û›HÚ[ˆ]X\ÝÛ™Bˆ +ˆ™\ÜË™[X\ÙK܈]]ÛX]XÈ[YÙH^\ÝË‚ˆ +‹ÂˆˆרÛÛ[X[™Ú[œ]Ù]™[�[œ]Ù]™[�HÌN‚ˆ[œ]Ù]™[� œ™\ÜÈHÛÛ[X[™Ú[œ]Ü™\ÛÛ™WÙ\™XÝ[ÛŠˆXÝ[™×Ü^Y\‹O›™]ÚÙ^\ˈXÝ[™×Ü^Y\‹O™[�ˆ +N‚ˆ[œ]Ù]™[� œ™[X\ÙHHÛÛ[X[™Ú[œ]Ü™\ÛÛ™WÙ\™XÝ[ÛŠˆXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\ˈXÝ[™×Ü^Y\‹O™[�ˆ +N‚ˆ Ê‚ˆ +ˆ™[X\ÙYÙ^\ÈÙ\™H[[[YYX][H™Y›Ü™H\ˆ +ˆYÙKˆ[˜ÛYH[H[ˆH]™[�Û˜\ÚÝÛÈBˆ +ˆÛÛ[X[™ÝXÚ\ÈVÍLH +ȘHØ[ˆ\ݛݘXÝË‚ˆ +‹Âˆ[œ]Ù]™[� š[HÛÛ[X[™Ú[œ]Ü™\ÛÛ™WÙ\™XÝ[ÛŠˆXÝ[™×Ü^Y\‹OšÙ^\ˆXÝ[™×Ü^Y\‹Oœ™[X\ÙZÙ^\ˈXÝ[™×Ü^Y\‹O™[�ˆ +N‚ˆ[œ]Ù]™[� �[YHHÝ[YN‚ˆÛÛ[X[™Ú[œ]ÚÛÜÝ\�Ý\]JˆXÝ[™×Ü^Y\‹ˆ[œ]Ù]™[� œ™\Üˈ[œ]Ù]™[� �[YBˆ +N‚ˆYŠ[œ]Ù]™[� œ™\ÜÊHˆ Ê‚ˆ +ˆØ\\™H[œ]ÈÝ[[]\ÈÜÚ]]™Bˆ +ˆYÙKˆHÛÛ™šYÝ\˜X›HÛÛ[X[™X]Ú\‚ˆ +ˆ\Y\ÈXXÚÝ\ ÜÈÚÜ™Ý[YHÈZ\‚ˆ +ˆ™XÛÜ™Y™\ÜÈ[Y\ˈ\™ XÛÙYÛÛ[X[™ˆ +ˆÛÛ�[�YHÈ[œÜXÝ[œ]Ù]™[� œ™\ÜÈÛ›K‚ˆ +‹Âˆ[œ]Ù]™[� œ™\ÜרÚÜ™BˆÛÛ[X[™Ú[œ]Ü™\ÛÛ™WÙ\™XÝ[ÛŠˆXÝ[™×Ü^Y\‹OšÙ^\ˈXÝ[™×Ü^Y\‹O™[�ˆ +NˆB‚ˆ[œ]Ù]™[� šÛBˆÛÛ[X[™Ú[œ]ÚÛÝšYÙÙ\—ØÛÛXÝ +ˆXÝ[™×Ü^Y\‹ˆ[œ]Ù]™[� š[ ˆ[œ]Ù]™[� �[YBˆ +N‚ˆYŠ[œ]Ù]™[� œ™\܈[œ]Ù]™[� šÛˆ[œ]Ù]™[� œ™[X\ÙJH‚ˆ[œ]Ù]™[� �XÚÜÈH[Y\—ÙÙ]XÚÊ +NˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÜ\Ú +XÝ[™×Ü^Y\‹ š[œ]Ù]™[� +N‚ˆYŠXÝ[™×Ü^Y\‹O™[� +HˆXÝ[™×Ü^Y\‹O™[� O˜ÛÛ[X[™Ý[YHBˆÛÛ[X[™Ú[œ]Ú\ÝÜžWÙ^\˜][Û—Ý[YWÙÙ] +ˆXÝ[™×Ü^Y\‹O™[� ˆ[œ]Ù]™[� �[YBˆ +NˆBˆB‚ˆB‚ˆ›ÝÙ^\ÈHXÝ[™×Ü^Y\‹OšÙ^\Έ›Ý™]ÚÙ^\ÈHXÝ[™×Ü^Y\‹O›™]ÚÙ^\ΈˆB‚ŸB‚�›ÚY^XÝ]WÚÙ^\ØÜš\Ê +BžÂˆ[�ˆ›ÜŠH È]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈ +ÊÊBˆˆYŠWÜ]\ÙH ‰ˆ +]™[ÚXÚ×Ú[—ÜØÜ™Y[Š +JH ‰ˆ +^Y\–ÜK›™]ÚÙ^\È +Ù^\ØÜš\˜]H ‰ˆ^Y\–ÜKšÙ^\ÊH^Y\–ÜKœ™[X\ÙZÙ^\ÊJBˆˆYŠ]™[ +Bˆˆ^XÝ]WÛ]™[ÚÙ^WÜØÜš\ + +Nˆ^XÝ]WÙ[�]WÚÙ^WÜØÜš\ +^Y\–ÜK™[� +NˆBˆ^XÝ]WÚÙ^WÜØÜš\ + +Nˆ^XÝ]WÚÙ^WÜØÜš\Ø[ + +NˆBˆBŸB‚�›ÚY^XÝ]WÝ\]\ØÜš\Ê +BžÂˆYŠØÜš\Ò\Ò[š]X[^™Y + �\]WÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J Š\]WÜØÜš\ +JNˆBˆYŠ]™[ ‰ˆØÜš\Ò\Ò[š]X[^™Y + Š]™[ O�\]WÜØÜš\ +JJBˆˆØÜš\Ñ^XÝ]J Š]™[ O�\]WÜØÜš\ +JNˆBŸB‚�›ÚY^XÝ]WÝ\]YØÜš\Ê +BžÂˆYŠØÜš\Ò\Ò[š]X[^™Y + �\]YÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J Š\]YÜØÜš\ +JNˆBˆYŠ]™[ ‰ˆØÜš\Ò\Ò[š]X[^™Y + Š]™[ O�\]YÜØÜš\ +JJBˆˆØÜš\Ñ^XÝ]J Š]™[ O�\]YÜØÜš\ +JNˆBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L LŒBŠ‚Šˆ^XÝ]HÛؘ[[™]™[ØÜš\È[[YYX][H™Y›Ü™H[‚Šˆ[™Ú[™HÙÚXØ[ÛØÚÈXÚÈ\È›ØÙ\ÜÙY ‚Š‹Â�›ÚY^XÝ]WÝ\][ÙÚXÜØÜš\Ê +BžÂˆYŠØÜš\Ò\Ò[š]X[^™Y + �\]WÛÙÚX×ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J �\]WÛÙÚX×ÜØÜš\ +NˆBˆYŠ]™[ ‰ˆØÜš\Ò\Ò[š]X[^™Y + ›]™[ O�\]WÛÙÚX×ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J ›]™[ O�\]WÛÙÚX×ÜØÜš\ +NˆBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L LŒBŠ‚Šˆ^XÝ]HÛؘ[[™]™[ØÜš\ÈY�\ˆ[ˆ[™Ú[™HÙÚXØ[ŠˆÛØÚÈXÚÈ\È›ØÙ\ÜÙY ™Y›Ü™H]ÈÛØÚȘ[YHY˜[˜Ù\Ë‚Š‹Â�›ÚY^XÝ]WÝ\]YÙÚXÜØÜš\Ê +BžÂˆYŠØÜš\Ò\Ò[š]X[^™Y + �\]YÛÙÚX×ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J �\]YÛÙÚX×ÜØÜš\ +NˆBˆYŠ]™[ ‰ˆØÜš\Ò\Ò[š]X[^™Y + ›]™[ O�\]YÛÙÚX×ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J ›]™[ O�\]YÛÙÚX×ÜØÜš\ +NˆBŸB‚�›ÚY˜]×Ý^ØšœÊ +BžÂˆ[�Nˆ×Ý^Øšˆ +�^ØšŽÂˆYŠ[]™[ +Bˆˆ™]\›ŽÂˆBˆ›ÜŠHH ÈH]™[ O›�[]^ØšœÈÈJÊÊBˆˆ^ØšˆH]™[ O�^ØšœÈ +ÈN‚ˆYŠ^Øš‹O�[YH ‰ˆ^Øš‹O�[YHHÝ[YJBBKËÒYˆH[YHØ\ÈÙ][™\ÜÙY ™[[Ý™HH^Øš™XÝ ‚ˆˆ]™[ O�^ØšœÖÚWK�[YBOH ˆ]™[ O�^ØšœÖÚWKœÜÚ][Û‹žH ˆ]™[ O�^ØšœÖÚWKœÜÚ][Û‹žHH ˆ]™[ O�^ØšœÖÚWK™›Û�H ˆ]™[ O�^ØšœÖÚWKœÜÚ][Û‹žˆH ˆYŠ]™[ O�^ØšœÖÚWK�^ +Bˆˆœ™YJ]™[ O�^ØšœÖÚWK�^ +Nˆ]™[ O�^ØšœÖÚWK�^H•SˆBˆBˆ[ÙBˆˆYŠ^Øš‹O�^ +Bˆˆ›Û�Üš[�Û[™Ý +ˆ^Øš‹OœÜÚ][Û‹ž ˆ^Øš‹OœÜÚ][Û‹žKˆ^Øš‹O™›Û� ˆ^Øš‹OœÜÚ][Û‹ž‹ˆ^Øš‹O�^ ˆÝ›[Š^Øš‹O�^ +Bˆ +NˆBˆBˆBŸB‚š[�™XÛÜ™[œ]Ê +BžÂˆ[�H ˆ™XÒÙ^\È™XÚÙ^NˆZ[� �ÝÚ[™ÝÈH MŽÂˆL̈X^Ü™X×Ý[YHHÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +�Œ +ŒLÈ ËÈ›ÝXÝ[Û‚‚ˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×Ô‘PÊH™]\›ˆ ˆYˆ +\^\™XÜÝ]\ËO˜™YÚ[ˆ +Bˆˆ^\™XÜÝ]\ËOœÝ\�[YHHÝ[YNˆ^\™XÜÝ]\ËOœÞ[˜Ý[YHH ˆYˆ +^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆœ™YJ^\™XÜÝ]\ËO˜�Y™™\ŠNˆ^\™XÜÝ]\ËO˜�Y™™\ˆH•SˆBˆ^\™XÜÝ]\ËO˜�Y™™\ˆH +™XÒÙ^\ÊŠXØ[ØÊÚ[™ÝÊÜ^\™XÜÝ]\ËOœÞ[˜Ý[YJœÚ^™[ÙŠ™XÒÙ^\ÊKÚ^™[ÙŠ™XÒÙ^\ÊJNˆYˆ +^\™XÜÝ]\ËO˜�Y™™\ˆOH•S +Bˆˆš[�Š‘\œ›ÜˆÈ[ØØ]H�Y™™\ˆ[ˆ™XÛÜ™[œ]È[ÙK—ˆŠNˆ™]\›ˆ ˆBˆ^\™XÜÝ]\ËO˜™YÚ[ˆH Nˆ^\™XÜÝ]\ËOœÙYYHÙ]ÙYY + +Nˆ^\™XÜÝ]\ËO˜ÜÙYYHÝ[YNˆܘ[™ +Ý[YJNˆ^\™XÜÝ]\ËO�XÚÜÈH[Y\—ÙÙ]XÚÊ +NˆBˆ[ÙBˆˆYˆ +^\™XÜÝ]\ËOœÞ[˜Ý[YI]Ú[™ÝÈ�HÚ[™ÝËLˆ +H ËÈ\Ý\È•Sž]\ˆˆ^\™XÜÝ]\ËO˜�Y™™\ˆH +™XÒÙ^\ÊŠ\™X[ØÊ^\™XÜÝ]\ËO˜�Y™™\‹Ú^™[ÙŠ™XÒÙ^\ÊJŠ +^\™XÜÝ]\ËOœÞ[˜Ý[YKÝÚ[™ÝÊÌJJ�Ú[™ÝÊÝÚ[™ÝÊJNˆYˆ +^\™XÜÝ]\ËO˜�Y™™\ˆOH•S +Bˆˆš[�Š‘\œ›ÜˆÈ[ØØ]H�Y™™\ˆ[ˆ™XÛÜ™[œ]È[ÙK—ˆŠNˆ™]\›ˆ ˆH[ÙHY[\Ù] +^\™XÜÝ]\ËO˜�Y™™\ŠÊ^\™XÜÝ]\ËOœÞ[˜Ý[YJÌJK +^\™XÜÝ]\ËOœÞ[˜Ý[YKÝÚ[™ÝÊÌJJ�Ú[™ÝÊÝÚ[™ÝËJ^\™XÜÝ]\ËOœÞ[˜Ý[YJÌJKLJNÈ ËÈ Lˆ™XØ]\ÙH LH\ÈÈ ÈÚ^™KLBˆBˆB‚ˆ ËÈ›ÝÈ™XÈBˆYŠ^\™XÜÝ]\ËO˜�Y™™\ˆ ‰ˆ^\™XÜÝ]\ËO˜™YÚ[ŠBˆˆ›Üˆ +H ÈPVÔVQT”ÎÈ +ÊÈ +Bˆˆ™XÚÙ^KšÙ^\ÖÜHH^Y\–ÜKšÙ^\Έ™XÚÙ^K›™]ÚÙ^\ÖÜHH^Y\–ÜK›™]ÚÙ^\Έ™XÚÙ^Kœ™[X\ÙZÙ^\ÖÜHH^Y\–ÜKœ™[X\ÙZÙ^\Έ™XÚÙ^Kœ^ZÙ^\ÖÜHH^Y\–ÜKœ^ZÙ^\ΈBˆ™XÚÙ^K�[YHHÝ[YNˆ™XÚÙ^Kš[�\�˜[H[�\�˜[ˆ™XÚÙ^KœÞ[˜Ý[YHH^\™XÜÝ]\ËOœÞ[˜Ý[YNˆ ËÜ™XÚÙ^KœÙYYHÙ]ÙYY + +NˆY[XÜJ œ^\™XÜÝ]\ËO˜�Y™™\–Ü^\™XÜÝ]\ËOœÞ[˜Ý[YWK œ™XÚÙ^KÚ^™[ÙŠ™XÚÙ^JH +NˆB‚ˆYˆ +Ý[YH�HX^Ü™X×Ý[YH +HÝÜ™XÛÜ™[œ]Ê +NÈ ËÈØY™BˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×Ô‘PÊH +ÊÜ^\™XÜÝ]\ËOœÞ[˜Ý[YN‚ˆ ËÙX�Y×Üš[�Š�[YNˆ YÞ[˜Îˆ Y‹ +LÌŠ][YK +LÌŠ\^\™XÜÝ]\ËOœÞ[˜Ý[YJNˆ ËÙX�Y×Üš[�ŠšÙ^\Έ Y‹^Y\–ÌKœ™[X\ÙZÙ^\É‘“Q×ÐUPÒÊN‚ˆ™]\›ˆ NŸB‚š[�^T™XÛÜ™Y[œ]Ê +BžÂˆ[�H ˆ™XÒÙ^\È™XÚÙ^NˆÚ\ˆ]ÓPVÐT‘×ÓSˆ +È WNˆÚ^™WÝš[\Ú^™HH ˆÚ\ˆXY\–Í—N‚ˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×ÔVJH™]\›ˆ ˆYˆ +\^\™XÜÝ]\ËO˜™YÚ[ˆ +H ËÝ[YH�H^\™XÜÝ]\ËOœÝ\�[YH ‰‚ˆˆYˆ +Ý›[Š^\™XÜÝ]\ËOœ] +HH  +HÙ]˜\ÙT] +] ”Ø]™\È‹ +Nˆ[ÙHݘÜJ] ^\™XÜÝ]\ËOœ] +NˆYˆ +]ÜÝ›[Š] +KLWHOH ËÉÈ +HݘÜJ] ‹ÈŠN‚ˆYˆ +^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆœ™YJ^\™XÜÝ]\ËO˜�Y™™\ŠNˆ^\™XÜÝ]\ËO˜�Y™™\ˆH•SˆBˆYŠ^\™XÜÝ]\ËOš[™JBˆˆ˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆB‚ˆ^\™XÜÝ]\ËOš[™HH›Ü[ŠÝ˜Ø] +] ^\™XÜÝ]\ËO™š[[˜[YJKœ˜ŠÈŠNˆYŠ^\™XÜÝ]\ËOš[™JBˆˆœÙYZÊ^\™XÜÝ]\ËOš[™K  ÑQR×ÑS‘ +Nˆš[\Ú^™HH�[ +^\™XÜÝ]\ËOš[™JNˆœÙYZÊ^\™XÜÝ]\ËOš[™K  ÑQR×ÔÑU +NÈ ËÈ܈™]Ú[™ +^\™XÜÝ]\ËOš[™JB‚ˆYˆ +š[\Ú^™HH +Bˆˆš[�Š‘[\H™XÛÜ™Y[œ]Èš[K—ˆŠNˆ™]\›ˆ ˆBˆ^\™XÜÝ]\ËO˜�Y™™\ˆH +™XÒÙ^\ÊŠXØ[ØÊ Kš[\Ú^™JÌJNˆYŠ\^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆš[�Š‘\œ›ÜˆÈ[ØØ]H�Y™™\ˆ›Üˆ™XÛÜ™Y[œ]Ë—ˆŠNˆ™]\›ˆ ˆBˆH[ÙBˆˆš[�Š‘\œ›ÜˆÈÜ[ˆ™XÛÜ™Y[œ]Èš[K—ˆŠNˆ™]\›ˆ ˆBˆœ™XY + šXY\‹ ‹ K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËOœÝ\�[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËO™[™[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËO�ÝÞ[˜Ý[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËO˜ÜÙYY Ú^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËOœÙYY Ú^™[ÙŠZ[� �Ý +K K^\™XÜÝ]\ËOš[™JNˆœ™XY + œ^\™XÜÝ]\ËO�XÚÜËÚ^™[ÙŠ[œÚYÛ™Y +K K^\™XÜÝ]\ËOš[™JNˆœ™XY +^\™XÜÝ]\ËO˜�Y™™\‹Ú^™[ÙŠ™XÒÙ^\ÊJŠ^\™XÜÝ]\ËO™[™[YJÌJK K^\™XÜÝ]\ËOš[™JN‚ˆ ËÈÞ[˜È]Ý\�[YBˆÝ[YHH^\™XÜÝ]\ËOœÝ\�[YNˆ^\™XÜÝ]\ËOœÞ[˜Ý[YHH ˆ^\™XÜÝ]\ËO˜™YÚ[ˆH Nˆܘ[™ +^\™XÜÝ]\ËO˜ÜÙYY +Nˆܘ[™ ÌŠ^\™XÜÝ]\ËOœÙYY +Nˆ ËÜÙ]ÝXÚÜÊ[Y\—ÙÙ]XÚÊ +K\^\™XÜÝ]\ËO�XÚÜÊNˆB‚ˆ ËÈ›ÝÈ^HBˆYŠ^\™XÜÝ]\ËO˜�Y™™\ˆ ‰ˆ^\™XÜÝ]\ËO˜™YÚ[ˆ ‰ˆ^\™XÜÝ]\ËOœÞ[˜Ý[YH^\™XÜÝ]\ËO�ÝÞ[˜Ý[YJBˆˆY[XÜJ œ™XÚÙ^K œ^\™XÜÝ]\ËO˜�Y™™\–Ü^\™XÜÝ]\ËOœÞ[˜Ý[YWKÚ^™[ÙŠ™XÚÙ^JH +N‚ˆYŠÝ[YHOH™XÚÙ^K�[YH +BˆˆL̈™^Þ[˜Ý[YHH™XÚÙ^KœÞ[˜Ý[YN‚ˆ ËÝ[YHH +LÌŠ\™XÚÙ^K�[YNˆš[�Š”^H™XÛÜ™Y[œ]ΈÝ]ÙˆÞ[˜ÈH[YNˆ Y ™XÕ[YNˆ Yˆ‹[YK™XÚÙ^K�[YJNˆ ÊšYˆ +[�\�˜[OH™XÚÙ^Kš[�\�˜[ +Bˆˆ ËÚ[�\�˜[H +LÌŠ\™XÚÙ^Kš[�\�˜[ˆš[�Š”^H™XÛÜ™Y[œ]ΈÝ]ÙˆÞ[˜ÈH[�\�˜[ˆ Y ™XÒ[�\�˜[ˆ Yˆ‹[�\�˜[ ™XÚÙ^Kš[�\�˜[ +NˆJ‹Â‚ˆÚ[JÝ[YHˆ™XÚÙ^K�[YH ‰ˆ™^Þ[˜Ý[YHˆ  +HˆY[XÜJ œ™XÚÙ^K œ^\™XÜÝ]\ËO˜�Y™™\–ËK[™^Þ[˜Ý[YWKÚ^™[ÙŠ™XÚÙ^JH +NˆBˆÝ[YHH™XÚÙ^K�[YN‚ˆÚ[JÝ[YH™XÚÙ^K�[YH ‰ˆ™^Þ[˜Ý[YH^\™XÜÝ]\ËO�ÝÞ[˜Ý[YH +HˆY[XÜJ œ™XÚÙ^K œ^\™XÜÝ]\ËO˜�Y™™\–ÊÊÛ™^Þ[˜Ý[YWKÚ^™[ÙŠ™XÚÙ^JH +NˆBˆÝ[YHH™XÚÙ^K�[YNˆB‚ˆYˆ +Ý[YHOH™XÚÙ^K�[YH +BˆˆYˆ +^\™XÜÝ]\ËOœÞ[˜Ý[YHOH™XÚÙ^KœÞ[˜Ý[YH +BˆˆL̈™^Þ[˜Ý[YHH™XÚÙ^KœÞ[˜Ý[YN‚ˆš[�Š”^H™XÛÜ™Y[œ]ΈÝ]ÙˆÞ[˜ÈHÞ[˜Õ[YNˆ Y ™XÔÞ[˜Õ[YNˆ Yˆ‹^\™XÜÝ]\ËOœÞ[˜Ý[YK™XÚÙ^KœÞ[˜Ý[YJN‚ˆÚ[J^\™XÜÝ]\ËOœÞ[˜Ý[YHˆ™XÚÙ^KœÞ[˜Ý[YH ‰ˆ™^Þ[˜Ý[YHˆ  +HˆY[XÜJ œ™XÚÙ^K œ^\™XÜÝ]\ËO˜�Y™™\–ËK[™^Þ[˜Ý[YWKÚ^™[ÙŠ™XÚÙ^JH +NˆBˆ^\™XÜÝ]\ËOœÞ[˜Ý[YHH™XÚÙ^KœÞ[˜Ý[YN‚ˆÚ[J^\™XÜÝ]\ËOœÞ[˜Ý[YH™XÚÙ^KœÞ[˜Ý[YH ‰ˆ™^Þ[˜Ý[YH^\™XÜÝ]\ËO�ÝÞ[˜Ý[YH +HˆY[XÜJ œ™XÚÙ^K œ^\™XÜÝ]\ËO˜�Y™™\–ÊÊÛ™^Þ[˜Ý[YWKÚ^™[ÙŠ™XÚÙ^JH +NˆBˆ^\™XÜÝ]\ËOœÞ[˜Ý[YHH™XÚÙ^KœÞ[˜Ý[YNˆB‚ˆYˆ +[�\�˜[OH™XÚÙ^Kš[�\�˜[ +H[�\�˜[H™XÚÙ^Kš[�\�˜[ˆ ËÜܘ[™ ÌŠ™XÚÙ^KœÙYY +Nˆ›Üˆ +H ÈPVÔVQT”ÎÈ +ÊÈ +Bˆˆ^Y\–ÜKšÙ^\ÈH™XÚÙ^KšÙ^\ÖÜNˆ^Y\–ÜK›™]ÚÙ^\ÈH™XÚÙ^K›™]ÚÙ^\ÖÜNˆ^Y\–ÜKœ™[X\ÙZÙ^\ÈH™XÚÙ^Kœ™[X\ÙZÙ^\ÖÜNˆ^Y\–ÜKœ^ZÙ^\ÈH™XÚÙ^Kœ^ZÙ^\ÖÜNˆBˆ ËÚ[œ]™Yœ™\Ú +^\™XÜÝ]\ËOœÝ]\ÊNˆBˆB‚ˆ ËÙX�Y×Üš[�ŠœÞ[˜Ý[Nˆ YÝÞ[˜Îˆ YÝ]\ΉY‹^\™XÜÝ]\ËOœÞ[˜Ý[YK^\™XÜÝ]\ËO�ÝÞ[˜Ý[YK^\™XÜÝ]\ËOœÝ]\ÊNˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×ÔVJH +ÊÜ^\™XÜÝ]\ËOœÞ[˜Ý[YNˆYˆ +^\™XÜÝ]\ËOœÞ[˜Ý[YH�H^\™XÜÝ]\ËO�ÝÞ[˜Ý[YHÝ[YH�H^\™XÜÝ]\ËO™[™[YH +HÝÜ™XÛÜ™[œ]Ê +N‚ˆ ËÙX�Y×Üš[�Š�[YNˆ YÞ[˜Îˆ Y‹ +LÌŠ][YK +LÌŠ\^\™XÜÝ]\ËOœÞ[˜Ý[YJNˆ ËÙX�Y×Üš[�ŠšÙ^\Έ Y‹^Y\–ÌKœ™[X\ÙZÙ^\É‘“Q×ÐUPÒÊN‚ˆ™]\›ˆ NŸB‚š[�ÝÜ™XÛÜ™[œ]Ê +BžÂˆYŠ^\™XÜÝ]\ÊBˆˆÝÚ]Ú +^\™XÜÝ]\ËOœÝ]\ÊBˆˆØ\ÙHWÔ‘P×Ô‘P΂ˆˆÚ\ˆ]ÓPVÐT‘×ÓSˆ +È WNˆÚ\ˆXY\–Í—HH’S” LŽÂ‚ˆYˆ +Ý›[Š^\™XÜÝ]\ËOœ] +HH  +HÙ]˜\ÙT] +] ”Ø]™\È‹ +Nˆ[ÙHݘÜJ] ^\™XÜÝ]\ËOœ] +NˆYˆ +]ÜÝ›[Š] +KLWHOH ËÉÈ +HݘÜJ] ‹ÈŠN‚ˆYˆ +^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆ^\™XÜÝ]\ËOš[™HH›Ü[ŠÝ˜Ø] +] ^\™XÜÝ]\ËO™š[[˜[YJK�ØŠÈŠNˆYŠ^\™XÜÝ]\ËOš[™JBˆˆ^\™XÜÝ]\ËO™[™[YHHÝ[YNˆYˆ +^\™XÜÝ]\ËOœÞ[˜Ý[YH ŠH^\™XÜÝ]\ËOœÞ[˜Ý[YHH ŽÂˆ[ÙH^\™XÜÝ]\ËOœÞ[˜Ý[YH OH ŽÂ‚ˆ�Üš]JXY\‹ ‹ K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËOœÝ\�[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËO™[™[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËOœÞ[˜Ý[YKÚ^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËO˜ÜÙYY Ú^™[ÙŠLÌŠK K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËOœÙYY Ú^™[ÙŠZ[� �Ý +K K^\™XÜÝ]\ËOš[™JNˆ�Üš]J œ^\™XÜÝ]\ËO�XÚÜËÚ^™[ÙŠ[œÚYÛ™Y +K K^\™XÜÝ]\ËOš[™JNˆ�Üš]J^\™XÜÝ]\ËO˜�Y™™\‹Ú^™[ÙŠ™XÒÙ^\ÊJŠ^\™XÜÝ]\ËOœÞ[˜Ý[YJÌJK K^\™XÜÝ]\ËOš[™JNˆ™›\Ú +^\™XÜÝ]\ËOš[™JNÈ ËÈØY™Bˆ˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆH[ÙH™]\›ˆ ‚ˆœ™YJ^\™XÜÝ]\ËO˜�Y™™\ŠNˆ^\™XÜÝ]\ËO˜�Y™™\ˆH•SˆH[ÙH™]\›ˆ ˆœ™XZΈBˆØ\ÙHWÔ‘P×ÔVN‚ˆˆYŠ^\™XÜÝ]\ËOš[™JBˆˆYˆ +^\™XÜÝ]\ËOš[™JH˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆ[ÙH™]\›ˆ ˆBˆœ™XZΈBˆØ\ÙHWÔ‘P×ÔÕÔ‚ˆˆYŠ^\™XÜÝ]\ËOš[™JBˆˆYˆ +^\™XÜÝ]\ËOš[™JH˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆ[ÙH™]\›ˆ ˆBˆœ™XZΈBˆB‚ˆ^\™XÜÝ]\ËOœÝ]\ÈHWÔ‘P×ÔÕÔˆ^\™XÜÝ]\ËO˜™YÚ[ˆH ˆ^\™XÜÝ]\ËOœÞ[˜Ý[YHH ˆœ™YT™XÛÜ™Y[œ]Ê +NˆH™]\›ˆ ‚ˆ™]\›ˆ NŸB‚š[�œ™YT™XÛÜ™Y[œ]Ê +BžÂˆ^\™XÜÝ]\ËOœÝ]\ÈHWÔ‘P×ÔÕÔˆYŠ^\™XÜÝ]\ËOš[™JH˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆYŠ^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆœ™YJ^\™XÜÝ]\ËO˜�Y™™\ŠNˆ^\™XÜÝ]\ËO˜�Y™™\ˆH•Sˆ™]\›ˆ NˆB‚ˆ™]\›ˆ ŸB‚˜WÜ^\™XÜÝ]\ʈ[š]Ú[œ]Ü™XÛÜ™\Š +BžÂˆ^\™XÜÝ]\ÈH +WÜ^\™XÜÝ]\ÊŠXØ[ØÊ KÚ^™[ÙŠ +œ^\™XÜÝ]\ÊJN‚ˆ™]\›ˆ^\™XÜÝ]\ΟB‚�›ÚYœ™YWÚ[œ]Ü™XÛÜ™\Š +BžÂˆYŠ^\™XÜÝ]\ÊBˆˆYŠ^\™XÜÝ]\ËO˜�Y™™\ŠBˆˆYŠ^\™XÜÝ]\ËOš[™JH˜ÛÜÙJ^\™XÜÝ]\ËOš[™JNˆœ™YJ^\™XÜÝ]\ËO˜�Y™™\ŠNˆ^\™XÜÝ]\ËO˜�Y™™\ˆH•SˆBˆœ™YJ^\™XÜÝ]\ÊNˆ^\™XÜÝ]\ÈH•SˆBŸB‚�›ÚY\]J[�[™Ø[YK[�\Ù]�ØZ] +BžÂˆ[�HH ˆ[�ÚÙ^\ÈH ‚ˆÚYˆÑˆYˆ +Ø]™Y]K™œÛ[Z]OH JH ËÈœÞ[˜È[˜X›Yˆˆ ËÈÈ™YXÙH[œ]][˜ÞKØZ][�[H\Ý \È + \ÊHÙˆHÝ\œ™[�ˆ ËÈœ˜[YHÈ™XY[œ]È܈È[ž][™È[ÙKˆÙHØ[ˆÙ]]Ø^HÚ]\È™XØ]\ÙBˆ ËÈHÔ\ÈÙˆ[[Ù\›ˆÛÛ\]\œÈ H]™[ˆÛ™\È[™ÝËY[™ Ý]]YÜÈ Bˆ ËÈ\™HÛÛ\]HÝ™\šÚ[›ÜˆÜ[�“Ô‰ÜÈ™YYË‚ˆÍ�\™Ù]Ý[YHH[Y\—Ý]XÚÜÊ +H +È L ÝšY[רÝ\œ™[�Ü™Yœ™\Úܘ]J +H H ˆM�Ý\œ™[�Ý[YHH[Y\—Ý]XÚÜÊ +NˆÚ[H +Ý\œ™[�Ý[YH\™Ù]Ý[YJBˆˆ\ÛY\ +\™Ù]Ý[YH HÝ\œ™[�Ý[YJNˆÝ\œ™[�Ý[YHH[Y\—Ý]XÚÜÊ +NˆBˆBˆÙ[™Y‚‚ˆÙ][�\�˜[ + +NˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×ÔVH ‰ˆWÜ]\ÙH ‰ˆ]™[ +HYˆ +\^T™XÛÜ™Y[œ]Ê +H +HÝÜ™XÛÜ™[œ]Ê +Nˆ[œ]™Yœ™\Ú +^\™XÜÝ]\ËOœÝ]\ÊNˆÚY™YˆÑP“Bˆ[ÝšYWÜ^X˜XÚ×Ý\]Jˆ +›Ý™]ÚÙ^\È ˆ +“Q×ÑTÐÈ“Q×ÐS–P•UÓŠJHOH ˆ +NˆÙ[™Y‚ˆYŠ^\™XÜÝ]\ËOœÝ]\ÈOHWÔ‘P×Ô‘PÈ ‰ˆWÜ]\ÙH ‰ˆ]™[ +HYˆ +\™XÛÜ™[œ]Ê +H +HÝÜ™XÛÜ™[œ]Ê +N‚ˆYˆ + +WÜ]\ÙH ‰ˆ[™Ø[YHOH JH[Ø^\Ý\]JBˆˆ^XÝ]WÝ\]\ØÜš\Ê +NˆB‚ˆ™]Ý[YHH ˆYŠWÜ]\ÙJBˆˆYŠ[™Ø[YHOH HÚXÚ×Ú[—ÜØÜ™Y[Š +JBˆˆ^XÝ]WÚÙ^\ØÜš\Ê +NˆB‚ˆYŠ +]™[ØÛÛ\]Y ‰ˆ]™[ O˜›ÜÜ×ÜÛÝÈOH“ÔÔ×ÔÓÕ×ÓÓˆ ‰ˆ]ÜÜYY\ +HÛÝÛ[Ý[Û‹�ÙÙÛHˆÓÕ×ÓSÕSÓ—ÓÑ‘ŠBˆˆYŠÛÝÛ[Ý[Û‹™\˜][ÛˆOHÛÝÛ[Ý[Û‹˜ÛÝ[�\ŠBˆˆ™]Ý[YHHÝ[YH +È[�\�˜[ˆBˆBˆ[ÙBˆˆ™]Ý[YHHÝ[YH +È[�\�˜[ˆB‚ˆÛÝÛ[Ý[Û‹˜ÛÝ[�\ŠÊΈYŠÛÝÛ[Ý[Û‹˜ÛÝ[�\ˆOH +ÛÝÛ[Ý[Û‹™\˜][Ûˆ +È JJBˆˆÛÝÛ[Ý[Û‹˜ÛÝ[�\ˆH ˆYŠÛÝÛ[Ý[Û‹�ÙÙÛHˆÓÕ×ÓSÕSÓ—ÓÓŠBˆˆÛÝÛ[Ý[Û‹™\˜][ÛˆHÛÝÛ[Ý[Û‹�ÙÙÛNˆBˆBˆYŠ™]Ý[YHˆÝ[YH +È L +Bˆˆ™]Ý[YHHÝ[YH +È L ˆB‚ˆÚ[JÝ[YH™]Ý[YJBˆˆYŠ[™Ø[YHOH H[Ø^\Ý\]JBˆˆ^XÝ]WÝ\][ÙÚXÜØÜš\Ê +NˆB‚ˆYŠ[™Ø[YHOH JBˆˆ\]WÜØÜ›Û\Š +NˆYŠYœ™Y^™X[ +Bˆˆ[�[ÜØ[]™HH ‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +\^Y\–ÚWK™[� +H +ÊØ[ÜØ[]™NˆBˆ[ÜØ[]™HH +[ÜØ[]™H�HPVÔVQT”ÊHÈ Hˆ ‚ˆYŠ]™[ OœÙ][YHˆ  +]™[ O�\HOH ˆ ‰ˆ[ÜØ[]™JJBˆ ËÚYŠ]™[ OœÙ][YHˆ  +]™[ O�\HOH ˆ ‰ˆ\^Y\–ÌK™[� ‰ˆ\^Y\–ÌWK™[� ‰ˆ\^Y\–Ì—K™[� ‰ˆ\^Y\–Ì×K™[� +JBˆˆ[�[ÜÛ›Ú›Ú[ˆH [ÜÛ›ØÜ™Y]ÈH ‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +\^Y\–ÚWKš›Ú[š[™ÊH +ÊØ[ÜÛ›Ú›Ú[ŽÂˆBˆ[ÜÛ›Ú›Ú[ˆH +[ÜÛ›Ú›Ú[ˆ�HPVÔVQT”ÊHÈ Hˆ ‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +^Y\–ÚWK˜Ü™Y]È JH +ÊØ[ÜÛ›ØÜ™Y]ΈBˆ[ÜÛ›ØÜ™Y]ÈH +[ÜÛ›ØÜ™Y]È�HPVÔVQT”ÊHÈ Hˆ ‚ˆYŠ[Y[Y�ˆ +Bˆˆ K][Y[Y�ˆBˆ[ÙHYŠ +]™[ OœÙ][YHˆ  ‰ˆ[ÜÛ›Ú›Ú[ŠHˆ + + +[›ÜÚ\™H ‰ˆÜ™Y]È JH +›ÜÚ\™H ‰ˆ[ÜÛ›ØÜ™Y]ÊJBˆ ‰ˆ[ÜÛ›Ú›Ú[ˆ +Bˆ +Bˆˆ[YWÛÝ™\Š +NˆBˆBˆBˆ\]WÜØÜ›ÛYØ™Ê +NˆYŠ]™[ O�\HOH ŠBˆˆ\]\Ý]\Ê +NˆBˆBˆYŠ[™Ø[YHOH HÚXÚ×Ú[—ÜØÜ™Y[Š +JBˆˆ\]WÙ[�Ê +NˆB‚ˆYŠ[™Ø[YHOH H[Ø^\Ý\]JBˆˆ^XÝ]WÝ\]YÙÚXÜØÜš\Ê +NˆB‚ˆ +Ê×Ý[YNˆB‚ˆB‚ˆ ÊŠŠŠŠŠŠŠŠŠŠŠˆÙž]Y]YZ[™È +ŠŠŠŠŠŠŠŠŠŠŠ‹Â‚ˆÛX\œØÜ™Y[ŠœØÜ™Y[ŠN‚ˆYŠ[™Ø[YHOH H ‰ˆWÜ]\ÙJBˆˆ˜]×ÜØÜ›ÛYØ™Ê +NˆYŠ]™[ O�\HOH ŠBˆˆ™Y˜]ÜÝ]\Ê +NˆBˆYŠ]™[ O�\HOH ŠBˆˆ˜]ÜÝ]\Ê +NˆBˆ˜]×Ý^ØšœÊ +NˆB‚ˆYŠZ[™Ø[YJBˆˆYŠ˜XÚÙÜ›Ý[™ +BˆˆÜš]\WØYÜØÜ™Y[Š  RS—ÒS• ˜XÚÙÜ›Ý[™ •S  +NˆBˆB‚ˆ ËÈ[�]HÜš]\È]Y]YZ[™ÂˆYŠ[™Ø[YHOH HÚXÚ×Ú[—ÜØÜ™Y[Š +JBˆYŠWÜ]\ÙJBˆˆ\Ü^WÙ[�Ê +NˆB‚ˆ ÊŠŠŠŠŠŠŠŠŠŠŠˆ\]YØÜš\ +ŠŠŠŠŠŠŠŠŠŠŠ‹ÂˆYŠ[™Ø[YHOH H[Ø^\Ý\]JBˆˆ^XÝ]WÝ\]YØÜš\Ê +NˆB‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +^Y\–ÚWK™[� ‰ˆ +^Y\–ÚWK›™]ÚÙ^\È ˆ“Q×ÔÕT• +JBˆˆÚÙ^\ÈH Nˆœ™XZΈBˆB‚ˆ ËÈ Œ LKÌL ÌŒˆUˆ[Ý™H]\ÙHY[�HÙÚXÈ\™Bˆ ÊšYŠ[™Ø[YHOH H ‰ˆWÜ]\ÙH ‰ˆ[›Ü]\ÙH ‰‚ˆ + +^Y\–ÌK™[� ‰ˆ +^Y\–ÌK›™]ÚÙ^\È ˆ“Q×ÔÕT• +JHˆ +^Y\–ÌWK™[� ‰ˆ +^Y\–ÌWK›™]ÚÙ^\È ˆ“Q×ÔÕT• +JHˆ +^Y\–Ì—K™[� ‰ˆ +^Y\–Ì—K›™]ÚÙ^\È ˆ“Q×ÔÕT• +JHˆ +^Y\–Ì×K™[� ‰ˆ +^Y\–Ì×K›™]ÚÙ^\È ˆ“Q×ÔÕT• +JJBˆ +J‹ÂˆYŠ[™Ø[YHOH H ‰ˆWÜ]\ÙH ‰ˆ[›Ü]\ÙH ‰ˆÚÙ^\ÊBˆˆYˆ +JÛÝ×ÛXZ[›Y[�WÙ›YÉŒJH +BˆˆÛÝ[™Ü]\ÙWÛ]\ÚXÊ JNˆÛÝ[™Ü]\ÙWÜØ[\J JNˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý œ]\ÙK Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +Nˆ]\Ù[Y[�J +Nˆ™]\›ŽÂˆBˆBˆYŠ[™Ø[YHOH H ‰ˆ +ÛÝ×ÛXZ[›Y[�WÙ›YÉŒJH +Bˆˆ˜XÚÝ×ÛXZ[›Y[�J +Nˆ™]\›ŽÂˆB‚ˆ ÊŠŠŠŠŠŠŠŠŠˆ\]HØÜ™Y[ˆ +ŠŠŠŠŠŠŠŠŠŠŠŠŠ‹Â‚ˆÜš]\WÙ˜]ÊœØÜ™Y[‹ RS—ÒS• PVÒS•   +NÈ ËÈ›ÝXÙK[Ø^\Ș]ÈÜš]\È]H™\žH[™ÙˆÝ\ˆY]Ù‚ˆYŠÜ]\ÙHOH ˆ ‰ˆ[›ÜØÜ™Y[œÚÝ ‰ˆ +›Ý™]ÚÙ^\È ˆ“Q×ÔÐÔ‘QS”ÒÕ +JBˆˆØÜ™Y[œÚÝ +œØÜ™Y[‹Ù][  JNˆB‚ˆ ËÈX�YÈÝY™‹ÚÝ[›Ý\X\ˆÛˆØÜ™Y[œÚ݈YŠX�Y×Ý[YHOH ‘‘‘‘‘‘‘ŠBˆˆX�Y×Ý[YHHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ NˆBˆYŠÝ[YHX�Y×Ý[YH ‰ˆX�Y×Û\ÙÖÌJBˆˆYŠX�Y×ÞWÛ\ÙËž�H  ‰ˆX�Y×ÞWÛ\ÙËžH�H  +BˆˆYˆ +X�Y×ÞWÛ\ÙË™›Û�Ú[™^  +HX�Y×ÞWÛ\ÙË™›Û�Ú[™^H ˆØÜ™Y[—Üš[�ŠœØÜ™Y[‹X�Y×ÞWÛ\ÙËž X�Y×ÞWÛ\ÙËžKX�Y×ÞWÛ\ÙË™›Û�Ú[™^ X�Y×Û\ÙÊNˆH[ÙHØÜ™Y[—Üš[�ŠœØÜ™Y[‹ šY[Û[Ù\Ë�”™\ËY›Û�ZYÚ + +K X�Y×Û\ÙÊNˆBˆ[ÙBˆˆX�Y×Û\ÙÖÌHH ˆX�Y×ÞWÛ\ÙËžH LNˆX�Y×ÞWÛ\ÙËžHH LNˆÚY™YˆP•Q×ÓSÑBˆYŠ]™[ OœÜÊBˆˆX�Y×Üš[�Š”ÜÚ][ÛŽˆ ZKÚYˆ ZKÜ]ÛŽˆ ZKÙ™œÙ]Έ ZKÉZH‹]™[ OœÜË]™[ O�ÚY Ý\œ™[�ÜÜ]Û‹]™[ Oœ]XZÙKÙžÞWÛÙ™œÙ] +NˆBˆÙ[™Y‚ˆB‚ˆYŠ\Ù]�ØZ] +Bˆˆ™ØWÝ�ØZ] + +NˆBˆšY[רÛÜWÜØÜ™Y[ŠœØÜ™Y[ŠNˆÜš]\WØÛX\Š +N‚ˆÚXÚ×Û]\ÚXÊ +NˆÛÝ[™Ý\]WÛ]\ÚXÊ +NŸB‚‚‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‹ÊˆÛX›ÈKÍ ÌŒ Lˆ™]È�[˜Ý[Ûˆ]Ø[ˆ\ÙHœšYÚ™\ÜËÙØ[[XHÛÜœ™XÝ[Û‚ˆ +ˆ[™\[™[�œ›ÛHHÛؘ[[]HÛˆ]›Ü›\ÈÚ\™H] ÜÈ]˜Z[X›K‚ˆ +ˆ\™Ø\™HXØÙ[\˜]YœšYÚ™\ÜËÙØ[[XHÛÜœ™XÝ[Ûˆ\È]˜Z[X›HÛˆÜ[‘Óˆ +ˆ]›Ü›\È\Ú[™ÈÓÓ ˆ™]\›œÈ HÛˆÝXØÙ\ÜË Ûˆ\œ›Ü‹‚ˆ +‹Âš[�Ù]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠ[�ÛK[�œŠBžÂˆšY[×ÜÙ]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠÛKœŠNˆ™]\›ˆ NŸB‚‹ËÈÚ[\H[]H˜YH ÈœØÜ™Y[ˆ˜YB�›ÚY˜YWÛÝ] +[�\K[�ÜYY +BžÂˆ[�KˆH ˆ[�‹ÈH ˆL̈[�\�˜[H ˆ[�Ý\œ™[�HÜYYÈÜYYˆ˜YNˆ×ÜØÜ™Y[ˆ +™˜�Y™™\ˆH•Sˆ×Ù˜]ÛY]ÙHHZ[›Y]ÙˆK˜[HH“S‘ÓSÑWÐU‘T�QÑN‚ˆ›ÜŠHH ˆH Ȉ �È +BˆˆÚ[JˆHH ‰ˆˆ � +BˆˆYŠ]\H\HOH JBˆˆˆH + +Ø]™Y]K˜œšYÚ™\ÜÈ +È �MŠH +ˆ + � HŠH È � +H H �MŽÂˆÈH �Mˆ H + +Ø]™Y]K™Ø[[XH +È �MŠH +ˆ + � HŠH È � +Nˆ™ØWÝ�ØZ] + +NˆYŠ\Ù]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠËŠJBˆˆYŠY˜�Y™™\ŠBˆˆ˜�Y™™\ˆH[ØÜØÜ™Y[ŠœØÜ™Y[‹O�ÚY œØÜ™Y[‹OšZYÚ œØÜ™Y[‹Oœ^[›Ü›X] +NˆÛÜ\ØÜ™Y[Š˜�Y™™\‹œØÜ™Y[ŠNˆBˆ ËÌ�MH +È[H“S‘ÓSÑWÐU‘T�QÑH\ÈXÝX[H[ˆ›[™ ÛÈ\ÙH �M[œÝXYˆK˜Ú[›™[ˆHK˜Ú[›™[ÈHK˜Ú[›™[ˆH �M +ˆ + � HŠH È �ˆÛX\œØÜ™Y[ŠœØÜ™Y[ŠNˆ]ØÜ™Y[ŠœØÜ™Y[‹˜�Y™™\‹   ™JNˆBˆBˆŠÊΈYŠ]\H\HOH JBˆˆšY[רÛÜWÜØÜ™Y[ŠœØÜ™Y[ŠNˆBˆBˆYŠ]\H\HOH ŠBˆˆÛÝ[™Ý\]WÛ]\ÚXÊ +NˆYŠ[]\ÚXÛÝ™\›\ +BˆˆÛÝ[™Ý›Û[YWÛ]\ÚXÊØ]™Y]K›]\ÚXÝ›Û +ˆ + � HŠH È � Ø]™Y]K›]\ÚXÝ›Û +ˆ + � HŠH È � +NˆBˆBˆ[�\�˜[H[Y\—ÙÙ][�\�˜[ +Ý\œ™[� +NˆYŠ[�\�˜[ˆÝ\œ™[� +Bˆˆ[�\�˜[HÝ\œ™[� È ŒˆBˆYŠ[�\�˜[ˆÝ\œ™[� È +Bˆˆ[�\�˜[HÝ\œ™[� È ˆBˆH +ÏH[�\�˜[ˆB‚ˆYŠ]\H\HOH ŠBˆˆYŠ[]\ÚXÛÝ™\›\ +BˆˆÛÝ[™ØÛÜÙWÛ]\ÚXÊ +NˆBˆB‚ˆYŠ]\H\HOH JBˆˆÛX\œØÜ™Y[ŠœØÜ™Y[ŠNˆšY[רÛÜWÜØÜ™Y[ŠœØÜ™Y[ŠNˆ™ØWÝ�ØZ] + +Nˆ ËÝH›XÚÈØÜ™Y[‹ÛÈÙH™]\›ˆÈ›Ü›X[[]BˆÙ]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠØ]™Y]K™Ø[[XKØ]™Y]K˜œšYÚ™\ÜÊNˆB‚ˆYŠ˜�Y™™\ŠBˆˆœ™Y\ØÜ™Y[Š ™˜�Y™™\ŠNˆBŸB‚‚‚�›ÚY\WØÛÛ�›ÛÊ +BžÂˆ[�‚ˆ›ÜŠH ÈPVÔVQT”ÎÈ +ÊÊBˆˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÑTÐËÓÓ•“ÓÑTÐÊNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÓSÕ‘UT Ø]™Y]KšÙ^\ÖÜVÔÑQÓSÕ‘UTJNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÓSÕ‘QÕÓ‹Ø]™Y]KšÙ^\ÖÜVÔÑQÓSÕ‘QÕÓ—JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÓSÕ‘SQ• Ø]™Y]KšÙ^\ÖÜVÔÑQÓSÕ‘SQ•JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÓSÕ‘T’QÒ Ø]™Y]KšÙ^\ÖÜVÔÑQÓSÕ‘T’QÒJNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÐUPÒËØ]™Y]KšÙ^\ÖÜVÔÑQÐUPÒ×JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÐUPÒÌ‹Ø]™Y]KšÙ^\ÖÜVÔÑQÐUPÒÌ—JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÐUPÒÌËØ]™Y]KšÙ^\ÖÜVÔÑQÐUPÒÌ×JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÐUPÒÍ Ø]™Y]KšÙ^\ÖÜVÔÑQÐUPÒÍJNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×Ò•ST Ø]™Y]KšÙ^\ÖÜVÔÑQÒ•STJNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÔÔPÒPS Ø]™Y]KšÙ^\ÖÜVÔÑQÔÔPÒPSJNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÔÕT• Ø]™Y]KšÙ^\ÖÜVÔÑQÔÕT•JNˆÛÛ�›ÛÜÙ]Ù^J^Y\˜ÛÛ�›ÛÚ[�\œÖÜK“Q×ÔÐÔ‘QS”ÒÕ Ø]™Y]KšÙ^\ÖÜVÔÑQÔÐÔ‘QS”ÒÕJNˆBŸB‚‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚�›ÚY\Ü^WØÜ™Y]Ê +BžÂˆL̈š[š\Ú[YHHÝ[YH +È L +ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYYˆ[�Û™HH ˆ[�ÈHšY[Û[Ù\Ë�”ÚY� È ˆ +È Îˆ[�ˆH +šY[Û[Ù\Ë�”™\È HšY[Û[Ù\Ë�”ÚY� +H È �ˆ[�HH ˆ[�HšY[Û[Ù\Ëš™\È È ŽÂˆ[�ÛÛ HH H›Û�[Û›ÝÚY + +H +ˆ MŽÂˆ[�ÛÛ ˆH +È›Û�[Û›ÝÚY + +H +ˆ ‚ˆYŠØ]™Y]K›ÙÛÈOH JBˆˆ™]\›ŽÂˆBˆ˜YWÛÝ] +  +N‚ˆ[›ØYÛ]™[ + +N‚ˆ›Ý™]ÚÙ^\ÈH ‚ˆÚ[JYÛ™JBˆˆHH ŽÂ‚ˆ›Û�Üš[�ŠÜÝ›ZY + ‹�Ü™Y]ÈŠKË ‹ �Ü™Y]ÈŠN‚ˆ›Û�Üš[�ŠÜÝ›ZY + K“Ü[�“ÔˆŠKÈ +Ȉ +ˆK K “Ü[�“ÔˆŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  �Ø\ÚÙ^K[[Ûˆ‹ˆŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ”›Ú™XÝXYŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  “\ÛX[ZÍŽ HŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ‘]™[Ü\ˆŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  ’ܘ]\ÈŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ‘]™[Ü\ˆŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÜÝ›ZY + K‘›Ü›Y\ˆÝY™ˆŠKÈ +Ȉ +ˆK K ‘›Ü›Y\ˆÝY™ˆŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  ‘šYÚˆÛܙȊNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ‘�YÝYHŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  ’Ð�[™™\ÜÙ[ˆŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ’Ú\˜žHŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  “Ü™˜[ŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  “Ü›ØÚWÖŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  ”ÖŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  •Z[ÈŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  �U[›™[ÈŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  •Ú]H˜YÛÛˆŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  ”ÛX›ÈŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÜÝ›ZY + K”Ü�ÈŠKÈ +Ȉ +ˆK K ”Ü�ÈŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  “[�^ ÓÔÖŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  ”ÖŠNÈ +ÊÛN‚ˆ›Û�Üš[�ŠÛÛ KÈ +Ȉ +ˆK  �[™›ÚYŠNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  �Ôž‘YKÛX›ËŠNÈ +ÊÛNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  �U[›™[Ë\ÛX[ZÍŽ HŠNÈ +ÊÛNˆ›Û�Üš[�ŠÛÛ ‹È +Ȉ +ˆK  •Ú]H˜YÛÛˆŠNÈ +ÊÛN‚ˆ\]J ‹ +N‚ˆÛ™HH +Ý[YHˆš[š\Ú[YJNˆÛ™HH +›Ý™]ÚÙ^\È ˆ +“Q×ÔÕT• +È“Q×ÑTÐÊJNˆBˆ˜YHH ÍNˆ˜YWÛÝ] +  +NŸB‚‚�›ÚY›Ü”Ú]ÝÛŠ[�Ý]\ËÛÛœÝÚ\ˆ +›\ÙË ‹‹ŠBžÂˆ˜WÛ\Ý\™Û\݈˜WÛ\ÝÝ]]Ø\™Ý[Y[�Έ[�N‚ˆÝ]XÈ[�Ú][™ÙÝÛˆH ‚ˆYŠÚ][™ÙÝÛŠBˆˆ™]\›ŽÂˆB‚ˆÚ][™ÙÝÛˆH Nˆ˜WÜÝ\� +\™Û\Ý \ÙÊN‚ˆ ËÜš[�ŠœØ]™Y]K›ÙÛÈ Yˆ‹Ø]™Y]K›ÙÛÊN‚ˆYŠY\ØX›[ÙÊBˆˆÝÚ]Ú +Ý]\ÊBˆˆØ\ÙH ‚ˆš[�Š—ŠŠŠŠŠŠŠŠŠŠŠŠˆÚ][™ÈÝÛˆ +ŠŠŠŠŠŠŠŠŠŠŠ——ˆŠNˆœ™XZΈY˜][‚ˆš[�Š—ŠŠŠŠŠŠŠŠŠŠˆ[ˆ\œ›ÜˆØØÝ\œ™Y +ŠŠŠŠŠŠŠŠŠˆ‚ˆ—ŠˆÚ][™ÈÝÛˆ +——ˆŠNˆœ™XZΈBˆB‚ˆYŠY\ØX›[ÙÊBˆˆ˜WØÛÜJÝ]]Ø\™Ý[Y[�Ë\™Û\Ý +NˆÜš]UÓÙÑš[UŠ\ÙËÝ]]Ø\™Ý[Y[�ÊNˆ˜WÙ[™ +Ý]]Ø\™Ý[Y[�ÊNˆB‚‚ˆÙ]˜[TÝ]\Ê–UTÊNˆØ]™\Ù][™ÜÊ +N‚ˆ ʈ[�žHÚ[�›ÜˆH[™Ú[™HÜ™Y]ÈØÜ™Y[‹ˆ +‹Âˆ ËÜØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÑS‘ÒS‘WÐÔ‘QUÂBB‚ˆ ËÈYŠÝ]\ÈOH ŠBˆ ËȈ ËÈ\Ü^WØÜ™Y]Ê +Nˆ ËÈB‚ˆYŠÝ\�\ÙÛ™JBˆÈˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÑS‘ÒS‘WÐÔ‘QUˆ\›WÝšY[Û[Ù\Ê +NˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙH]™[]HŠNˆBˆYˆ +Ý\�\ÙÛ™JBˆˆ[›ØYÛ]™[Ü™\Š +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹‹‹‹‹‹‹‹‹‹—ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆ[›ØYÛ]™[ + +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‘Û™HW—ˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙHܘ\XÜÈ]HŠNˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆœ™Y\ØÜ™Y[Š �œØÜ™Y[ŠNÈ ËÈ[ØØ]YžH[š]ÝšY[Û[Ù\ˆBˆYŠÝ\�\ÙÛ™H ‰ˆ^[›Ü›X]OHVSÞ +H›ÜŠHH ÈHPVГS‘S‘ÔÎÈJÊÊBˆˆœ™YJ›[™X›\ÖÚWJNˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆœ™Y\ØÜ™Y[Š ˜˜XÚÙÜ›Ý[™ +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹ˆŠNˆBˆÚY™YˆÐPÒWÐ�PÒÑÔ“ÕS‘ˆYŠÝ\�\ÙÛ™JH›ÜŠHH ÈHPVÐÐPÒQÐ�PÒÑÔ“ÕS‘ÎÈJÊÊBˆˆœ™Y\ØÜ™Y[Š ˜™×ØØXÚVÚWJNˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹ˆŠNˆBˆÙ[™Y‚ˆYŠÝ\�\ÙÛ™JBˆˆœ™Y\Üš]\Ê +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆ[›ØYØ[Ù›Û�Ê +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—Û™HWˆŠNˆB‚‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙHØ[YH]K‹‹‹‹‹‹‹‹‹‹‹——ˆŠNˆB‚ˆYŠÝ\�\ÙÛ™JBˆˆœ™YWÙ[�Ê +NˆBˆYŠÝ\�\ÙÛ™JBˆˆœ™YWÛ[Ù[Ê +NˆBˆYŠÝ\�\ÙÛ™JBˆˆœ™YWÛ[Ù[ØXÚJ +NˆBˆYŠÝ\�\ÙÛ™JBˆˆÛX\—ÜØÜš\Ê +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—”™[X\ÙHØ[YH]K‹‹‹‹‹‹‹‹‹‹‹—Û™HWˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙH[Y\‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆ›Ü•[Y\‘^] + +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—Û™HWˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙH[œ]\™Ø\™K‹‹‹‹‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆÛÛ�›ÛÙ^] + +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—Û™HWˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙHÛÝ[™Þ\Ý[K‹‹‹‹‹‹‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆÛÝ[™Ù^] + +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—Û™HWˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š”™[X\ÙHš[PØXÚ[™ÈÞ\Ý[K‹‹ˆŠNˆBˆYŠÝ\�\ÙÛ™JBˆˆZ×Ý\›J +NˆBˆYŠY\ØX›[ÙÊBˆˆš[�Š—Û™HWˆŠNˆB‚ˆYŠ[Ù[ÛY\Ý +Bˆˆœ™YPÛÛ[X[™\Ý +[Ù[ÛY\Ý +NÈ ËÈ[Ý™Y\™H™XØ]\ÙH\Ý\È›Ý[š]X[^™YYˆÚ]ÝÛˆ\È[š]X]Yœ›ÛH[œÚYHHY[�BˆBˆYŠ[Ù[ÝÛY\Ý +Bˆˆœ™YPÛÛ[X[™\Ý +[Ù[ÝÛY\Ý +NˆBˆYŠ]™[ÛY\Ý +Bˆˆœ™YPÛÛ[X[™\Ý +]™[ÛY\Ý +NˆBˆYŠ]™[Ü™\˜ÛY\Ý +Bˆˆœ™YPÛÛ[X[™\Ý +]™[Ü™\˜ÛY\Ý +NˆB‚ˆœ™YS[Ù[\Ý + +NˆÛX\—ÜØ]™YØ[ÝÜÙ[XÝØ\™Ý[Y[�Ê +Nˆœ™YJØ]™[]™[Ø[ÝÜÙ[XÝØ\™ÜÊNˆØ]™[]™[Ø[ÝÜÙ[XÝØ\™ÜÈH•SˆYŠØ]™[]™[ +Bˆˆœ™YJØ]™[]™[ +NˆØ]™[]™[H•SˆBˆØ]™[]™[ØÛÝ[�H ˆœ™YJ[ÝÜÙ[XÝØ\™ÜÊNˆ[ÝÜÙ[XÝØ\™ÜÈH•Sˆœ™YYš[[˜[YXØXÚJ +NˆØ—Ý\›]˜[œÊ +N‚ˆ ËÈœ™YH[œ]™XÛÜ™\‚ˆœ™YWÚ[œ]Ü™XÛÜ™\Š +N‚ˆYŠY\ØX›[ÙÊBˆˆš[�Š—ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠˆÛ™H +ŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠŠ——ˆŠNˆB‚ˆYŠY\ØX›[ÙÊBˆˆ˜WØÛÜJÝ]]Ø\™Ý[Y[�Ë\™Û\Ý +NˆÜš]UÓÙÑš[UŠ\ÙËÝ]]Ø\™Ý[Y[�ÊNˆ˜WÙ[™ +Ý]]Ø\™Ý[Y[�ÊNˆB‚ˆ˜WÙ[™ +\™Û\Ý +NˆÚ][™ÙÝÛˆH ˆ›Ü‘^] +Ý]\ÊNŸB‚‚�›ÚYÝZ\Ý\�\ + +BžÂˆ[�N‚ˆYŠY›Û�ÛØY + ›Y[�KÙ›Û� H‹XÚÙš[K +JBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈØY›Û�ÌHWˆŠNˆBˆYŠY›Û�ÛØY + K›Y[�KÙ›Û� ˆ‹XÚÙš[K +JBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈØY›Û�̈WˆŠNˆBˆYŠY›Û�ÛØY + ‹›Y[�KÙ›Û� È‹XÚÙš[K +JBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈØY›Û�ÌÈWˆŠNˆB‚‚ˆ›Ü•[Y\’[š] + +N‚ˆÛÛ�›ÛÚ[š] + ŠNˆ\WØÛÛ�›ÛÊ +N‚ˆ[š]ÝšY[Û[Ù\Ê +NˆYŠ]šY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊJBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈÙ]šY[È[ÙNˆ Y YWˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ÊNˆB‚ˆ›ÜŠHH ÈH �MŽÈJÊÊBˆˆ™[Û�X›VÚWHHNˆBŸB‚‚�›ÚYÝ\�\ + +BžÂˆ[�N‚ˆš[�Š‘š[PØXÚ[™ÈÞ\Ý[H[š] ‹‹‹‹‹‹—ŠNˆYŠZ×Ú[š] + +JBˆˆš[�Š‘[˜X›YˆŠNˆBˆ[ÙBˆˆš[�Š‘\ØX›YˆŠNˆB‚ˆØYYÚØÛÜ™Qš[J +NˆÛX\”Ø]™YØ[YJ +N‚ˆ[š]ÝšY[Û[Ù\Ê JNˆYŠ]šY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊJBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈÙ]šY[È[ÙNˆ Y YWˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ÊNˆB‚ˆš[�Š•[Y\ˆ[š] ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆ›Ü•[Y\’[š] + +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š’[š]X[^™HÛÝ[™ ‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆYŠÛÝ[™Ú[š] + +JBˆˆYŠØYÜÜXÚX[ÜÛÝ[™Ê +JBˆˆš[�Š‘Û™HWˆŠNˆBˆ[ÙBˆˆš[�Š—ˆŠNˆBˆYŠ\ÛÝ[™ÜÝ\�Ü^X˜XÚÊ +JBˆˆš[�Š•Ø\›š[™ÎˆØ[‰Ý^HÛÝ[™WˆŠNˆBˆЗÜÙ]›Û[YJЗÓPTÕT•“Ó Ø]™Y]KœÛÝ[™›Û +NˆЗÜÙ]›Û[YJЗՓÒPÑU“Ó Ø]™Y]KœÛÝ[™›Û +NˆBˆ[ÙBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈ[š]X[^™HÛÝ[™ —ˆŠNˆB‚ˆ ËÈ[š] ˆ[œ]™XÛÜ™\‚ˆ[š]Ú[œ]Ü™XÛÜ™\Š +N‚ˆš[�Š“ØY[™È›Û�Ë‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆØYØ[Ù›Û�Ê +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™ÈÜš]\Ë‹‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆØYÜÜXÚX[ÜÜš]\Ê +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™È]™[Ü™\‹‹‹‹‹‹‹‹‹‹—ŠNˆØYÛ]™[Ü™\Š +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™È[Ù[ÛÛœÝ[�Ë‹‹‹‹‹—ŠNˆØYÛ[Ù[ØÛÛœÝ[�Ê +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™ÈØÜš\Ù][™ÜË‹‹‹‹‹—ŠNˆØYÜØÜš\ÜÙ][™Ê +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™ÈØÜš\Ë‹‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆØYÜØÜš\Ê +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™È[Ù[Ë‹‹‹‹‹‹‹‹‹‹‹‹‹‹——ˆŠNˆØYÛ[Ù[Ê +N‚ˆš[�Š“Øš™XÝ[™Ú[™H[š] ‹‹‹‹‹‹‹‹‹‹—ŠNˆYŠX[Ø×Ù[�Ê +JBˆˆ›Ü”Ú]ÝÛŠ K“›Ý[›ÝYÚY[[ÜžH›ÜˆØ[YHØš™XÝÈWˆŠNˆBˆš[�Š‘Û™HWˆŠN‚ˆš[�Š“ØY[™ÈY[�K� ‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆØYÛY[�WÝ + +Nˆš[�Š‘Û™HWˆŠN‚ˆ Ê‚ˆܘ]\È + KLŒ � +H[Ý™YH˜[œÛ][Ûˆ[™Y[�H�[˜Ý[ÛœÈÈH[™ÙˆH[™Ú[™HœÝ\�\ˆ�[˜Ý[Û‹ˆ�]™Y›Ü™HH˜ÛÛ�›Û[š]ˆ�[˜Ý[Ûˆ +™]™\�YH›Û��[˜Ý[ÛˆÈØY™Y›Ü™HØÜš\ÊBˆ +‹Âˆš[�Š“ØY[™È˜[œÛ][Û‹‹‹‹‹‹‹‹‹‹—ŠNˆØ—Ú[š]˜[œÊ +Nˆš[�Š‘Û™HWˆŠN‚ˆš[�Š’[œ][š] ‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹—ŠNˆÛÛ�›ÛÚ[š] +Ø]™Y]K�\ÙZ›ÞJNˆ\WØÛÛ�›ÛÊ +Nˆš[�Š‘Û™HWˆŠN‚ˆÚY™YˆÐPÒWÐ�PÒÑÔ“ÕS‘ˆš[�Š�ØXÚ[™È˜XÚÙÜ›Ý[™Ë‹‹‹‹‹‹‹‹‹—ŠNˆØXÚWØ[ؘXÚÙÜ›Ý[™Ê +Nˆš[�Š‘Û™HWˆŠNˆÙ[™Y‚‚ˆš[�Š�Ü™X]H›[™[™ÈX›\Ë‹‹‹‹‹‹—ŠNˆYŠ^[›Ü›X]OHVSÞ +BˆˆÜ™X]WØ›[™ÝX›\×Þ +›[™X›\ÊNˆB‚ˆ›ÜŠHH ÈHPVÔSÔÒV‘H È ÈJÊÊBˆˆ™[Û�X›VÚWHHNˆBˆš[�Š‘Û™HWˆŠN‚ˆYŠØ]™Y]K›ÙÛÊÊȈ L +BˆˆØ]™Y]K›ÙÛÈH ˆB‚ˆš[�Š”Ø]™HÙ][™ÜÈÛȘ\‹‹‹‹‹‹‹‹‹—ŠNˆØ]™\Ù][™ÜÊ +Nˆš[�Š‘Û™HWˆŠN‚ˆÝ\�\ÙÛ™HH N‚ˆš[�Š——ˆŠN‚ŸB‚‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚‚‹ËÈ™]\›œÈ Ûˆ\œ›Ü‹ LHÛˆ\ØØ\Bš[�^YÚYŠÚ\ˆ +™š[[˜[YK[� [�K[�›ÜÚÚ\ +BžÂˆ[šYÚY—Ú[™›È +š[™›ÈHØ[ØÊ KÚ^™[ÙŠ +š[™›ÊJNˆ×ÜØÜ™Y[ˆ +˜˜XÚØ�Y™™\ˆH•Sˆ×ÜØÜ™Y[ˆ +�[\™ÈH˜XÚÙÜ›Ý[™ˆ[�™\Ý[H NˆL̈Þ[˜ÝÜÛÝ[™ˆL̈\Ý[YNˆL̈Z[\ÙXÛÛ™ΈL̈[\[YK[\™]Ý[YNÈ ËÈ[\ܘ\žH]ڛ܈[™Ø[YHÚYˆ^B‚ˆÞ[˜ÝÜÛÝ[™H +ÛÝ[™ÙÙ][�\�˜[ + +HOH ‘‘‘‘‘‘‘ŠNˆ[\[YHHÝ[YNˆ[\™]Ý[YHH™]Ý[YNˆÝ[YHH ˆZ[\ÙXÛÛ™ÈH ˆ\Ý[YHH ˆ˜XÚÙÜ›Ý[™H•S‚ˆYŠJ™\Ý[H[šYÚY—ÛÜ[Šš[[˜[YKXÚÙš[K[™›ÊJJBˆˆÛÝÈ^YÚY—Ù[™ˆB‚ˆÚ[JZ[™›ËO™Û™JBˆˆYŠZ[\ÙXÛÛ™È�H[™›ËOš[™›ÖÌK›™^œ˜[YJBˆˆ[šYÚY—ÙXÛÙWÙœ˜[YJ[™›ÊNˆBˆYŠJ˜XÚØ�Y™™\ˆH[šYÚY—ÙÙ]�Y™™\Š[™›ÊJJBˆˆœ™XZΈBˆÜš]\WØYÜØÜ™Y[Š K ˜XÚØ�Y™™\‹•S  +NˆYŠ[™›ËO™œ˜[YHOH +Bˆˆ™ØWÝ�ØZ] + +Nˆ\]J  +NˆBˆ[ÙBˆˆ\]J  JNˆB‚ˆYŠÞ[˜ÝÜÛÝ[™ +BˆˆZ[\ÙXÛÛ™È +ÏHÛÝ[™ÙÙ][�\�˜[ + +NˆBˆ[ÙBˆˆZ[\ÙXÛÛ™È +ÏH +Ý[YH H\Ý[YJH +ˆ L  ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYYˆB‚ˆ\Ý[YHHÝ[YN‚ˆYŠ[›ÜÚÚ\ ‰ˆ +›Ý™]ÚÙ^\È ˆ +“Q×ÑTÐÈ“Q×ÐS–P•UÓŠJJBˆˆ™\Ý[H LNˆœ™XZΈBˆB‚‚œ^YÚY—Ù[™‚ˆ[šYÚY—ØÛÜÙJ[™›ÊNˆœ™YJ[™›ÊNˆÝ[YHH[\[YNˆ™]Ý[YHH[\™]Ý[YNˆ˜XÚÙÜ›Ý[™H[\™Îˆ ËÜÝ[™\™Ü[]J JNÈ ËÒܘ]\È + KLŒ � +H\ØX›YÈš^HœÈ›Ü\ÜÝYB‚ˆYŠ OH™\Ý[ +Bˆˆš[�Š—•Ø\›š[™Ë[ˆ\œ›ÜˆØØÝ\œ™YÚ[H^Z[™È[š[X]YÚYˆš[H É\ÉË—ˆ‹š[[˜[YJNˆBˆ™]\›ˆ™\Ý[‚ŸB‚‚ˆÚY™YˆÑP“B‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L LL‚Š‚Šˆ™\Ù\�™H›ØÚÚ[™È^]ÙX›J +H™Z]š[܈\ÈHܘ\\ˆ\›Ý[™ŠˆH™]\ØX›H[ÝšYHT\ˈ™]\›ˆ HÛˆÛÛ\][Û‹ Ûˆ\œ›Ü‹Šˆ܈ LHÚ[ˆÜ™X]Ü‹Y[˜X›Y[œ][�\œ�\È^X˜XÚË‚Š‹Âš[�^]ÙX›JÛÛœÝÚ\ˆ +œ] [�›ÜÚÚ\ +BžÂˆ[�™]˜[H Nˆ[�ÛÝ\˜ÙWÚYH LNˆ×Û[ÝšYWÜ^X˜XÚÈ +œ^X˜XÚÈH•Sˆ×ÜØÜ™Y[ˆ +œØÜ™Y[œÚÝÙœ˜[YHH•S‚ˆ[ÝšYWÜ^X˜XÚ×ÜÝÜØ[ + +NˆÛÝ\˜ÙWÚYH[ÝšYWÜÛÝ\˜ÙWÛØY +] SÕ’QWÓÐQS‘×ÔÕ‘PSJNˆYŠÛÝ\˜ÙWÚY +Hˆ™]\›ˆ ˆBˆ^X˜XÚÈH[ÝšYWÜ^X˜XÚ×Ü^JˆÛÝ\˜ÙWÚY ˆSÕ’QWÐÒS“‘SÐUUˈØ]™Y]K›]\ÚXÝ›Û ˆ�YBˆ +NˆYŠ\^X˜XÚÊHˆ™]˜[H ˆÛÝÈ]Z]ˆBˆYŠ[[ÝšYWÜ^X˜XÚ×ÜÙ]Ú[�\œ�\ +^X˜XÚË[›ÜÚÚ\ +JHˆ™]˜[H ˆÛÝÈ]Z]ˆB‚ˆ ʈYØXÞH^X˜XÚÈ\Ù\ÈHÙX“H\Ü^HÚ^™H[™\™Ø\™HUUˆÝ]] ˆ +‹Âˆ[ÝšYWÜ^X˜XÚ×ÜÙ]ÝÚY +^X˜XÚËSÕ’QWÔÒV‘WÓ�UU‘JNˆ[ÝšYWÜ^X˜XÚ×ÜÙ]ÚZYÚ +^X˜XÚËSÕ’QWÔÒV‘WÓ�UU‘JN‚ˆÚ[J^X˜XÚËO˜XÝ]™JHˆ[�[�\œ�\Ü™\]Y\ÝYˆ[�™\Ù[�Ùœ˜[YN‚ˆ[œ]™Yœ™\Ú +^\™XÜÝ]\ËOœÝ]\ÊNˆ[�\œ�\Ü™\]Y\ÝYBˆ +›Ý™]ÚÙ^\È ˆ +“Q×ÑTÐÈ“Q×ÐS–P•UÓŠJHOH ˆYŠ[�\œ�\Ü™\]Y\ÝY ‰ˆ^X˜XÚËOš[�\œ�\ +Hˆ™]˜[H LNˆBˆ[ÝšYWÜ^X˜XÚ×Ý\]J[�\œ�\Ü™\]Y\ÝY +NˆYŠ\^X˜XÚËO˜XÝ]™JHˆœ™XZΈBˆ™\Ù[�Ùœ˜[YHH^X˜XÚËO™œ˜[YWÙ\�NˆYŠ™\Ù[�Ùœ˜[YJHˆYŠ[[ÝšYWÜ^X˜XÚ×Ù˜]×Ý×Þ]]Š^X˜XÚËOš[™^ +JHˆ™]˜[H ˆœ™XZΈBˆBˆYŠ^X˜XÚËO˜Ý\œ™[�Ùœ˜[YH ‰‚ˆ[›ÜØÜ™Y[œÚÝ ‰‚ˆ +›Ý™]ÚÙ^\È ˆ“Q×ÔÐÔ‘QS”ÒÕ +JHˆYŠ\ØÜ™Y[œÚÝÙœ˜[YHˆØÜ™Y[œÚÝÙœ˜[YKO�ÚYOH^X˜XÚËO˜Ý\œ™[�Ùœ˜[YKO�ÚYˆØÜ™Y[œÚÝÙœ˜[YKOšZYÚOH^X˜XÚËO˜Ý\œ™[�Ùœ˜[YKOšZYÚ +HˆYŠØÜ™Y[œÚÝÙœ˜[YJHˆœ™Y\ØÜ™Y[Š œØÜ™Y[œÚÝÙœ˜[YJNˆBˆØÜ™Y[œÚÝÙœ˜[YHH[ØÜØÜ™Y[Šˆ^X˜XÚËO˜Ý\œ™[�Ùœ˜[YKO�ÚY ˆ^X˜XÚËO˜Ý\œ™[�Ùœ˜[YKOšZYÚ ˆVSÌÌ‚ˆ +NˆBˆYŠØÜ™Y[œÚÝÙœ˜[YJHˆ]]—Ý×ܙ؊^X˜XÚËO˜Ý\œ™[�Ùœ˜[YKØÜ™Y[œÚÝÙœ˜[YJNˆØÜ™Y[œÚÝ +ØÜ™Y[œÚÝÙœ˜[YK•S  +NˆBˆBˆ\ÛY\ + L +NˆB‚œ]Z]‚ˆYŠØÜ™Y[œÚÝÙœ˜[YJHˆœ™Y\ØÜ™Y[Š œØÜ™Y[œÚÝÙœ˜[YJNˆBˆYŠ^X˜XÚÈ ‰ˆ^X˜XÚËO™˜Z[Y ‰ˆ™]˜[ˆ +Hˆ™]˜[H ˆBˆYŠ^X˜XÚÈ ‰ˆ^X˜XÚËO˜XÝ]™JHˆ[ÝšYWÜ^X˜XÚ×ÜÝÜ +^X˜XÚÊNˆBˆÚ[JÛÝ\˜ÙWÚY�H  ‰ˆ[[ÝšYWÜÛÝ\˜ÙWÝ[›ØY +ÛÝ\˜ÙWÚY +JHˆ[ÝšYWÜ^X˜XÚ×Ý\]J +Nˆ\ÛY\ + L +NˆBˆ™]\›ˆ™]˜[ŸBˆÙ[™Y‚‚‚‚�›ÚY^\ØÙ[™JÚ\ˆ +™š[[˜[YJBžÂˆÚ\ˆ +˜�YŽÂˆÚ^™WÝÚ^™Nˆ[�ÜΈÚ\ˆ +˜ÛÛ[X[™H•SˆÚ\ˆšY[Ùš[VÓPVЕQ‘‘T—ÓS—Nˆ[�H HH ÚÚ\Û™HH ›ÜÚÚ\H Nˆ[�ÛÜÚ[™ÈH Ý]\΂ˆ\™Ó\Ý\™Û\݈Ú\ˆ\™Ø�Y–ÓPVÐT‘×ÓSˆ +È WHHˆŽÂ‚ˆ ËÈ™XYš[BˆYŠ�Y™™\—ÜZÙš[Jš[[˜[YK ˜�Y‹ œÚ^™JHOH JBˆˆ™]\›ŽÂˆB‚ˆÝ\œ™[�ØÙ[™HHš[[˜[YN‚ˆ ËÈ›ÝÈ[�\œ™]HÛÛ�[�ÈÙˆ�Yˆ[™HžH[™BˆÜÈH ˆÚ[J�Y–ÜÜ×JBˆˆ\œÙP\™ÜÊ ˜\™Û\Ý �Yˆ +ÈÜË\™Ø�YŠNˆÛÛ[X[™HÑUÐT‘Ê +NˆYŠÛÛ[X[™ÌJBˆˆYŠXÛÜÚ[™È ‰ˆÝšXÛ\ +ÛÛ[X[™ ›]\ÚXÈŠHOH +Bˆˆ]\ÚXÊÑUÐT‘Ê JKÑUÒS•ÐT‘Ê ŠK]Û +ÑUÐT‘Ê ÊJJNˆBˆ[ÙHYŠXÛÜÚ[™È ‰ˆÝšXÛ\ +ÛÛ[X[™ ˜[š[X][ÛˆŠHOH +BˆˆÝ˜ÜJšY[Ùš[KÑUÐT‘Ê JJNˆHÑUÒS•ÐT‘Ê ŠNˆHHÑUÒS•ÐT‘Ê ÊNˆÚÚ\Û™HHÑUÒS•ÐT‘Ê +Nˆ›ÜÚÚ\HÑUÒS•ÐT‘Ê JNˆÝ]\ÈH^YÚYŠšY[Ùš[K K›ÜÚÚ\ +NˆYŠÝ]\ÈOH LH ‰ˆ\ÚÚ\Û™JBˆˆÛÜÚ[™ÈH NˆBˆBˆ[ÙHYŠXÛÜÚ[™È ‰ˆÝšXÛ\ +ÛÛ[X[™ �šY[ÈŠHOH +BˆˆÚY™YˆÑP“BˆÝ˜ÜJšY[Ùš[KÑUÐT‘Ê JJNˆÚÚ\Û™HHÑUÒS•ÐT‘Ê ŠNˆ›ÜÚÚ\HÑUÒS•ÐT‘Ê ÊNˆÝ]\ÈH^]ÙX›JšY[Ùš[K›ÜÚÚ\ +NˆYŠÝ]\ÈOH LH ‰ˆ\ÚÚ\Û™JBˆˆÛÜÚ[™ÈH NˆBˆ[ÙHYŠÝ]\ÈOH +Bˆˆš[�Š�[ˆ\œ›ÜˆØØÝ\œ™YÚ[ˆžZ[™ÈÈ^HHšY[È \׈‹šY[Ùš[JNˆBˆÙ[ÙBˆš[�Š”ÚÚ\[™ÈšY[È \ÎÈÙX“H^X˜XÚÈ›ÝÝ\Ü�YÛˆ\È]›Ü›WˆŠNˆÙ[™Y‚ˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ œÚ[[˜ÙHŠHOH +BˆˆÛÝ[™ØÛÜÙWÛ]\ÚXÊ +NˆBˆBˆ ËÈÛÈÈ™^›Û‹X›[šÈ[™BˆÜÈ +ÏHÙ]™]Ó[™TÝ\� +�Yˆ +ÈÜÊNˆBˆYŠ�YˆOH•S +Bˆˆœ™YJ�YŠNˆ�YˆH•SˆBˆÝ\œ™[�ØÙ[™HH•Sˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆ^Y\–ÚWK™\ØX›ZÙ^\ÈH^Y\–ÚWK›™]ÚÙ^\ÈH^Y\–ÚWKœ^ZÙ^\ÈH ˆBŸB‚‚‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚‚‚‚�›ÚYØ[Y[Ý™\Š +BžÂˆ[�Û™HH ˆÚ\ˆ\�Y™–ÓPVЕQ‘‘T—ÓS—HHȈŸN‚ˆ]\ÚXÊ™]KÛ]\ÚXËÙØ[Y[Ý™\ˆ‹  +N‚ˆÝ[YHH ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÑÐSQWÓÕ‘TŽÂ‚ˆYŠÝ\ÝØÙ[™\ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝØÙ[™\ÊNˆÝ˜Ø] +\�Y™‹™Ø[Y[Ý™\‹�ŠNˆYŠ\ÝXÚÙš[J\�Y™‹XÚÙš[JH�H +Bˆˆ^\ØÙ[™J\�Y™ŠNˆÛ™HH NˆBˆBˆ[ÙBˆˆYŠ\ÝXÚÙš[J™]KÜØÙ[™\ËÙØ[Y[Ý™\‹�‹XÚÙš[JH�H +Bˆˆ^\ØÙ[™J™]KÜØÙ[™\ËÙØ[Y[Ý™\‹�ŠNˆÛ™HH NˆB‚ˆB‚ˆÚ[JYÛ™JBˆˆ›Û�Üš[�ŠÜÝ›ZY + ËŠ‘ÐSQHÕ‘TˆŠJK LL +ÈšY[Û[Ù\Ë�”ÚY�  Ë Š‘ÐSQHÕ‘TˆŠJNˆÛ™HH +Ý[YHˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ‰ˆ\ÛÝ[™Ü]Y\žWÛ]\ÚXÊ•S •S +JNˆÛ™HH +›Ý™]ÚÙ^\È ˆ +“Q×ÑTÐÈ“Q×ÐS–P•UÓŠJNˆ\]J  +NˆB‚ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÑÐSQWÓÕ‘TŽÂŸB‚‚‚‚�›ÚY[˜[YJ[�YÜØÛÜ™JBžÂˆ[�Û™HH ˆ[�Ü[–ÌLHHÈ          NˆZ[� �ÝØÛÜ™NˆÚ\ˆ˜[YVÓPVÓ�SQWÓSˆ +È WNˆ[�K NˆÚ\ˆ\�Y™–ÓPVЕQ‘‘T—ÓS—HHȈŸNˆ[�ÛÛ HH Nˆ[�ÛÛ ˆH ŽÂ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÒSÓÑ—Ñ�SQN‚ˆYŠ\ØÛÜ™X™ÊBˆˆ ËÈ™]È[\›˜]]™H˜XÚÙÜ›Ý[™] ‚ˆYŠÝ\ÝšÙÜ™ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝšÙÜ™ÊNˆÝ˜Ø] +\�Y™‹š\ØÛÜ™HŠNˆØYؘXÚÙÜ›Ý[™ +\�Y™ŠNˆBˆ[ÙBˆˆØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÚ\ØÛÜ™HŠNˆBˆB‚ˆYŠYÜØÛÜ™JBˆˆ›ÜŠH È]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈ +ÊÊBˆˆYŠ^Y\–ÜKœØÛÜ™HˆØ]™\ØÛÜ™KšYÚØÖÎWJBˆˆØ]™\ØÛÜ™KšYÚØÖÎWHH^Y\–ÜKœØÛÜ™NˆÝ˜ÜJØ]™\ØÛÜ™KšØÛÜ™[–ÎWK^Y\–ÜK›˜[YJNˆÜ[–ÎWHH N‚ˆ›ÜŠHHÈH�H  ‰ˆ^Y\–ÜKœØÛÜ™HˆØ]™\ØÛÜ™KšYÚØÖÚWNÈKKJBˆˆØÛÜ™HHØ]™\ØÛÜ™KšYÚØÖÚWNˆÝ˜ÜJ˜[YKØ]™\ØÛÜ™KšØÛÜ™[–ÚWJNˆØ]™\ØÛÜ™KšYÚØÖÚWHH^Y\–ÜKœØÛÜ™NˆÝ˜ÜJØ]™\ØÛÜ™KšØÛÜ™[–ÚWK^Y\–ÜK›˜[YJNˆÜ[–ÚWHH NˆØ]™\ØÛÜ™KšYÚØÖÚH +È WHHØÛÜ™NˆÝ˜ÜJØ]™\ØÛÜ™KšØÛÜ™[–ÚH +È WK˜[YJNˆÜ[–ÚH +È WHH ˆBˆBˆBˆØ]™RYÚØÛÜ™Qš[J +NˆB‚ˆÝ[YHH ‚ˆÚ[JYÛ™JBˆˆHH MŽÂˆYŠZ\ØÛÜ™X™ÊBˆˆ›Û�Üš[�ŠÜÝ›ZY + ËŠ’[Ùˆ˜[YHŠJKH H›Û�ZYÚ + ÊH H L +ÈšY[Û[Ù\Ë�”ÚY�  Ë Š’[Ùˆ˜[YHŠJNˆB‚ˆ›ÜŠHH ÈH LÈJÊÊBˆˆ›Û�Üš[�ŠØÛÛ +Ü[–ÚWKÛÛ JKH +ÈšY[Û[Ù\Ë�”ÚY� Ü[–ÚWK ‰LšKˆ \È‹H +È KØ]™\ØÛÜ™KšØÛÜ™[–ÚWJNˆ›Û�Üš[�ŠØÛÛ +Ü[–ÚWKÛÛ ŠKH +ÈšY[Û[Ù\Ë�”ÚY� Ü[–ÚWK  +ØÛÜ™Y›Ü›X]ȉLHˆ’]M�ˆ‰Hˆ’]M� +KØ]™\ØÛÜ™KšYÚØÖÚWJNˆH +ÏH +šY[Û[Ù\Ë�”™\È HšY[Û[Ù\Ë�”ÚY� H Mˆ H ÌŠH È LÈ ËÙ›Û�ÚZYÚÖÝÜ[–ÚWWH +È ŽÂˆB‚ˆ ËÈܘ]\È + KLŒ ŒÊHYYH‘“Q×ÐS–P•UÓˆˆÈ^]H[Ùˆ˜[YHØÜ™Y[‚ˆ\]J  +NˆÛ™HH +Ý[YHˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ +NˆÛ™HH +›Ý™]ÚÙ^\È ˆ +“Q×ÔÕT•“Q×ÐS–P•UÓˆ“Q×ÑTÐÊJNˆBˆ[›ØYؘXÚÙÜ›Ý[™ + +NˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÒSÓÑ—Ñ�SQNŸB‚‚‚‚‹ËÈ]™[ÛÛ\]Y ÚÝÈ›Û�\ÈÝY™‚�›ÚYÚÝØÛÛ\]J[��[JBžÂˆ[�Û™HH ˆ[�K‹ΈL̈ÛX\˜›Û�\ÖÍHHÈ L  L  L  L NˆL̈Y™X›Û�\ÖÍHHÈ L  L  L  L NˆL̈�\Ú›Û�\ÖÍHHÈ L  L  L  L NˆL̈™^[YHH ˆL̈š[š\Ú[YHH ˆ[�Ú[ˆH ˆÚ\ˆ\�Y™–ÓPVЕQ‘‘T—ÓS—HHȈŸN‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÔÒÕ×ÐÓÓTUN‚ˆYŠÛÛ\]X™ÊBˆˆ ËÈ™]È[\›˜]]™H˜XÚÙÜ›Ý[™] ‚ˆYŠÝ\ÝšÙÜ™ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝšÙÜ™ÊNˆÝ˜Ø] +\�Y™‹˜ÛÛ\]HŠNˆØYؘXÚÙÜ›Ý[™ +\�Y™ŠNˆBˆ[ÙBˆˆØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËØÛÛ\]HŠNˆBˆB‚ˆ]\ÚXÊ™]KÛ]\ÚXËØÛÛ\]H‹  +N‚ˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ�\ÚÌH�H H ‰ˆÚÝÜ�\Ú›Û�\ÈOH JBˆˆ�\Ú›Û�\ÖÚWHH›ÛX^�\Ú™\Ù]ÚWH +ˆØØ›Û�\Ù\ÖÌ—NˆBˆYŠØØ›Û�\Ù\ÖÌ×HOH JBˆˆÛX\˜›Û�\ÖÚWHH�[H +ˆØØ›Û�\Ù\ÖÌNˆBˆ[ÙBˆˆÛX\˜›Û�\ÖÚWHHØØ›Û�\Ù\ÖÌNˆBˆY™X›Û�\ÖÚWHH^Y\–ÚWK›]™\È +ˆØØ›Û�\Ù\ÖÌWNˆB‚ˆ\]J  +N‚ˆÝ[YHH ˆÚ[JYÛ™JBˆˆYŠ\ØÛÛ\]VÍWJBˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÛ\]VÌKšY[Û[Ù\Ë�”ÚY� +ÈØÛÛ\]VÌWK Ë Š”ÝYÙH ZHÛÛ\]HHŠK�[JNˆBˆ[ÙBˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÛ\]VÌKšY[Û[Ù\Ë�”ÚY� +ÈØÛÛ\]VÌWK Ë Š”ÝYÙHŠJNˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÛ\]VÌ—KšY[Û[Ù\Ë�”ÚY� +ÈØÛÛ\]VÌ×K Ë ‰ZH‹�[JNˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÛ\]VÍKšY[Û[Ù\Ë�”ÚY� +ÈØÛÛ\]VÍWK Ë Š�ÛÛ\]HŠJNˆB‚ˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØ›Û�\ÖÌKšY[Û[Ù\Ë�”ÚY� +ÈØ›Û�\ÖÌWK  Š�ÛX\ˆ›Û�\ÈŠJNˆ›ÜŠHH ˆH ‹ÈH ÎÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊˈHˆ +È ‹ÈHÈ +È ŠHYŠ^Y\–ÚWK›]™\Ȉ +Bˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØ›Û�\ÖÚ—KšY[Û[Ù\Ë�”ÚY� +ÈØ›Û�\ÖÚ×K   +ØÛÜ™Y›Ü›X]ȉL[Hˆˆ‰[HŠKÛX\˜›Û�\ÖÚWJNˆBˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +È›Û�\ÖÌKšY[Û[Ù\Ë�”ÚY� +È›Û�\ÖÌWK  Š“Y™H›Û�\ÈŠJNˆ›ÜŠHH ˆH ‹ÈH ÎÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊˈHˆ +È ‹ÈHÈ +È ŠHYŠ^Y\–ÚWK›]™\Ȉ +Bˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +È›Û�\ÖÚ—KšY[Û[Ù\Ë�”ÚY� +È›Û�\ÖÚ×K   +ØÛÜ™Y›Ü›X]ȉL[Hˆˆ‰[HŠKY™X›Û�\ÖÚWJNˆBˆYŠ�\ÚÌH�H H ‰ˆÚÝÜ�\Ú›Û�\ÈOH JBˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +Ș›Û�\ÖÌKšY[Û[Ù\Ë�”ÚY� +Ș›Û�\ÖÌWK  Š”�\Ú›Û�\ÈŠJNˆ›ÜŠHH ˆH ‹ÈH ÎÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊˈHˆ +È ‹ÈHÈ +È ŠHYŠ^Y\–ÚWK›]™\Ȉ +Bˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +Ș›Û�\ÖÚ—KšY[Û[Ù\Ë�”ÚY� +Ș›Û�\ÖÚ×K   +ØÛÜ™Y›Ü›X]ȉL[Hˆˆ‰[HŠK�\Ú›Û�\ÖÚWJNˆBˆBˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÜ™VÌKšY[Û[Ù\Ë�”ÚY� +ÈØÛÜ™VÌWK  Š•Ý[ØÛÜ™HŠJNˆ›ÜŠHH ˆH ‹ÈH ÎÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊˈHˆ +È ‹ÈHÈ +È ŠHYŠ^Y\–ÚWK›]™\Ȉ +Bˆˆ›Û�Üš[�ŠšY[Û[Ù\ËšÚY� +ÈØÛÜ™VÚ—KšY[Û[Ù\Ë�”ÚY� +ÈØÛÜ™VÚ×K   +ØÛÜ™Y›Ü›X]ȉLHˆ’]M�ˆ‰Hˆ’]M� +K^Y\–ÚWKœØÛÜ™JNˆB‚ˆÚ[JÝ[YHˆ™^[YJBˆˆYŠYš[š\Ú[YJBˆˆš[š\Ú[YHHÝ[YH +È  +ˆÛؘ[ØÛÛ™šYË™Ø[YWÜÜYYˆB‚ˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK›]™\Ȉ +BˆˆYŠÛX\˜›Û�\ÖÚWHˆ +BˆˆYØÛÜ™JK L +NˆÛX\˜›Û�\ÖÚWH OH Lˆš[š\Ú[YHH ˆBˆ[ÙHYŠY™X›Û�\ÖÚWHˆ +BˆˆYØÛÜ™JK L +NˆY™X›Û�\ÖÚWH OH Lˆš[š\Ú[YHH ˆBˆ[ÙHYŠ�\ÚÌH�H H ‰ˆÚÝÜ�\Ú›Û�\ÈOH H ‰ˆ +�\Ú›Û�\ÖÚWHˆ +JBˆˆYØÛÜ™JK L +Nˆ�\Ú›Û�\ÖÚWH OH Lˆš[š\Ú[YHH ˆBˆBˆB‚ˆYŠYš[š\Ú[YH ‰ˆJ™^[YH ˆ MJJBˆˆÛÝ[™ÜÝÜÜØ[\JÚ[ŠNˆÚ[ˆHÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û È ‹Ø]™Y]K™Y™™XÝ›Û È ‹ L +NˆBˆ™^[YJÊΈB‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÐS–P•UÓˆ“Q×ÑTÐÊJBˆˆÛ™HH NˆBˆYŠš[š\Ú[YH ‰ˆÝ[YHˆš[š\Ú[YJBˆˆÛ™HH NˆB‚ˆ\]J  +NˆB‚ˆ ËÈY™[XZ[™\ˆÙˆØÛÜ™K[˜Ø\ÙH^Y\ˆÚÚ\ÈÛÝ[�\‚ˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK›]™\Ȉ +BˆˆYŠ�\ÚÌH�H H ‰ˆÚÝÜ�\Ú›Û�\ÈOH JBˆˆYØÛÜ™JK�\Ú›Û�\ÖÚWJNˆBˆYØÛÜ™JKÛX\˜›Û�\ÖÚWJNˆYØÛÜ™JKY™X›Û�\ÖÚWJNˆBˆBˆ[›ØYؘXÚÙÜ›Ý[™ + +N‚ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÔÒÕ×ÐÓÓTUNŸB‚�›ÚYØ]™[]™[[™›Ê +BžÂˆ[�Nˆ×ÜÙ]Ù[�žH +œÙ]H]™[Ù]È +ÈÝ\œ™[�ÜÙ]ˆ×ÜØ]™[]™[ +œØ]™HHØ]™[]™[ +ÈÝ\œ™[�ÜÙ]‚ˆØ]™KO™›YÈHÙ] OœØ]™Y›YΈ ËÈÛ‰ÝÚXÚÈ›YÈ\™HØ]™H[[™›Ë›ÜˆÚ[\HÙÚXˆ›ÜŠHH ÈHÙ] O›X^^Y\œÎÈJÊÊBˆˆØ]™KOœ]™\ÖÚWHH^Y\–ÚWK›]™\ΈØ]™KOœÜ™Y]ÖÚWHH^Y\–ÚWK˜Ü™Y]ΈØ]™KOœØÛÜ™\ÖÚWHH^Y\–ÚWKœØÛÜ™NˆØ]™KOœÜ]ÛšX[ÚWHH^Y\–ÚWKœÜ]ÛšX[ˆØ]™KOœÜ]Û›\ÚWHH^Y\–ÚWKœÜ]Û›\ˆØ]™KOœÙX\�[VÚWHH^Y\–ÚWK�ÙX\�[NˆØ]™KOœÛÛÝ\›X\ÚWHH^Y\–ÚWK˜ÛÛÝ\›X\ˆÝ›˜ÜJØ]™KOœ˜[YVÚWK^Y\–ÚWK›˜[YKPVÓ�SQWÓSŠNˆBˆØ]™KO˜Ü™Y]ÈHÜ™Y]ΈØ]™KO›]™[HÝ\œ™[�Û]™[ˆØ]™KOœÝYÙHHÝ\œ™[�ÜÝYÙNˆØ]™KO�ÚXÚÜÙ]HÝ\œ™[�ÜÙ]ˆÝ›˜ÜJØ]™KO™˜[YKÙ] O›˜[YKPVÓ�SQWÓSˆ H JNˆÙ]ÜØ]™YØ[ÝÜÙ[XÝØ\™Ý[Y[�ÊÝ\œ™[�ÜÙ] [ÝÜÙ[XÝØ\™ÜÊNŸB‚�›ÚYž]šXÝÜž\ÜÙJ[�]H +™[� +BžÂˆYŠ[� ‰‚ˆ[� Oš[œZ[ˆ ˆ’S—ÔRS—Ó“Ó‘H ‰‚ˆY[� O™˜[[™È ‰‚ˆJ[� O™X]ÜÝ]H ˆPUÔÕUWÑPQ +H ‰‚ˆY[� Oœš\Ú[™È ‰‚ˆ +[� OšY[™È ˆQS‘×ÐPÕU‘JH ‰‚ˆ[� OœÜÚ][Û‹žHH[� O˜˜\ÙH +Bˆˆ[� O�ZÙXXÝ[ÛˆH•Sˆ[� O�™[ØÚ]KžH[� O�™[ØÚ]KžˆH ˆ[� OšY[™ÈHQS‘×Ó“Ó‘Nˆ[�ÜÙ]Ø[š[J[� S’WÕ’PÕÔ–K +NˆBŸB‚œÝ]XÈ›ÚYÚXÚ×ÝšXÝÜžWÜÜÙJ +BžÂˆYˆ + +[™Ø[YH ˆ JH ‰ˆ]™[ØÛÛ\]YÙY™X][™×Ø›ÜÜÈ +Bˆˆ[�Nˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆ[�]Jˆ\HÙ[ŽÂˆÙ[ˆH^Y\–ÚWK™[�ˆYŠÙ[ˆ ‰ˆ˜[Y[š[JÙ[‹S’WÕ’PÕÔ–JH ‰ˆÙ[‹O˜[š[[�[HOHS’WÕ’PÕÔ–JBˆˆž]šXÝÜž\ÜÙJÙ[ŠNˆ[™Ø[YHH ˆBˆ[ÙHYˆ +Ù[ˆ ‰ˆÙ[‹O˜[š[[�[HOHS’WÕ’PÕÔ–H ‰ˆÙ[‹O˜[š[X][™ÊBˆˆ[™Ø[YHH ˆB‚ˆÙ[ˆH\ˆBˆBŸB‚š[�^[]™[ +Ú\ˆ +™š[[˜[YJBžÂˆ[�K\KØ[]™HH ‚ˆÚ[Ø[ + +N‚ˆØ]™[]™[[™›Ê +NÈ ËÈ�\Ý[ˆØ\ÙHÙHÜÙH[HY�\ˆ]™[\Èœ™YY‚ˆØYÛ]™[ +š[[˜[YJN‚ˆYŠ[›ÜØ]™JBˆˆØ]™QØ[YQš[J +NˆØ]™RYÚØÛÜ™Qš[J +NˆØ]™TØÜš\š[J +NˆBˆ›ÜØ]™HH ‚ˆÝ[YHH ˆ™^[ˆH ˆÝ[Ù\ˆH•Sˆš\œÝ^Y\ˆH•Sˆ\HH]™[ O�\N‚ˆ ËÈš^\ÈHÝ\�]™[^XÝ][™È\Ý�]Ûˆ�Yˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK›]™\Ȉ +Bˆˆ^Y\–ÚWK™\ØX›ZÙ^\ÈH^Y\–ÚWK›™]ÚÙ^\ÈH^Y\–ÚWKœ^ZÙ^\ÈH ˆ^Y\–ÚWK�ÙX\�[HH]™[ OœÙ]ÙX\ˆ^Y\–ÚWKš›Ú[š[™ÈH ˆ^Y\–ÚWKš\Ü^YYH NˆÜ]Ûœ^Y\ŠJNˆ^Y\–ÚWK™[� Oœ�\Ú ›X^H ˆBˆB‚ˆ ËÙ^XÝ]HHØÜš\Ú[ˆ]™[Ý\�YˆYŠØÜš\Ò\Ò[š]X[^™Y + ›]™[ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J ›]™[ÜØÜš\ +NˆBˆYŠØÜš\Ò\Ò[š]X[^™Y + Š]™[ O›]™[ÜØÜš\ +JJBˆˆØÜš\Ñ^XÝ]J Š]™[ O›]™[ÜØÜš\ +JNˆB‚ˆÚ[JY[™Ø[YJBˆˆ\]J K +N‚ˆYˆ +]™[ O™›Ü˜ÙWÙš[š\Ú]™[ +Bˆˆ]™[ØÛÛ\]YH Nˆ[™Ø[YHH Nˆ]™[ O™›Ü˜ÙWÙš[š\Ú]™[H ˆBˆYˆ +]™[ O™›Ü˜ÙWÙØ[Y[Ý™\ŠBˆˆ ËÙ[�]Jˆ[\HÙ[ŽÂˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊH ËÛ]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÂˆˆ^Y\–ÚWK›]™\ÈH ˆYŠ›ÜÚ\™JBˆˆ^Y\–ÚWK˜Ü™Y]ÈH ˆBˆ[ÙBˆˆÜ™Y]ÈH ˆBˆYˆ +^Y\–ÚWK™[� +B‚BBB^‚BBBBZÚ[Ù[�]J^Y\–ÚWK™[� ÒSÑS•UWÕ’QÑÑT—ÓU‘SÑÐSQWÓÕ‘TŠN‚BBBB\^Y\–ÚWK™[�H•S‚BBB_Bˆ ËÜÙ[ˆH^Y\–ÚWK™[�ˆ ËÜ^Y\—ÙYJ +NˆBˆ ËÜÙ[ˆH[\ˆ ËÚÚ[Ø[ + +Nˆ[™Ø[YHH Nˆ]™[ O™›Ü˜ÙWÙØ[Y[Ý™\ˆH ˆBˆYŠ]™[ØÛÛ\]Y +Bˆˆ[™Ø[YHH +Yš[™[� +TWÑS‘SVJH]™[ O�\Hš[™[� +TWÑS‘U‘S +JNÈ ËÈ[™ÈÚ[ˆ[[™[ZY\ÈYH܈H›Û�\È]™[ˆÚXÚ×ÝšXÝÜžWÜÜÙJ +NˆBˆBˆ ËÙ^XÝ]HHØÜš\Ú[ˆ]™[š[š\ÚYˆYŠØÜš\Ò\Ò[š]X[^™Y + ™[™]™[ÜØÜš\ +JBˆˆØÜš\Ñ^XÝ]J ™[™]™[ÜØÜš\ +NˆBˆYŠØÜš\Ò\Ò[š]X[^™Y + Š]™[ O™[™]™[ÜØÜš\ +JJBˆˆØÜš\Ñ^XÝ]J Š]™[ O™[™]™[ÜØÜš\ +JNˆBˆYŠ[›Ù˜Y[Ý] +Bˆˆ˜YWÛÝ] +  +NˆB‚ˆ›ÜŠHH ÈH]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÎÈJÊÊBˆˆYŠ^Y\–ÚWK™[� +Bˆˆ›ÛX^�\Ú™\Ù]ÚWHH^Y\–ÚWK™[� Oœ�\Ú ›X^ˆ^Y\–ÚWKœÜ]ÛšX[H^Y\–ÚWK™[� O™[™\™ÞWÜÝ]KšX[ØÝ\œ™[�ˆ^Y\–ÚWKœÜ]Û›\H^Y\–ÚWK™[� O™[™\™ÞWÜÝ]K›\ØÝ\œ™[�ˆBˆ ËÈ™\Ù]ˆ^Y\–ÚWK�ÙX\�[HH ˆB‚ˆYŠ[]\ÚXÛÝ™\›\ +BˆˆÛÝ[™ØÛÜÙWÛ]\ÚXÊ +NˆBˆÛÝ[™ÜÝÜ[ÜØ[\J˜[ÙJN‚ˆ[›ØYÛ]™[ + +N‚ˆ ËÈ\™H[žH^Y\œÈ[]™O‚Y›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +^Y\–ÚWK›]™\Ȉ +BˆˆØ[]™HH Nˆœ™XZΈBˆB‚ˆ™]\›ˆ + +\HOH ˆ ‰ˆ[™Ø[YHOH ŠHØ[]™JNŸB‚‹ËÈØ\ÚÙ^K[[Ûˆˆ +™]ÛÛ ÐH[šÛ›ÝÛŠB‹ËÈ Œ NKL KL ‹Ë‹Ëț܈Ù[XÝØÜ™Y[‹ˆÜ]ÛˆØ[\H[�]H›Üˆ^Y\—Ú[™^ ‚œÝ]XÈ[�]H +œÜ]Û™^[\J[�^Y\—Ú[™^ +BžÂˆÚ\ŠˆÔUÓ—ÓSÑSÓ�SQHH•SˆÛÛœÝ[�ÔUÓ—ÓSÑSÒS‘VHSÑSÒS‘VÓ“Ó‘N‚ˆ[�]BJ™^[\N‚\×Û[Ù[ +›[Ù[‚\×ÜÙ]Ù[�žH +œÙ]‚‚Y›Ø]Ü×Þ‚Y›Ø]Ü×ÞN‚Y›Ø]Ü×ގ‚Z[�\™XÝ[ێ‚BB‚\Ù]H]™[Ù]È +ÈÝ\œ™[�ÜÙ]‚‚KËÈÙ]Ü]Ûˆ]šX�]\È[™Ü]Ûˆ[�]K‚‚\Ü×ÞH +›Ø] +\ÛY[�VÜ^Y\—Ú[™^VÌN‚\Ü×ÞHH ‚\Ü×ÞˆH +›Ø] +\ÛY[�VÜ^Y\—Ú[™^VÌWN‚Y\™XÝ[ÛˆHÜ\™XÝ[Û–Ü^Y\—Ú[™^N‚‚KËÈ™^Ù[XÝX›H[Ù[[ˆÞXÛKˆÙIÛ\ÙH\‚KËÈÈXÚYHÚ]ÙHÜ]Û‹‚‚[[Ù[H™^^Y\›[Ù[Š•S ^Y\—Ú[™^ +N‚‚Y^[\HHÜ]ÛŠÜ×Þ Ü×Þ‹Ü×ÞK\™XÝ[Û‹ÔUÓ—ÓSÑSÓ�SQKÔUÓ—ÓSÑSÒS‘V [Ù[ +Nˆ‚KËÈÛÜH[Ù[ ÜȘ[YHÈ^Y\ˆ›Ü\�K‚‚\ݘÜJ^Y\–Ü^Y\—Ú[™^K›˜[YK[Ù[ O›˜[YJN‚‚KËÈYˆÛÛ܈Ù[XÝ[Ûˆ\È[ÝÙY[™ÙHØ[�‚KËÈ^Y\œÈÚ]Ø[YH[Ù[ÈÈ\ÙHY™™\™[�‚KËÈX\Ë[ˆ\ÙH™^X\[ˆÞXÛKˆÝ\�Ú\ÙB‚KËÈ�\ÝÛÈÚ]Y˜][X\ ‚‚ZYˆ +ÛÛÝ\œÙ[XÝ ‰ˆ +Ù] O››ÜØ[YH ˆ ŠJB‚^‚B\^Y\–Ü^Y\—Ú[™^K˜ÛÛÝ\›X\H™^ÛÛÝ\›X\Š[Ù[  LK^Y\—Ú[™^ +N‚_B‚Y[ÙB‚^‚B\^Y\–Ü^Y\—Ú[™^K˜ÛÛÝ\›X\H ‚_B‚‚KËÈ\HX\ÈÜ]Û™Y[�]K‚ˆ[�ÜÙ]ØÛÛÝ\›X\ +^[\K^Y\–Ü^Y\—Ú[™^K˜ÛÛÝ\›X\ +Nˆ‚KËÈÛÈH[�]HÛ›ÝÜÈÝÈ]Ø[YHÈ™K‚‚Y^[\KOœÜ]Û�\HHÔUÓ—ÕTWÔVQT—ÔÑSPÕˆ‚\™]\›ˆ^[\NŸB‚‹ËÈØYØ]™YÙ[XÝØÜ™Y[‚œÝ]XÈ›ÚYØYÜÙ[XÝÜØÜ™Y[—Ú[™›Ê×ÜØ]™[]™[ +œØ]™JBžÂˆ[�HH ˆ\™Ó\Ý\™Û\݈Ú\ˆ\™Ø�Y–ÓPVÐT‘×ÓSˆ +È WHHˆŽÂˆÚ\ˆ +™š[[˜[YHHˆŽÈ ËÈ›Ý\ÙY �\Ý�\ÙY[�ÈÑUÒS•ÐT‘Ê +BˆÚ\ˆ +˜ÛÛ[X[™HˆŽÈ ËÈ›Ý\ÙY �\Ý�\ÙY[�ÈÑUÒS•ÐT‘Ê +B‚ˆ ËÈØY[Ù[ÛØYˆ›ÜŠHH ÈHØ]™KOœÙ[XÝØYÛÝ[�ÈJÊÊBˆˆ×Û[Ù[ +�[\[Ù[ˆÛÛ[X[™HÑUÐT‘Ê +N‚ˆYŠXÛÛ[X[™XÛÛ[X[™ÌJHÛÛ�[�YNˆ\œÙP\™ÜÊ ˜\™Û\Ý Ø]™KOœÙ[XÝØYÚWK\™Ø�YŠN‚ˆ[\[Ù[Hš[™[Ù[ +ÑUÐT‘Ê JJNˆYˆ +[\[Ù[ +Bˆˆ\]WÛ[Ù[ÛØY›YÊ[\[Ù[ ÑUÒS•ÐT‘Ê ŠJNˆBˆB‚ˆ\œÙP\™ÜÊ ˜\™Û\Ý Ø]™KOœÙ[XÝ]\ÚXË\™Ø�YŠNˆÛÛ[X[™HÑUÐT‘Ê +NˆYŠÛÛ[X[™ ‰ˆÛÛ[X[™ÌJH]\ÚXÊÑUÐT‘Ê JKÑUÒS•ÐT‘Ê ŠK]Û +ÑUÐT‘Ê ÊJJN‚ˆ\œÙP\™ÜÊ ˜\™Û\Ý Ø]™KOœÙ[XݘXÚÙÜ›Ý[™ \™Ø�YŠNˆÛÛ[X[™HÑUÐT‘Ê +NˆYŠÛÛ[X[™ ‰ˆÛÛ[X[™ÌJHØYؘXÚÙÜ›Ý[™ +ÑUÐT‘Ê JJN‚ˆ™]\›ŽÂŸB‚š[�Ù[XÝ^Y\Š[� +œ^Y\œËÚ\ˆ +™š[[˜[YK[�\ÙTØ]™YØ[YJBžÂ‚\×Û[Ù[ +�[\[Ù[‚\×Û[Ù[ +›[Ù[Û™]ÖÓPVÔVQT”×HHÈ•SN‚Z[�N‚Z[�^]H ‚Z[�\ØØ\HH ‚Z[�Y˜][Ù[XÝH ‚][œÚYÛ™Y^][^HH ‚Z[�^Y\œ×Ø�\ÞHH ‚Z[�^Y\œ×Ü™XYHH ‚XÚ\ˆÝš[™ÖÓPVЕQ‘‘T—ÓS—HHȈˆN‚XÚ\ˆ +˜�Y‹ +˜ÛÛ[X[™‚\Ú^™WÝÚ^™HH ‚\™Y™—ÝÜÈH ‚P\™Ó\Ý\™Û\Ý‚XÚ\ˆ\™Ø�Y–ÓPVÐT‘×ÓSˆ +È WHHˆŽÂ‚\×ÜÙ]Ù[�žH +œÙ]H]™[Ù]È +ÈÝ\œ™[�ÜÙ]‚\×ÜØ]™[]™[ +œØ]™HHØ]™[]™[ +ÈÝ\œ™[�ÜÙ]‚Z[�ØYØÛÝ[�H ‚Z[�Ø]™YÜÙ[XÝÜØÜ™Y[ˆH ‚Z[�\×Ùš\œÝÜÙ[XÝH N‚‚\Ø]™[]™[[™›Ê +N‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÔÑSPÕ‚ˆÚ[Ø[ + +N‚‚KËÈ[š]X[^™H^Y\ˆÚ^™Y\œ˜^\Ë‚‚Y[�]H +™^[\VÜÙ] O›X^^Y\œ×N‚Z[�™XYVÜÙ] O›X^^Y\œ×N‚‚KËÈ[š]X[^™H‚Y›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚^‚BY^[\VÚWHH•S‚B\™XYVÚWHH ‚_B‚‚KËÈ[ÝÈÙ[XÝÈ ØIÈ\ÈHš\œÝÚ\ˆÙˆ[ÝÜÙ[XÝ ‚KËÈYˆ\™IÜÈ ØIÈ[ˆ\™H\È[ÝÜÙ[XÝ ‚‚ZYˆ +X[ÝÜÙ[XÝØ\™Ü‚B_ +[ÝÜÙ[XÝØ\™ÜÖÌHOH ØI‚BBI‰ˆ[ÝÜÙ[XÝØ\™ÜÖÌHOH ÐIÊJB‚^‚B\™\Ù]Ü^XX›WÛ\Ý + JN‚_B‚‚KËÈ™\Ù]Y[[ÜžH›Üˆ^Y\ˆ\œ˜^K‚‚[Y[\Ù] +^Y\‹ Ú^™[ÙŠ +œ^Y\ŠH +ˆPVÔVQT”ÊN‚‚KËÈØYØ[YHÙ[XÝY[™HØ]™HØ[YH]˜Z[X›O‚ZYˆ +\ÙTØ]™YØ[YH ‰ˆØ]™JB‚^‚BZYˆ +Ø]™KOœÙ[XÝ›YÊB‚B^‚BB[ØYÜÙ[XÝÜØÜ™Y[—Ú[™›ÊØ]™JN‚BB[ØYÜ^XX›WÛ\Ý +‚BBBYÙ]ÜØ]™YØ[ÝÜÙ[XÝØ\™Ý[Y[�ÊÝ\œ™[�ÜÙ] +B‚BBJN‚BB\Ø]™YÜÙ[XÝÜØÜ™Y[ˆH N‚B_B‚_B‚‚KËÈX\šÈš\Ü^YYˆ›Üˆ[^Y\œË‚‚Y›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚^‚B\^Y\–ÚWKš\Ü^YYH^Y\œÖÚWN‚_B‚‚Y›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚^‚BZYˆ +Ø]™[]™[ØÝ\œ™[�ÜÙ]Kœ]™\ÖÚWHˆ +B‚B^‚BBZ\×Ùš\œÝÜÙ[XÝH ‚BBXœ™XZ΂B_B‚_B‚‚KËÈØY[™\HÙ[XÝ[Ûˆ^š[K‚‚ZYˆ +š[[˜[YH ‰ˆš[[˜[YVÌJB‚^‚BZYˆ +�Y™™\—ÜZÙš[Jš[[˜[YK ˜�Y‹ œÚ^™JHOH JB‚B^‚BBX›Ü”Ú]ÝÛŠ K‘˜Z[YÈØY^Y\ˆÙ[XÝš[H É\ÉÈ‹š[[˜[YJN‚B_B‚B]Ú[H +ÜÈÚ^™JB‚B^‚BBT\œÙP\™ÜÊ ˜\™Û\Ý �Yˆ +ÈÜË\™Ø�YŠN‚BBXÛÛ[X[™HÑUÐT‘Ê +N‚BBZYˆ +ÛÛ[X[™ ‰ˆÛÛ[X[™ÌJB‚BB^‚BBBZYˆ +ÝšXÛ\ +ÛÛ[X[™ ›]\ÚXÈŠHOH +B‚BBB^‚BBBB[]\ÚXÊÑUÐT‘Ê JKÑUÒS•ÐT‘Ê ŠK]Û +ÑUÐT‘Ê ÊJJN‚BBBBKËÈÐU‘B‚BBBB[][\ݘØ]Ü +Ø]™KOœÙ[XÝ]\ÚXËÛÛ[X[™ ÑUÐT‘Ê JKÑUÐT‘Ê ŠKÑUÐT‘Ê ÊK•S +N‚BBB_B‚BBBY[ÙHYˆ +ÝšXÛ\ +ÛÛ[X[™ ˜[ÝÜÙ[XÝŠHOH +B‚BBB^‚BBBB[ØYÜ^XX›WÛ\Ý +�Yˆ +ÈÜÊN‚BBBB\Ù]ÜØ]™YØ[ÝÜÙ[XÝØ\™Ý[Y[�Ê‚BBBBBXÝ\œ™[�ÜÙ] ‚BBBBBX[ÝÜÙ[XÝØ\™Ü‚BBBBJN‚BBB_B‚BBBY[ÙHYˆ +ÝšXÛ\ +ÛÛ[X[™ ˜˜XÚÙÜ›Ý[™ŠHOH +B‚BBB^‚BBBB[ØYؘXÚÙÜ›Ý[™ +ÑUÐT‘Ê JJN‚BBBBKËÈÐU‘B‚BBBB[][\ݘØ]Ü +Ø]™KOœÙ[XݘXÚÙÜ›Ý[™ ÛÛ[X[™ ÑUÐT‘Ê JK•S +N‚BBB_B‚BBBY[ÙHYˆ +ÝšXÛ\ +ÛÛ[X[™ ›ØYŠHOH +B‚BBB^‚BBBB][\[Ù[Hš[™[Ù[ +ÑUÐT‘Ê JJN‚BBBBZYˆ +][\[Ù[ +B‚BBBB^‚BBBBB[ØYØØXÚYÛ[Ù[ +ÑUÐT‘Ê JKš[[˜[YKÑUÒS•ÐT‘Ê ŠJN‚BBBB_B‚BBBBY[ÙB‚BBBB^‚BBBBB]\]WÛ[Ù[ÛØY›YÊ[\[Ù[ ÑUÒS•ÐT‘Ê ŠJN‚BBBB_B‚BBBBKËÈÐU‘B‚BBBBZYˆ +ØYØÛÝ[�PVÔÑSPÕÓÐQÊB‚BBBB^‚BBBBB[][\ݘØ]Ü +Ø]™KOœÙ[XÝØYÛØYØÛÝ[�KÛÛ[X[™ ÑUÐT‘Ê JKÑUÐT‘Ê ŠK•S +N‚BBBBB[ØYØÛÝ[� +Ê΂BBBB_B‚BBB_B‚BBBY[ÙHYˆ +ÛÛ[X[™ ‰ˆÛÛ[X[™ÌJB‚BBB^‚BBBB\š[�Š�ÛÛ[X[™ É\ÉÈ\È›Ý[™\œÝÛÙ[ˆš[H É\É׈‹ÛÛ[X[™ š[[˜[YJN‚BBB_B‚BB_B‚‚BB\ÜÈ +ÏHÙ]™]Ó[™TÝ\� +�Yˆ +ÈÜÊN‚B_B‚B\Ø]™KOœÙ[XÝØYÛÝ[�HØYØÛÝ[�È ËÈÐU‘H�[X™\ˆÙˆÐQÛÛ[X[™‚B\Ø]™KOœÙ[XÝ›YÈH N‚‚BZYˆ +�YˆOH•S +B‚B^‚BBYœ™YJ�YŠN‚BBX�YˆH•S‚B_B‚_B‚Y[ÙH ËÈÚ]Ý]Ù[XÝ �‚^‚BZYˆ +\×Ùš\œÝÜÙ[XÝ +\ÚÚ\Ù[XÝÌVÌH ‰ˆ\Ù] O››ÜÙ[XÝ +JH ËÈ›ÈÙ[XÝ\ÈÚÚ\Ù[XÝÚ]Ý]˜[Y\‚B^‚BBYY˜][Ù[XÝH NÈ ËțܛX[Ù[XÝ܈ÚÚ\Ù[XÝ Û›ÜÙ[XÝÈ HOH›Ü›X[Ù[XÝ‚B_B‚‚BZYˆ +[›ÜÚ\™JB‚B^‚BBXÜ™Y]ÈHÓÓ•S•QT΂B_B‚BY[ÙH›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚B^‚BBZYˆ +^Y\œÖÚWJB‚BB^‚BBB\^Y\–ÚWK˜Ü™Y]ÈHÓÓ•S•QT΂BB_B‚B_B‚‚BZYˆ +ÚÚ\Ù[XÝÌVÌHÙ] O››ÜÙ[XÝ +B‚B^‚BBY›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚BB^‚BBBZYˆ +\^Y\œÖÚWJB‚BBB^‚BBBBXÛÛ�[�YN‚BBB_B‚BBB\Ý›˜ÜJ^Y\–ÚWK›˜[YKÚÚ\Ù[XÝÚWKPVÓ�SQWÓSŠN‚‚BBBZYˆ +Y˜][Ù[XÝ +B‚BBB^‚BBBB\^Y\–ÚWK›]™\ÈHVQT—ÓU‘T΂BBBBZYˆ +JÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÐÔ‘QU×ÐPÕU‘JJB‚BBBB^‚BBBBBZYˆ +›ÜÚ\™JB‚BBBBB^‚BBBBBBKK\^Y\–ÚWK˜Ü™Y]΂BBBBB_B‚BBBBBY[ÙB‚BBBBB^‚BBBBBBKKXÜ™Y]΂BBBBB_B‚BBBB_B‚BBB_B‚BBBY[ÙB‚BBB^‚BBBB\^Y\–ÚWK›]™\ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]Kœ]™\ÖÚWN‚BBBB\^Y\–ÚWKœØÛÜ™HHØ]™[]™[ØÝ\œ™[�ÜÙ]KœØÛÜ™\ÖÚWN‚BBBBZYˆ +›ÜÚ\™JH^Y\–ÚWK˜Ü™Y]ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]KœÜ™Y]ÖÚWN‚BBBBY[ÙHÜ™Y]ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]K˜Ü™Y]΂BBB_B‚BB_B‚‚BB\ØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÔÑSPÕ‚‚BB\™]\›ˆ N‚B_B‚‚BZYˆ +\Ø]™YÜÙ[XÝÜØÜ™Y[ŠB‚B^‚BBZYˆ +[›ØÚØ™È ‰ˆ›Û�\ÊB‚BB^‚BBBKËÈ™]È[\›˜]]™H˜XÚÙÜ›Ý[™] ‚‚BBBZYˆ +Ý\ÝšÙÜ™ÈOH•S +B‚BBB^‚BBBB\ݘÜJÝš[™ËÝ\ÝšÙÜ™ÊN‚BBBB\ݘØ] +Ýš[™Ë�[›ØÚؙȊN‚BBBB[ØYؘXÚÙÜ›Ý[™ +Ýš[™ÊN‚BBB_B‚BBBY[ÙB‚BBB^‚BBBB[ØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÝ[›ØÚؙȊN‚BBB_B‚BB_B‚BBY[ÙB‚BB^‚BBBKËÈ™]È[\›˜]]™H˜XÚÙÜ›Ý[™] ‚‚BBBZYˆ +Ý\ÝšÙÜ™ÈOH•S +B‚BBB^‚BBBB\ݘÜJÝš[™ËÝ\ÝšÙÜ™ÊN‚BBBB\ݘØ] +Ýš[™ËœÙ[XÝŠN‚BBBB[ØYؘXÚÙÜ›Ý[™ +Ýš[™ÊN‚BBB_B‚BBBY[ÙB‚BBB^‚BBBB[ØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÜÙ[XÝŠN‚BBB_B‚BB_B‚BBZYˆ +[]\ÚXÊ™]KÛ]\ÚXËÛY[�H‹ K +JB‚BB^‚BBB[]\ÚXÊ™]KÛ]\ÚXËÜ™[Z^‹ K +N‚BB_B‚B_B‚_B‚‚Y›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚^‚BZYˆ +^Y\œÖÚWJB‚B^‚BBY^[\VÚWHHÜ]Û™^[\JJN‚BB\^Y\–ÚWKœ^ZÙ^\ÈH ‚BBZYˆ +Y˜][Ù[XÝ +B‚BB^‚BBB\^Y\–ÚWK›]™\ÈHVQT—ÓU‘T΂BBBZYˆ +JÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÐÔ‘QU×ÐPÕU‘JJB‚BBB^‚BBBBZYˆ +›ÜÚ\™JB‚BBBB^‚BBBBBKK\^Y\–ÚWK˜Ü™Y]΂BBBB_B‚BBBBY[ÙB‚BBBB^‚BBBBBKKXÜ™Y]΂BBBB_B‚BBB_B‚BB_B‚BBY[ÙB‚BB^‚BBB\^Y\–ÚWK›]™\ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]Kœ]™\ÖÚWN‚BBB\^Y\–ÚWKœØÛÜ™HHØ]™[]™[ØÝ\œ™[�ÜÙ]KœØÛÜ™\ÖÚWN‚BBBZYˆ +›ÜÚ\™JH^Y\–ÚWK˜Ü™Y]ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]KœÜ™Y]ÖÚWN‚BBBY[ÙHÜ™Y]ÈHØ]™[]™[ØÝ\œ™[�ÜÙ]K˜Ü™Y]΂BB_B‚B_B‚_B‚‚WÝ[YHH ‚‚KËÈÝ^H[ˆÙ[XÝ[Ûˆ[�[\ØØ\H܈^] ‚‚KËÈ‚KËÈ^]H[^Y\œÈ™XYH +Ù[XÝY +H[™^][^H^\™Y ‚‚KËÈ\ØØ\HH\ØØ\HÙ^H™\ÜÙY ‚‚]Ú[H +J^]\ØØ\JJB‚^‚B\^Y\œ×Ø�\ÞHH ‚B\^Y\œ×Ü™XYHH ‚‚BKËÈÛÜ›ÝYÚ^Y\œË‚‚BY›Üˆ +HH ÈHÙ] O›X^^Y\œÎÈJÊÊB‚B^‚BBKËÈÝ\œ™[�^Y\ˆ[™^›ÝY]Ù[XÝY‚BBZYˆ +\™XYVÚWJB‚BB^‚BBBB‚BBBKËÈ\È\ÈÚ\™HÙH™\Ù[�^Y\ˆÙ[XÝ[ۜˈHÙÚXÈ\Èۙ‚BBBKËÈ[™H]HY\ÜÞKÛÈ�XÚÛH\H˜\ÚXØ[KÙHØ[�ÈÜ]Û‚‚BBBKËÈ[ˆ^[\H[�]HÈÙ]Ý\�Y [™]^[\H[�]B‚BBBKËÈ\ÈÚ]^Y\ˆÙY\ÈÛˆHÙ[XÝ[ÛˆØÜ™Y[‹ˆ[ˆÙHÝÚ]Ú‚BBBKËÈ]È[Ù[ ØÛÛÜ‹Ø[š[X][Ûˆ˜\ÙYÛˆHÚ]X][Ûˆ[™^Y\‚‚BBBKËÈ[œ] ‚‚BBBKË‚BBBKËÈ KˆYˆ[ˆ^[\H[�]H^\ÝÈ[™\È^Z[™ÈH˜[œÚ][Ûˆ‚BBBKËÈ[ˆÙK‹‹‚‚BBBKË‚BBBKËÈJHÈ›Ý[™ÈYˆH[š[X][Ûˆ\ۉݚ[š\ÚY ‚‚BBBKË‚BBBKËÈŠHYˆ]TÈš[š\ÚY ‹‹‚‚BBBKË‚BBBKËÈ KH KˆYˆH[š[X][Ûˆ\ÈS’WÔÑSPÕS‹[ˆ^HS’WÔÑSPÕ ‚‚BBBKËÈ‚BBBKËÈ KH ‹ˆYˆ[šX[]Ûˆ\ÈS’WÔÑSPÕÕU [ˆÙHÝÚ]ÚÈ™]È‚BBBKËÈ[Ù[ +Yˆ]˜Z[X›JK‚‚BBBKË‚BBBKËÈ ‹ˆYˆ^Y\ˆ\Û‰Ý^YYY] \ÈÛÛYHÜ™Y]È܈‚BBBKËÈØ[ˆ˜]Èœ›ÛHÜ™Y]ÛÛ[™™\ÜÙY[žHXÝ[Ûˆ�]Û‹‚BBBKËÈ[ˆÙIÛX[Ú]Z\ˆÜ™Y]ÛÛ[™Ü]ÛˆB‚BBBKËÈš\œÝ^[\H +Ù[XÝX›H[Ù[™]šY]ÊKˆ]š[™È[ˆ‚BBBKËÈ^[\HÜ]Û™Y[ÛÈ[È\ÈH^Y\ˆ\ÈÛÛ\]Y‚BBBKËÈ\ÈÝ\ [™ÛÈ] ÜÈÒÈÈ�[ˆXÝ[ۜȜ›ÛH[žHÙˆ‚BBBKËÈHÝ\œË‚‚BBBKË‚BBBKËÈ ËˆYˆH^Y\ˆ™\ÜÙYY�܈šYÚ[œÝXY[™\™IÜ‚BBBKËÈ[ˆ^[\HÜ]Û™Y [ˆÙHš[™H™]š[Ý\ËÛ™^‚BBBKËÈÚ\˜XÝ\ˆ[ˆ[™K[™™XÛÜ™]ÈH˜\šXX›Kˆ[ˆÙB‚BBBKËÈÙYHYˆ^[\H\ÈS’WÔÑSPÕS‹ˆYˆ]Ù\Û‰ÝÙHÝÚ]Ú‚BBBKËÈÈ™]È[Ù[ ˆYˆ]Ù\Ë^HS’WÔÑSPÕ ‚‚BBBKË‚BBBKËÈ ˆYˆH^Y\ˆ™\ÜÙ\È\܈ÝÛ‹ÙH]™H[ˆ^[\H‚BBBKËÈÜ]Û™Y[™ÛÛÝ\œÙ[XÝ\È[˜X›Y [ˆÞXÛHÈB‚BBBKËÈ[Ù[ ÜÈ™]š[Ý\ËÛ™^ÛÛ܈Ù]ÚÚXÙK‚‚BBBKË‚BBBKËÈ KˆYˆH^Y\ˆ™\ÜÙ\È[žHXÝ[Ûˆ�]Ûˆ[™ÙH]™B‚BBBKËÈ[ˆ^[\HÜ]Û™Y [ˆÙHX\šÈH^Y\‰ÜÈ™XYH[^H‚BBBKËÈ›YË[™Ý[[YKˆÙYHH\™[�ÙÚXÈ›ØÚț܈‚BBBKËÈÙ[XÝ[Ûˆ[^H ˆ^]]Z[ˈ\È\ÈH^Y\‚‚BBBKËÈXZÚ[™ÈZ\ˆÙ[XÝ[ÛˆÚÚXÙK‚‚‚BBBKËÈ^[\H^\ÝÈ[™Ù[Xݘ[œÚ][Ûˆ[š[X][Û�‚BBBZYˆ +^[\VÚWH‚BBBBI‰ˆ +^[\VÚWKO˜[š[[�[HOHS’WÔÑSPÕSˆ^[\VÚWKO˜[š[[�[HOHS’WÔÑSPÕÕU +JB‚BBB^‚BBBBKËÈYˆÝ[[š[X][™È[ˆÈ›Ý[™Ëˆ]H˜[œÚ][Ûˆš[š\Ú ‚‚BBBBZYˆ +^[\VÚWKO˜[š[X][™ÊB‚BBBB^‚BBBB_B‚BBBBY[ÙB‚BBBB^‚BBBBBKËȘ[œÚ][ÛˆÈÙ[XÝ[š[X][Û‹‚‚BBBBBZYˆ +^[\VÚWKO˜[š[[�[HOHS’WÔÑSPÕSŠB‚BBBBB^‚BBBBBBY[�ÜÙ]Ø[š[J^[\VÚWKS’WÔÑSPÕ  +N‚BBBBB_B‚‚BBBBBKËȘ[œÚ][Ûˆœ›ÛHÙ[XÝ +^Y\ˆÙ[XÝY[›Ý\ˆ[Ù[ [™B‚BBBBBKËÈÙ[XÝÝ]˜[œÚ][Ûˆ\È›ÝÈš[š\ÚY +Kˆ™\X]ÙˆY� ÜšYÚÙ^H‚BBBBBKËÈÙÚXÈ™[ÝÈ[™›Ø˜X›H™YYÈÛÛœÛÛY][Û‹‚‚BBBBBZYˆ +^[\VÚWKO˜[š[[�[HOHS’WÔÑSPÕÕU ‰ˆ[Ù[Û™]ÖÚWJB‚BBBBB^‚BBBBBBKËÈ\H™]È[Ù[ ‚‚BBBBBBY[�ÜÙ]Û[Ù[ +^[\VÚWK[Ù[Û™]ÖÚWKO›˜[YK +N‚BBBBBB[[Ù[Û™]ÖÚWHH•S‚‚BBBBBBKËÈÛÜH^[\H[Ù[˜[YHÈ^Y\ˆ˜[YH˜\šXX›K‚‚BBBBBB\ݘÜJ^Y\–ÚWK›˜[YK^[\VÚWKO›[Ù[ O›˜[YJN‚‚BBBBBBKËÈYˆÛÛÜœÙ[XÝ\È[˜X›Y[™›ÜØ[YH ˆ\È[˜X›Y ÚÚ\‚BBBBBBKËÈÝ\�]™^]˜ZX[›HÛÛ܈ÞXÛKˆÝ\�Ú\ÙH�\ÝÝ\�‚BBBBBBKËÈÚ]Y˜][ÛÛ܈Ù] + +K‚‚BBBBBBZYˆ +ÛÛÝ\œÙ[XÝ ‰ˆ +Ù] O››ÜØ[YH ˆ ŠJB‚BBBBBB^‚BBBBBBB\^Y\–ÚWK˜ÛÛÝ\›X\H™^ÛÛÝ\›X\Š^[\VÚWKO›[Ù[  LKJN‚BBBBBB_B‚BBBBBBY[ÙB‚BBBBBB^‚BBBBBBB\^Y\–ÚWK˜ÛÛÝ\›X\H ‚BBBBBB_B‚‚BBBBBBKËÈ\HÛÛ܈Ù] ‚‚BBBBBBY[�ÜÙ]ØÛÛÝ\›X\ +^[\VÚWK^Y\–ÚWK˜ÛÛÝ\›X\ +N‚BBBBB_B‚BBBB_B‚BBB_B‚BBBY[ÙHYˆ +\^Y\–ÚWKš\Ü^YY‚BBBBI‰ˆ +›ÜÚ\™HÜ™Y]Ȉ +B‚BBBBI‰ˆ +^Y\–ÚWK›™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠJB‚BBB^‚‚BBBBKËÈ›ÝÈ\È^Y\ˆ\È^YY ‚‚BBBB\^Y\œÖÚWHH^Y\–ÚWKš\Ü^YYH N‚BBBBKËÜš[�ЉY Y Yˆ‹K^Y\–ÚWK›]™\Ë[[YYX]VÚWJN‚‚BBBBKËÈ›ÜÚ\™HYX[œÈXXÚ^Y\ˆ\ÈZ\ˆÝۈܙY]ÛÛ ‚‚BBBBZYˆ +›ÜÚ\™JB‚BBBB^‚BBBBB\^Y\–ÚWK˜Ü™Y]ÈHÓÓ•S•QT΂BBBB_B‚‚BBBBKËÈÜ™Y]ÈÚX]H[™š[š]HÜ™Y]ˈYˆ] ÜÈ›Ý[˜X›Y ‚BBBBKËÈ[ˆYXÝHÜ™Y] ‚‚BBBBZYˆ +JÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÐÔ‘QU×ÐPÕU‘JJB‚BBBB^‚BBBBBZYˆ +›ÜÚ\™JB‚BBBBB^‚BBBBBBKK\^Y\–ÚWK˜Ü™Y]΂BBBBB_B‚BBBBBY[ÙB‚BBBBB^‚BBBBBBKKXÜ™Y]΂BBBBB_B‚BBBB_B‚‚BBBBKËÈÚ]™H^Y\ˆY˜][�[X™\ˆÙˆ]™\ËÜ]Û‚‚BBBBKËÈ^[\H[Ù[[™Ø[˜Ù[HÙ^H›YË‚‚BBBB\^Y\–ÚWK›]™\ÈHVQT—ÓU‘T΂BBBBY^[\VÚWHHÜ]Û™^[\JJN‚BBBB\^Y\–ÚWKœ^ZÙ^\ÈH ‚‚BBBBKËÈ^HÛÝ[™Y™™XÝ ‚‚BBBBZYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\�H +B‚BBBB^‚BBBBB\ÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +N‚BBBB_B‚BBB_B‚BBBY[ÙHYˆ + +^Y\–ÚWK›™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠH ‰ˆ^[\VÚWJH ËÒܘ]\È + KL KLŒJH[Ý™YH˜[žX�]ÛˆˆÛÙHÈ™Y›Ü™HÙˆH›Y� ÜšYÚˆÛÙHÈš^H�YÈ]XZÙ\È›ÈÚ\˜XÝ\ˆÚÜÙ[ˆÚ[ˆ›Ý\™H™\ÜÙYÙÙ]\‚‚BBB^‚BBBBZYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +B‚BBBB^‚BBBBB\ÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +N‚BBBB_B‚BBBBKËÈX^H[ÝHXÚÙYYHB‚BBBBZYˆ +˜[Y[š[J^[\VÚWKS’WÔPÒÊJB‚BBBB^‚BBBBBY[�ÜÙ]Ø[š[J^[\VÚWKS’WÔPÒË +N‚BBBB_B‚BBBBY^[\VÚWKOœÝ[[YHHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ŽÂ‚BBBB\™XYVÚWHH N‚BBB_B‚BBBY[ÙHYˆ +^Y\–ÚWK›™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +H ‰ˆ^[\VÚWJB‚BBB^‚BBBBKËÈÚ]™H^Y\ˆH™YY˜XÚÈÛÝ[™ ‚‚BBBBZYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\�H +B‚BBBB^‚BBBBB\ÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +N‚BBBB_B‚‚BBBBKËÈÙ][Ù[[ˆ\ÙHšYÚ›ÝË‚‚BBBBKËÈ] ÜÈÙ]H™]È[Ù[ ˆY�Ù^HH™]š[Ý\È[Ù[‚BBBBKËÈ[ˆÞXÛKˆšYÚÙ^HH™^ ‚‚BBBBZYˆ + +^Y\–ÚWK›™]ÚÙ^\È ˆ“Q×ÓSÕ‘SQ• +JB‚BBBB^‚BBBBB[[Ù[Û™]ÖÚWHH™]œ^Y\›[Ù[Š^[\VÚWKO›[Ù[ JN‚BBBB_B‚BBBBY[ÙB‚BBBB^‚BBBBB[[Ù[Û™]ÖÚWHH™^^Y\›[Ù[Š^[\VÚWKO›[Ù[ JN‚BBBB_B‚‚BBBBKËÈÈÙH]™HHÙ[XÝÝ]˜[œÚ][Û�ÈYˆÛÈ^H]\™Kˆ‚BBBBKËÈÝ\�Ú\ÙHÝÚ]ÚÈ™]È[Ù[ ˆ‚BBBBZYˆ +˜[Y[š[J^[\VÚWKS’WÔÑSPÕÕU +JB‚BBBB^ÂBBBBBB‚BBBBBY[�ÜÙ]Ø[š[J^[\VÚWKS’WÔÑSPÕÕU  +NÂBBBB‚BBBB_B‚BBBBY[ÙB‚BBBB^‚BBBBBKËÈ\H™]È[Ù[ ‚‚BBBBBY[�ÜÙ]Û[Ù[ +^[\VÚWK[Ù[Û™]ÖÚWKO›˜[YK +N‚BBBBB[[Ù[Û™]ÖÚWHH•S‚‚BBBBBKËÈÛÜH^[\H[Ù[˜[YHÈ^Y\ˆ˜[YH˜\šXX›K‚‚BBBBB\ݘÜJ^Y\–ÚWK›˜[YK^[\VÚWKO›[Ù[ O›˜[YJN‚‚BBBBBKËÈYˆÛÛÜœÙ[XÝ\È[˜X›Y[™›ÜØ[YH ˆ\È[˜X›Y ÚÚ\‚BBBBBKËÈÝ\�]™^]˜ZX[›HÛÛ܈ÞXÛKˆÝ\�Ú\ÙH�\ÝÝ\�‚BBBBBKËÈÚ]Y˜][ÛÛ܈Ù] + +K‚‚BBBBBZYˆ +ÛÛÝ\œÙ[XÝ ‰ˆ +Ù] O››ÜØ[YH ˆ ŠJB‚BBBBB^‚BBBBBB\^Y\–ÚWK˜ÛÛÝ\›X\H™^ÛÛÝ\›X\Š^[\VÚWKO›[Ù[  LKJN‚BBBBB_B‚BBBBBY[ÙB‚BBBBB^‚BBBBBB\^Y\–ÚWK˜ÛÛÝ\›X\H ‚BBBBB_B‚‚BBBBBKËÈ\HÛÛ܈Ù] ‚‚BBBBBY[�ÜÙ]ØÛÛÝ\›X\ +^[\VÚWK^Y\–ÚWK˜ÛÛÝ\›X\ +N‚BBBB_BBBBBB‚BBB_B‚BBBY[ÙHYˆ +^Y\–ÚWK›™]ÚÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓŠH ‰ˆÛÛÝ\œÙ[XÝ ‰ˆ^[\VÚWJB‚BBB^‚BBBB\^Y\–ÚWK˜ÛÛÝ\›X\H + +^Y\–ÚWK›™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +HÈ™^ÛÛÝ\›X\ˆˆ™]˜ÛÛÝ\›X\ŠJ^[\VÚWKO›[Ù[ ^Y\–ÚWK˜ÛÛÝ\›X\ JN‚BBBBY[�ÜÙ]ØÛÛÝ\›X\ +^[\VÚWK^Y\–ÚWK˜ÛÛÝ\›X\ +N‚BBB_B‚BB_B‚BBY[ÙHYˆ +™XYVÚWHOH JB‚BB^‚BBBZYˆ + + +]˜[Y[š[J^[\VÚWKS’WÔPÒÊH^[\VÚWKO›[Ù[]K˜[š[X][Û–ÐS’WÔPÒ×KO›ÛÜ ›[ÙJH ‰ˆÝ[YHˆ^[\VÚWKOœÝ[[YJHY^[\VÚWKO˜[š[X][™ÊB‚BBB^‚BBBB\™XYVÚWHH ŽÂ‚BBBBY^][^HHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY‚BBB_B‚BB_B‚BBY[ÙHYˆ +™XYVÚWHOH ŠB‚BB^‚BBBY›Û�Üš[�ŠÛY[�VÚWVÌ—KÛY[�VÚWVÌ×K  Š”™XYHHŠJN‚BB_B‚‚BBZYˆ +^[\VÚWHOH•S +B‚BB^‚BBB\^Y\œ×Ø�\ÞJÊ΂BB_B‚BBZYˆ +™XYVÚWHOH ŠB‚BB^‚BBB\^Y\œ×Ü™XYJÊ΂BB_B‚B_B‚‚BZYˆ +^Y\œ×Ø�\ÞH ‰ˆ^Y\œ×Ø�\ÞHOH^Y\œ×Ü™XYH ‰ˆ^][^H ‰ˆÝ[YHˆ^][^JB‚B^‚BBY^]H N‚B_B‚B]\]J  +N‚‚BZYˆ +›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÈ\ØØ\WÙ›YÈOH LJH ËÒܘ]\È + Œ L LŒJHYYH™]È™\ØØ\Hˆ›YÈ[ˆHÙ[XÝØÜ™Y[ˆžH\Ú[™ÈH™ÛÝÛXZ[›Y[�Hˆ�[˜Ý[Ûˆ[™H›YÈŒLH‚‚B^‚BBY\ØØ\HH Nˆ\ØØ\WÙ›YÈH ‚B_B‚_B‚‚KËÈ›ÈÛ™Ù\ˆ]HÙ[XÝØÜ™Y[‚‚ZÚ[Ø[ + +N‚\ÛÝ[™ØÛÜÙWÛ]\ÚXÊ +N‚\ØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÔÑSPÕ‚‚\™]\›ˆ +Y\ØØ\JNŸB‚�›ÚY^YØ[YJ[� +œ^Y\œË[œÚYÛ™YÚXÚÜÙ] [�\ÙTØ]™YØ[YJBžÂˆ[�NˆÝ\œ™[�Û]™[H ˆÝ\œ™[�ÜÝYÙHH NˆÝ\œ™[�ÜÙ]HÚXÚÜÙ]ˆ×ÜÙ]Ù[�žH +œÙ]H]™[Ù]È +ÈÝ\œ™[�ÜÙ]ˆ×ÜØ]™[]™[ +œØ]™HHØ]™[]™[ +ÈÝ\œ™[�ÜÙ]ˆ×Û]™[Ù[�žH +›N‚ˆ\ÙTØ]™HH ˆ\ÙTÙ]H LN‚ˆYŠÚXÚÜÙ]�H�[WÙY™šXÝ[Y\ÊBˆˆ™]\›ŽÂˆBˆ ËțܔÚ]ÝÛŠ K’[YØ[Ù]ÚÜÙ[Žˆ[™^ ZH +\™H\™HÛ›H ZHÙ]ÊHH‹ÚXÚÜÙ] �[WÙY™šXÝ[Y\ÊN‚ˆ[Ý×ÜÙXÜ™]ØÚ\œÈHÙ] OšY˜ÛÛ\]NˆVQT—ÓU‘TÈHÙ] O›]™\Έ]\ÚXÛÝ™\›\HÙ] O›]\ÚXÛÝ™\›\ˆ˜YHHÙ] O˜Ý\ݘYNˆÓÓ•S•QTÈHÙ] O˜Ü™Y]ΈXYÚX×Ý\HHÙ] O�\[\ˆYŠVQT—ÓU‘TÈOH +BˆˆVQT—ÓU‘TÈH ÎÈ ËÈY˜][ˆBˆYŠÓÓ•S•QTÈOH +BˆˆÓÓ•S•QTÈH NÈ ËÈY˜][ˆBˆYŠ˜YHOH +Bˆˆ˜YHH �È ËÈY˜][ˆBˆØ[Y\^Y\ˆHÙ] O››ÜØ[YN‚ˆYŠ\ÙTØ]™YØ[YHOH H ‰ˆØ]™KO™›YÊBˆˆY[\Ù] +^Y\‹ Ú^™[ÙŠ +œ^Y\ŠH +ˆ +NˆYŠ[ØYØÜš\š[J +JBˆˆš[�Š•Ø\›š[™Ë˜Z[YÈØYØÜš\Ø]™HWˆŠNˆBˆÝ\œ™[�Û]™[HØ]™KO›]™[ˆÝ\œ™[�ÜÝYÙHHØ]™KOœÝYÙNˆYŠØ]™KO™›YÈOH ŠH ËÈÛ‰ÝÚXÚÈ H܈ ™XÝX\ÙHYˆÙH\ÙHØ]™YØ[YHH›YÈ]\Ý™HŒˆˆ›ÜŠHH ÈHÙ] O›X^^Y\œÎÈJÊÊBˆˆ^Y\–ÚWK›]™\ÈHØ]™KOœ]™\ÖÚWNˆ^Y\–ÚWK˜Ü™Y]ÈHØ]™KOœÜ™Y]ÖÚWNˆ^Y\–ÚWKœØÛÜ™HHØ]™KOœØÛÜ™\ÖÚWNˆ^Y\–ÚWK˜ÛÛÝ\›X\HØ]™KOœÛÛÝ\›X\ÚWNˆ^Y\–ÚWK�ÙX\�[HHØ]™KOœÙX\�[VÚWNˆ^Y\–ÚWKœÜ]ÛšX[HØ]™KOœÜ]ÛšX[ÚWNˆ^Y\–ÚWKœÜ]Û›\HØ]™KOœÜ]Û›\ÚWNˆÝ›˜ÜJ^Y\–ÚWK›˜[YKØ]™KOœ˜[YVÚWKPVÓ�SQWÓSŠNˆBˆÜ™Y]ÈHØ]™KO˜Ü™Y]ΈBˆØYÜ^XX›WÛ\Ý +ˆÙ]ÜØ]™YØ[ÝÜÙ[XÝØ\™Ý[Y[�ÊÝ\œ™[�ÜÙ] +Bˆ +Nˆ ËÜ™\Ù]Ü^XX›WÛ\Ý + JNÈ ËÈY\È™XØ]\ÙH\™IÜÈ›ÈÙ[XÝØÜ™Y[‹[\ܘ\žHÛÛ][Û‚ˆB‚ˆ›ÜØ]™HH N‚ˆ ËÈš^Ø]™H[ˆ[™^\Ý[�]™[ˆYˆ +Ý\œ™[�Û]™[�HÙ] O›�[[]™[È +BˆˆÝ\œ™[�Û]™[HÙ] O›�[[]™[ËLNˆB‚ˆHHÙ] O›]™[Ü™\ˆ +ÈÝ\œ™[�Û]™[ˆÙ] O››ÜÙ[XÝHKO››ÜÙ[X݈Yˆ +Ø]™KOœÙ[XÝÚÚ\Ù[XÝÌJHHHØYÜÚÚ\Ù[XÝ +Ø]™KOœÙ[XÝÚÚ\Ù[XÝ Ù] +NÈ ËÈÐQÚÚ\Ù[X݈›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYŠKOœÚÚ\Ù[XÝÚWJBˆˆÝ˜ÜJÚÚ\Ù[XÝÚWKKOœÚÚ\Ù[XÝÚWJNˆBˆ[ÙBˆˆÚÚ\Ù[XÝÚWVÌHH ˆBˆB‚ˆYŠ +\ÙTØ]™YØ[YHOH H ‰ˆØ]™KO™›YÈOH ŠH\ÙTØ]™YØ[YHOH ˆÙ[XÝ^Y\Š^Y\œË•S \ÙTØ]™YØ[YJJH ËÈYˆØ]™H›YÈ\È ˆÛ‰ÝÙ[XÝ^Y\‚ˆˆÚ[JÝ\œ™[�Û]™[Ù] O›�[[]™[ÊBˆˆYŠœ˜[˜ÚÛ˜[YVÌJH ËÈœ˜[˜ÚÚXÚÚ[™Âˆˆ ËØÝ\œ™[�ÜÝYÙHH NÈ ËÚ�[\ �[\ ‹‹ˆ\š\ÈÙHۉݙYYÈ™\Ù]] [Ù\œÈÚÝ[ZÙHØ\™HÙˆ] ‚ˆ›ÜŠHH ÈHÙ] O›�[[]™[ÎÈJÊÊBˆˆYŠÙ] O›]™[Ü™\–ÚWK˜œ˜[˜Ú˜[YH ‰ˆÝšXÛ\ +Ù] O›]™[Ü™\–ÚWK˜œ˜[˜Ú˜[YKœ˜[˜ÚÛ˜[YJHOH +BˆˆÝ\œ™[�Û]™[HNˆœ™XZΈBˆ ËÚYŠ]™[Ü™\–ÝÚXÚÜÙ]VÚWKO™ÛÛ™^OLJH +ÊØÝ\œ™[�ÜÝYÙNÈÖ ˆÛÛ[Y[�Y\È[™HÝ] ˆÙY[\ÈÈ™HØ]\ÙHÙˆ[˜XÝ\˜]HÝYÙHÈÛÛ\]HY\ÜØYÙK‚ˆBˆœ˜[˜ÚÛ˜[YVÌHH ËËÈÛX\ˆ\ÛÈÙHÛÛ‰ÝÝXÚÈ\™BˆBˆHHÙ] O›]™[Ü™\ˆ +ÈÝ\œ™[�Û]™[ˆVQT—ÓRS—ÖˆHKOž—ØÛÛÜ™ÖÌNˆVQT—ÓPVÖˆHKOž—ØÛÛÜ™ÖÌWNˆ‘ÒRQÒHKOž—ØÛÛÜ™ÖÌ—N‚ˆYŠKO�\HOHWÕTWÐÕUÔÐÑS‘JBˆˆ^\ØÙ[™JKO™š[[˜[YJNˆBˆ[ÙHYŠKO�\HOHWÕTWÔÑSPÕÔÐÔ‘QSŠBˆˆY[\Ù] +Ø]™KOœÙ[XÝÚÚ\Ù[XÝ Ú^™[ÙŠØ]™KOœÙ[XÝÚÚ\Ù[XÝ +JNÈ ËÈ‘TÑUÚÚ\Ù[X݈Ù] O››ÜÙ[XÝH ˆ›ÜŠHH ÈHÙ] O›X^^Y\œÎÈJÊÊH ËÈ™\Ù]ÚÚ\Ù[X݈ˆYŠKOœÚÚ\Ù[XÝÚWJBˆˆÚÚ\Ù[XÝÚWVÌHH ˆBˆBˆ›ÜŠHH ÈHÙ] O›X^^Y\œÈÈJÊÊBˆˆ^Y\œÖÚWHH +^Y\–ÚWK›]™\Ȉ +NˆBˆYŠÙ[XÝ^Y\Š^Y\œËKO™š[[˜[YK\ÙTØ]™YØ[YJHOH +Bˆˆœ™XZΈBˆBˆ[ÙHYŠKO�\HOHWÕTWÔÒÒTÔÑSPÕ +BˆˆÙ] O››ÜÙ[XÝHKO››ÜÙ[X݈›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYŠKOœÚÚ\Ù[XÝÚWJBˆˆÝ˜ÜJÚÚ\Ù[XÝÚWKKOœÚÚ\Ù[XÝÚWJNˆBˆ[ÙBˆˆÚÚ\Ù[XÝÚWVÌHH ˆBˆBˆØ]™WÜÚÚ\Ù[XÝ +Ø]™KOœÙ[XÝÚÚ\Ù[XÝ ÚÚ\Ù[XÝ +NÈ ËÈÈÐU‘H’SBˆÙ[XÝ^Y\Š^Y\œË•S \ÙTØ]™YØ[YJNÈ ËÈ™K\Ù[XÝH^Y\‚ˆBˆ[ÙHYŠ\^[]™[ +KO™š[[˜[YJJBˆˆ[�[ÜÛ]™\×Þ™\›ÈH ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆYˆ +^Y\–ÚWK›]™\ÈH +H +ÊØ[ÜÛ]™\×Þ™\›ÎˆBˆ[ÜÛ]™\×Þ™\›ÈH +[ÜÛ]™\×Þ™\›È�HPVÔVQT”ÊHÈ Hˆ ‚ˆ ËÚYŠ +^Y\–ÌK›]™\ÈH  ‰ˆ^Y\–ÌWK›]™\ÈH  ‰ˆ^Y\–Ì—K›]™\ÈH  ‰ˆ^Y\–Ì×K›]™\ÈH +H +BˆYŠ[ÜÛ]™\×Þ™\›ÊBˆˆYŠ +\Ù] O››ÜÚÝÙØ[Y[Ý™\ˆ ‰ˆJÛÝ×ÛXZ[›Y[�WÙ›YÉŒŠJH +BˆˆØ[Y[Ý™\Š +NˆBˆYŠ\Ù] O››ÜÚÝÚÙˆ ‰ˆJÛÝ×ÛXZ[›Y[�WÙ›YÉ� +JBˆˆ[˜[YJ JNˆBˆ›ÜŠHH ÈHÙ] O›X^^Y\œÎÈJÊÊBˆˆ^Y\–ÚWKš\Ü^YYH ˆ^Y\–ÚWK�ÙX\�[HH ˆBˆBˆœ™XZΈBˆYŠKO™ÛÛ™^OH JBˆˆYˆ +\Ù] O››ÜÚÝØÛÛ\]JHÚÝØÛÛ\]JÝ\œ™[�ÜÝYÙJNˆ›ÜŠHH ÈHÙ] O›X^^Y\œÎÈJÊÊBˆˆ^Y\–ÚWKœÜ]ÛšX[H ˆ^Y\–ÚWKœÜ]Û›\H ˆBˆ +ÊØÝ\œ™[�ÜÝYÙNˆØ]™KOœÝYÙHHÝ\œ™[�ÜÝYÙNˆBˆÝ\œ™[�Û]™[ +ÊΈHHÙ] O›]™[Ü™\ˆ +ÈÝ\œ™[�Û]™[ˆØ]™KO›]™[HÝ\œ™[�Û]™[ˆ ËÌŒ ËL‹L� ÛÛ™^H ‹[™Ø[YBˆYŠ +H H JKO™ÛÛ™^OH ŠBˆˆÝ\œ™[�Û]™[HÙ] O›�[[]™[ΈBˆYŠ\ÙTØ]™JBˆˆÛÝÈ[™Ø[YNÈ ËÜ]ZXÚÈ^]Ú]Ý]Ø]š[™Ë›ÜˆØÜš\ØYØ[YHÙÚXˆBˆKËÝÚ[B‚ˆYŠÝ\œ™[�Û]™[�HÙ] O›�[[]™[ÊBˆˆ Ê‚ˆܘ]\È + KLŒ � +H™\Ù]]™[ ÜÝYÙH˜[Y\ÈÚ[ˆHØ[YH\Èš[š\ÚY™Y›Ü™HØ]š[™È] ‚ˆ]Ú[]]ÛX]XØ[H\˜\ÙHHÝ\œ™[�Ø[YH›ÙÜ™\ÜÈ�]Û›HY�\ˆH[™[™Ë‚ˆÝÙ]™\‹]Ú[XZ[�Z[ˆH�[Y\רÛÛ\]Yˆ[�XÝ ‚ˆÚ]Ý]\Èš^H^Y\ˆØ[ˆ[˜Ü™X\ÙHH�[Y\רÛÛ\]Yˆ[™š[š][HžBˆ�\Ýš[š\Ú[™ÈHØ[YHÛ˜ÙH[™ØY[™ÈH[™[™È\™XÝHÝÈX[žH[Y\ÈHØ[� ‚ˆ +‹Âˆ›Û�\È +ÏHØ]™KO�[Y\רÛÛ\]Y +ÊΈÝ\œ™[�Û]™[H ˆÝ\œ™[�ÜÝYÙHH NˆØ]™KO›]™[HÝ\œ™[�Û]™[ˆØ]™KOœÝYÙHHÝ\œ™[�ÜÝYÙNˆØ]™QØ[YQš[J +NˆYŠ[›Ù˜Y[Ý] +Bˆˆ˜YWÛÝ] +  +NˆBˆYŠ\Ù] O››ÜÚÝÚÙŠBˆˆ[˜[YJ JNˆBˆBˆB‚™[™Ø[YN‚ˆ ËÈÛX\ˆÛؘ[ØÜš\˜\šX[�\݈œ˜[˜ÚÛ˜[YVÌHH ˆÛÝ[™ØÛÜÙWÛ]\ÚXÊ +NŸB‚š[�Y[�WÙY™šXÝ[J +BžÂˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�X^\Ü^HH Nˆ[�K‹ˆ ËÙ›Ø]ÛY\ˆH ˆ[�˜\ž ˜\žK˜\�˘\šˆ×Ù˜]ÛY]Ù˜]ÛY]ÙHZ[›Y]Ùˆ˜]ÛY]Ù ˜[HH“S‘ÓSÑWÐSN‚ˆ˜\žHšY[Û[Ù\Ëš™\È È Nˆ˜\žHHÛ[™^J  +H H ŽÂˆ˜\�ÈHšY[Û[Ù\Ëš™\È +ˆ È È Nˆ˜\šH H +ˆ +›Û�ZYÚ + +H +È JH +È ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—Ó‘U×ÑÐSQWÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆØYØ[YQš[J +N‚ˆÚ[J\]Z] +BˆˆYŠ�[WÙY™šXÝ[Y\Ȉ JBˆˆÛY[�]^J ‹ L‹ Š‘Ø[YH[ÙHŠJNˆH +Ù[XÝ܈ H +Ù[XÝ܈OH�[WÙY™šXÝ[Y\ÊJH ÈX^\Ü^H +ˆX^\Ü^Nˆ›ÜŠˆH HHÈHX^\Ü^H +È ‰ˆH�[WÙY™šXÝ[Y\ÎÈŠÊËJÊÊBˆˆYŠˆX^\Ü^JBˆˆ ËÈܘ]\È + L LŒ ŒJHYY˜[œÛ][Ûˆ™X]\™HÈHœÙ]ˆ˜[YBˆ ËÈ]Ú[Ù]HœÙ]ˆ˜[YH[ˆH›]™[Ë�ˆš[H[™˜[œÛ]H]ˆ ËÈ[ÝH™YYÈYH™]È›\ÙÚY Û\ÙÜ݈ˆ[œÝ[˜ÙH[ˆ[Ý\ˆ�˜[œÛ][Û‹�ˆš[H[™]ˆ ËÈHØ[YH˜[Y\È\È\ÙYžH[]™[Ù]ˆYŠ›Û�\È�H]™[Ù]ÖÚWKšY˜ÛÛ\]JBˆˆÛY[�]^J +Ù[XÝ܈OHJK‹ ‰\È‹Š]™[Ù]ÖÚWK›˜[YJJNˆBˆ[ÙBˆˆYŠ]™[Ù]ÖÚWKšY˜ÛÛ\]Hˆ JBˆˆÛY[�]^J +Ù[XÝ܈OHJK‹ Љ\È Hš[š\ÚØ[YH ZH[Y\ÈÈ[“ØÚÈŠKŠ]™[Ù]ÖÚWK›˜[YJK]™[Ù]ÖÚWKšY˜ÛÛ\]JNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OHJK‹ Љ\È Hš[š\ÚØ[YHÈ[“ØÚÈŠKŠ]™[Ù]ÖÚWK›˜[YJJNˆBˆBˆBˆ[ÙBˆˆœ™XZΈBˆBˆÛY[�]^J +Ù[XÝ܈OHJK ‹ Š�˜XÚÈŠJN‚ˆ ËÙ˜]ÈHØÜ›Û˜\‚ˆYŠ�[WÙY™šXÝ[Y\ȈX^\Ü^JBˆˆÜš]\WØYØ›Þ +˜\ž ˜\žK˜\�˘\š  ÛÛÜ—Ø›XÚË ™˜]ÛY]Ù +NÈ ËÛÝ]\˜›ÞˆÜš]\WØYÛ[™J˜\ž ˜\žK˜\ž +È ˜\žK KÛÛÜ—ÝÚ]K•S +NˆÜš]\WØYÛ[™J˜\ž ˜\žK˜\ž ˜\žH +Ș\š  KÛÛÜ—ÝÚ]K•S +NˆÜš]\WØYÛ[™J˜\ž +È ˜\žK˜\ž +È ˜\žH +Ș\š  KÛÛÜ—ÝÚ]K•S +NˆÜš]\WØYÛ[™J˜\ž ˜\žH +Ș\š ˜\ž +È ˜\žH +Ș\š  KÛÛÜ—ÝÚ]K•S +NˆÜš]\WØYØ›Þ +˜\ž +È K˜\žH +ÈÙ[XÝ܈ +ˆ +˜\š H ÊH È�[WÙY™šXÝ[Y\Ë Ë Ë ‹ÛÛÜ—ÝÚ]K•S +NÈ ËÜÛY\‚ˆBˆB‚ˆ\]J  +N‚ˆYŠ�[WÙY™šXÝ[Y\ÈOH JH ËÈÖ ˆ[ÙÈÚ]Û›HÛ™HÙ]Ú[]]ÈØY]Y™šXÝ[K‚ˆˆYŠÙ[XÝ܈OH�[WÙY™šXÝ[Y\ÊBˆˆ]Z]H NˆBˆ[ÙHYŠ›Û�\È�H]™[Ù]ÖÜÙ[XÝÜ—KšY˜ÛÛ\]JBˆˆØ]™\ÛÝHÙ[XÝ܎ˆÝ›˜ÜJØ]™[]™[ÜØ]™\ÛÝK™˜[YK]™[Ù]ÖÜØ]™\ÛÝK›˜[YKPVÓ�SQWÓSˆ H JNˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—Ó‘U×ÑÐSQWÓQS•Nˆ™]\›ˆØ]™\Û݈BˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H�[WÙY™šXÝ[Y\ΈBˆYŠÙ[XÝ܈ˆ�[WÙY™šXÝ[Y\ÊBˆˆÙ[XÝ܈H ˆBˆ ËÚYŠÙ[XÝÜ��[WÙY™šXÝ[Y\ÊHÛY\ˆHÙ[XÝ܈ +ˆ �N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠBˆ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆYŠÙ[XÝ܈OH�[WÙY™šXÝ[Y\ÊBˆˆ]Z]H NˆBˆ[ÙHYŠ›Û�\È�H]™[Ù]ÖÜÙ[XÝÜ—KšY˜ÛÛ\]JBˆˆØ]™\ÛÝHÙ[XÝ܎ˆÝ›˜ÜJØ]™[]™[ÜØ]™\ÛÝK™˜[YK]™[Ù]ÖÜØ]™\ÛÝK›˜[YKPVÓ�SQWÓSˆ H JNˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—Ó‘U×ÑÐSQWÓQS•Nˆ™]\›ˆØ]™\Û݈BˆBˆBˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—Ó‘U×ÑÐSQWÓQS•Nˆ™]\›ˆ LNŸB‚š[�ØYÜØ]™YÙØ[YJ +BžÂˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�Ø]™YÝ]\ÈH ˆÚ\ˆ˜[YVÓPVЕQ‘‘T—ÓS—HHȈŸNˆ[�ÛÛ HH N ÛÛ ˆH ŽÂ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÓÐQÑÐSQWÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆYŠ +Ø]™YÝ]\ÈHØYØ[YQš[J +JJBˆˆÙ]ZÓ˜[YJ˜[YK +NˆBˆ›ÜŠØ]™\ÛÝH ÈØ]™\ÛÝ�[WÙY™šXÝ[Y\ÎÈØ]™\ÛÝ +ÊÊHYŠØ]™[]™[ÜØ]™\ÛÝK™›YÈ ‰ˆØ]™[]™[ÜØ]™\ÛÝK›]™[ +Bˆˆœ™XZΈB‚ˆÚ[J\]Z] +BˆˆYŠØ]™\ÛÝ�H�[WÙY™šXÝ[Y\ÊH ËțݛÝ[™ˆˆÛY[�]^J ‹ M  Š“ØYØ[YHŠJNˆÛY[�]^ + ÛÛ K L‹Š”Ø]™Yš[NˆŠJNˆÛY[�]^ + ÛÛ ‹ L‹Š“›Ý›Ý[™HŠJNˆÛY[�]^J K ‹ Š�˜XÚÈŠJN‚ˆ Ê‚ˆܘ]\È + KLŒ � +HZ[›Üˆš^[ˆHÙ[XÝ܈�[X™\ˆYˆ›ÈØ]™H\È›Ý[™ ‚ˆ\™IÜÈ›ÈÙ[XÝ܈Œˆˆ[ˆ\ÈY[�KÛ›H  +ØY +H܈ H +˜XÚÊK‚ˆ +‹ÂˆÙ[XÝ܈H NˆBˆ[ÙBˆˆÛY[�]^J ‹ M  Š“ØYØ[YHŠJNˆÛY[�]^ + ÛÛ K L‹Š”Ø]™Yš[NˆŠJNˆYŠØ]™YÝ]\ÊBˆˆÛY[�]^ + ÛÛ ‹ L‹‰\È‹˜[YJNˆBˆ[ÙBˆˆÛY[�]^ + ÛÛ ‹ L‹Š“›Ý›Ý[™HŠJNˆB‚ˆYŠØ]™YÝ]\ÊBˆˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K LKŠ“[ÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ LK‰\È‹Ø]™[]™[ÜØ]™\ÛÝK™˜[YJNˆÛY[�]^ + ÛÛ K Š”ÝYÙNˆŠJNˆÛY[�]^ + ÛÛ ‹ ‰Y‹Ø]™[]™[ÜØ]™\ÛÝKœÝYÙJNˆÛY[�]^ + ÛÛ K KŠ“]™[ˆŠJNˆÛY[�]^ + ÛÛ ‹ K‰Y‹Ø]™[]™[ÜØ]™\ÛÝK›]™[ +NˆÛY[�]^ + ÛÛ K ‹Š�Ü™Y]ΈŠJN‚ˆYŠ›ÜÚ\™J^ˆÛY[�]^ + ÛÛ ‹ ‹‰Y ÉY ÉY ÉY‹ˆØ]™[]™[ÜØ]™\ÛÝKœÜ™Y]ÖÌKˆØ]™[]™[ÜØ]™\ÛÝKœÜ™Y]ÖÌWKØ]™[]™[ÜØ]™\ÛÝKœÜ™Y]ÖÌ—KˆØ]™[]™[ÜØ]™\ÛÝKœÜ™Y]ÖÌ×JNˆH[ÙHˆÛY[�]^ + ÛÛ ‹ ‹‰Y‹Ø]™[]™[ÜØ]™\ÛÝK˜Ü™Y]ÊNˆB‚ˆÛY[�]^ + ÛÛ K ËŠ”^Y\ˆ]™\ΈŠJNˆÛY[�]^ + ÛÛ ‹ ˉY ÉY ÉY ÉY‹ˆØ]™[]™[ÜØ]™\ÛÝKœ]™\ÖÌKˆØ]™[]™[ÜØ]™\ÛÝKœ]™\ÖÌWKØ]™[]™[ÜØ]™\ÛÝKœ]™\ÖÌ—KˆØ]™[]™[ÜØ]™\ÛÝKœ]™\ÖÌ×JNˆBˆÛY[�]^J +Ù[XÝ܈OH JK ‹ Š�˜XÚÈŠJNˆBˆ\]J  +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠÙ[XÝ܈OH  ‰ˆ +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘SQ• +JBˆˆÚ[J JBˆˆ K\Ø]™\Û݈YŠØ]™\ÛÝ +BˆˆØ]™\ÛÝH�[WÙY™šXÝ[Y\È H NˆBˆYŠØ]™[]™[ÜØ]™\ÛÝK™›YÈ ‰ˆØ]™[]™[ÜØ]™\ÛÝK›]™[ +Bˆˆœ™XZΈBˆBˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠÙ[XÝ܈OH  ‰ˆ +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +JBˆˆÚ[J JBˆˆ +ÊÜØ]™\Û݈YŠØ]™\Û݈�[WÙY™šXÝ[Y\È H JBˆˆØ]™\ÛÝH ˆBˆYŠØ]™[]™[ÜØ]™\ÛÝK™›YÈ ‰ˆØ]™[]™[ÜØ]™\ÛÝK›]™[ +Bˆˆœ™XZΈBˆBˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠØ]™YÝ]\ÊBˆˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H NˆBˆYŠÙ[XÝ܈ˆ JBˆˆÙ[XÝ܈H ˆBˆBˆ[ÙBˆˆÙ[XÝ܈H NˆB‚ˆYŠ +›Ý™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠJBˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆ™]\›ˆØ]™\Û݈œ™XZΈØ\ÙH N‚ˆ]Z]H Nˆœ™XZΈBˆBˆBˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÓÐQÑÐSQWÓQS•Nˆ™]\›ˆ LNŸB‚š[�ÚÛÜÙWÛ[ÙJ[� +œ^Y\œÊBžÂˆ[�]Z]H ˆ[�™[˜XÚÈH ˆ[�Ù[XÝ܈H ˆ[�Ý]\ÈH ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÑÐSQWÔÕT•ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆÚ[J\]Z] +BˆˆÛY[�]^J ‹ K Š�ÚÛÜÙH[ÙHŠJNˆÛY[�]^J +Ù[XÝ܈OH +K Ë Š“™]ÈØ[YHŠJNˆÛY[�]^J +Ù[XÝ܈OH JK  Š“ØYØ[YHŠJNˆÛY[�]^J +Ù[XÝ܈OH ŠK ‹ Š�˜XÚÈŠJN‚ˆ\]J  +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H ŽÂˆBˆYŠÙ[XÝ܈ˆ ŠBˆˆÙ[XÝ܈H ˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠBˆˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆÝ]\ÈHY[�WÙY™šXÝ[J +NˆYŠÝ]\ÈOH LJBˆˆ^YØ[YJ^Y\œËÝ]\Ë +Nˆ™[˜XÚÈH Nˆ]Z]H NˆBˆœ™XZΈØ\ÙH N‚ˆÝ]\ÈHØYÜØ]™YÙØ[YJ +NˆYŠÝ]\ÈOH LJBˆˆ^YØ[YJ^Y\œËÝ]\Ë JNˆ™[˜XÚÈH Nˆ]Z]H NˆBˆœ™XZΈY˜][‚ˆ]Z]H Nˆœ™XZΈBˆBˆBˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÑÐSQWÔÕT•ÓQS•Nˆ™]\›ˆ™[˜XÚΟB‚�›ÚY\›WÝšY[Û[Ù\Ê +BžÂˆšY[Û[Ù\Ëš™\ÈH ˆšY[Û[Ù\Ë�”™\ÈH ˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆYŠÝ\ÝØÙ[™\ÈOH•S +Bˆˆœ™YJÝ\ÝØÙ[™\ÊNˆBˆÝ\ÝØÙ[™\ÈH•SˆYŠÝ\ÝšÙÜ™ÈOH•S +Bˆˆœ™YJÝ\ÝšÙÜ™ÊNˆBˆÝ\ÝšÙÜ™ÈH•SˆYŠÝ\Ý]™[ÈOH•S +Bˆˆœ™YJÝ\Ý]™[ÊNˆBˆÝ\Ý]™[ÈH•SˆYŠÝ\Ý[Ù[ÈOH•S +Bˆˆœ™YJÝ\Ý[Ù[ÊNˆBˆÝ\Ý[Ù[ÈH•SŸB‚‹ËÈØYšY[È[ÙHœ›ÛHš[B�›ÚY[š]ÝšY[Û[Ù\Ê[�ÙÊBžÂˆÚ\ˆ +™š[[˜[YHH™]KÝšY[Ë�ŽÂˆ[�\ˆ™Y™—ÝÜË[ŽÂˆÚ^™WÝÚ^™NˆÚ\ˆ +˜�YˆH•SˆÚ\ˆ +˜ÛÛ[X[™H•SˆÚ\ˆ +�˜[YHH•S  +�˜[YLŽÂˆ\™Ó\Ý\™Û\݈Ú\ˆ\™Ø�Y–ÓPVÐT‘×ÓSˆ +È WHHˆŽÂ‚ˆ Ë‚ˆYŠÙÊBˆˆš[�Š’[š]X[^š[™ÈšY[Ë‹‹‹‹‹‹‹‹‹‹‹—ˆŠNˆB‚ˆ ËÈ\ÙH[ˆ[\›˜]]™HšY[Ë�Yˆ\™H\ÈÛ™KˆÛÛYHÙˆ\ÙH\™HۙȚ[[˜[Y\ÎÈÜ™X]H[Ý\ˆRÜÈÚ]›ÜœZÈ[™[ÝIÛ™Hš[™K‚ˆÙYš[™HžYš[J +HYŠ +\[Ü[œXÚÙš[J XÚÙš[JJHOKLJHÈÛÜÙ\XÚÙš[J\ +NÈš[[˜[YOVÈÛÝÈ™XYš[NÈBˆÚYˆÒSˆS•VˆžYš[J™]KÝšY[ÜË�ŠNˆÙ[™Y‚ˆÝ[™YˆžYš[B‚œ™XYš[N‚ˆ ËÈ™XYš[BˆYŠ�Y™™\—ÜZÙš[Jš[[˜[YK ˜�Y‹ œÚ^™JHOH JBˆˆšY[Ó[ÙHH ˆš[�ЉÉ\ÉțݛÝ[™ —ˆ‹š[[˜[YJNˆÛÝÈ’QSÓSÑTΈB‚ˆš[�Š”™XY[™ÈšY[ÈÙ][™ÜÈœ›ÛH É\ÉË—ˆ‹š[[˜[YJN‚ˆ ËÈ›ÝÈ[�\œ™]HÛÛ�[�ÈÙˆ�Yˆ[™HžH[™BˆÜÈH ˆÚ[JÜÈÚ^™JBˆˆ\œÙP\™ÜÊ ˜\™Û\Ý �Yˆ +ÈÜË\™Ø�YŠNˆÛÛ[X[™HÑUÐT‘Ê +N‚ˆYŠÛÛ[X[™ ‰ˆÛÛ[X[™ÌJBˆˆYŠÝšXÛ\ +ÛÛ[X[™ �šY[ÈŠHOH +Bˆˆ˜[YHHÑUÐT‘Ê JNˆYŠ +˜[YLˆHݘڊ˜[YK Þ ÊJJBˆˆšY[Û[Ù\Ëš™\ÈH]ÚJ˜[YJNˆšY[Û[Ù\Ë�”™\ÈH]ÚJ˜[YLˆ +È JNˆšY[Ó[ÙHH �MNˆBˆ[ÙBˆˆšY[Ó[ÙHHÑUÒS•ÐT‘Ê JNˆBˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ œØÙ[™\ÈŠHOH +Bˆˆ[ˆHÝ›[ŠÑUÐT‘Ê JJNˆÝ\ÝØÙ[™\ÈHX[ØÊ[ˆ +È JNˆÝ˜ÜJÝ\ÝØÙ[™\ËÑUÐT‘Ê JJNˆÝ\ÝØÙ[™\ÖÛ[—HH ˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ ˜˜XÚÙÜ›Ý[™ÈŠHOH +Bˆˆ[ˆHÝ›[ŠÑUÐT‘Ê JJNˆÝ\ÝšÙÜ™ÈHX[ØÊ[ˆ +È JNˆÝ˜ÜJÝ\ÝšÙÜ™ËÑUÐT‘Ê JJNˆÝ\ÝšÙÜ™ÖÛ[—HH ˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ ›]™[ÈŠHOH +Bˆˆ[ˆHÝ›[ŠÑUÐT‘Ê JJNˆÝ\Ý]™[ÈHX[ØÊ[ˆ +È JNˆÝ˜ÜJÝ\Ý]™[ËÑUÐT‘Ê JJNˆÝ\Ý]™[ÖÛ[—HH ˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ ›[Ù[ÈŠHOH +Bˆˆ[ˆHÝ›[ŠÑUÐT‘Ê JJNˆÝ\Ý[Ù[ÈHX[ØÊ[ˆ +È JNˆÝ˜ÜJÝ\Ý[Ù[ËÑUÐT‘Ê JJNˆÝ\Ý[Ù[ÖÛ[—HH ˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ ˜ÛÛÝ\™\ŠHOH +Bˆˆš[�Š—�ÛÛÜ™\\È›ÝÝ\Ü�Y[ž[[Ü™Kˆ[[Ù[\È\™H\Ü^YYÚ]H ̘š]ÛÛ܈ØÜ™Y[‹——ˆŠNˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ ™›Ü˜Ù[[ÙHŠHOH +HßBˆ[ÙHYŠÛÛ[X[™ ‰ˆÛÛ[X[™ÌJBˆˆš[�Š�ÛÛ[X[™ É\ÉÈ›Ý[™\œÝÛÙ[ˆš[H É\ÉÈWˆ‹ÛÛ[X[™ š[[˜[YJNˆBˆBˆ ËÈÛÈÈ™^[™BˆÜÈ +ÏHÙ]™]Ó[™TÝ\� +�Yˆ +ÈÜÊNˆB‚ˆYŠ�YˆOH•S +Bˆˆœ™YJ�YŠNˆ�YˆH•SˆB‚•’QSÓSÑT΂ˆšY[Û[Ù\Ë›[ÙHHšY[Ó[ÙNˆšY[Û[Ù\Ë™š[\ˆHØ]™Y]KœÝÙš[\ŽÂˆÝÚ]Ú +šY[Ó[ÙJBˆˆ ËÈ ÌŒ �  HU‘ÐBˆØ\ÙH ‚ˆšY[Û[Ù\Ëš™\ÈH ÌŒˆšY[Û[Ù\Ë�”™\ÈH � ˆšY[Û[Ù\ËšØØ[HH NˆšY[Û[Ù\Ë�”ØØ[HH NˆšY[Û[Ù\ËšÚY�H ˆšY[Û[Ù\Ë�”ÚY�H ˆšY[Û[Ù\˙ٙœÙ]H ŒÌNˆVQT—ÓRS—ÖˆH MŒˆVQT—ÓPVÖˆH ŒÌŽÂˆ‘ÒRQÒH MŒˆœ™XZ΂ˆ ËÈ   �̈ HÔU‘ÐBˆØ\ÙH N‚ˆšY[Û[Ù\Ëš™\ÈH  ˆšY[Û[Ù\Ë�”™\ÈH �̎ˆšY[Û[Ù\ËšØØ[HH +›Ø] +LK�NˆšY[Û[Ù\Ë�”ØØ[HH +›Ø] +LKŒLΈšY[Û[Ù\ËšÚY�H ˆšY[Û[Ù\Ë�”ÚY�H ŒˆšY[Û[Ù\˙ٙœÙ]H �ŒÎˆVQT—ÓRS—ÖˆH N ŽÂˆVQT—ÓPVÖˆH ��ˆ‘ÒRQÒH N ŽÂˆœ™XZ΂ˆ ËÈ �    H‘ÐBˆØ\ÙH Ž‚ˆšY[Û[Ù\Ëš™\ÈH � ˆšY[Û[Ù\Ë�”™\ÈH  ˆšY[Û[Ù\ËšØØ[HH ŽÂˆšY[Û[Ù\Ë�”ØØ[HH ŽÂˆšY[Û[Ù\ËšÚY�H MŒˆšY[Û[Ù\Ë�”ÚY�H ÍNˆšY[Û[Ù\˙ٙœÙ]H �ˆVQT—ÓRS—ÖˆH ÌŒNˆVQT—ÓPVÖˆH �Nˆ‘ÒRQÒH ÌŒNˆœ™XZ΂ˆ ËÈ ÌŒ   H‘ˆØ\ÙH ΂ˆšY[Û[Ù\Ëš™\ÈH ÌŒˆšY[Û[Ù\Ë�”™\ÈH  ˆšY[Û[Ù\ËšØØ[HH ‹Œ�NˆšY[Û[Ù\Ë�”ØØ[HH ŽÂˆšY[Û[Ù\ËšÚY�H Œ ˆšY[Û[Ù\Ë�”ÚY�H ÍNˆšY[Û[Ù\˙ٙœÙ]H �ˆVQT—ÓRS—ÖˆH ÌŒNˆVQT—ÓPVÖˆH �Nˆ‘ÒRQÒH ÌŒNˆœ™XZ΂ˆ ËÈ    HÕ‘ÐBˆØ\ÙH ‚ˆšY[Û[Ù\Ëš™\ÈH ˆšY[Û[Ù\Ë�”™\ÈH  ˆšY[Û[Ù\ËšØØ[HH ‹�NˆšY[Û[Ù\Ë�”ØØ[HH ŽÂˆšY[Û[Ù\ËšÚY�H � ˆšY[Û[Ù\Ë�”ÚY�H ÍNˆšY[Û[Ù\˙ٙœÙ]H �ˆVQT—ÓRS—ÖˆH ÌŒNˆVQT—ÓPVÖˆH �Nˆ‘ÒRQÒH ÌŒNˆœ™XZ΂ˆ ËÈ  Œ  HÕ‘ÐBˆØ\ÙH N‚ˆšY[Û[Ù\Ëš™\ÈH ˆšY[Û[Ù\Ë�”™\ÈH Œ ˆšY[Û[Ù\ËšØØ[HH ‹�NˆšY[Û[Ù\Ë�”ØØ[HH ‹�NˆšY[Û[Ù\ËšÚY�H � ˆšY[Û[Ù\Ë�”ÚY�H ˆšY[Û[Ù\˙ٙœÙ]H N ˆVQT—ÓRS—ÖˆH NˆVQT—ÓPVÖˆH N ŽÂˆ‘ÒRQÒH Nˆœ™XZ΂ˆ ËÈMŒ M  HRˆØ\ÙH Ž‚ˆšY[Û[Ù\Ëš™\ÈHMŒˆšY[Û[Ù\Ë�”™\ÈH M ˆšY[Û[Ù\ËšØØ[HH ΈšY[Û[Ù\Ë�”ØØ[HH ‹Œ�NˆšY[Û[Ù\ËšÚY�H ÌŒˆšY[Û[Ù\Ë�”ÚY�H ˆšY[Û[Ù\˙ٙœÙ]H LŒŽÂˆVQT—ÓRS—ÖˆH ÍŒŽÂˆVQT—ÓPVÖˆH L�ˆ‘ÒRQÒH ÍŒŽÂˆœ™XZ΂ˆ ËÈÝ\ÝÛHšY[È[ÙBˆØ\ÙH �MN‚ˆšY[Û[Ù\˙ٙœÙ]HšY[Û[Ù\Ë�”™\È +ˆ ŽMŒ�Nˆš[�Š—•\Ú[™ÈX�YÈšY[È[ÙNˆ Y Yˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ÊNˆœ™XZΈY˜][‚ˆ›Ü”Ú]ÝÛŠ K’[�˜[YšY[È[ÙNˆ Y[ˆ Ù]KÝšY[Ë� ËÝ\Ü�Y[Ù\Ηˆ‚ˆŒ H ÌŒ � ˆ‚ˆŒH H   �Ì—ˆ‚ˆŒˆ H �   ˆ‚ˆŒÈ H ÌŒ  ˆ‚ˆ� H   ˆ‚ˆ�H H  Œ ˆ‚ˆ�ˆ HMŒ M —ˆ‹šY[Ó[ÙJNˆœ™XZΈB‚ˆšY[×ÜÝ™]Ú +Ø]™Y]KœÝ™]Ú +N‚ˆYŠ +œØÜ™Y[ˆH[ØÜØÜ™Y[ŠšY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ËVSÌÌŠJHOH•S +Bˆˆ›Ü”Ú]ÝÛŠ K“›Ý[›ÝYÚY[[ÜžHWˆŠNˆBˆšY[Û[Ù\Ëœ^[H^[ž]\ÖÊ[� +]œØÜ™Y[‹Oœ^[›Ü›X]Nˆ ËÝšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆÛX\œØÜ™Y[ŠœØÜ™Y[ŠN‚ˆYŠÙÊBˆˆš[�Š’[š]X[^™YšY[Ë‹‹‹‹‹‹‹‹‹‹‹— Y Y +[ÙNˆ Y +W—ˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ËšY[Ó[ÙJNˆBŸB‚‚‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚‚‹ËÈÙ]Ù^H܈�]ÛˆØY™[H +Ú]ÝÚ]Ú[™ÊB�›ÚYØY™WÜÙ] +[� +˜\œ‹[�[™^ [�™]ÚÙ^K[�ÛÙ^JBžÂˆ[�Nˆ›ÜŠHH ÈH LŽÈJÊÊBˆˆYŠ\œ–ÚWHOH™]ÚÙ^JBˆˆ\œ–ÚWHHÛÙ^NˆBˆBˆ\œ–Ú[™^HH™]ÚÙ^NŸB‚�›ÚYÙ^X›Ø\™ÜÙ]\ +[�^Y\ŠBžÂˆ[�]Z]H Ȉ[�ÙYH ˆ[�Ù[XÝ܈H ˆ[�Ù][™ÈH LNˆ[�HH ˆ[�ÈH ˆ[�ÚÈH ˆ[�\ØX›YÙ^VÓPVЕ—Ó•SWHHÈ             HNˆ[�ÛÛ HH Nˆ[�ÛÛ ˆH ŽÂ‚ˆ™Y™—ݛٙœÙ]Ȉ™Y™—ÝÜ΂ˆÚ\Šˆ�YŽÂˆÚ\ŠˆÛÛ[X[™ˆÚ\Šˆš[[˜[YHH�˜[œÛ][Û‹ÛY[�K�ŽÂˆˆÚ\ˆ�]Û›˜[Y\ÖÓPVЕ—Ó•SWVÌÌ—NˆˆÚ^™WÝÚ^™Nˆ\™Ó\Ý\™Û\݈ˆÚ\ˆ\™Ø�Y–ÓPVÐT‘×ÓSˆ +È WHHˆŽÂˆ[�ÔSÓ”×Ó•SHHPVЕ—Ó•SH +È Î‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ЕUÓ—ÐÓÓ‘’Q×ÓQS•N‚ˆš[�Š“ØY[™ÈÛÛ�›ÛÙ][™ÜË‹‹‹‹‹‹—ŠN‚ˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÓSÕ‘UTK“[Ý™H\ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÓSÕ‘QÕÓ—K“[Ý™HÝÛˆŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÓSÕ‘SQ•K“[Ý™HY�ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÓSÕ‘T’QÒK“[Ý™HšYÚŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÐUPÒ×K�]XÚÈ HŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÐUPÒÌ—K�]XÚÈ ˆŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÐUPÒÌ×K�]XÚÈ ÈŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÐUPÒÍK�]XÚÈ ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÒ•STK’�[\ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÔÔPÒPSK”ÜXÚX[ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÔÕT•K”Ý\�ŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÔÐÔ‘QS”ÒÕK”ØÜ™Y[œÚÝŠNˆÝ˜ÜJ�]Û›˜[Y\ÖÔÑQÑTÐ×K‘^]ŠN‚ˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ‚ˆ Ê‚ˆܘ]\È + L LŒ ŒJHYY[ˆ[\›˜]]™HØØ][Ûˆ›ÜˆH˜[œÛ][Ûˆš[K›ÝÈ] ÜÈÜÜÚX›HÈ\ÙH[ˆ[ˆ^\›˜[›Û\‚ˆ›ÝÈH[Ù\ˆØ[ˆØY^Ü�Y˜[œÛ][Ûˆš[\ÈžH\Ú[™È™š[\Ý™X[HˆØÜš\�[˜Ý[ۜˆ\ÙY�[›ÜˆÜ™X][™ÈÝ\ÝÛH˜[œÛ][ÛœÈÚ]Ý][œXÚÈHØ[YBˆHY˜][[™Ú[™H˜[œÛ][ÛˆØØ][ÛˆÚ[™HXZ[�Z[™Y›Üˆ˜XÚÝØ\™ÛÛ\]Xš[]B‚ˆܘ]\È + LKLŒ ŒJH[�™\�YH]š[Üš]K›ÝÈH^\›˜[š[HÚ[Ý™\œšYHH[�\›˜[š[Bˆ\ÙY�[ÈXZ[�Z[ˆH[™Û\Ú˜[œÛ][Ûˆ[�XÝ[œÚYHHZÈš[HYˆ›ÈÝ\ˆ[™ÝXYÙHš[H\È›Ý[™[ˆH^\›˜[]ˆÝ\�Ú\ÙH[ÝHÚ[™YYțۘXÚÈH[™Û\Úš[H]™\žH[YH[›Ý\ˆ[™ÝXYÙH\È\ÙY[™[ˆ™[[Ý™Yˆ\ÈÜ\˜][Ûˆ\È™YYYÛ›HYˆH[™Û\Ú˜[œÛ][Ûˆš[H\Ù\ÈÛÛYHÝ\ÝÛHY[�H^ț܈[™Û\Ú[™ÝXYÙHÛˆ +‹ÂˆYŠ�Y™™\—ÜZÙš[Jš[[˜[YK ˜�Y‹ œÚ^™JHOH JBˆˆÛÝÈY˜][Ùš[NˆBˆ[ÙBˆˆÛÝÈ›ØÙYYˆB‚™Y˜][Ùš[N‚‚ˆYŠ�Y™™\—ÜZÙš[J™]KÛY[�K�‹ ˜�Y‹ œÚ^™JHOH JBˆˆÛÝÈš[š\ÚˆBˆ[ÙBˆˆÛÝÈ›ØÙYYˆB‚œ›ØÙYY‚‚ˆ ËÈ™XYš[Bˆ ËÈ›ÝÈ[�\œ™]HÛÛ�[�ÈÙˆ�Yˆ[™HžH[™BˆÜÈH ˆÚ[JÜÈÚ^™JBˆˆ\œÙP\™ÜÊ ˜\™Û\Ý �Yˆ +ÈÜË\™Ø�YŠNˆÛÛ[X[™HÑUÐT‘Ê +NˆYŠÛÛ[X[™ÌJBˆˆYŠÝšXÛ\ +ÛÛ[X[™ ™\ØX›ZÙ^HŠHOH +BˆˆÙYH˜[œÛ]WÔÑQ +ÑUÐT‘Ê JJNˆYŠÙY�H +Bˆˆ\ØX›YÙ^VÜÙYHH NˆBˆBˆ[ÙHYŠÝšXÛ\ +ÛÛ[X[™ œ™[˜[YZÙ^HŠHOH +BˆˆÙYH˜[œÛ]WÔÑQ +ÑUÐT‘Ê JJNˆYŠÙY�H +BˆˆÝ˜ÜJ�]Û›˜[Y\ÖÜÙYKÑUÐT‘Ê ŠJNˆBˆB‚ˆBˆ ËÈÛÈÈ™^[™BˆÜÈ +ÏHÙ]™]Ó[™TÝ\� +�Yˆ +ÈÜÊNˆBˆYŠ�YˆOH•S +Bˆˆœ™YJ�YŠNˆ�YˆH•SˆB‚™š[š\Ú‚‚ˆÚ[J\ØX›YÙ^VÜÙ[XÝÜ—JHYŠ +ÊÜÙ[XÝ܈ˆPVЕ—Ó•SH H JHœ™XZ΂ˆÚ[J\]Z] +Bˆˆ›Ù™œÙ]H MŽÂˆÛY[�]^J ‹ N  Š”^Y\ˆ ZHŠK^Y\ˆ +È JNˆ›ÜŠHH ÈHPVЕ—Ó•SNÈJÊÊBˆˆYŠY\ØX›YÙ^VÚWJBˆˆÛY[�]^ + +Ù[XÝ܈OHJKÛÛ K›Ù™œÙ] ‰\È‹�]Û›˜[Y\ÖÚWJNˆÛY[�]^ + +Ù[XÝ܈OHJKÛÛ ‹›Ù™œÙ] ‰\È‹ÛÛ�›ÛÙÙ]Ù^[˜[YJØ]™Y]KšÙ^\ÖÜ^Y\—VÚWJJNˆ›Ù™œÙ] +ÊΈBˆB‚ˆ +ÊݛٙœÙ]ˆYŠØ]™Y]Kš›Þ\�[X›VÜ^Y\—JBˆˆÛY[�]^ + +Ù[XÝ܈OHÔSÓ”×Ó•SH H ÊKÛÛ K›Ù™œÙ] +ÊËŠ”�[X›H[˜X›YŠJNˆBˆ[ÙBˆˆÛY[�]^ + +Ù[XÝ܈OHÔSÓ”×Ó•SH H ÊKÛÛ K›Ù™œÙ] +ÊËŠ”�[X›H\ØX›YŠJNˆB‚ˆÛY[�]^J +Ù[XÝ܈OHÔSÓ”×Ó•SH H ŠK +ÊݛٙœÙ]  Š“ÒÈŠJNˆÛY[�]^J +Ù[XÝ܈OHÔSÓ”×Ó•SH H JK +ÊݛٙœÙ]  Š�Ø[˜Ù[ŠJNˆÛY[�]^J +Ù[XÝ܈OHÔSÓ”×Ó•SJK +ÊݛٙœÙ]  Š‘Y˜][ŠJNˆ\]J +]™[OH•S +K +N‚ˆYŠÙ][™Èˆ LJBˆˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆØ]™Y]KšÙ^\ÖÜ^Y\—VÜÙ][™×HHÚΈÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆÙ][™ÈH LNˆBˆYŠÙ][™Èˆ LJBˆˆÈHÛÛ�›ÛÜØØ[šÙ^J +NˆYŠÊBˆˆØY™WÜÙ] +Ø]™Y]KšÙ^\ÖÜ^Y\—KÙ][™ËËÚÊNˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆÙ][™ÈH LNˆ ËÈ™]™[�XØÚY[�[ØÜ™Y[œÚ݈›Ý™]ÚÙ^\ÈH ˆBˆBˆBˆ[ÙBˆˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +BˆˆˆˆYŠ K\Ù[XÝ܈ +Bˆˆœ™XZΈBˆBˆÚ[JÙ[XÝ܈PVЕ—Ó•SH ‰ˆ\ØX›YÙ^VÜÙ[XÝÜ—JNˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆˆˆYŠ +ÊÜÙ[XÝ܈ˆPVЕ—Ó•SH H JHœ™XZΈBˆÚ[J\ØX›YÙ^VÜÙ[XÝÜ—JNˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈HÔSÓ”×Ó•SNˆBˆYŠÙ[XÝ܈ˆÔSÓ”×Ó•SJBˆˆÙ[XÝ܈H ˆÚ[J\ØX›YÙ^VÜÙ[XÝÜ—JHYŠ +ÊÜÙ[XÝ܈ˆPVЕ—Ó•SH H JHœ™XZΈB‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +N‚ˆYˆ +Ù[XÝ܈OHÔSÓ”×Ó•SH H È ‰‚ˆ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ +JHÛÛ�[�YN‚ˆYŠÙ[XÝ܈OHÔSÓ”×Ó•SH H ÊBˆˆØ]™Y]Kš›Þ\�[X›VÜ^Y\—H�H NˆBˆ[ÙHYŠÙ[XÝ܈OHÔSÓ”×Ó•SH H ŠH ËÈÒˆˆ]Z]H ŽÂˆBˆ[ÙHYŠÙ[XÝ܈OHÔSÓ”×Ó•SH H JH ËÈØ[˜Ù[ˆˆ]Z]H NˆBˆ[ÙHYŠÙ[XÝ܈OHÔSÓ”×Ó•SJH ËÈY˜][ˆˆÛX\˜�]ÛœÊ^Y\ŠNˆBˆ[ÙBˆˆÙ][™ÈHÙ[XÝ܎ˆÚÈHØ]™Y]KšÙ^\ÖÜ^Y\—VÜÙ][™×NˆØ]™Y]KšÙ^\ÖÜ^Y\—VÜÙ][™×HH ˆÙ^X›Ø\™ÙÙ]\ÝÙ^J +NˆBˆBˆBˆB‚ˆYŠ]Z]OH ŠBˆˆ\WØÛÛ�›ÛÊ +NˆØ]™\Ù][™ÜÊ +NˆBˆ[ÙBˆˆØYÙ][™ÜÊ +NˆB‚ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ЕUÓ—ÐÓÓ‘’Q×ÓQS•N‚ˆ\]J  +Nˆ›Ý™]ÚÙ^\ÈH ˆš[�Š‘Û™HWˆŠNŸB‚�›ÚYY[�WÛÜ[Ûœ×Ú[œ] + +BžÂˆ[�]Z]H ˆ[�Ù[XÝ܈H NÈ ËÈ ˆ[�ÜÜÈH MŽÂˆÚYˆS‘“ÒQˆ[�ÔSÓ”×Ó•SHH ŽÂˆÙ[ÙBˆ[�ÔSÓ”×Ó•SHH NˆÙ[™Y‚‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÐÓÓ•“ÓÓÔSÓ”×ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆ ËÈܘ]\È + L LŒ ŒJHYYHÙXÛÛ™[œÝ[˜ÙHÙˆH˜ÛÛ�›ÛÚ[š]ˆ�[˜Ý[ÛˆÚ[H[ˆHÛÛ�›ÛÜ[ۜˆ ËÈ\ÙY�[È™Yœ™\ÚÛÛYH^˜[œÛ][ÛˆYˆH[™ÝXYÙH\ÈÚ[™ÙY›Û‹]KY›Hˆ[™™KY]XÝ[XÝ]™HÛÛ�›ÛˆÛÛ�›ÛÚ[š] +Ø]™Y]K�\ÙZ›ÞJN‚ˆÚ[J\]Z] +BˆˆÛY[�]^J ‹ÜÜËLK Š�ÛÛ�›ÛÜ[ۜȊJNˆYŠØ]™Y]K�\ÙZ›ÞJBˆˆÛY[�]^ + +Ù[XÝ܈OH +KÜÜË L‹Š‘Ø[YTYÈ[˜X›YŠJNˆYŠXÛÛ�›ÛÙÙ]›ÞY[˜X›Y + +JBˆˆÛY[�]^ + +Ù[XÝ܈OH +KÜÜÊÌLK L‹Šˆ H]šXÙH›Ý™XYHŠJNˆBˆBˆ[ÙBˆˆÛY[�]^ + +Ù[XÝ܈OH +KÜÜË L‹Š‘Ø[YTYÈ\ØX›YŠJNˆBˆÛY[�]^ + +Ù[XÝ܈OH JKÜÜË LKŠ”Ù]\^Y\ˆ K‹‹ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ŠKÜÜË Š”Ù]\^Y\ˆ ‹‹‹ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ÊKÜÜË KŠ”Ù]\^Y\ˆ Ë‹‹ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÜÜË ‹Š”Ù]\^Y\ˆ ‹‹ˆŠJNˆÚYˆS‘“ÒQˆYŠØ]™Y]Kš\×ÝÝXÚYÝšXœ˜][Û—Ù[˜X›Y +BˆˆÛY[�]^J +Ù[XÝ܈OH JK  Š•ÝXÚYšXœ˜][Ûˆ[˜X›YŠJNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OH JK  Š•ÝXÚYšXœ˜][Ûˆ\ØX›YŠJNˆBˆÛY[�]^J +Ù[XÝ܈OH ŠK ‹ Š�˜XÚÈŠJNˆÙ[ÙBˆÛY[�]^J +Ù[XÝ܈OH JK K Š�˜XÚÈŠJNˆÙ[™Y‚‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈HÔSÓ”×Ó•SNˆBˆYŠÙ[XÝ܈ˆÔSÓ”×Ó•SJBˆˆÙ[XÝ܈H ˆBˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆÛÛ�›ÛÝ\ÙZ›ÞJ +Ø]™Y]K�\ÙZ›ÞH�H JJNˆœ™XZΈØ\ÙH N‚ˆÙ^X›Ø\™ÜÙ]\ + +Nˆœ™XZΈØ\ÙH Ž‚ˆÙ^X›Ø\™ÜÙ]\ + JNˆœ™XZΈØ\ÙH ΂ˆÙ^X›Ø\™ÜÙ]\ + ŠNˆœ™XZΈØ\ÙH ‚ˆÙ^X›Ø\™ÜÙ]\ + ÊNˆœ™XZΈÚYˆS‘“ÒQˆØ\ÙH N‚ˆØ]™Y]Kš\×ÝÝXÚYÝšXœ˜][Û—Ù[˜X›Y�H Nˆœ™XZΈÙ[™Y‚ˆY˜][‚ˆ]Z]H +›Ý™]ÚÙ^\È ˆ“Q×ÐS–P•UÓŠNˆBˆBˆBˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÐÓÓ•“ÓÓÔSÓ”×ÓQS•NŸB‚‚‹Ê‚ˆܘ]\È + ‹LŒ ŒÊH™XY�\ÝYHX\Ý\ˆ ÈY™™XÝ›Û È]\ÚXݛۘ[™ÙH[™[˜Ü™[Y[�ˆ›Ý[™˜[Y\ÈZÙH L žHY˜][XZÙH[Ü™HÙ[œÙH[ˆÛÛYHZÙH Ì ÌLŒˆÛËH˜[œÙ™\œ™YH\™ÛÙY›Û[YHY�\ÝY[�ÈHœÛÝ[™Z^ˆÛÙH[œÝXYÙˆÚ[™Ú[™ÈHY˜][›Û[Y\ˆX\Ý\ˆ›ÝÈÛÙ\Èœ›ÛH È L [™Y˜][È L ˆY™™XÝÈ +Ø[\\ÊH›ÝÈÛÙ\Èœ›ÛH È L [™Y˜][È L ˆ]\ÚXÈ›ÝÈÛÙ\Èœ›ÛH È Œ [™Y˜][È L Š‹Â�›ÚYY[�WÛÜ[Ûœ×ÜÛÝ[™ + +BžÂˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�\ŽÂˆ[�ÛÛ HH Nˆ[�ÛÛ ˆH ŽÂ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÔÓÕS‘ÓÔSÓ”×ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆÚ[J\]Z] +BˆˆÛY[�]^J ‹ MK Š”ÛÝ[™Ü[ۜȊJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K L‹Š“X\Ý\ˆ›Û[YNˆŠJNÈ ËÈܘ]\È + ‹LŒ ŒÊH™[˜[YYœ›ÛHÛÝ[™ÈX\Ý\ˆ›Û[YBˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ L‹‰ZH‹Ø]™Y]KœÛÝ[™›Û +NˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ K LKŠ‘Y™™XÝÈ›Û[YNˆŠJNÈ ËÈܘ]\È + ‹LŒ ŒÊH™[˜[YYœ›ÛHÑ–ÈY™™XÝÈ›Û[YBˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ ‹ LK‰ZH‹Ø]™Y]K™Y™™XÝ›Û +NˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ K Š“]\ÚXÈ›Û[YNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ ‹ ‰ZH‹Ø]™Y]K›]\ÚXÝ›Û +NˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ K KŠ�‘ÓNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ ‹ K +Ø]™Y]K�\Ù[]\ÚXÈÈŠ‘[˜X›YŠHˆŠ‘\ØX›YŠJJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K ‹Š”ÚÝÈ]\ΈŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ ‹ +Ø]™Y]KœÚÝÝ]\ÈÈŠ–Y\ÈŠHˆŠ“›ÈŠJJNˆÛY[�]^J +Ù[XÝ܈OH JK K Š�˜XÚÈŠJN‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H NˆBˆYŠÙ[XÝ܈ˆ JBˆˆÙ[XÝ܈H ˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆˆ\ˆH ‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘SQ• +Bˆˆ\ˆH LNˆBˆ[ÙHYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +Bˆˆ\ˆH NˆB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ËÈܘ]\È + ‹LŒ ŒÊH™]ÛÜšÙYHÛ[™[�\ÙY�[œÛÝ[™›ÛˆÈXÝ\ÈHX\Ý\ˆ›Û[YH›Üˆ›ÝÛÝ[™ Û]\ÚXˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆØ]™Y]KœÛÝ[™›Û +ÏH H +ˆ\ŽÂˆYŠØ]™Y]KœÛÝ[™›Û +BˆˆØ]™Y]KœÛÝ[™›ÛH ˆBˆYŠØ]™Y]KœÛÝ[™›Ûˆ L +BˆˆØ]™Y]KœÛÝ[™›ÛH L ˆBˆЗÜÙ]›Û[YJЗՓÒPÑU“Ó Ø]™Y]KœÛÝ[™›Û +N‚ˆ ËÈܘ]\È + ‹LŒ ŒÊHÞ[˜Ú›Ûš^™HÛÝ[™ Û]\ÚXÈ›Û[Y\ÈÈX\Ý\‚ˆØ]™Y]K™Y™™XÝ›ÛHØ]™Y]KœÛÝ[™›ÛˆØ]™Y]K›]\ÚXÝ›ÛHØ]™Y]KœÛÝ[™›Ûˆœ™XZΈØ\ÙH N‚ˆØ]™Y]K™Y™™XÝ›Û +ÏH H +ˆ\ŽÂˆYŠØ]™Y]K™Y™™XÝ›Û +BˆˆØ]™Y]K™Y™™XÝ›ÛH ˆBˆYŠØ]™Y]K™Y™™Xݛۈ L +BˆˆØ]™Y]K™Y™™XÝ›ÛH L ˆBˆœ™XZΈØ\ÙH ΂ˆYŠY\ŠBˆˆœ™XZΈBˆYŠ\Ø]™Y]K�\Ù[]\ÚXÊBˆˆØ]™Y]K�\Ù[]\ÚXÈH Nˆ]\ÚXÊ™]KÛ]\ÚXËÜ™[Z^‹ K +NˆBˆ[ÙBˆˆØ]™Y]K�\Ù[]\ÚXÈH ˆÛÝ[™ØÛÜÙWÛ]\ÚXÊ +NˆBˆœ™XZΈØ\ÙH Ž‚ˆØ]™Y]K›]\ÚXÝ›Û +ÏH H +ˆ\ŽÂˆYŠØ]™Y]K›]\ÚXÝ›Û +BˆˆØ]™Y]K›]\ÚXÝ›ÛH ˆBˆYŠØ]™Y]K›]\ÚXݛۈ Œ +BˆˆØ]™Y]K›]\ÚXÝ›ÛH Œ ˆBˆÛÝ[™Ý›Û[YWÛ]\ÚXÊØ]™Y]K›]\ÚXÝ›Û Ø]™Y]K›]\ÚXÝ›Û +Nˆœ™XZΈØ\ÙH ‚ˆØ]™Y]KœÚÝÝ]\ÈH\Ø]™Y]KœÚÝÝ]\Έœ™XZΈY˜][‚ˆ]Z]H NˆBˆBˆBˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÔÓÕS‘ÓÔSÓ”×ÓQS•NŸB‚�›ÚYY[�WÛÜ[Ûœ×ØÛÛ™šYÊ +H ËÈÖ ˆØYœ›ÛH ÈØ]™HÈY˜][ ˜Ù™Ëˆ™\ÝÜ™HÜ[�›Ôˆ™˜XÝÜžHˆÙ][™ÜË‚žÂˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�Ø]™YH ˆ[�ØYYH ˆ[�™\ÝÜ™YH ‚ˆ›Ý™]ÚÙ^\ÈH ‚ˆ ËÈܘ]\È + LKLŒ ŒJH™[[Ý™YÜXÙ\ÈÛˆHˆÛ™HHˆ^Èš^˜[œÛ][Û‚ˆÚ[J\]Z] +BˆˆÛY[�]^J ‹ MK Š�ÛÛ™šYÝ\˜][ÛˆÙ][™ÜÈŠJN‚ˆYŠØ]™YOH JBˆˆÛY[�]^J +Ù[XÝ܈OH +K LË Š”Ø]™HÙ][™ÜÈÈY˜][ ˜Ù™É\ÈŠKŠˆÛ™HHŠJNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OH +K LË Š”Ø]™HÙ][™ÜÈÈY˜][ ˜Ù™É\ÈŠKˆŠNˆB‚ˆYŠØYYOH JBˆˆÛY[�]^J +Ù[XÝ܈OH JK L‹ Š“ØYÙ][™ÜÈœ›ÛHY˜][ ˜Ù™É\ÈŠKŠˆÛ™HHŠJNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OH JK L‹ Š“ØYÙ][™ÜÈœ›ÛHY˜][ ˜Ù™É\ÈŠKˆŠNˆB‚ˆYŠ™\ÝÜ™YOH JBˆˆÛY[�]^J +Ù[XÝ܈OH ŠK LK Š”™\ÝÜ™HÜ[�›ÔˆY˜][É\ÈŠKŠˆÛ™HHŠJNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OH ŠK LK Š”™\ÝÜ™HÜ[�›ÔˆY˜][É\ÈŠKˆŠNˆB‚ˆÛY[�]^J +Ù[XÝ܈OH ÊK ‹ Š�˜XÚÈŠJN‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆB‚ˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H ΈBˆYŠÙ[XÝ܈ˆ ÊBˆˆÙ[XÝ܈H ˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆØ]™X\ÙY˜][ + +NˆØ]™YH Nˆœ™XZ΂ˆØ\ÙH N‚ˆØYœ›ÛYY˜][ + +Nˆ ËØ›Ü”Ú]ÝÛŠ ‹—”Ù][™ÜÈØYYœ›ÛHY˜][ ˜Ù™Ëˆ™\Ý\�™\]Z\™Y ——ˆŠNˆ[š]ÝšY[Û[Ù\Ê +NˆYŠ]šY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊJBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈÙ]šY[È[ÙNˆ Y YWˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ÊNˆBˆЗÜÙ]›Û[YJЗՓÒPÑU“Ó Ø]™Y]KœÛÝ[™›Û +NˆÛÝ[™Ý›Û[YWÛ]\ÚXÊØ]™Y]K›]\ÚXÝ›Û Ø]™Y]K›]\ÚXÝ›Û +NˆØYYH Nˆœ™XZΈØ\ÙH Ž‚ˆÛX\œÙ][™ÜÊ +Nˆ ËØ›Ü”Ú]ÝÛŠ ‹—”Ù][™ÜÈØYYœ›ÛHY˜][ ˜Ù™Ëˆ™\Ý\�™\]Z\™Y ——ˆŠNˆ[š]ÝšY[Û[Ù\Ê +NˆYŠ]šY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊJBˆˆ›Ü”Ú]ÝÛŠ K•[˜X›HÈÙ]šY[È[ÙNˆ Y YWˆ‹šY[Û[Ù\Ëš™\ËšY[Û[Ù\Ë�”™\ÊNˆBˆЗÜÙ]›Û[YJЗՓÒPÑU“Ó Ø]™Y]KœÛÝ[™›Û +NˆÛÝ[™Ý›Û[YWÛ]\ÚXÊØ]™Y]K›]\ÚXÝ›Û Ø]™Y]K›]\ÚXÝ›Û +Nˆ™\ÝÜ™YH Nˆœ™XZΈY˜][‚ˆ]Z]H NˆBˆBˆBˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËL ‚Š‚Šˆ™]\›ˆY[�H\Ü^H^›ÜˆHÛÛ\Ú[ÛˆX�YŠˆ\Ü^HZ\‹‚Š‹ÂœÝ]XÈÚ\ŠˆÛÛ\Ú[Û—ÙX�Y×Ý\WÜÝš[™ÊWÙX�Y×Ù\Ü^HX�Y×ÙšY[ WÙX�Y×Ù\Ü^H›]Øš] WÙX�Y×Ù\Ü^H›Ú™XÝYØš] +H‚ˆYˆ + +X�Y×ÙšY[ ˆ›]Øš] +H ‰ˆ +X�Y×ÙšY[ ˆ›Ú™XÝYØš] +JHˆ™]\›ˆŠ‘›] +țڙXÝYŠNˆH[ÙHYˆ +X�Y×ÙšY[ ˆ›]Øš] +Hˆ™]\›ˆŠ‘›]ŠNˆH[ÙHYˆ +X�Y×ÙšY[ ˆ›Ú™XÝYØš] +Hˆ™]\›ˆŠ”›Ú™XÝYŠNˆH[ÙHˆ™]\›ˆŠ‘\ØX›YŠNˆBŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ �‹L ËL ‚Š‚ŠˆÞXÛHÛÛ\Ú[ÛˆX�YÈ\Ü^H[ÙH›ÜˆÛ™HÛÛ\Ú[Ûˆ\K‚Š‚ŠˆXXÚÛÛ\Ú[Ûˆ\H\Ù\ÈÛÈX�YÈš]Î‚Š‚Šˆ›]Øš]H˜]ÈH›Ü›X[ ‘™XÝ[™ÛHÝ™\›^K‚Šˆ›Ú™XÝYØš]H˜]ÈH›Ú™XÝY ÑÝX™HÝ™\›^K‚Š‚ŠˆHÛÈš]ÈÛÛXš[™H[�È›Ý\ˆÜÜÚX›HÝ]\Î‚Š‚Šˆ H›Û™BŠˆ HH›]Šˆ ˆH›Ú™XÝYŠˆ ÈH›] +țڙXÝYŠ‚Šˆ\™XÝ[ÛˆÛÛ�›ÛÈÞXÛHÜ™\Ž‚Š‚ŠˆÑÑÓWÑT‘PÕSÓ—Ð�PÒÕÐT‘HÞXÛH˜XÚÝØ\™ ‚ŠˆÑÑÓWÑT‘PÕSӗѓԕÐT‘HÞXÛH›Ü�Ø\™ ‚Š‚Šˆ™]\›ˆ˜[YH\ÈH\]YX�YÈš]šY[ ‚Š‹ÂœÝ]XÈWÙX�Y×Ù\Ü^HÛÛ\Ú[Û—ÙX�Y×Ý\WØÞXÛJÛÛœÝWÙX�Y×Ù\Ü^HX�Y×ÙšY[ ÛÛœÝWÙX�Y×Ù\Ü^H›]Øš] ÛÛœÝWÙX�Y×Ù\Ü^H›Ú™XÝYØš] ÛÛœÝWÛY[�WÝÙÙÛWÙ\™XÝ[ÛˆÙÙÛWÙ\™XÝ[ÛŠH‚ˆ Ê‚ˆ +ˆØØ[Û›KˆXÝX[Ý]H\ÈÛÛ�›ÛYžBˆ +ˆHØ]™Y]K™X�YÚ[™›Èš]šY[ ˆ\È�\݈ +ˆÚ]™\È\ÈHÚ[\H[™X\ˆ˜[YHÈÛÜšÈÚ]ˆ +ˆ›ÜˆÞXÛ[™ÈÛÈÙHÉÝ™YYHX\ÜÚ]™HY‹Ù[ÙBˆ +ˆÚZ[‹‚ˆ +‹ÂˆÙYš[™HÓÓTÒSÓ—ÑP•Q×ÑTÔVWÓ“Ó‘H ˆÙYš[™HÓÓTÒSÓ—ÑP•Q×ÑTÔVWÑ“U BˆÙYš[™HÓÓTÒSÓ—ÑP•Q×ÑTÔVWÔ“Ò‘PÕQ ‚ˆÙYš[™HÓÓTÒSÓ—ÑP•Q×ÑTÔVWГÕ È‚ˆ Ê‚ˆ +ˆ[�ØÜ˜]ÚYˈ\ÙH\™H[�[H˜[Y\Ë�]ÛÛ\[\‚ˆ +ˆÚ[›ÝÈHš]YˆÙHžHÈ\ÙH[H[ˆÜ\˜][ۜˆ +ˆ]Ø]\ÙH[\XÚ][�YÙ\ˆ›Û[Ý[Û‹‚ˆ +‹Âˆ[�Ý]Nˆ[�X�Y×Ù›YÜ΂ˆ Ê‚ˆ +ˆÛÜšÈ[ˆ[ˆ[�ØÜ˜]Ú˜[YH™XØ]\ÙH[�[H˜[Y\È\™Bˆ +ˆÝ[š]šY[Ë[™š]Ú\ÙHÜ\˜]ܜțÛ[ÝH[Bˆ +ˆÈ[�[ž]Ø^K‚ˆ +‹ÂˆX�Y×Ù›YÜÈHX�Y×ÙšY[‚ˆ Ê‚ˆ +ˆÛÛ�™\�Ý\œ™[�š]šY[Ý]H[�ÈHÛÛ\X݈ +ˆ\Ü^H[ÙH˜[YK‚ˆ +‚ˆ +ˆš] H›]\Ü^H[˜X›Y ‚ˆ +ˆš] HH›Ú™XÝY\Ü^H[˜X›Y ‚ˆ +‹ÂˆÝ]HHÓÓTÒSÓ—ÑP•Q×ÑTÔVWÓ“Ó‘N‚ˆYˆ +X�Y×Ù›YÜÈ ˆ›]Øš] +HˆÝ]HHÓÓTÒSÓ—ÑP•Q×ÑTÔVWÑ“UˆB‚ˆYˆ +X�Y×Ù›YÜÈ ˆ›Ú™XÝYØš] +HˆÝ]HHÓÓTÒSÓ—ÑP•Q×ÑTÔVWÔ“Ò‘PÕQˆB‚ˆ Ê‚ˆ +ˆÝ\›ÝYÚH›Ý\ˆ\Ü^H[Ù\Ë‚ˆ +‚ˆ +ˆ˜XÚÝØ\™‚ˆ +ˆ›Û™H H›] H›Ú™XÝY H›Ý H›Û™Bˆ +‚ˆ +ˆ›Ü�Ø\™‚ˆ +ˆ›Û™H Oˆ›] Oˆ›Ú™XÝY Oˆ›Ý Oˆ›Û™Bˆ +‹ÂˆÝÚ]Ú +ÙÙÛWÙ\™XÝ[ÛŠHˆØ\ÙHÑÑÓWÑT‘PÕSÓ—Ð�PÒÕÐT‘‚ˆÝ]KKN‚ˆYˆ +Ý]HÓÓTÒSÓ—ÑP•Q×ÑTÔVWÓ“Ó‘JHˆÝ]HHÓÓTÒSÓ—ÑP•Q×ÑTÔVWГÕˆB‚ˆœ™XZ΂ˆØ\ÙHÑÑÓWÑT‘PÕSӗѓԕÐT‘‚ˆY˜][‚ˆÝ]JÊ΂ˆYˆ +Ý]HˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWГÕ +HˆÝ]HHÓÓTÒSÓ—ÑP•Q×ÑTÔVWÓ“Ó‘NˆB‚ˆœ™XZΈB‚ˆ Ê‚ˆ +ˆÛX\ˆÛ›HHÛÈš]ÈX[˜YÙYžH\ÈÛÛ\Ú[Û‚ˆ +ˆX�YÈÜ[Û‹ˆX]™H[Ý\ˆX�YÈ›YÜÈ[�ÝXÚY ‚ˆ +‹ÂˆX�Y×Ù›YÜÈ �HŠ›]Øš]›Ú™XÝYØš] +N‚ˆ Ê‚ˆ +ˆ^[™ÛÛ\XÝÝ]H˜XÚÈ[�ÈHX�YÈš]šY[ ‚ˆ +‹ÂˆYˆ +Ý]H ˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWÑ“U +HˆX�Y×Ù›YÜÈH›]Øš]ˆB‚ˆYˆ +Ý]H ˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWÔ“Ò‘PÕQ +HˆX�Y×Ù›YÜÈH›Ú™XÝYØš]ˆB‚ˆ™]\›ˆ +WÙX�Y×Ù\Ü^JYX�Y×Ù›YÜ΂ˆÝ[™YˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWÓ“Ó‘BˆÝ[™YˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWÑ“UˆÝ[™YˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWÔ“Ò‘PÕQˆÝ[™YˆÓÓTÒSÓ—ÑP•Q×ÑTÔVWГÕŸB‚�›ÚYY[�WÛÜ[Ûœ×ÙX�YÊ +HˆÙYš[™HQS•WÔÔ×ÖH MˆÙYš[™HQS•WÒUST×ÓPT‘ÒS—ÖH ‚ˆÙYš[™HÓÓSS—ÌWÔÔ×Ö LLBˆÙYš[™HÓÓSS—Ì—ÔÔ×ÖÓÓSS—ÌWÔÔ×Ö +È MˆÙYš[™HQS•WÒUSWÑ’T”ÕÒS‘V ‚ˆ ËÈÙ[XÝ[ÛœÈ[�[Y\˜]Ü‹ˆ[ˆ ËÈÙ[XÝ[Ûˆ][\ÈÚÝ[™HXÙYˆ ËÈ\™Hš\œÝ ‚ˆ\YYˆ[�[H‚ˆ ËÈš\œÝ][HØ[ˆ™Bˆ ËÈÚ]]™\ˆÙHZÙKˆ ËÈ�]]]\Ý™HÙ]ˆ ËÈÈHQS•WÒUSWÑ’T”ÕÒS‘Vˆ ËÈÛÛœÝ[� ‚ˆUSWÔT‘“Ô“PS�ÑHHQS•WÒUSWÑ’T”ÕÒS‘V ‚ˆ ËÈ][\È™]ÙY[ˆHš\œÝˆ ËÈ[™\ÝØ[ˆÛÈ[ˆ[žBˆ ËÈÜ™\‹‚ˆUSWÔÔÒUSÓ‹ˆUSWÐÓÓÐUPÒˈUSWÐÓÓГÑKˆUSWÐÓÓÔÔPÑKˆUSWÐÓÓÔ�S‘ÑK‚ˆ ËÈ\È\ÈH�˜XÚÈ‚ˆ ËÈÙ[XÝ[Ûˆ[™ÚÝ[ˆ ËÈ[Ø^\È™H\Ý ‚ˆUSWÑVUˆHWÜÙ[XÝ[ۜ΂ˆ[�Ü×ÞNˆ[�]Z]H ˆWÜÙ[XÝ[ÛœÈÙ[XÝ܈H ˆ›Ý™]ÚÙ^\ÈH ˆˆWÛY[�WÝÙÙÛWÙ\™XÝ[ÛˆÙÙÛWÙ\™XÝ[ÛˆHÑÑÓWÑT‘PÕSӗѓԕÐT‘‚ˆÚ[J\]Z] +H‚ˆ ËÈ\Ü^HY[�H]K‚ˆÛY[�]^J ‹QS•WÔÔ×ÖK Š‘X�YÈÙ][™ÜÈŠJN‚ˆ ËÈY[�H][\Ë‚ˆ ËÈHÜÚ][Ûˆ\ÈÛÛ�›ÛYžHH[˜Ü™[Y[�Y[�YÙ\‹‚ˆ ËÈ[�YÙ\ˆ\ÈH˜\ÙH˜[YHÙˆHY[�H]HBˆ ËÈ\ÈÝ]XÈÙ™œÙ] ˆ™[ÝÈXXÚ][K\ÈH˜[YBˆ ËÈ[˜Ü™[Y[�ÈžHÛ™KˆÙHØ[ˆ[ˆY܈™[[Ý™Bˆ ËÈY[�H][\È\™H[™HÛˆØÜ™Y[ˆÜÚ][ÛˆÚ[ˆ ËÈZÙHØ\™HÙˆ]Ù[ˆÚ]Ý]\È™YY[™ÈÈY\܈ ËÈÚ]H�[˜ÚÙˆ\™ÛÛœÝ[�Ë‚‚ˆ ËÈ™\Ù]Y[�H][HÜÚ][ÛˆK‚ˆÜ×ÞHHQS•WÔÔ×ÖH +ÈQS•WÒUST×ÓPT‘ÒS—ÖN‚ˆÛY[�]^ + +Ù[XÝ܈OHUSWÔT‘“Ô“PS�ÑJKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ”\™›Ü›X[˜ÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÔT‘“Ô“PS�ÑJKÓÓSS—Ì—ÔÔ×Ö Ü×ÞK +Ø]™Y]K™X�YÚ[™›È ˆP•Q×ÑTÔVWÔT‘“Ô“PS�ÑHÈŠ‘[˜X›YŠHˆŠ‘\ØX›YŠJJNˆÜ×ÞJÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHUSWÔÔÒUSÓŠKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ�˜\ÚXÈ›Ü\�Y\ΈŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÔÔÒUSÓŠKÓÓSS—Ì—ÔÔ×Ö Ü×ÞK +Ø]™Y]K™X�YÚ[™›È ˆP•Q×ÑTÔVWÔ“ÔT•QTÈÈŠ‘[˜X›YŠHˆŠ‘\ØX›YŠJJNˆÜ×ÞJÊÎÈ‚ˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÐUPÒÊKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ�ÛÛ\Ú[Ûˆ]XÚΈŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÐUPÒÊKÓÓSS—Ì—ÔÔ×Ö Ü×ÞKÛÛ\Ú[Û—ÙX�Y×Ý\WÜÝš[™ÊØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSÓ—ÐUPÒ×Ì‘ P•Q×ÑTÔVWÐÓÓTÒSÓ—ÐUPÒ×ÌÑ +JNˆÜ×ÞJÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓГÑJKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ�ÛÛ\Ú[Ûˆ›ÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓГÑJKÓÓSS—Ì—ÔÔ×Ö Ü×ÞKÛÛ\Ú[Û—ÙX�Y×Ý\WÜÝš[™ÊØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSӗГÑWÌ‘ P•Q×ÑTÔVWÐÓÓTÒSӗГÑWÌÑ +JNˆÜ×ÞJÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÔÔPÑJKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ�ÛÛ\Ú[ÛˆÜXÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÔÔPÑJKÓÓSS—Ì—ÔÔ×Ö Ü×ÞKÛÛ\Ú[Û—ÙX�Y×Ý\WÜÝš[™ÊØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSÓ—ÔÔPÑWÌ‘ P•Q×ÑTÔVWÐÓÓTÒSÓ—ÔÔPÑWÌÑ +JNˆÜ×ÞJÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÔ�S‘ÑJKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠ”˜[™ÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHUSWÐÓÓÔ�S‘ÑJKÓÓSS—Ì—ÔÔ×Ö Ü×ÞK +Ø]™Y]K™X�YÚ[™›È ˆP•Q×ÑTÔVWÔ�S‘ÑHÈŠ‘[˜X›YŠHˆŠ‘\ØX›YŠJJNˆÜ×ÞJÊ΂ˆ ËÈ\Ü^H^]]BˆÛY[�]^J +Ù[XÝ܈OHUSWÑVU +KÜ×ÞH +È +QS•WÒUST×ÓPT‘ÒS—ÖJK Š�˜XÚÈŠJN‚ˆ ËÈ�[ˆ[ˆ[™Ú[™H\]K‚ˆ\]J +]™[OH•S +K +N‚ˆ ËÈYˆ\Ù\ˆ™\ÜÙ\È\ ÙÝÛˆ܈\ØË] ÜÈXÝXØÛÜ™[™ÛK‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘UT“Q×ÓSÕ‘QÕÓˆ“Q×ÑTÐÊJH‚ˆ ËÈYˆ\Ù\ˆ™\ÜÙ\È\ØØ\K[ˆÙ]]Z]ˆ ËÈ›YÈ[[YYX][Kˆ[ÙHÚ\ÙK[˜Ü™[Y[�ˆ ËÈ܈XÜ™[Y[�Ù[XÝ܈\È™YYY ‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊHˆ]Z]H NˆˆH[ÙHYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Hˆ ËÈ^H™Y\Yˆ]˜Z[X›K‚ˆ ËÈܘ]\È + LŒ ŒŠH[Ý™YH‘QTÛÝ[™ÈÛÜšÈÛ›HÚ]T ÑÕÓˆÙ^\ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +HˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ËÈYˆÙH\™H]HÜ][KÛ܈ ËÈÈ\Ý ˆÝ\�Ú\ÙK[Ý™HÛ™H\ ‚ˆYŠÙ[XÝ܈HQS•WÒUSWÑ’T”ÕÒS‘V +HˆÙ[XÝ܈HUSWÑVUˆH[ÙHˆ K\Ù[XÝ܎ˆB‚ˆH[ÙHYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠH‚ˆ ËÈ^H™Y\Yˆ]˜Z[X›K‚ˆ ËÈܘ]\È + LŒ ŒŠH[Ý™YH‘QTÛÝ[™ÈÛÜšÈÛ›HÚ]T ÑÕÓˆÙ^\ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +HˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ËÈYˆÙH\™H]H\Ý][Bˆ ËÈ +ÚXÚÚÝ[™H˜˜XÚÈŠK[‚ˆ ËÈÛܘXÚÈÈš\œÝ ˆÝ\�Ú\ÙBˆ ËÈ[Ý™HÛ™HÝÛ‹‚ˆYŠÙ[XÝ܈�HUSWÑVU +HˆÙ[XÝ܈HQS•WÒUSWÑ’T”ÕÒS‘VˆˆH[ÙHˆ +ÊÜÙ[XÝ܎ˆBˆBˆB‚‚ˆ ËÈÙÙÛHÙ[XÝ[Ûˆ˜[YHÛˆY� ÜšYÚÜ‚ˆ ËÈšYÙÙ\ˆ�]Ûˆ™\ÜË‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJHˆˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +HˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆÙÙÛWÙ\™XÝ[ÛˆH +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘SQ• +HÈÑÑÓWÑT‘PÕSÓ—Ð�PÒÕÐT‘ˆÑÑÓWÑT‘PÕSӗѓԕÐT‘ˆˆ ËÈ\È\ÈÚ\™HY[�H][\È\™H^XÝ]Y ‚ˆÝÚ]Ú +Ù[XÝÜŠHˆØ\ÙHUSWÔT‘“Ô“PS�ÑN‚ˆØ]™Y]K™X�YÚ[™›È�HP•Q×ÑTÔVWÔT‘“Ô“PS�ÑNˆœ™XZΈØ\ÙHUSWÔÔÒUSÓŽ‚ˆØ]™Y]K™X�YÚ[™›È�HP•Q×ÑTÔVWÔ“ÔT•QTΈœ™XZÎȈØ\ÙHUSWÐÓÓÐUPÒ΂ˆØ]™Y]K™X�YÚ[™›ÈHÛÛ\Ú[Û—ÙX�Y×Ý\WØÞXÛJØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSÓ—ÐUPÒ×Ì‘ P•Q×ÑTÔVWÐÓÓTÒSÓ—ÐUPÒ×ÌÑ ÙÙÛWÙ\™XÝ[ÛŠNˆœ™XZΈØ\ÙHUSWÐÓÓГÑN‚ˆØ]™Y]K™X�YÚ[™›ÈHÛÛ\Ú[Û—ÙX�Y×Ý\WØÞXÛJØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSӗГÑWÌ‘ P•Q×ÑTÔVWÐÓÓTÒSӗГÑWÌÑ ÙÙÛWÙ\™XÝ[ÛŠNˆœ™XZΈØ\ÙHUSWÐÓÓÔÔPÑN‚ˆØ]™Y]K™X�YÚ[™›ÈHÛÛ\Ú[Û—ÙX�Y×Ý\WØÞXÛJØ]™Y]K™X�YÚ[™›ËP•Q×ÑTÔVWÐÓÓTÒSÓ—ÔÔPÑWÌ‘ P•Q×ÑTÔVWÐÓÓTÒSÓ—ÔÔPÑWÌÑ ÙÙÛWÙ\™XÝ[ÛŠNˆœ™XZΈØ\ÙHUSWÐÓÓÔ�S‘ÑN‚ˆØ]™Y]K™X�YÚ[™›È�HP•Q×ÑTÔVWÔ�S‘ÑNˆœ™XZΈØ\ÙHUSWÑVU‚ˆ]Z]H NˆBˆBˆB‚ˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ‚ˆÝ[™YˆQS•WÔÔ×ÖBˆÝ[™YˆQS•WÒUST×ÓPT‘ÒS—ÖBˆÝ[™YˆÓÓSS—ÌWÔÔ×ÖˆÝ[™YˆÓÓSS—Ì—ÔÔ×ÖˆÝ[™YˆQS•WÒUSWÑ’T”ÕÒS‘VŸB‚‹Ê‚ŠˆØ\ÚÙ^K[[Ûˆ‹‚Šˆ Œ Œ‹L KL BŠˆŠˆ\Ü^HÚX]Ü[ÛœÈY[�H[™Šˆ\H^Y\ˆÙ[XÝ[ÛœË‚Š‹Â�›ÚYY[�WÛÜ[Ûœ×ØÚX]Ê +BžÂˆÙYš[™HQS•WÔÔ×ÖH MˆÙYš[™HQS•WÒUST×ÓPT‘ÒS—ÖH ‚ˆÙYš[™HÓÓSS—ÌWÔÔ×Ö LLBˆÙYš[™HÓÓSS—Ì—ÔÔ×ÖÓÓSS—ÌWÔÔ×Ö +È M‚ˆ\YYˆÝ�XÝ×ÛÜ[Û—Û\݈ˆWØÚX]ÛÜ[ÛœÈXÝ]™NˆWØÚX]ÛÜ[ÛœÈY[�NˆÚ\ˆX™[ÌŒNˆH×ÛÜ[Û—Û\Ý‚ˆ[�Ü[Û—Û\ÝØÛÝ[�H Έ×ÛÜ[Û—Û\ÝÜ[Û—Û\Ý×HHˆ˘XÝ]™HHÒPUÓÔSÓ”×ÒSTPÐP“WÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÒSTPÐP“WÓQS•K ›X™[H’[\XØX›HX\˜ÚˆˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÐÔ‘QU×ÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÐÔ‘QU×ÓQS•K ›X™[H’[™š[š]HÜ™Y]ΈˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÑS‘T‘ÖWÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÑS‘T‘ÖWÓQS•K ›X™[H’[™š[š]H[™\™ÞNˆˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÒPSÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÒPSÓQS•K ›X™[H’[™š[š]HX[ˆˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÓU‘T×ÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÓU‘T×ÓQS•K ›X™[H’[™š[š]H]™\ΈˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÓUSRUÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÓUSRUÓQS•K ›X™[H“][Z]Û]ÚˆˆKˆ˘XÝ]™HHÒPUÓÔSÓ”×ÕÑÐPÕU‘K ›Y[�HHÒPUÓÔSÓ”×ÕÑÓQS•K ›X™[H•ÝXÚÙˆX]ˆˆBˆNˆˆ[�Ü[Û—Û\ÝØÝ\œÛ܈H ˆ[�Ü[Û—Ø]˜Z[X›WØÛÝ[�H ˆ[�Ü[Û—Ø]˜Z[X›WÙš\œÝH ˆ[�Ü×ÞHH ˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆˆ›Ý™]ÚÙ^\ÈH ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÐÒPUÓÔSÓ”×ÓQS•NÈ‚ˆ ËÜš[�Š——ˆY[�WÛÜ[Ûœ×ØÚX]Ê +HŠN‚ˆÚ[H +\]Z] +Bˆˆ ʈ\Ü^HY[�H]Kˆ +‹ÂˆÛY[�]^J ‹QS•WÔÔ×ÖK Š�ÚX]Ü[ۜȊJNˆˆ Ê‚ˆ +ˆ™\Ù]Y[�H][HÜÚ][ÛˆH[™ˆ +ˆ˜[YY[�H][HÛÝ[� ‚ˆ +‹ÂˆÜ[Û—Ø]˜Z[X›WØÛÝ[�H ˆÜ[Û—Ø]˜Z[X›WÙš\œÝH ˆÜ×ÞHHQS•WÔÔ×ÖH +ÈQS•WÒUST×ÓPT‘ÒS—ÖN‚ˆ Ê‚ˆ +ˆ]\˜]H›ÝYÚHÜ[Ûˆ\݈ +ˆ\œ˜^H[™\Ü^H]˜Z[X›H][\Ë‚ˆ +ˆˆ +ˆ]XXÚ˜[YÜ[Û‹[˜Ü™[Y[�ˆ +ˆÜ[ÛˆÛÝ[�[™HÜÚ][Û‹‚ˆ +‹Â‚ˆ›Üˆ +Ü[Û—Û\ÝØÝ\œÛ܈H ÈÜ[Û—Û\ÝØÝ\œÛ܈Ü[Û—Û\ÝØÛÝ[�ÈÜ[Û—Û\ÝØÝ\œÛÜŠÊÊBˆÈˆYˆ +Ûؘ[ØÛÛ™šY˘ÚX]È ˆÜ[Û—Û\ÝÛÜ[Û—Û\ÝØÝ\œÛÜ—K›Y[�JBˆÈˆ ʈˆ +ˆYˆÜ[Ûˆ]˜Z[X›HÛÝ[�\ÈÝ[ \ˆ +ˆ\ÈHš\œÝ]˜Z[X›HÜ[Û‹ˆ™XÛÜ™Bˆ +ˆ[™^›Üˆ\ÙHÝۜݙX[K‚ˆ +‹Â‚ˆYˆ +[Ü[Û—Ø]˜Z[X›WØÛÝ[� +BˆˆÜ[Û—Ø]˜Z[X›WÙš\œÝHÜ[Û—Û\ÝØÝ\œÛ܎ˆBˆˆ ʈš[�HY[�H^[™Û‹ÛÙ™ˆÝ]\ˈ +‹ÂˆÛY[�]^ + +Ù[XÝ܈OHÜ[Û—Û\ÝØÝ\œÛÜŠKÓÓSS—ÌWÔÔ×Ö Ü×ÞKŠÜ[Û—Û\ÝÛÜ[Û—Û\ÝØÝ\œÛÜ—K›X™[ +JNˆÛY[�]^ + +Ù[XÝ܈OHÜ[Û—Û\ÝØÝ\œÛÜŠKÓÓSS—Ì—ÔÔ×Ö Ü×ÞK +Ûؘ[ØÛÛ™šY˘ÚX]È ˆÜ[Û—Û\ÝÛÜ[Û—Û\ÝØÝ\œÛÜ—K˜XÝ]™HÈŠ“ÛˆŠHˆŠ“Ù™ˆŠJJNˆˆÜ[Û—Ø]˜Z[X›WØÛÝ[� +ÊΈÜ×ÞJÊΈHˆB‚ˆ ʈ›È][\È]˜ZX[›Kˆ[\�^Y\‹ˆ +‹ÂˆYˆ +[Ü[Û—Ø]˜Z[X›WØÛÝ[� +BˆˆÛY[�]^J Ü×ÞK Š“›ÈÚX]È]˜Z[X›KˆŠJNˆH‚ˆ Ê‚ˆ +ˆYH^]Ü[Û‹ˆÙHØ[ˆ\ÙHH\œ˜^HÚ^™Hˆ +ˆ›ÜˆHÙ[XÝ܈[™^YHÈ [™^[™Ë‚ˆ +‹ÂˆˆÜ×ÞJÊÎȈÛY[�]^J +Ù[XÝ܈OHÜ[Û—Û\ÝØÛÝ[� +KÜ×ÞK Š�˜XÚÈŠJN‚ˆ ʈ�[ˆ[ˆ[™Ú[™H\]Kˆ +‹Âˆ\]J +]™[OH•S +K +Nˆˆ ʈˆ +ˆ[™H\Ù\ˆ[œ][™Ü[]HÙ[XÝ܈ˆ +ˆ\›ÜšX]H˜[YKˆˆ +ˆˆ +ˆš\œÝÙHÙ]Ù[XÝ܈Èš\œÝ][H[ˆØ\ÙHˆ +ˆHš\œÝ]˜Z[X›IÜÈ[™^\È›Ý ‚ˆ +ˆˆ +ˆ™^ [™H�]ۜˈTÐÈ]Z]ÈHY[�Hˆ +ˆ[œÝ[�Kˆ\ ÑÝÛˆÙ[XÝ\™Ù]][K‚ˆ +ˆY� ÔšYÚ ÐXÝ[Ûˆ�]ÛœÈÙÙÛH˜[YK‚ˆ +‹Â‚ˆYˆ +\Ù[XÝ܈ ‰ˆÜ[Û—Ø]˜Z[X›WÙš\œÝ +BˆˆÙ[XÝ܈HÜ[Û—Ø]˜Z[X›WÙš\œÝˆB‚ˆYˆ +›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆB‚ˆYˆ +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ ʈ^H™Y\Yˆ]˜Z[X›Kˆ +‹ÂˆYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ʈܘ\\›Ý[™Yˆ™YYY ˆ +‹ÂˆYˆ +Ù[XÝ܈HÜ[Û—Ø]˜Z[X›WÙš\œÝ +BˆˆÙ[XÝ܈HÜ[Û—Û\ÝØÛÝ[�ˆBˆ[ÙBˆˆÙ[XÝÜ‹KNˆB‚ˆ ʈÚÚ\\ØX›Y][\ˈ +‹ÂˆÚ[H +JÛؘ[ØÛÛ™šY˘ÚX]È ˆÜ[Û—Û\ÝÜÙ[XÝÜ—K›Y[�JH ‰ˆÙ[XÝ܈ˆÜ[Û—Ø]˜Z[X›WÙš\œÝ +BˆÈˆÙ[XÝÜ‹KNˆHˆBˆˆYˆ +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ ʈ^H™Y\Yˆ]˜Z[X›Kˆ +‹ÂˆYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ ʈܘ\\›Ý[™Yˆ™YYY ˆ +‹ÂˆYˆ +Ù[XÝ܈�HÜ[Û—Û\ÝØÛÝ[� +BˆˆÙ[XÝ܈HÜ[Û—Ø]˜Z[X›WÙš\œÝˆBˆ[ÙBˆˆÙ[XÝÜŠÊΈB‚ˆ ʈÚÚ\\ØX›Y][\ˈ +‹ÂˆÚ[H +JÛؘ[ØÛÛ™šY˘ÚX]È ˆÜ[Û—Û\ÝÜÙ[XÝÜ—K›Y[�JH ‰ˆÙ[XÝ܈Ü[Û—Û\ÝØÛÝ[� +BˆˆÙ[XÝÜŠÊΈBˆH‚ˆ ʈˆ +ˆÙÙÛHÙ[XÝ[Ûˆ˜[YHÛˆY� ÜšYÚÜ‚ˆ +ˆšYÙÙ\ˆ�]Ûˆ™\ÜË‚ˆ +‹ÂˆYˆ +›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆˆYˆ +Ûؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆ Ê‚ˆ +ˆZÙHXÝ[Ûˆ˜\ÙYÛˆÙ[XÝÜ‹‚ˆ +ˆˆ +ˆH\ÝÜ[Ûˆ\ÈH^]][KÛÈYˆ] ܈ +ˆÝ\ˆÙ[XÝ܈˜[YHÙH^]\ÈY[�Kˆˆ +‚ˆ +ˆÝ\�Ú\ÙH\ÙHÙ[XÝ܈\È\œ˜^HÙ^HÈÙ]Hˆ +ˆš]ÙHØ[�ÈÙÙÛH[ˆÝ\ˆ\™Ù]˜[YK‚ˆ +‹Â‚ˆYˆ +Ù[XÝ܈Ü[Û—Û\ÝØÛÝ[� +BˆˆÛؘ[ØÛÛ™šY˘ÚX]È�HÜ[Û—Û\ÝÜÙ[XÝÜ—K˜XÝ]™NˆBˆ[ÙBˆˆ]Z]H NˆHˆBˆBˆˆ ËÜØ]™\Ù][™ÜÊ +Nˆˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÐÒPUÓÔSÓ”×ÓQS•N‚ˆÝ[™YˆQS•WÔÔ×ÖBˆÝ[™YˆQS•WÒUST×ÓPT‘ÒS—ÖBˆÝ[™YˆÓÓSS—ÌWÔÔ×ÖˆÝ[™YˆÓÓSS—Ì—ÔÔ×ÖŸB‚�›ÚYY[�WÛÜ[Ûœ×ÜÞ\Ý[J +BžÂˆÙYš[™HÖT×ÓÔÖWÔÔÈ M‚ˆ[�[HˆÖT×ÓÔÓÑˈÖT×ÓÔÕ”ÑSPQÑKˆÖT×ÓÔÐÒPUˈÖT×ÓÔÑP•QˈÖT×ÓÔÐÓÓ‘’QˈÖT×ÓÔÐ�PÒˆN‚ˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�ÛÛ HH LLNˆ[�ÛÛ ˆHÛÛ JÌMˆ[�^ÛX™[ÈH ˆ[�‘UHÖT×ÓÔÐ�PÒΈ[�[™HH ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÔÖTÕSWÓÔSÓ”×ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ˆYˆ +›ÙX�YÛÜ[ÛœÊH^ÛX™[ÈH Nˆ‘U OH^ÛX™[ΈˆÚ[J\]Z] +Bˆˆ[™HH ‚ˆÛY[�]^J ‹ÖT×ÓÔÖWÔÔËL‹ Š”Þ\Ý[HÜ[ۜȊJN‚ˆÛY[�]^ + ÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ•Ý[�SNˆŠJNˆÛY[�]^ + ÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KЉ\ÈЈŠKÛÛ[X\š[� +Ù]Þ\Ý[T˜[JЖUTÊJJNˆ[™JÊΈˆÛY[�]^ + ÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ•\ÙY�SNˆŠJNˆÛY[�]^ + ÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KЉ\ÈЈŠKÛÛ[X\š[� +Ù]\ÙY˜[JЖUTÊJJNˆ[™JÊ΂ˆÛY[�]^ + ÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ“X^^Y\œÎˆŠJNˆÛY[�]^ + ÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KЉZHŠK]™[Ù]ÖØÝ\œ™[�ÜÙ]K›X^^Y\œÊNˆ[™JÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÓÑÊKÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ‘š[HÙÙÚ[™ÎˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÓÑÊKÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™K +Ø]™Y]K�\Ù[ÙÈÈŠ‘[˜X›YŠHˆŠ‘\ØX›YŠJJNˆ[™JÊ΂ˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJKÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ•™\œÝ\È[XYÙNˆŠK +NˆYŠ™\œÝ\Ù[XYÙHOH +BˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJKÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KŠ‘\ØX›YžH[Ù[HŠJNˆBˆ[ÙHYŠ™\œÝ\Ù[XYÙHOH JBˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJKÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KŠ‘[˜X›YžH[Ù[HŠJNˆBˆ[ÙBˆˆYŠØ]™Y]K›[ÙJBˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJKÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KŠ‘\ØX›YŠJNÈ ËÓ[ÙH H H^Y\œÈÐS‰Õ]XÚÈXXÚÝ\‚ˆBˆ[ÙBˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJKÛÛ ‹ÖT×ÓÔÖWÔÔÈ +È[™KŠ‘[˜X›YŠJNÈ ËÓ[ÙH ˆ H^Y\œÈÐSˆ]XÚÈXXÚÝ\‚ˆBˆBˆ[™JÊΈˆYˆ +Ûؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÓPTÕT—ÓQS•JBˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÐÒPUÊKÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ�ÚX]Ü[ۜˋ‹ˆŠJNˆ[™JÊΈB‚ˆYˆ +[›ÙX�YÛÜ[ÛœÊBˆˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÑP•QÊKÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ‘X�YÈÙ][™ÜË‹‹ˆŠJNˆ[™JÊΈB‚ˆÛY[�]^ + +Ù[XÝ܈OHÖT×ÓÔÐÓÓ‘’QÊKÛÛ KÖT×ÓÔÖWÔÔÈ +È[™KŠ�ÛÛ™šYÈÙ][™ÜË‹‹ˆŠJN‚ˆ ʈ^˜H[™\ț܈ÜXÚ[™Ëˆ +‹Âˆ[™H +ÏH ŽÂ‚ˆÛY[�]^J +Ù[XÝ܈OH‘U +KÖT×ÓÔÖWÔÔÈ +È[™K Š�˜XÚÈŠJN‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎‚ˆ ʈÚÚ\\ØX›Y][\ˈ +‹Â‚ˆYˆ +Ù[XÝ܈OHÖT×ÓÔÐÒPUÈ ‰ˆJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÓPTÕT—ÓQS•JJBˆˆ K\Ù[XÝ܎ˆB‚ˆYˆ +Ù[XÝ܈OHÖT×ÓÔÑP•QÈ ‰ˆ›ÙX�YÛÜ[ÛœÊBˆˆ K\Ù[XÝ܎ˆB‚ˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎‚ˆ ʈÚÚ\\ØX›Y][\ˈ +‹Â‚ˆYˆ +Ù[XÝ܈OHÖT×ÓÔÐÒPUÈ ‰ˆJÛؘ[ØÛÛ™šY˘ÚX]È ˆÒPUÓÔSÓ”×ÓPTÕT—ÓQS•JJBˆˆ +ÊÜÙ[XÝ܎ˆB‚ˆYˆ +Ù[XÝ܈OHÖT×ÓÔÑP•QÈ ‰ˆ›ÙX�YÛÜ[ÛœÊBˆˆ +ÊÜÙ[XÝ܎ˆH‚ˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H‘UˆBˆYŠÙ[XÝ܈ˆ‘U +BˆˆÙ[XÝ܈H ˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +N‚ˆYˆ +Ù[XÝ܈OH‘U +H]Z]H Nˆ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÓÑÊHØ]™Y]K�\Ù[ÙÈH\Ø]™Y]K�\Ù[ÙΈ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÕ”ÑSPQÑJBˆˆYˆ +™\œÝ\Ù[XYÙHˆ JBˆˆYˆ +Ø]™Y]K›[ÙJBˆˆØ]™Y]K›[ÙHH ˆBˆ[ÙBˆˆØ]™Y]K›[ÙHH NˆBˆBˆBˆ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÐÒPUÊBˆˆY[�WÛÜ[Ûœ×ØÚX]Ê +NˆBˆ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÑP•QÈ ‰ˆ[›ÙX�YÛÜ[ÛœÊBˆˆY[�WÛÜ[Ûœ×ÙX�YÊ +NˆBˆ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÐÒPUÊBˆˆY[�WÛÜ[Ûœ×ØÚX]Ê +NˆBˆ[ÙHYˆ +Ù[XÝ܈OHÖT×ÓÔÑP•QÈ ‰ˆ[›ÙX�YÛÜ[ÛœÊHY[�WÛÜ[Ûœ×ÙX�YÊ +Nˆ[ÙHYˆ +Ù[XÝÜ�OTÖT×ÓÔÐÓÓ‘’QÊHY[�WÛÜ[Ûœ×ØÛÛ™šYÊ +Nˆ[ÙH]Z]H NˆBˆBˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÔÖTÕSWÓÔSÓ”×ÓQS•N‚ˆÝ[™YˆÖT×ÓÔÖWÔÔŸB‚‚�›ÚYY[�WÛÜ[Ûœ×ÝšY[Ê +BžÂˆ[�]Z]H ˆ[�Ù[XÝ܈H ˆ[�\ŽÂˆ[�ÛÛ HH LMKÛÛ ˆH N‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—Õ’QS×ÓÔSÓ”×ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ‚ˆÚ[J\]Z] +BˆˆÛY[�]^J ‹ MK Š•šY[ÈÜ[ۜȊJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K LËŠ�œšYÚ™\ÜΈŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ LˉZH‹Ø]™Y]K˜œšYÚ™\ÜÊNˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ K L‹Š‘Ø[[XNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ ‹ L‹‰ZH‹Ø]™Y]K™Ø[[XJNˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ K LKŠ•Ú[™ÝÈÙ™œÙ]ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ ‹ LK‰ZH‹Ø]™Y]K�Ú[™ÝÜÜÊN‚ˆÚYˆÑˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ K Š‘\Ü^H[ÙNˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ ‹ Ø]™Y]K™�[ØÜ™Y[ˆÈŠ‘�[ŠHˆŠ•Ú[™ÝÈŠJN‚ˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K KŠ•šY[ȘXÚÙ[™ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ K +Ü[™ÛÈŠ“Ü[‘ÓŠHˆŠ”ÑŠJJN‚ˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ K ‹Š”ØØ[NˆŠJNˆÚY™YˆS‘“ÒQˆYŠØ]™Y]KšÜØØ[HOH +BˆÙ[ÙB‚BZYŠØ]™Y]K™�[ØÜ™Y[ŠBˆÙ[™Y‚ˆˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ ‹ ‹Š�]]ÛX]XÈŠJNˆBˆ[ÙBˆˆÛY[�]^ + +Ù[XÝ܈OH JKÛÛ ‹ ‹‰M Œ™ž H Z^ ZH‹Ø]™Y]KšÜØØ[K +[� +JšY[Û[Ù\Ëš™\È +ˆØ]™Y]KšÜØØ[JK +[� +JšY[Û[Ù\Ë�”™\È +ˆØ]™Y]KšÜØØ[JJNˆB‚ˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ K ËŠ’\™Ø\™Hš[\ŽˆŠJNˆˆÚ\ˆ +™š[\“˜[YNˆYˆ +Ø]™Y]KšÜØØ[HOH KŒ ‰ˆ\Ø]™Y]K™�[ØÜ™Y[ŠBˆš[\“˜[YHH‘\ØX›YŽÂˆ[ÙHYˆ +Ü[™Û +Bˆš[\“˜[YHH’YÚ]X[]HŽÂˆ[ÙHYˆ +Ø]™Y]KšÙš[\ŠBˆš[\“˜[YHH”Ú[\HŽÂˆ[ÙBˆš[\“˜[YHH�š[[™X\ˆŽÂˆÛY[�]^ + +Ù[XÝ܈OH ŠKÛÛ ‹ ËŠš[\“˜[YJJNˆB‚ˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ K Š”ÛÙ�Ø\™Hš[\ŽˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH ÊKÛÛ ‹  + +Ø]™Y]KšÜØØ[H�H ‹ŒØ]™Y]K™�[ØÜ™Y[ŠHÈŠÙž›]\“˜[Y\ÖÜØ]™Y]KœÝÙš[\—JHˆŠ‘\ØX›YŠJJN‚ˆÚ\ˆœÛ[Z]Ý^ÌÌ—NˆÝÚ]Ú +Ø]™Y]K™œÛ[Z] +BˆˆØ\ÙH ‚ˆÛœš[�ŠœÛ[Z]Ý^ Ú^™[ÙŠœÛ[Z]Ý^ +K‰\È‹Š‘\ØX›YŠJNˆœ™XZΈØ\ÙH N‚ˆÛœš[�ŠœÛ[Z]Ý^ Ú^™[ÙŠœÛ[Z]Ý^ +K‰ZH +”Þ[˜ÊH‹šY[רÝ\œ™[�Ü™Yœ™\Úܘ]J +JNˆœ™XZΈØ\ÙH Ž‚ˆÛœš[�ŠœÛ[Z]Ý^ Ú^™[ÙŠœÛ[Z]Ý^ +K‰ZH‹ Œ +Nˆœ™XZΈØ\ÙH ΂ˆÛœš[�ŠœÛ[Z]Ý^ Ú^™[ÙŠœÛ[Z]Ý^ +K‰ZH‹ L +Nˆœ™XZΈY˜][‚ˆÛœš[�ŠœÛ[Z]Ý^ Ú^™[ÙŠœÛ[Z]Ý^ +K‰\È‹Š•[šÛ›ÝÛˆŠJNˆœ™XZΈB‚ˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ K KŠ‘”È[Z]ˆŠJNˆÛY[�]^ + +Ù[XÝ܈OH +KÛÛ ‹ KœÛ[Z]Ý^ +N‚ˆYŠØ]™Y]K™�[ØÜ™Y[ŠBˆˆÛY[�]^ + +Ù[XÝ܈OHJKÛÛ K ‹Š‘�[ØÜ™Y[ˆ\NˆŠJNˆÛY[�]^ + +Ù[XÝ܈OHJKÛÛ ‹ ‹ +Ø]™Y]KœÝ™]ÚÈŠ”Ý™]ÚÈØÜ™Y[ˆŠHˆŠ”™\Ù\�™H\ÜXݘ][ÈŠJJNˆBˆ[ÙHYŠÙ[XÝ܈OHJBˆˆÙ[XÝ܈H +›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +HȈ LˆB‚ˆÛY[�]^J +Ù[XÝ܈OH L +KK Š�˜XÚÈŠJNˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H LˆBˆYŠÙ[XÝ܈ˆ L +BˆˆÙ[XÝ܈H ˆBˆÙ[™Y‚‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆˆ\ˆH ‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘SQ• +Bˆˆ\ˆH LNˆBˆ[ÙHYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘T’QÒ +Bˆˆ\ˆH NˆB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆØ]™Y]K˜œšYÚ™\ÜÈ +ÏH +ˆ\ŽÂˆYŠØ]™Y]K˜œšYÚ™\ÜÈ L�MŠBˆˆØ]™Y]K˜œšYÚ™\ÜÈH L�MŽÂˆBˆYŠØ]™Y]K˜œšYÚ™\ÜȈ �MŠBˆˆØ]™Y]K˜œšYÚ™\ÜÈH �MŽÂˆBˆ™ØWÝ�ØZ] + +NˆÙ]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠØ]™Y]K™Ø[[XKØ]™Y]K˜œšYÚ™\ÜÊNˆœ™XZΈØ\ÙH N‚ˆØ]™Y]K™Ø[[XH +ÏH +ˆ\ŽÂˆYŠØ]™Y]K™Ø[[XH L�MŠBˆˆØ]™Y]K™Ø[[XHH L�MŽÂˆBˆYŠØ]™Y]K™Ø[[XHˆ �MŠBˆˆØ]™Y]K™Ø[[XHH �MŽÂˆBˆ™ØWÝ�ØZ] + +NˆÙ]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠØ]™Y]K™Ø[[XKØ]™Y]K˜œšYÚ™\ÜÊNˆœ™XZΈØ\ÙH Ž‚ˆØ]™Y]K�Ú[™ÝÜÜÈ +ÏH\ŽÂˆYŠØ]™Y]K�Ú[™ÝÜÜÈ LŠBˆˆØ]™Y]K�Ú[™ÝÜÜÈH LŽÂˆBˆYŠØ]™Y]K�Ú[™ÝÜÜȈ Œ +BˆˆØ]™Y]K�Ú[™ÝÜÜÈH ŒˆBˆœ™XZΈÚYˆÑˆØ\ÙH ΂ˆšY[×Ù�[ØÜ™Y[—Ù›\ + +Nˆœ™XZΈØ\ÙH ‚ˆØ]™Y]K�\ÙYÛH\Ø]™Y]K�\ÙYÛˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆÙ]ØÛÛÜ—ØÛÜœ™XÝ[ÛŠØ]™Y]K™Ø[[XKØ]™Y]K˜œšYÚ™\ÜÊNˆœ™XZΈØ\ÙH N‚ˆÚY›™YˆS‘“ÒQˆYŠØ]™Y]K™�[ØÜ™Y[ŠBˆˆœ™XZΈBˆØ]™Y]KšÜØØ[H +ÏH\ˆ +ˆ Œ�NˆYŠØ]™Y]KšÜØØ[H Œ�JBˆˆØ]™Y]KšÜØØ[HH Œ�NˆBˆYŠØ]™Y]KšÜØØ[Hˆ Œ +BˆˆØ]™Y]KšÜØØ[HH Œ ˆBˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆÙ[ÙBˆØ]™Y]KšÜØØ[H +ÏH\ˆ +ˆ Œ�NˆYŠØ]™Y]KšÜØØ[H Œ +BˆˆØ]™Y]KšÜØØ[HH ŒˆBˆYŠØ]™Y]KšÜØØ[Hˆ Œ +BˆˆØ]™Y]KšÜØØ[HH Œ ˆBˆÙ[™Y‚ˆØ\ÙH Ž‚ˆÚY›™YˆS‘“ÒQˆYˆ +Ü[™Û +\Ø]™Y]K™�[ØÜ™Y[ˆ ‰ˆØ]™Y]KšÜØØ[HOH KŒ +JBˆˆœ™XZΈBˆÙ[™Y‚ˆØ]™Y]KšÙš[\ˆ +ÏH\ŽÂˆYŠØ]™Y]KšÙš[\ˆ +BˆˆØ]™Y]KšÙš[\ˆH NˆBˆYŠØ]™Y]KšÙš[\ˆˆ JBˆˆØ]™Y]KšÙš[\ˆH ˆBˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊN‚BBBXœ™XZΈØ\ÙH ΂ˆYŠ\Ø]™Y]K™�[ØÜ™Y[ˆ ‰ˆØ]™Y]KšÜØØ[H ‹Œ +Bˆˆœ™XZΈBˆšY[Û[Ù\Ë™š[\ˆ +ÏH\ŽÂˆYŠšY[Û[Ù\Ë™š[\ˆˆ“UT—ÓPV H JBˆˆšY[Û[Ù\Ë™š[\ˆH ˆBˆYŠšY[Û[Ù\Ë™š[\ˆ +BˆˆšY[Û[Ù\Ë™š[\ˆH“UT—ÓPV H NˆBˆØ]™Y]KœÝÙš[\ˆHšY[Û[Ù\Ë™š[\ŽÂˆY[\Ù] +[P�Y™™\‹   L� MŒ +N‚BBB]šY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆœ™XZΈØ\ÙH‚ˆØ]™Y]K™œÛ[Z]H +Ø]™Y]K™œÛ[Z] +È\ŠH H ˆYˆ +Ø]™Y]K™œÛ[Z] +HØ]™Y]K™œÛ[Z] +ÏH ˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆœ™XZΈØ\ÙHN‚ˆšY[×ÜÝ™]Ú + +Ø]™Y]KœÝ™]Ú�H JJNˆœ™XZΈÙ[™Y‚ˆY˜][‚ˆ]Z]H NˆBˆBˆBˆØ]™\Ù][™ÜÊ +Nˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—Õ’QS×ÓÔSÓ”×ÓQS•NŸB‚‚�›ÚYY[�WÛÜ[ÛœÊ +BžÂˆÙYš[™HÔÖWÔÔÈ LBˆÙYš[™HÔÖÔÔÈ Mˆˆ\YYˆ[�[Hˆ’QS×ÓÔSÓ‹ˆÓÕS‘ÓÔSÓ‹ˆÓÓ•“ÓÓÔSÓ‹ˆÖTÕSWÓÔSÓ‹‚ˆS‘ÓÔSÓ‚ˆHWÜÙ[XÝ܎‚ˆ[�]Z]H ˆ[�WÛÙ™œÙ]HÔÖWÔÔΈ[��PÒ×ÓÔSÓˆHS‘ÓÔSӎˆWÜÙ[XÝ܈Ù[XÝ܈H’QS×ÓÔSӎ‚ˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÓÔSÓ”×ÓQS•Nˆ›Ý™]ÚÙ^\ÈH ȈˆÚ[J\]Z] +BˆÈˆÛY[�]^J +Ù[XÝ܈OH’QS×ÓÔSÓŠKWÛÙ™œÙ] +Õ’QS×ÓÔSÓ‹ Š•šY[ÈÜ[ۜˋ‹ˆŠJNˆÛY[�]^J +Ù[XÝ܈OHÓÕS‘ÓÔSÓŠKWÛÙ™œÙ] +ÔÓÕS‘ÓÔSÓ‹ Š”ÛÝ[™Ü[ۜˋ‹ˆŠJNˆÛY[�]^J +Ù[XÝ܈OHÓÓ•“ÓÓÔSÓŠKWÛÙ™œÙ] +ÐÓÓ•“ÓÓÔSÓ‹ Š�ÛÛ�›ÛÜ[ۜˋ‹ˆŠJNˆÛY[�]^J +Ù[XÝ܈OHÖTÕSWÓÔSÓŠKWÛÙ™œÙ] +ÔÖTÕSWÓÔSÓ‹ Š”Þ\Ý[HÜ[ۜˋ‹ˆŠJNˆˆÛY[�]^J +Ù[XÝ܈OH�PÒ×ÓÔSÓŠKWÛÙ™œÙ] +Ð�PÒ×ÓÔSÓŠÌ‹ Š�˜XÚÈŠJN‚ˆ\]J +]™[OH•S +K +N‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +BˆˆYŠÙ[XÝ܈H’QS×ÓÔSÓŠBˆˆÙ[XÝ܈H�PÒ×ÓÔSӎˆBˆ[ÙH K\Ù[XÝ܎‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÙ[XÝ܈ˆ�PÒ×ÓÔSÓŠBˆˆÙ[XÝ܈H’QS×ÓÔSӎˆB‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÓSÕ‘SQ•“Q×ÓSÕ‘T’QÒ“Q×ÐS–P•UÓŠJBˆ‚ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆB‚ˆYŠÙ[XÝÜ�OP�PÒ×ÓÔSÓŠH]Z]H Nˆ[ÙHYŠÙ[XÝÜ�OU’QS×ÓÔSÓŠHY[�WÛÜ[Ûœ×ÝšY[Ê +Nˆ[ÙHYŠÙ[XÝÜ�OTÓÕS‘ÓÔSÓŠHY[�WÛÜ[Ûœ×ÜÛÝ[™ + +Nˆ[ÙHYŠÙ[XÝÜ�OPÓÓ•“ÓÓÔSÓŠHY[�WÛÜ[Ûœ×Ú[œ] + +Nˆ[ÙHYŠÙ[XÝÜ�OTÖTÕSWÓÔSÓŠBˆˆY[�WÛÜ[Ûœ×ÜÞ\Ý[J +NȈBˆˆ[ÙH]Z]H NˆBˆBˆØ]™\Ù][™ÜÊ +NˆYŠÜ]\ÙHOH JBˆˆÜ]\ÙHH ŽÂˆBˆ›Ý™]ÚÙ^\ÈH ˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÓÔSÓ”×ÓQS•N‚ˆÝ[™YˆÕÐÒPUˆÝ[™YˆÔÖWÔÔˆÝ[™YˆÔÖÔÔˆÝ[™YˆÒPUÔUTÑWÔÔÖBŸB‚‹ËÈ KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKB‚‚�›ÚYÜ[˜›Ü“XZ[Š[�\™ØËÚ\ˆ +Š˜\™ÝŠBžÂˆÜš]WÛX\H•Sˆ[�]Z]H ˆ[�™[˜XÚÈH Nˆ[�Ù[XÝ܈H ˆL̈[�›Ý[YHH ˆ[�Ý\�YH ˆÚ\ˆ\�Y™–ÓPVЕQ‘‘T—ÓS—HHȈŸNˆ[�^Y\œÖÓPVÔVQT”×HHÌ    Nˆ[�Nˆ[�\™Û‚ˆš[�Š“Ü[�›Ôˆ \ËÛÛ\[H]Nˆˆ×ÑUW×È——ˆ‹‘T”ÒSÓŠN‚ˆYŠ\™ØÈˆ JBˆˆ\™ÛHÝ›[Š\™Ý–ÌWJNˆYŠ\™Ûˆ M ‰ˆ[Y[XÛ\ +\™Ý–ÌWK›Ù™œØÜ™Y[šÚ[H‹ M +JBˆˆQ�USÓÑ‘”ÐÔ‘QS—ÒÒSHÙ]˜[Y[� + +Ú\ˆ +ŠX\™Ý–ÌWH +È M ˆ‹ˆŠNˆBˆYŠ\™Ûˆ M ‰ˆ[Y[XÛ\ +\™Ý–ÌWKœÚÝÙš[\Ý\ÙYH‹ M +JBˆˆš[�š[U\ØYÙTÝ]\ÝXÜÈHÙ]˜[Y[� + +Ú\ˆ +ŠX\™Ý–ÌWH +È M ˆ‹ˆŠNˆBˆB‚‚ˆ[Ù[ÛY\ÝHÜ™X]S[Ù[ÛÛ[X[™\Ý + +Nˆ[Ù[ÝÛY\ÝHÜ™X]S[Ù[ÝÛÛ[X[™\Ý + +Nˆ]™[ÛY\ÝHÜ™X]S]™[ÛÛ[X[™\Ý + +Nˆ]™[Ü™\˜ÛY\ÝHÜ™X]S]™[Ü™\�ÛÛ[X[™\Ý + +NˆÜ™X]S[Ù[\Ý + +N‚ˆ ËÈØY™XÙ\ÜØ\žHÛÛ\Û™[�Ë‚ˆš[�Š‘Ø[YHÙ[XÝYˆ \×—ˆ‹XÚÙš[JNˆØYÙ][™ÜÊ +NˆÝ\�\ + +N‚X›Ý™]ÚÙ^\ÈH ‚ˆYŠÚÚ\ÜÙ] +Bˆ‚ˆ ËÈ™]È[\›˜]]™H˜XÚÙÜ›Ý[™] ‚ˆYŠÝ\ÝšÙÜ™ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝšÙÜ™ÊNˆÝ˜Ø] +\�Y™‹›ÙÛÈŠNˆØYؘXÚÙÜ›Ý[™ +\�Y™ŠNˆBˆ[ÙBˆˆØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÛÙÛÈŠNˆB‚ˆÚ[JÝ[YHÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ˆ ‰ˆJ›Ý™]ÚÙ^\È ˆ +“Q×ÐS–P•UÓˆ“Q×ÑTÐÊJJBˆˆ\]J  +NˆB‚ˆ]\ÚXÊ™]KÛ]\ÚXËÜ™[Z^‹ K +N‚ˆ ËÈ™]È[\›˜]]™HØÙ[™H] ‚ˆYŠÝ\ÝØÙ[™\ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝØÙ[™\ÊNˆÝ˜Ø] +\�Y™‹›ÙÛË�ŠNˆ^\ØÙ[™J\�Y™ŠNˆBˆ[ÙBˆˆ^\ØÙ[™J™]KÜØÙ[™\ËÛÙÛË�ŠNˆBˆBˆÛX\œØÜ™Y[Š˜XÚÙÜ›Ý[™ +N‚ˆÚ[J\]Z] +BˆˆYŠÚÚ\ÜÙ]  ‰ˆJÛÝ×ÛXZ[›Y[�WÙ›YÉŽ +JBˆˆYŠÝ[YH�H[�›Ý[YJBˆˆ ËÈ™]È[\›˜]]™HØÙ[™H] ‚ˆYŠÝ\ÝØÙ[™\ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝØÙ[™\ÊNˆÝ˜Ø] +\�Y™‹š[�›Ë�ŠNˆ^\ØÙ[™J\�Y™ŠNˆBˆ[ÙBˆˆ^\ØÙ[™J™]KÜØÙ[™\ËÚ[�›Ë�ŠNˆBˆ\]J  +Nˆ[�›Ý[YHHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ Œˆ™[˜XÚÈH NˆÝ\�YH ˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÑTÐÊBˆˆ]Z]H NˆBˆBˆ[ÙBˆˆÝ\�YH Nˆ™[˜XÚÈH ˆB‚ˆYˆ +ÛÝ×ÛXZ[›Y[�WÙ›YÈOH +HÛÝ×ÛXZ[›Y[�WÙ›YÈH ˆYŠ\Ý\�Y +BˆˆYŠ +Ý[YH HÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +H +Ûؘ[ØÛÛ™šYË™Ø[YWÜÜYY È ŠJBˆˆÛY[�]^J   Š”‘TÔÈÕT•ŠJNˆBˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÐS–P•UÓŠJBˆˆÝ\�YH Nˆ™[˜XÚÈH NˆBˆBˆ[ÙHYŠÚÚ\ÜÙ]�H +BˆˆØYØ[YQš[J +Nˆ^YØ[YJ^Y\œË\ÙTÙ]�H È\ÙTÙ]ˆÚÚ\ÜÙ] \ÙTØ]™JNˆBˆ[ÙBˆˆÛY[�]^J +Ù[XÝ܈OH +K ‹ Š”Ý\�Ø[YHŠJNˆÛY[�]^J +Ù[XÝ܈OH JK Ë Š“Ü[ۜȊJNˆÛY[�]^J +Ù[XÝ܈OH ŠK  Š’ÝÈÈ^HŠJNˆÛY[�]^J +Ù[XÝ܈OH ÊK K Š’[Ùˆ˜[YHŠJNˆÛY[�]^J +Ù[XÝ܈OH +K ‹ Š”]Z]ŠJNˆYŠÙ[XÝ܈ +BˆˆÙ[XÝ܈H ˆBˆYŠÙ[XÝ܈ˆ +BˆˆÙ[XÝ܈H ˆB‚ˆYŠ›Ý™]ÚÙ^\ÊBˆˆ[�›Ý[YHHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ŒˆB‚ˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘UT +Bˆˆ K\Ù[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ“Q×ÓSÕ‘QÕÓŠBˆˆ +ÊÜÙ[XÝ܎ˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\  Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆBˆYŠ›Ý™]ÚÙ^\È ˆ +“Q×ÐS–P•UÓŠJBˆˆYŠÛؘ[ÜØ[\WÛ\Ý ˜™Y\̈�H +BˆˆÛÝ[™Ü^WÜØ[\JÛؘ[ÜØ[\WÛ\Ý ˜™Y\Ì‹ Ø]™Y]K™Y™™XÝ›Û Ø]™Y]K™Y™™XÝ›Û  L +NˆBˆÝÚ]Ú +Ù[XÝÜŠBˆˆØ\ÙH ‚ˆ›ÜŠHH ÈHPVÔVQT”ÎÈJÊÊBˆˆ^Y\œÖÚWHH^Y\–ÚWK›™]ÚÙ^\È ˆ +“Q×ÐS–P•UÓŠNˆBˆ™[˜XÚÈHÚÛÜÙWÛ[ÙJ^Y\œÊNˆYŠ™[˜XÚÊBˆˆÝ\�YH ˆBˆœ™XZΈØ\ÙH N‚ˆY[�WÛÜ[ÛœÊ +Nˆœ™XZΈØ\ÙH Ž‚ˆˆ[�™]š[Ý\ÓÛÜH]\ÚXÛÛ܈Ú\ˆ™]š[Ý\Ó]\ÚXÖÜÚ^™[ÙŠÝ\œ™[�]\ÚXÊWN‚ˆY[\Ù] +™]š[Ý\Ó]\ÚXË Ú^™[ÙŠ™]š[Ý\Ó]\ÚXÊJNˆÝ˜ÜJ™]š[Ý\Ó]\ÚXËÝ\œ™[�]\ÚXÊN‚ˆYŠÝ\ÝØÙ[™\ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝØÙ[™\ÊNˆÝ˜Ø] +\�Y™‹šÝÝË�ŠNˆ^\ØÙ[™J\�Y™ŠNˆBˆ[ÙBˆˆ^\ØÙ[™J™]KÜØÙ[™\ËÚÝÝË�ŠNˆBˆYŠÝšXÛ\ +™]š[Ý\Ó]\ÚXËÝ\œ™[�]\ÚXÊHOH +Bˆˆ]\ÚXÊ™]š[Ý\Ó]\ÚXË™]š[Ý\ÓÛÜ  +NˆBˆ™[˜XÚÈH Nˆœ™XZΈBˆØ\ÙH ΂ˆ[˜[YJ +Nˆ™[˜XÚÈH Nˆœ™XZΈY˜][‚ˆ]Z]H Nˆœ™XZΈBˆ[�›Ý[YHHÝ[YH +ÈÛؘ[ØÛÛ™šYË™Ø[YWÜÜYY +ˆ ŒˆBˆBˆYŠ™[˜XÚÊBˆˆYŠÝ\�Y +Bˆˆ ʈˆܘ]\È + L LŒ ŒJHYY[ˆY][Û˜[[œÝ[˜ÙHÙˆH˜[œÛ][Ûˆ�[˜Ý[Ûˆ]Y[�HØÜ™Y[‚ˆ\ÙYÈ™Yœ™\Ú[^Ú]Ý]ÛÜÙH[™™[Ü[ˆH[™Ú[™B‚ˆܘ]\È + ‹LŒ ŒÊHYY[ˆY][Û˜[[œÝ[˜ÙHÙˆHšY[×Û[ÙH�[˜Ý[Ûˆ]Y[�HØÜ™Y[‚ˆ\ÙYÈ™Yœ™\ÚHÝXÚØÜ™Y[ˆ›Ü\�Y\ÈÛˆ[™›ÚYÚ]Ý]™\Ý\�[™Âˆ +‹ÂˆšY[×ÜÙ]Û[ÙJšY[Û[Ù\ÊNˆØ—Ú[š]˜[œÊ +NˆˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÓQS•NˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÕUN‚ˆYŠÝ\ÝšÙÜ™ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝšÙÜ™ÊNˆÝ˜Ø] +\�Y™‹�]XˆŠNˆØYؘXÚÙÜ›Ý[™ +\�Y™ŠNˆBˆ[ÙBˆˆØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÝ]XˆŠNˆBˆBˆ[ÙBˆˆØÜ™Y[—ÜÝ]\È �H’S—ÔÐÔ‘QS—ÓQS•NˆØÜ™Y[—ÜÝ]\ÈHS—ÔÐÔ‘QS—ÕUN‚ˆYŠÝ\ÝšÙÜ™ÈOH•S +BˆˆÝ˜ÜJ\�Y™‹Ý\ÝšÙÜ™ÊNˆÝ˜Ø] +\�Y™‹�]HŠNˆØYؘXÚÙÜ›Ý[™ +\�Y™ŠNˆBˆ[ÙBˆˆØYØØXÚYؘXÚÙÜ›Ý[™ +™]KØ™ÜËÝ]HŠNˆBˆB‚ˆYŠ\ÛÝ[™Ü]Y\žWÛ]\ÚXÊ•S •S +JBˆˆ]\ÚXÊ™]KÛ]\ÚXËÜ™[Z^‹ K +NˆBˆ™[˜XÚÈH ˆBˆ\]J  +NˆBˆ›Ü”Ú]ÝÛŠ Q�USÔÒUÕÓ—ÓQTÔÐQÑJNŸB‚ˆÝ[™YˆÑUÐT‘ˆÝ[™YˆÑUÐT‘×ÓS‚ˆÝ[™YˆÑUÐT‘ÔˆÝ[™YˆÑUÐT‘ÔÓS‚ˆÝ[™YˆÑUÒS•ÐT‘ˆÝ[™YˆÑUÑ“ÐUÐT‘ˆÝ[™YˆÑUÒS•ÐT‘ÔˆÝ[™YˆÑUÑ“ÐUÐT‘Ô \ No newline at end of file diff --git a/engine/openborscript.c b/engine/openborscript.c index 112adb435..16424ee52 100644 --- a/engine/openborscript.c +++ b/engine/openborscript.c @@ -3559,7 +3559,8 @@ HRESULT openbor_getentityproperty(ScriptVariant **varlist , ScriptVariant **pret (*pretvar)->lVal = (LONG)(ent->death_state & DEATH_STATE_DEAD); break; case _ep_aiflag_jumpid: - (*pretvar)->lVal = (LONG)ent->jump.animation_id; + ScriptVariant_ChangeType(*pretvar, VT_UINTEGER64); + (*pretvar)->ullVal = ent->jump.animation_id; break; case _ep_aiflag_jumping: (*pretvar)->lVal = (LONG)ent->jumping; @@ -3712,20 +3713,20 @@ HRESULT openbor_getentityproperty(ScriptVariant **varlist , ScriptVariant **pret case _ep_animnum: case _ep_animationid: { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)ent->animnum; + ScriptVariant_ChangeType(*pretvar, VT_UINTEGER64); + (*pretvar)->ullVal = ent->animnum; break; } case _ep_prevanimationid: { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)ent->animnum_previous; + ScriptVariant_ChangeType(*pretvar, VT_UINTEGER64); + (*pretvar)->ullVal = ent->animnum_previous; break; } case _ep_animpos: { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)ent->animpos; + ScriptVariant_ChangeType(*pretvar, VT_UINTEGER64); + (*pretvar)->ullVal = ent->animpos; break; } case _ep_animvalid: @@ -4324,8 +4325,8 @@ HRESULT openbor_getentityproperty(ScriptVariant **varlist , ScriptVariant **pret } case _ep_guardpoints: { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)ent->guardpoints; + ScriptVariant_ChangeType(*pretvar, VT_INTEGER64); + (*pretvar)->llVal = ent->guardpoints; break; } case _ep_hasplatforms: @@ -5199,8 +5200,8 @@ HRESULT openbor_getentityproperty(ScriptVariant **varlist , ScriptVariant **pret } case _ep_seal: { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)ent->seal; + ScriptVariant_ChangeType(*pretvar, VT_INTEGER64); + (*pretvar)->llVal = ent->seal; break; } case _ep_sealtime: @@ -5620,6 +5621,8 @@ HRESULT openbor_changeentityproperty(ScriptVariant **varlist , ScriptVariant **p s_model *tempmodel ; char *tempstr = NULL; LONG ltemp, ltemp2; + int64_t lltemp; + uint64_t ulltemp; DOUBLE dbltemp; int propind; int i = 0; @@ -5872,9 +5875,9 @@ HRESULT openbor_changeentityproperty(ScriptVariant **varlist , ScriptVariant **p } case _ep_animpos: { - if(SUCCEEDED(ScriptVariant_IntegerValue(varlist[2], <emp))) + if(SUCCEEDED(ScriptVariant_Unsigned64Value(varlist[2], &ulltemp))) { - ent->animpos = (LONG)ltemp; + ent->animpos = ulltemp; } break; } @@ -6403,9 +6406,9 @@ HRESULT openbor_changeentityproperty(ScriptVariant **varlist , ScriptVariant **p } case _ep_guardpoints: { - if(SUCCEEDED(ScriptVariant_IntegerValue(varlist[2], <emp))) + if(SUCCEEDED(ScriptVariant_Integer64Value(varlist[2], &lltemp))) { - ent->guardpoints = (LONG)ltemp; + ent->guardpoints = lltemp; } break; } @@ -7184,9 +7187,9 @@ HRESULT openbor_changeentityproperty(ScriptVariant **varlist , ScriptVariant **p } case _ep_seal: { - if(SUCCEEDED(ScriptVariant_IntegerValue(varlist[2], <emp))) + if(SUCCEEDED(ScriptVariant_Integer64Value(varlist[2], &lltemp))) { - ent->seal = (LONG)ltemp; + ent->seal = lltemp; } break; } @@ -15500,7 +15503,8 @@ HRESULT openbor_updateframe(ScriptVariant **varlist , ScriptVariant **pretvar, i //executeanimation(entity, int anim, int resetable); HRESULT openbor_executeanimation(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { - LONG anim, resetable = 0; + animation_id_t anim = ANI_NONE; + LONG resetable = 0; entity *e; *pretvar = NULL; @@ -15544,7 +15548,7 @@ HRESULT openbor_executeanimation(ScriptVariant **varlist , ScriptVariant **pretv return S_OK; } - if(paramCount > 1 && FAILED(ScriptVariant_IntegerValue(varlist[1], &anim))) + if(paramCount > 1 && FAILED(ScriptVariant_Unsigned64Value(varlist[1], &anim))) { goto executeanimation_error; } @@ -15552,7 +15556,7 @@ HRESULT openbor_executeanimation(ScriptVariant **varlist , ScriptVariant **pretv { goto executeanimation_error; } - ent_set_anim(e, (int)anim, (int)resetable); + ent_set_anim(e, anim, (int)resetable); return S_OK; @@ -15564,7 +15568,8 @@ HRESULT openbor_executeanimation(ScriptVariant **varlist , ScriptVariant **pretv //performattack(entity, int anim, int resetable); HRESULT openbor_performattack(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { - LONG anim, resetable = 0; + animation_id_t anim = ANI_NONE; + LONG resetable = 0; entity *e; *pretvar = NULL; @@ -15607,7 +15612,7 @@ HRESULT openbor_performattack(ScriptVariant **varlist , ScriptVariant **pretvar, return S_OK; } - if(paramCount > 1 && FAILED(ScriptVariant_IntegerValue(varlist[1], &anim))) + if(paramCount > 1 && FAILED(ScriptVariant_Unsigned64Value(varlist[1], &anim))) { goto performattack_error; } @@ -15615,7 +15620,7 @@ HRESULT openbor_performattack(ScriptVariant **varlist , ScriptVariant **pretvar, { goto performattack_error; } - ent_set_anim(e, (int)anim, (int)resetable); + ent_set_anim(e, anim, (int)resetable); return S_OK; @@ -15627,7 +15632,8 @@ HRESULT openbor_performattack(ScriptVariant **varlist , ScriptVariant **pretvar, //setidle(entity, int anim, int resetable, int stalladd); HRESULT openbor_setidle(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { - LONG anim = 0, resetable = 0, stalladd = 0; + animation_id_t anim = ANI_NONE; + LONG resetable = 0, stalladd = 0; entity *e; extern unsigned int _time; @@ -15675,7 +15681,7 @@ HRESULT openbor_setidle(ScriptVariant **varlist , ScriptVariant **pretvar, int p return S_OK; } - if(paramCount > 1 && FAILED(ScriptVariant_IntegerValue(varlist[1], &anim))) + if(paramCount > 1 && FAILED(ScriptVariant_Unsigned64Value(varlist[1], &anim))) { goto setidle_error; } @@ -15687,7 +15693,7 @@ HRESULT openbor_setidle(ScriptVariant **varlist , ScriptVariant **pretvar, int p { goto setidle_error; } - ent_set_anim(e, (int)anim, (int)resetable); + ent_set_anim(e, anim, (int)resetable); if(stalladd > 0) { diff --git a/engine/source/openborscript/constants.c b/engine/source/openborscript/constants.c index cd30d042c..f798a8d97 100644 --- a/engine/source/openborscript/constants.c +++ b/engine/source/openborscript/constants.c @@ -30,13 +30,15 @@ else if(stricmp(#x, constname)==0) {\ #define ICMPSCONSTA(x, y) \ else if(strnicmp(constname, #x, sizeof(#x)-1)==0 && constname[sizeof(#x)-1] >= '1' && constname[sizeof(#x)-1]<='9') \ { \ - v.lVal = (LONG)(y[atoi(constname+(sizeof(#x)-1))-1]);\ + ScriptVariant_ChangeType(&v, VT_UINTEGER64);\ + v.ullVal = (uint64_t)(y[atoi(constname+(sizeof(#x)-1))-1]);\ } #define ICMPSCONSTB(x, y) \ else if(strnicmp(constname, #x, sizeof(#x)-1)==0 && constname[sizeof(#x)-1] >= '1' && constname[sizeof(#x)-1]<='9') \ { \ - v.lVal = (LONG)(y[atoi(constname+(sizeof(#x)-1))+STA_ATKS-1]);\ + ScriptVariant_ChangeType(&v, VT_UINTEGER64);\ + v.ullVal = (uint64_t)(y[atoi(constname+(sizeof(#x)-1))+STA_ATKS-1]);\ } #define ICMPSCONSTC(x) \ diff --git a/engine/source/openborscript/entity.c b/engine/source/openborscript/entity.c index 9ceb9066f..b68bc5d72 100644 --- a/engine/source/openborscript/entity.c +++ b/engine/source/openborscript/entity.c @@ -53,19 +53,19 @@ static const entity_property_info entity_properties[] = { .id_string = "ENTITY_PROPERTY_ANIMATION_FRAME", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, animpos), - .type = VT_INTEGER }, + .type = VT_UINTEGER64 }, {.property = ENTITY_PROPERTY_ANIMATION_ID, .id_string = "ENTITY_PROPERTY_ANIMATION_ID", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, animnum), - .type = VT_INTEGER }, + .type = VT_UINTEGER64 }, {.property = ENTITY_PROPERTY_ANIMATION_ID_PREVIOUS, .id_string = "ENTITY_PROPERTY_ANIMATION_ID_PREVIOUS", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, animnum_previous), - .type = VT_INTEGER }, + .type = VT_UINTEGER64 }, {.property = ENTITY_PROPERTY_ANIMATION_STATE, .id_string = "ENTITY_PROPERTY_ANIMATION_STATE", @@ -365,7 +365,7 @@ static const entity_property_info entity_properties[] = { .id_string = "ENTITY_PROPERTY_GUARD_POINTS", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, guardpoints), - .type = VT_INTEGER }, + .type = VT_INTEGER64 }, {.property = ENTITY_PROPERTY_GUARD_TIME, .id_string = "ENTITY_PROPERTY_GUARD_TIME", @@ -425,7 +425,7 @@ static const entity_property_info entity_properties[] = { .id_string = "ENTITY_PROPERTY_JUMP_ANIMATION_ID", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, jump.animation_id), - .type = VT_INTEGER }, + .type = VT_UINTEGER64 }, {.property = ENTITY_PROPERTY_JUMP_STATE, .id_string = "ENTITY_PROPERTY_JUMP_STATE", @@ -737,7 +737,7 @@ static const entity_property_info entity_properties[] = { .id_string = "ENTITY_PROPERTY_SEAL_ENERGY", .config_flags = PROPERTY_ACCESS_CONFIG_MACRO_DEFAULT, .offset = PROPERTY_MEMBER_OFFSET(entity, seal), - .type = VT_INTEGER }, + .type = VT_INTEGER64 }, {.property = ENTITY_PROPERTY_SEAL_TIME, .id_string = "ENTITY_PROPERTY_SEAL_TIME",