В этой справке уже есть статья о том, как добавить миссию. Если используем её автоматическую генерацию, то у нас есть некоторые "события", которые можно использовать в отдельных участках кода.
Всего таких событий три: "код победы", "код провала" и "код очистки". Первый блок выполняется когда миссия завершилась удачно ( по-умолчанию ). Второй блок будет выполнен тогда, миссия была провалена. И третий - когда нужно очистить игру от созданных элементов в миссии: актёров, маркеров и т.п.
Для вызова этих "событий" нужно воспользоваться атрибутом Mission и указать ему анонимную функцию для выполнения:
[Mission]
public void MISSION() {
var index = Int.local( 0 ); // 0@
var counter = Int.local( 1 ); // 1@
var x = Float.local( 2 ); // 2@
var enemyArray = Array<Actor>.local( 50, 9 ); // 50@ ... 59@
var enemyMarkerArray = Array<Marker>.local( 60, 9 ); // 60@ ... 69@
x.value = 0.0;
enemyArray.each( index, actor => {
actor.create_random( x, 1400.0, 13.0 );
enemyMarkerArray[ index ].create_above_actor( actor );
x += 1.2;
} );
cycle( delegate {
wait( 0 );
counter.value = 0;
enemyArray.each( index, actor => {
and( actor.is_dead(), delegate {
counter += 1;
and( enemyMarkerArray[ index ].is_enabled(), delegate {
enemyMarkerArray[ index ].disable();
} );
} );
} );
and( counter >= enemyArray.count, delegate {
jump( 0 );
} );
} );
label = 0;
// далее пишем события:
Mission.OnPassed = delegate {
show_text_styled( "M_PASSD", 5000, 1 );
};
Mission.OnFailed = delegate {
show_text_styled( "M_FAIL", 5000, 1 );
};
Mission.OnClear = delegate {
comment = "clear all markers and actors";
to( index, 0, enemyMarkerArray.count, delegate {
and( enemyMarkerArray[ index ].is_enabled(), delegate {
enemyMarkerArray[ index ].disable();
} );
and( enemyArray[ index ].is_defined(), delegate {
enemyArray[ index ].remove_references().destroy();
} );
} );
};
}
События можно писать в любом месте кода миссии. Я рекомендую это делать в самом конце. Вот такой код получится в итоге:
//------------- Mission: MISSION (0) --------------- :MISSION 03A4: name_thread 'MISSION' 0050: gosub @MISSION_START 00D6: if 0112: wasted_or_busted // mission only 004D: jump_if_false @MISSION_END 0050: gosub @MISSION_FAILED :MISSION_END 0004: $409 = 0 // $ = ? (int) 00D8: mission_cleanup 004E: end_thread :MISSION_START 0317: increment_mission_attempts 0004: $409 = 1 // $ = ? (int) 0007: 2@ = 0.0 // @ = ? (float) for 0@ = 0 to 9 0376: 50@(0@,9i) = create_random_actor_at 2@ 1400.0 13.0 0187: 60@(0@,9i) = create_marker_above_actor 50@(0@,9i) 000B: 2@ += 1.2 // @ += ? (float) end :MISSION_LOOP_0 0001: wait 0 ms 0006: 1@ = 0 // @ = ? (int) for 0@ = 0 to 9 00D6: if 0118: actor 50@(0@,9i) dead then 000A: 1@ += 1 // @ += ? (int) 00D6: if 075C: marker 60@(0@,9i) enabled then 0164: disable_marker 60@(0@,9i) end end end 00D6: if 0029: 1@ >= 9 // @ >= ? (int) then 0002: jump @MISSION_0 end 0002: jump @MISSION_LOOP_0 :MISSION_0 :MISSION_PASSED 0050: gosub @MISSION_CLEAR 00BA: show_text_styled GXT 'M_PASSD' time 5000 style 1 0051: return :MISSION_FAILED 0050: gosub @MISSION_CLEAR 00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 0051: return :MISSION_CLEAR /* clear all markers and actors */ int 0@ for 0@ = 0 to 9 00D6: if 075C: marker 60@(0@,9i) enabled then 0164: disable_marker 60@(0@,9i) end 00D6: if 056D: actor 50@(0@,9i) defined then 01C2: remove_references_to_actor 50@(0@,9i) // Like turning an actor into a random pedestrian 009B: destroy_actor 50@(0@,9i) end end 0051: return
Часто будут возникать ситуации, когда нужно написать собственный код провала. В помощь нам придут команды прыжков на метку провала и победы, а также переход с возвратом на метку чистки.
Использовать эти команды можно только в миссиях с автоматической генерацией. Вот пример:
[Mission]
public void MISSION() {
var checkpoint = Checkpoint.local( 0 ).create( 140.0, 1440.0, 13.0 );
jf( 0, PlayerActor.is_near_point_3d_on_foot( 1, 140.0, 1440.0, 13.0, 3.0, 3.0, 3.0 ) );
and( !PlayerChar.is_money_greater( 4000 ), delegate {
jump_failed(); // прыжок на метку провала
} );
and( PlayerActor.is_current_weapon( WeaponNumber.AK47 ), delegate {
jump( 1 );
} );
jump_passed(); // прыжок на метку победы
label = 1;
gosub_clear(); // переход на метку чистки с возвратом
show_text_highpriority( "GXTNAME", 5000, 1 );
show_text_styled( "M_FAIL", 5000, 1 );
@return();
Mission.OnPassed = delegate {
show_text_styled( "M_PASSD", 5000, 1 );
};
Mission.OnFailed = delegate {
show_text_styled( "M_FAIL", 5000, 1 );
};
Mission.OnClear = delegate {
checkpoint.disable();
};
}
Если использовать персональные блоки для провала или успеха, то перед этими метками команду "jump_passed" использовать обязательно! Также обязательным условием является завершать свои блоки командой "@return". Вот такой результат получится:
//------------- Mission: MISSION (0) --------------- :MISSION 03A4: name_thread 'MISSION' 0050: gosub @MISSION_START 00D6: if 0112: wasted_or_busted // mission only 004D: jump_if_false @MISSION_END 0050: gosub @MISSION_FAILED :MISSION_END 0004: $409 = 0 // $ = ? (int) 00D8: mission_cleanup 004E: end_thread :MISSION_START 0317: increment_mission_attempts 0004: $409 = 1 // $ = ? (int) 018A: 0@ = create_checkpoint_at 140.0 1440.0 13.0 :MISSION_AUTO_LABEL_0 0001: wait 0 ms 00D6: if 00FE: actor $3 sphere 1 in_sphere 140.0 1440.0 13.0 radius 3.0 3.0 3.0 004D: jump_if_false @MISSION_AUTO_LABEL_0 00D6: if 810A: not player $2 money > 4000 then 0002: jump @MISSION_FAILED end 00D6: if 02D8: actor $3 current_weapon == 30 then 0002: jump @MISSION_1 end 0002: jump @MISSION_PASSED :MISSION_1 0050: gosub @MISSION_CLEAR 00BC: show_text_highpriority GXT 'GXTNAME' time 5000 flag 1 00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 0051: return :MISSION_PASSED 0050: gosub @MISSION_CLEAR 00BA: show_text_styled GXT 'M_PASSD' time 5000 style 1 0051: return :MISSION_FAILED 0050: gosub @MISSION_CLEAR 00BA: show_text_styled GXT 'M_FAIL' time 5000 style 1 0051: return :MISSION_CLEAR 0164: disable_marker 0@ 0051: return