1 #using scripts\codescripts\struct;
3 #using scripts\shared\array_shared;
4 #using scripts\shared\callbacks_shared;
5 #using scripts\shared\clientfield_shared;
6 #using scripts\shared\demo_shared;
7 #using scripts\shared\flag_shared;
8 #using scripts\shared\hud_util_shared;
9 #using scripts\shared\laststand_shared;
10 #using scripts\shared\system_shared;
11 #using scripts\shared\util_shared;
13 #insert scripts\shared\shared.gsh;
14 #insert scripts\shared\version.gsh;
16 #using scripts\zm\_zm_bgb;
17 #using scripts\zm\_zm_equipment;
18 #using scripts\zm\_zm_stats;
19 #using scripts\zm\_zm_unitrigger;
20 #using scripts\zm\_zm_utility;
21 #using scripts\zm\_zm_weapons;
23 #insert scripts\zm\_zm_perks.gsh;
24 #insert scripts\zm\_zm_utility.gsh;
25 #insert scripts\zm\craftables\_zm_craftables.gsh;
79 #precache( "string", "ZOMBIE_BUILDING" );
80 #precache( "string", "ZOMBIE_BUILD_PIECE_MISSING" );
81 #precache( "string", "ZOMBIE_BUILD_PIECE_GRAB" );
82 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_MORE" );
83 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_GRAB" );
84 #precache( "triggerstring", "ZOMBIE_CRAFTABLE_NO_SWITCH" );
85 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_SWITCH" );
86 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_WRONG" );
87 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_ONLY_ONE" );
88 #precache( "triggerstring", "ZOMBIE_BUILD_PIECE_HAVE_ONE" );
89 #precache( "triggerstring", "ZOMBIE_GO_TO_THE_BOX_LIMITED" );
90 #precache( "triggerstring", "ZOMBIE_GO_TO_THE_BOX" );
91 #precache( "triggerstring", "ZOMBIE_CRAFTABLE_CHANGE_BUILD" );
93 #precache( "fx", "zombie/fx_crafting_dust_zmb" );
95 #define ZM_CRAFTABLES_LOOKAT_DOT 0.76
96 #define ZM_CRAFTABLES_NOT_ENOUGH_PIECES_UI_DURATION 3.5
97 #define ZM_CRAFTABLES_FULLY_CRAFTED_UI_DURATION 3.5
99 #namespace zm_craftables;
112 DEFAULT( level.craftable_piece_swap_allowed,
true );
114 zombie_craftables_callbacks = [];
116 level.craftablePickUps = [];
117 level.craftables_crafted = [];
118 level.a_uts_craftables = [];
120 if ( !isdefined( level.craftable_piece_count ) )
122 level.craftable_piece_count = 0;
125 level._effect[
"building_dust"] =
"zombie/fx_crafting_dust_zmb";
127 if ( isdefined( level.init_craftables ) )
129 [[level.init_craftables]]();
133 open_table = SpawnStruct();
134 open_table.name =
"open_table";
141 if ( isdefined( level.use_swipe_protection ) )
162 self.hint_string =
"";
171 if ( isdefined( player.is_drinking ) &&
IS_DRINKING( player.is_drinking ) )
173 self.hint_string =
"";
177 if ( isdefined( player.screecher_weapon ) )
179 self.hint_string =
"";
183 initial_current_weapon = player getCurrentWeapon();
187 self.hint_string =
"";
196 if ( isdefined(
self.origin_parent ) )
198 return self.origin_parent.origin;
206 if ( isdefined(
self.link_parent ) )
208 trigger EnableLinkTo();
209 trigger LinkTo(
self.link_parent );
210 trigger SetMovingPlatformEnabled(
true );
216 self endon(
"disconnect" );
217 self notify(
"craftables_watch_swipes" );
218 self endon(
"craftables_watch_swipes" );
222 self waittill(
"melee_swipe", zombie );
224 if ( distancesquared( zombie.origin,
self.origin ) > zombie.meleeattackdist * zombie.meleeattackdist )
229 trigger = level._unitriggers.trigger_pool[
self GetEntityNumber()];
231 if ( isdefined( trigger ) && isdefined( trigger.stub.piece ) )
233 piece = trigger.stub.piece;
235 if ( !isdefined( piece.damage ) )
242 if ( piece.damage > 12 )
248 if ( IsAlive(
self ) )
250 self playlocalsound( level.zmb_laugh_alias );
273 Assert( isdefined( level.zombie_craftableStubs[ str_craftable ] ),
"Craftable " + str_craftable +
" has not been added yet." );
277 s_craftable = level.zombie_craftableStubs[ str_craftable ];
278 s_craftable.is_open_table =
true;
279 s_craftable.str_model = str_model;
280 s_craftable.v_angle_offset = v_angle_offset;
281 s_craftable.v_origin_offset = v_origin_offset;
294 function add_zombie_craftable( craftable_name, str_to_craft, str_crafting, str_taken, onFullyCrafted, need_all_pieces )
296 if ( !isdefined( level.zombie_include_craftables ) )
298 level.zombie_include_craftables = [];
301 if ( isdefined( level.zombie_include_craftables ) && !isdefined( level.zombie_include_craftables[ craftable_name ] ) )
307 if ( isdefined( str_to_craft ) )
313 if ( isdefined( str_crafting ) )
321 craftable_struct = level.zombie_include_craftables[ craftable_name ];
323 if ( !isdefined( level.zombie_craftableStubs ) )
325 level.zombie_craftableStubs = [];
328 craftable_struct.str_to_craft = str_to_craft;
329 craftable_struct.str_crafting = str_crafting;
330 craftable_struct.str_taken = str_taken;
331 craftable_struct.onFullyCrafted = onFullyCrafted;
332 craftable_struct.need_all_pieces = need_all_pieces;
334 level.zombie_craftableStubs[ craftable_struct.name ] = craftable_struct;
339 if ( isdefined( level.zombie_craftableStubs[ craftable_name ] ) )
341 level.zombie_craftableStubs[ craftable_name ].hide_when_unavailable = hide_when_unavailable;
347 if ( isdefined( level.zombie_craftableStubs[ craftable_name ] ) )
349 return IS_TRUE( level.zombie_craftableStubs[ craftable_name ].hide_when_unavailable );
356 if ( isdefined( level.zombie_craftableStubs[ craftable_name ] ) )
358 level.zombie_craftableStubs[ craftable_name ].useTime = build_time;
364 bits = GetMinBitCountForNum( n_count );
370 craftable_struct = level.zombie_include_craftables[ craftable_name ];
372 craftable_struct.vox_id = vox_id;
377 if ( !isdefined( level.zombie_include_craftables ) )
379 level.zombie_include_craftables = [];
382 if ( !isDefined( level.craftableIndex ) )
384 level.craftableIndex = 0;
387 level.zombie_include_craftables[ craftableStub.name ] = craftableStub;
388 craftableStub.hash_id = HashString(craftablestub.name);
416 function generate_zombie_craftable_piece( craftablename, pieceName, radius, height, drop_offset, hud_icon,
onPickup,
onDrop, onCrafted, use_spawn_num,
tag_name, can_reuse, client_field_value, is_shared = FALSE, vox_id, b_one_time_vo =
false, hint_string, slot = 0 )
418 pieceStub = spawnstruct();
420 craftable_pieces = [];
422 if ( !isdefined( pieceName ) )
424 AssertMsg(
"You must provide an alias name for this piece" );
427 craftable_pieces_structs =
struct::get_array( craftablename +
"_" + pieceName,
"targetname" );
429 if (!isDefined(level.craftablePieceIndex))
431 level.craftablePieceIndex = 0;
434 foreach ( index,
struct in craftable_pieces_structs )
436 craftable_pieces[ index ] =
struct;
437 craftable_pieces[ index ].hasSpawned =
false;
440 pieceStub.spawns = craftable_pieces;
442 pieceStub.craftableName = craftableName;
443 pieceStub.pieceName = pieceName;
444 if ( craftable_pieces.size )
446 pieceStub.modelName = craftable_pieces[0].model;
448 pieceStub.hud_icon = hud_icon;
449 pieceStub.radius = radius;
450 pieceStub.height = height;
452 pieceStub.can_reuse = can_reuse;
453 pieceStub.drop_offset = drop_offset;
454 pieceStub.max_instances = 256;
458 pieceStub.onCrafted = onCrafted;
459 pieceStub.use_spawn_num = use_spawn_num;
460 pieceStub.is_shared = is_shared;
461 pieceStub.vox_id = vox_id;
462 pieceStub.hint_string = hint_string;
463 pieceStub.inventory_slot = slot;
465 pieceStub.hash_id = HashString(pieceName);
469 pieceStub.b_one_time_vo = b_one_time_vo;
472 if ( isdefined( client_field_value ) )
476 Assert( IsString( client_field_value ),
"Client field value for shared item (" + pieceName +
") should be a string (the name of the ClientField to use)" );
477 pieceStub.client_field_id = client_field_value;
481 pieceStub.client_field_state = client_field_value;
490 self.max_instances = max_instances;
491 self.managing_pieces =
true;
492 self.piece_allocated = [];
498 spawns1 = piece1.spawns;
499 spawns2 = piece2.spawns;
501 spawns = ArrayCombine( spawns1, spawns2,
true,
false );
503 if ( isdefined( piece3 ) )
505 spawns3 = piece3.spawns;
506 spawns = ArrayCombine( spawns, spawns3,
true,
false );
507 spawns = array::randomize( spawns );
511 piece3.spawns = spawns;
515 spawns = array::randomize( spawns );
518 piece1.spawns = spawns;
519 piece2.spawns = spawns;
524 if ( !isdefined(
self.a_pieceStubs ) )
526 self.a_pieceStubs = [];
534 if ( isdefined( can_reuse ) )
536 pieceStub.can_reuse = can_reuse;
539 self.a_pieceStubs[
self.a_pieceStubs.size] = pieceStub;
540 DEFAULT(
self.inventory_slot, pieceStub.inventory_slot );
550 self endon(
"craftable_piece_released" + slot );
553 self waittill(
"bled_out" );
563 DEFAULT(
self.current_craftable_pieces, [] );
565 foreach ( index, piece
in self.current_craftable_pieces )
567 if ( isdefined( piece ) )
569 return_to_start_pos =
false;
571 if ( isdefined( level.safe_place_for_craftable_piece ) )
573 if ( !
self [[level.safe_place_for_craftable_piece]]( piece ) )
575 return_to_start_pos =
true;
579 if ( return_to_start_pos )
588 if ( isdefined( piece.onDrop ) )
590 piece [[ piece.onDrop ]]( self );
596 self.current_craftable_pieces[index] = undefined;
597 self notify(
"craftable_piece_released" + index );
602 #define PIECE_UNITRIGGER_OFFSET (0,0,12)
606 if ( isdefined(
self.origin_parent ) )
616 if ( !isdefined( radius ) )
621 if ( !isdefined( script_height ) )
626 script_width = script_height;
628 if ( !isdefined( script_width ) )
633 script_length = script_height;
635 if ( !isdefined( script_length ) )
641 unitrigger_stub = spawnstruct();
643 unitrigger_stub.origin = origin;
647 if ( isdefined( script_length ) )
649 unitrigger_stub.script_length = script_length;
653 unitrigger_stub.script_length = 13.5;
656 if ( isdefined( script_width ) )
658 unitrigger_stub.script_width = script_width;
662 unitrigger_stub.script_width = 27.5;
665 if ( isdefined( script_height ) )
667 unitrigger_stub.script_height = script_height;
671 unitrigger_stub.script_height = 24;
674 unitrigger_stub.radius = radius;
679 unitrigger_stub.cursor_hint =
"HINT_NOICON";
681 if ( isdefined( hint_string ) )
683 unitrigger_stub.hint_string_override = hint_string;
684 unitrigger_stub.hint_string = unitrigger_stub.hint_string_override;
688 unitrigger_stub.hint_string = &
"ZOMBIE_BUILD_PIECE_GRAB";
691 unitrigger_stub.script_unitrigger_type =
"unitrigger_box_use";
694 if (isdefined (b_nolook) &&
IS_TRUE(Int(b_nolook)))
696 unitrigger_stub.require_look_toward =
false;
699 unitrigger_stub.require_look_at =
false;
705 case "trigger_radius":
706 unitrigger_stub.script_unitrigger_type =
"unitrigger_radius";
709 case "trigger_radius_use":
710 unitrigger_stub.script_unitrigger_type =
"unitrigger_radius_use";
714 unitrigger_stub.script_unitrigger_type =
"unitrigger_box";
717 case "trigger_box_use":
718 unitrigger_stub.script_unitrigger_type =
"unitrigger_box_use";
736 return unitrigger_stub;
743 DEFAULT( player.current_craftable_pieces, [] );
745 self setInvisibleToPlayer( player, !can_use );
746 self SetHintString(
self.stub.hint_string );
764 if ( isdefined( player.current_craftable_pieces[slot] ) && !
IS_TRUE(
self.piece.is_shared ) )
766 if ( !level.craftable_piece_swap_allowed )
768 self.hint_string = &
"ZOMBIE_CRAFTABLE_NO_SWITCH";
773 cpiece = player.current_craftable_pieces[slot];
775 if ( spiece.pieceName == cpiece.pieceName && spiece.craftableName == cpiece.craftableName )
777 self.hint_string =
"";
781 if ( isdefined(
self.hint_string_override ) )
783 self.hint_string =
self.hint_string_override;
787 self.hint_string = &
"ZOMBIE_BUILD_PIECE_SWITCH";
793 if ( isdefined(
self.hint_string_override ) )
795 self.hint_string =
self.hint_string_override;
799 self.hint_string = &
"ZOMBIE_BUILD_PIECE_GRAB";
808 self endon(
"kill_trigger" );
810 slot =
self.stub.piece.inventory_slot;
814 self waittill(
"trigger", player );
817 self.stub notify(
"trigger", player );
819 if ( player !=
self.parent_player )
824 if ( isdefined( player.screecher_weapon ) )
831 if ( !level.craftable_piece_swap_allowed && isdefined( player.current_craftable_pieces[slot] ) && !
IS_TRUE(
self.stub.piece.is_shared ) )
846 self.stub.hint_string =
"";
847 self SetHintString(
self.stub.hint_string );
861 if ( !isdefined( piece ) )
872 assert( isdefined( piece ) );
874 if ( isdefined( piece ) )
878 altmodel = undefined;
881 while ( pass < 2 && !done )
883 grenade =
self MagicGrenadeType(
"buildable_piece", origin, dir, 30000 );
887 if ( !isdefined( altmodel ) )
889 altmodel =
spawn(
"script_model", grenade.origin );
890 altmodel SetModel( piece.modelName );
893 altmodel.origin = grenade.angles;
894 altmodel.angles = grenade.angles;
895 altmodel linkTo( grenade,
"", ( 0, 0, 0 ), ( 0, 0, 0 ) );
896 grenade.altmodel = altmodel;
898 grenade waittill(
"stationary" );
900 grenade_origin = grenade.origin;
901 grenade_angles = grenade.angles;
903 landed_on = grenade GetGroundEnt();
907 if ( isdefined( landed_on ) && landed_on == level )
913 origin = grenade_origin;
914 dir = ( -dir[0] / 10, -dir[1] / 10, -1 );
919 if ( !isdefined( endangles ) )
921 endangles = grenade_angles;
926 if ( isdefined( altmodel ) )
931 if ( isdefined( piece.onDrop ) )
933 piece [[ piece.onDrop ]]( self );
945 self endon(
"death" );
946 self endon(
"stationary" );
948 while ( isdefined(
self ) )
950 self waittill(
"grenade_bounce", pos, normal, ent );
952 if ( IsPlayer( ent ) )
963 self endon(
"pickup" );
966 if ( isdefined( level.exploding_jetgun_fx ) )
968 PlayFxOnTag( level.exploding_jetgun_fx,
self.model,
"tag_origin" );
972 PlayFxOnTag( level._effect[
"powerup_on"],
self.model,
"tag_origin" );
975 wait return_time - 6;
988 self notify(
"respawn" );
995 self notify(
"craftable_piece_released" + slot );
996 piece =
self.current_craftable_pieces[slot];
997 self.current_craftable_pieces[slot] = undefined;
999 if ( isdefined( piece ) )
1015 self notify(
"craftable_piece_released" + slot );
1016 self endon(
"craftable_piece_released" + slot );
1022 origin =
self.origin;
1023 angles =
self.angles;
1024 piece =
self.current_craftable_pieces[slot];
1025 if ( IsDefined(piece) && isdefined(piece.start_origin) )
1027 origin = piece.start_origin;
1028 angles = piece.start_angles;
1030 self waittill(
"disconnect" );
1033 if ( isdefined(
self ) )
1042 if ( !isdefined( piece ) )
1044 piece =
self.current_craftable_pieces[slot];
1047 if ( isdefined( piece ) )
1054 if ( isdefined( piece.onDrop ) )
1056 piece [[ piece.onDrop ]]( self );
1060 self.current_craftable_pieces[slot] = undefined;
1061 self notify(
"craftable_piece_released" + slot );
1068 pieceStub = pieceSpawn.pieceStub;
1069 slot = pieceStub.inventory_slot;
1072 DEFAULT(
self.current_craftable_pieces, [] );
1074 self notify(
"player_got_craftable_piece_for_" + pieceSpawn.craftableName );
1077 if ( !
IS_TRUE( pieceStub.is_shared ) && isdefined(
self.current_craftable_pieces[slot] ) )
1079 other_piece =
self.current_craftable_pieces[slot];
1085 if ( isdefined( pieceStub.onPickup ) )
1087 pieceSpawn [[ pieceStub.onPickup ]]( self );
1093 if (
IS_TRUE( pieceStub.is_shared ) )
1095 if ( isdefined( pieceStub.client_field_id ) )
1102 if ( isdefined( pieceStub.client_field_state ) )
1109 pieceSpawn notify(
"pickup" );
1111 if (
IS_TRUE( pieceStub.is_shared ) )
1114 pieceSpawn.in_shared_inventory =
true;
1118 slot = pieceSpawn.inventory_slot;
1119 self.current_craftable_pieces[slot] = pieceSpawn;
1129 if ( !isdefined( piece ) )
1131 piece =
self.current_craftable_pieces[slot];
1134 if ( isdefined( piece ) )
1139 self.current_craftable_pieces[slot] = undefined;
1140 self notify(
"craftable_piece_released" + slot );
1146 if ( !isdefined( level.craftable_claimed_locations ) )
1148 level.craftable_claimed_locations = [];
1151 if ( !isdefined( level.craftable_claimed_locations[location] ) )
1153 level.craftable_claimed_locations[location] =
true;
1166 candidate_list = [];
1168 foreach ( zone
in level.zones )
1170 if ( isdefined( zone.unitrigger_stubs ) )
1172 candidate_list = ArrayCombine( candidate_list, zone.unitrigger_stubs,
true,
false );
1184 while ( index < closest.size )
1186 if (
IS_TRUE( closest[index].registered ) && isdefined( closest[index].piece ) )
1203 self.current_spawn = 0;
1204 self.managed_spawn =
true;
1205 self.pieceStub = pieceStub;
1207 if (
self.spawns.size >= 1 &&
self.spawns.size > 1 )
1214 for ( i = 0; i <
self.spawns.size; i++ )
1216 if (
IS_TRUE( pieceStub.piece_allocated[i] ) )
1218 spawnweights[i] = 0;
1223 spawnweights[i] = 0.01;
1228 spawnweights[i] = 1.0;
1231 totalweight += spawnweights[i];
1236 totalweight = float(
int( totalweight ) );
1239 r = RandomFloat( totalweight );
1241 for ( i = 0; i <
self.spawns.size; i++ )
1243 if ( !any_good || spawnweights[i] >= 1.0 )
1245 r -= spawnweights[i];
1249 self.current_spawn = i;
1250 pieceStub.piece_allocated[
self.current_spawn] =
true;
1257 self.current_spawn = RandomInt(
self.spawns.size );
1258 pieceStub.piece_allocated[
self.current_spawn] =
true;
1267 if ( isdefined(
self.current_spawn ) )
1269 self.pieceStub.piece_allocated[
self.current_spawn] =
false;
1270 self.current_spawn = undefined;
1273 self.start_origin = undefined;
1280 self.current_spawn = 0;
1282 if (
self.spawns.size >= 1 &&
self.spawns.size > 1 )
1284 self.current_spawn = RandomInt(
self.spawns.size );
1286 while ( isdefined(
self.spawns[
self.current_spawn].
claim_location ) &&
1289 ArrayRemoveIndex(
self.spawns,
self.current_spawn );
1291 if (
self.spawns.size < 1 )
1293 self.current_spawn = 0;
1297 self.current_spawn = RandomInt(
self.spawns.size );
1304 self.current_spawn = 0;
1306 if (
self.spawns.size >= 1 &&
self.spawns.size > 1 )
1308 self.current_spawn = int( min( num,
self.spawns.size - 1 ) );
1317 if (
self.spawns.size < 1 )
1322 if (
IS_TRUE(
self.managed_spawn ) )
1324 if ( !isdefined(
self.current_spawn ) )
1330 if ( !isdefined(
self.current_spawn ) )
1332 self.current_spawn = 0;
1335 spawndef =
self.spawns[
self.current_spawn];
1339 self.unitrigger.piece =
self;
1341 self.radius = pieceStub.radius;
1342 self.height = pieceStub.height;
1343 self.craftableName = pieceStub.craftableName;
1344 self.pieceName = pieceStub.pieceName;
1345 self.modelName = pieceStub.modelName;
1346 self.hud_icon = pieceStub.hud_icon;
1347 self.tag_name = pieceStub.tag_name;
1348 self.drop_offset = pieceStub.drop_offset;
1349 self.start_origin = spawndef.origin;
1350 self.start_angles = spawndef.angles;
1351 self.client_field_state = pieceStub.client_field_state;
1352 self.is_shared = pieceStub.is_shared;
1353 self.inventory_slot = pieceStub.inventory_slot;
1355 self.model =
Spawn(
"script_model",
self.start_origin );
1357 if ( isdefined(
self.start_angles ) )
1359 self.model.angles =
self.start_angles;
1362 self.model SetModel( pieceStub.modelName );
1364 if ( isdefined( pieceStub.onSpawn ) )
1366 self [[ pieceStub.onSpawn ]]();
1369 self.model.hud_icon = pieceStub.hud_icon;
1370 self.pieceStub = pieceStub;
1372 self.unitrigger.origin_parent =
self.model;
1381 if (
self.spawns.size < 1 )
1386 if (
IS_TRUE(
self.managed_spawn ) )
1388 if ( !isdefined(
self.current_spawn ) && !isdefined( origin ) )
1391 spawndef =
self.spawns[
self.current_spawn];
1392 self.start_origin = spawndef.origin;
1393 self.start_angles = spawndef.angles;
1396 else if ( !isdefined(
self.current_spawn ) )
1398 self.current_spawn = 0;
1403 if (
IS_TRUE( use_random_start ) )
1406 spawndef =
self.spawns[
self.current_spawn];
1407 self.start_origin = spawndef.origin;
1408 self.start_angles = spawndef.angles;
1409 origin = spawndef.origin;
1410 angles = spawndef.angles;
1414 if ( !isdefined( origin ) )
1416 origin =
self.start_origin;
1420 origin = origin + ( 0, 0,
self.drop_offset );
1421 unitrigger_offset -= ( 0, 0,
self.drop_offset );
1424 if ( !isdefined( angles ) )
1426 angles =
self.start_angles;
1430 self.model =
Spawn(
"script_model", origin );
1432 if ( isdefined( angles ) )
1434 self.model.angles = angles;
1437 self.model SetModel(
self.modelName );
1439 if ( isdefined( level.equipment_safe_to_drop ) )
1441 if ( ! [[level.equipment_safe_to_drop]](
self.model ) )
1443 origin =
self.start_origin;
1444 angles =
self.start_angles;
1445 self.model.origin = origin;
1446 self.model.angles = angles;
1452 self [[
self.onSpawn ]]();
1455 self.unitrigger =
generate_piece_unitrigger(
"trigger_radius_use", origin + unitrigger_offset, angles, 0,
self.radius,
self.height,
self.piecestub.hint_string,
IS_TRUE(
self.model.canMove ) );
1456 self.unitrigger.piece =
self;
1458 self.model.hud_icon =
self.hud_icon;
1460 self.unitrigger.origin_parent =
self.model;
1468 if (
IS_TRUE(
self.managed_spawn ) )
1473 if ( isdefined(
self.model ) )
1475 self.model
delete();
1478 self.model = undefined;
1480 if ( isdefined(
self.unitrigger ) )
1485 self.unitrigger = undefined;
1490 if ( isdefined(
self.model ) )
1498 if ( isdefined(
self.model ) )
1509 pieceSpawn = spawnstruct();
1510 pieceSpawn.spawns = pieceStub.spawns;
1512 if (
IS_TRUE( pieceStub.managing_pieces ) )
1516 else if ( isdefined( pieceStub.use_spawn_num ) )
1526 if( isdefined( pieceStub.special_spawn_func ) )
1528 pieceSpawn [[pieceStub.special_spawn_func]]( pieceStub ) ;
1535 if ( pieceSpawn.spawns.size >= 1 )
1537 pieceSpawn.hud_icon = pieceStub.hud_icon;
1540 if ( isdefined( pieceStub.onPickup ) )
1542 pieceSpawn.onPickup = pieceStub.onPickup;
1549 if ( isdefined( pieceStub.onDrop ) )
1551 pieceSpawn.onDrop = pieceStub.onDrop;
1558 if ( isdefined( pieceStub.onCrafted ) )
1560 pieceSpawn.onCrafted = pieceStub.onCrafted;
1572 Assert( isdefined( craftable_name ) );
1573 Assert( isdefined( level.zombie_craftableStubs[ craftable_name ] ),
"Called craftable_think() without including the craftable - " + craftable_name );
1577 craftable = level.zombie_craftableStubs[ craftable_name ];
1579 if ( !isdefined( craftable.a_pieceStubs ) )
1581 craftable.a_pieceStubs = [];
1588 craftableSpawn = spawnstruct();
1590 craftableSpawn.craftable_name = craftable_name;
1592 if ( !isdefined( craftableSpawn.a_pieceSpawns ) )
1594 craftableSpawn.a_pieceSpawns = [];
1599 craftablePickUps = [];
1601 foreach ( pieceStub
in craftable.a_pieceStubs )
1603 DEFAULT( craftableSpawn.inventory_slot, pieceStub.inventory_slot );
1604 if ( !isdefined( pieceStub.generated_instances ) )
1606 pieceStub.generated_instances = 0;
1610 if ( isdefined( pieceStub.pieceSpawn ) &&
IS_TRUE( pieceStub.can_reuse ) )
1612 piece = pieceStub.pieceSpawn;
1614 else if ( pieceStub.generated_instances >= pieceStub.max_instances )
1616 piece = pieceStub.pieceSpawn;
1621 pieceStub.pieceSpawn = piece;
1622 pieceStub.generated_instances++;
1625 craftableSpawn.a_pieceSpawns[craftableSpawn.a_pieceSpawns.size] = piece;
1628 craftableSpawn.stub =
self;
1630 return craftableSpawn;
1635 trig = GetEnt( trigger_targetname,
"targetname" );
1637 if ( !isdefined( trig ) )
1642 if ( isdefined( trig.target ) )
1644 model = getent( trig.target,
"targetname" );
1646 if ( isdefined( model ) )
1657 trig = GetEnt( trigger_targetname,
"targetname" );
1659 if ( !isdefined( trig ) )
1670 triggers = GetEntArray( trigger_targetname,
"targetname" );
1673 foreach ( trig
in triggers )
1685 if ( !isdefined( trig ) )
1690 unitrigger_stub = spawnstruct();
1692 unitrigger_stub.craftableStub = level.zombie_include_craftables[ equipname ];
1694 angles = trig.script_angles;
1696 if ( !isdefined( angles ) )
1698 angles = ( 0, 0, 0 );
1701 unitrigger_stub.origin = trig.origin + ( anglestoright( angles ) * -6 );
1703 unitrigger_stub.angles = trig.angles;
1705 if ( isdefined( trig.script_angles ) )
1707 unitrigger_stub.angles = trig.script_angles;
1710 unitrigger_stub.equipname = equipname;
1711 unitrigger_stub.weaponname = GetWeapon( weaponname );
1712 unitrigger_stub.trigger_hintstring = trigger_hintstring;
1713 unitrigger_stub.delete_trigger = delete_trigger;
1714 unitrigger_stub.crafted =
false;
1715 unitrigger_stub.persistent = persistent;
1716 unitrigger_stub.useTime = int( 3 * 1000 );
1718 if ( isdefined(
self.useTime ) )
1720 unitrigger_stub.useTime =
self.useTime;
1722 else if ( isdefined( trig.useTime ) )
1724 unitrigger_stub.useTime = trig.useTime;
1732 tmins = trig GetMins();
1733 tmaxs = trig GetMaxs();
1734 tsize = tmaxs-tmins;
1736 if ( isdefined( trig.script_depth ) )
1738 unitrigger_stub.script_length = trig.script_depth;
1742 unitrigger_stub.script_length = tsize[1];
1745 if ( isdefined( trig.script_width ) )
1747 unitrigger_stub.script_width = trig.script_width;
1751 unitrigger_stub.script_width = tsize[0];
1754 if ( isdefined( trig.script_height ) )
1756 unitrigger_stub.script_height = trig.script_height;
1760 unitrigger_stub.script_height = tsize[2];
1763 unitrigger_stub.target = trig.target;
1764 unitrigger_stub.targetname = trig.targetname;
1766 unitrigger_stub.script_noteworthy = trig.script_noteworthy;
1767 unitrigger_stub.script_parameters = trig.script_parameters;
1769 unitrigger_stub.cursor_hint =
"HINT_NOICON";
1771 if ( isdefined( level.zombie_craftableStubs[ equipname ].str_to_craft ) )
1773 unitrigger_stub.hint_string = level.zombie_craftableStubs[ equipname ].str_to_craft;
1776 unitrigger_stub.script_unitrigger_type =
"unitrigger_box_use";
1777 unitrigger_stub.require_look_at =
true;
1778 unitrigger_stub.require_look_toward =
false;
1782 if ( isdefined( unitrigger_stub.craftableStub.custom_craftablestub_update_prompt ) )
1784 unitrigger_stub.custom_craftablestub_update_prompt = unitrigger_stub.craftableStub.custom_craftablestub_update_prompt;
1791 unitrigger_stub.piece_trigger = trig;
1792 trig.trigger_stub = unitrigger_stub;
1794 if ( isdefined( trig.zombie_weapon_upgrade ) )
1796 unitrigger_stub.zombie_weapon_upgrade = GetWeapon( trig.zombie_weapon_upgrade );
1799 if ( isdefined( unitrigger_stub.target ) )
1801 unitrigger_stub.model = getent( unitrigger_stub.target,
"targetname" );
1803 if ( isdefined( unitrigger_stub.model ) )
1805 if ( isdefined( unitrigger_stub.zombie_weapon_upgrade ) )
1807 unitrigger_stub.model useweaponhidetags( unitrigger_stub.zombie_weapon_upgrade );
1814 if ( isdefined( unitrigger_stub.model.script_parameters ) )
1816 a_utm_params = strtok( unitrigger_stub.model.script_parameters,
" ");
1817 foreach ( param
in a_utm_params )
1819 if ( param ==
"starts_visible" )
1821 b_start_visible =
true;
1824 else if ( param ==
"starts_empty" )
1826 b_start_empty =
true;
1832 if ( b_start_visible !==
true )
1834 unitrigger_stub.model Ghost();
1835 unitrigger_stub.model NotSolid();
1841 if ( unitrigger_stub.equipname ==
"open_table" )
1843 unitrigger_stub.a_uts_open_craftables_available = [];
1845 unitrigger_stub.b_open_craftable_checking_input =
false;
1852 if ( isdefined( unitrigger_stub.model ) && b_start_empty ===
true )
1854 for ( i = 0; i < unitrigger_stub.craftableSpawn.a_pieceSpawns.size; i++ )
1856 if ( isdefined( unitrigger_stub.craftableSpawn.a_pieceSpawns[i].tag_name ) )
1858 if ( unitrigger_stub.craftableSpawn.a_pieceSpawns[i].crafted !==
true )
1860 unitrigger_stub.model HidePart( unitrigger_stub.craftableSpawn.a_pieceSpawns[i].tag_name );
1865 unitrigger_stub.model ShowPart( unitrigger_stub.craftableSpawn.a_pieceSpawns[i].tag_name );
1871 if ( delete_trigger )
1876 level.a_uts_craftables[level.a_uts_craftables.size] = unitrigger_stub;
1877 return unitrigger_stub;
1886 unitrigger_stub = spawnstruct();
1888 unitrigger_stub.craftableStub = level.zombie_include_craftables[
self.name ];
1890 unitrigger_stub.equipname =
self.name;
1896 level.a_uts_craftables[level.a_uts_craftables.size] = unitrigger_stub;
1897 return unitrigger_stub;
1905 for ( i = 0; i <
self.a_pieceSpawns.size; i++ )
1906 if (
self.a_pieceSpawns[i].pieceName == piece.pieceName &&
self.a_pieceSpawns[i].craftablename == piece.craftablename )
1922 if (
self.craftable_name ==
"open_table" &&
1925 return self.stub.a_uts_open_craftables_available[
self.n_open_craftable_choice ];
1942 if (
self.craftable_name ==
"open_table" &&
1944 isdefined(
self.stub.a_uts_open_craftables_available[
self.stub.n_open_craftable_choice ].craftableSpawn ) )
1946 return self.stub.a_uts_open_craftables_available[
self.stub.n_open_craftable_choice ].craftableSpawn;
1962 uts_craftable =
self.stub;
1964 if ( isdefined( uts_craftable.n_open_craftable_choice ) &&
1966 isdefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) )
1972 if (
IS_TRUE( uts_craftable.craftableStub.need_all_pieces ) )
1975 foreach ( piece
in self.a_pieceSpawns )
1977 if ( !
IS_TRUE( piece.in_shared_inventory ) )
1988 foreach ( piece
in self.a_pieceSpawns )
2007 foreach ( pieceSpawn
in craftableSpawn_check.a_pieceSpawns )
2009 if ( isdefined( pieceSpawn_check ) )
2011 if ( pieceSpawn.pieceName == pieceSpawn_check.pieceName &&
2012 pieceSpawn.craftablename == pieceSpawn_check.craftablename )
2014 pieceSpawn.crafted =
true;
2017 if ( isdefined( pieceSpawn.onCrafted ) )
2019 pieceSpawn thread [[pieceSpawn.onCrafted]]( player );
2027 if (
IS_TRUE( pieceSpawn.is_shared ) &&
IS_TRUE( pieceSpawn.in_shared_inventory ) )
2029 pieceSpawn.crafted =
true;
2032 if ( isdefined( pieceSpawn.onCrafted ) )
2034 pieceSpawn thread [[pieceSpawn.onCrafted]]( player );
2038 pieceSpawn.in_shared_inventory =
false;
2049 foreach ( pieceSpawn
in craftableSpawn_check.a_pieceSpawns )
2051 if ( isdefined( pieceSpawn_check ) )
2053 if ( pieceSpawn.pieceName == pieceSpawn_check.pieceName &&
2054 pieceSpawn.craftablename == pieceSpawn_check.craftablename )
2056 pieceSpawn.crafting =
true;
2061 if (
IS_TRUE( pieceSpawn.is_shared ) &&
IS_TRUE( pieceSpawn.in_shared_inventory ) )
2063 pieceSpawn.crafting =
true;
2073 if ( isdefined( pieceSpawn_check ) )
2075 pieceSpawn_check.crafting =
false;
2080 foreach ( pieceSpawn
in craftableSpawn_check.a_pieceSpawns )
2083 if (
IS_TRUE( pieceSpawn.is_shared ) &&
IS_TRUE( pieceSpawn.in_shared_inventory ) )
2085 pieceSpawn.crafting =
false;
2092 for ( i = 0; i <
self.a_pieceSpawns.size; i++ )
2094 if (
self.a_pieceSpawns[i].pieceName == piece.pieceName &&
self.a_pieceSpawns[i].craftablename == piece.craftablename )
2096 return IS_TRUE(
self.a_pieceSpawns[i].crafted );
2106 if( !IsDefined(level.shared_crafting_in_progress) )
2107 level.shared_crafting_in_progress =
self;
2112 if (
IS_EQUAL(
self,level.shared_crafting_in_progress) )
2113 level.shared_crafting_in_progress = undefined;
2119 return (
IS_EQUAL(
self, level.shared_crafting_in_progress) );
2120 return !IsDefined( level.shared_crafting_in_progress);
2129 foreach ( pieceSpawn
in craftableSpawn_check.a_pieceSpawns )
2131 if ( isdefined( pieceSpawn_check ) )
2133 if ( pieceSpawn.pieceName == pieceSpawn_check.pieceName &&
2134 pieceSpawn.craftablename == pieceSpawn_check.craftablename )
2136 return pieceSpawn.crafting;
2141 if (
IS_TRUE( pieceSpawn.is_shared ) &&
2142 IS_TRUE( pieceSpawn.in_shared_inventory ) &&
2154 for ( i = 0; i <
self.a_pieceSpawns.size; i++ )
2155 if (
self.a_pieceSpawns[i].pieceName == piece.pieceName &&
self.a_pieceSpawns[i].craftablename == piece.craftablename )
2157 return IS_TRUE(
self.a_pieceSpawns[i].crafted ) ||
IS_TRUE(
self.a_pieceSpawns[i].crafting );
2165 if (
IS_TRUE(
self.stub.craftableStub.need_all_pieces ) )
2168 foreach ( piece
in self.a_pieceSpawns )
2170 if ( !
IS_TRUE( piece.in_shared_inventory ) && !piece.crafted )
2179 for ( i = 0; i <
self.a_pieceSpawns.size; i++ )
2180 if ( !
IS_TRUE(
self.a_pieceSpawns[i].crafted ) )
2190 level waittill( craftable_name +
"_crafted", player );
2197 if ( !isdefined( craftableSpawn ) )
2202 if ( !isdefined( slot ) )
2204 slot = craftableSpawn.inventory_slot;
2209 if ( !isdefined( slot ) )
2214 if ( !isdefined(
self.current_craftable_pieces[slot] ) )
2241 if (
IS_TRUE(craftableSpawn.stub.crafted ) && !continuing )
2255 if ( isdefined( craftableSpawn.stub ) &&
2256 isdefined( craftableSpawn.stub.custom_craftablestub_update_prompt ) &&
2257 isdefined( craftableSpawn.stub.playertrigger[0] ) &&
2258 isdefined( craftableSpawn.stub.playertrigger[0].stub ) &&
2259 !craftableSpawn.stub.playertrigger[ 0 ].stub [[ craftableSpawn.stub.custom_craftablestub_update_prompt ]](
self,
true, craftableSpawn.stub.playertrigger[
self GetEntityNumber() ] ) )
2275 uts_craftable =
self.stub;
2278 !isdefined( uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ] ) )
2284 uts_source = uts_craftable.a_uts_open_craftables_available[ uts_craftable.n_open_craftable_choice ];
2287 uts_target = uts_craftable;
2289 uts_target.craftableStub = uts_source.craftableStub;
2290 uts_target.craftableSpawn = uts_source.craftableSpawn;
2291 uts_target.crafted = uts_source.crafted;
2292 uts_target.cursor_hint = uts_source.cursor_hint;
2293 uts_target.custom_craftable_update_prompt = uts_source.custom_craftable_update_prompt;
2294 uts_target.equipname = uts_source.equipname;
2295 uts_target.hint_string = uts_source.hint_string;
2296 uts_target.persistent = uts_source.persistent;
2297 uts_target.prompt_and_visibility_func = uts_source.prompt_and_visibility_func;
2298 uts_target.trigger_func = uts_source.trigger_func;
2299 uts_target.trigger_hintstring = uts_source.trigger_hintstring;
2300 uts_target.weaponname = uts_source.weaponname;
2303 uts_target.craftableSpawn.stub = uts_target;
2317 DEFAULT(
self.current_craftable_pieces, [] );
2319 if ( isdefined( slot ) )
2327 if ( isdefined( slot ) &&
2328 isdefined(
self.current_craftable_pieces[slot] ) &&
2329 IS_TRUE(
self.current_craftable_pieces[slot].crafted ) )
2335 if ( isdefined( craftableSpawn.stub.n_open_craftable_choice ) )
2338 craftableSpawn = uts_craftable.craftableSpawn;
2343 uts_craftable = craftableSpawn.stub;
2347 if ( !isdefined( uts_craftable.model ) && isdefined( uts_craftable.craftableStub.str_model ) )
2349 craftableStub = uts_craftable.craftableStub;
2350 s_model =
struct::get( uts_craftable.target,
"targetname" );
2352 if ( isdefined( s_model ) )
2354 m_spawn =
Spawn(
"script_model", s_model.origin );
2356 if ( isdefined( craftableStub.v_origin_offset ) )
2358 m_spawn.origin += craftableStub.v_origin_offset;
2361 m_spawn.angles = s_model.angles;
2363 if ( isdefined( craftableStub.v_angle_offset ) )
2365 m_spawn.angles += craftableStub.v_angle_offset;
2368 m_spawn SetModel( craftableStub.str_model );
2369 uts_craftable.model = m_spawn;
2373 if ( isdefined( uts_craftable.model ) )
2375 for ( i = 0; i < craftableSpawn.a_pieceSpawns.size; i++ )
2377 if ( isdefined( craftableSpawn.a_pieceSpawns[i].tag_name ) )
2379 uts_craftable.model NotSolid();
2381 if ( !
IS_TRUE( craftableSpawn.a_pieceSpawns[i].crafted ) )
2383 uts_craftable.model HidePart( craftableSpawn.a_pieceSpawns[i].tag_name );
2387 uts_craftable.model show();
2388 uts_craftable.model ShowPart( craftableSpawn.a_pieceSpawns[i].tag_name );
2406 if ( isdefined( level.craftable_crafted_custom_func ) )
2408 self thread [[level.craftable_crafted_custom_func]]( craftableSpawn );
2420 self playsound(
"zmb_buildable_piece_add" );
2422 assert ( isdefined( level.zombie_craftableStubs[ craftableSpawn.craftable_name ].str_crafting ),
"Missing builing hint" );
2424 if ( isdefined( level.zombie_craftableStubs[ craftableSpawn.craftable_name ].str_crafting ) )
2426 return level.zombie_craftableStubs[ craftableSpawn.craftable_name ].str_crafting;
2439 b_open_craftables_remaining =
false;
2441 foreach ( uts_craftable
in level.a_uts_craftables )
2443 if ( isdefined( level.zombie_include_craftables[ uts_craftable.equipname ] ) &&
2444 IS_TRUE( level.zombie_include_craftables[ uts_craftable.equipname ].is_open_table ) )
2447 b_piece_crafted =
false;
2449 foreach ( pieceSpawn
in uts_craftable.craftableSpawn.a_pieceSpawns )
2451 if (
IS_TRUE( pieceSpawn.crafted ) )
2453 b_piece_crafted =
true;
2458 if ( !b_piece_crafted )
2460 b_open_craftables_remaining =
true;
2466 if ( !b_open_craftables_remaining )
2468 foreach ( uts_craftable
in level.a_uts_craftables )
2470 if ( uts_craftable.equipname ==
"open_table" )
2482 craftableSpawn.crafted =
true;
2483 craftableSpawn.stub.crafted =
true;
2484 craftableSpawn notify(
"crafted",
self );
2485 level.craftables_crafted[ craftableSpawn.craftable_name ] =
true;
2486 level notify( craftableSpawn.craftable_name +
"_crafted",
self );
2493 foreach ( uts_craftable
in level.a_uts_craftables )
2495 if ( uts_craftable.craftableStub.name == str_craftable_name )
2497 player = GetPlayers()[0];
2501 if ( isdefined( uts_craftable.craftableStub.onFullyCrafted ) )
2503 uts_craftable [[ uts_craftable.craftableStub.onFullyCrafted ]]();
2514 ArrayRemoveValue( level.a_uts_craftables,
self );
2520 self SetHintString(
self.stub.hint_string );
2532 DEFAULT( player.current_craftable_pieces, [] );
2541 self.hint_string =
"";
2552 if ( isdefined(
self.custom_craftablestub_update_prompt ) && !
self [[
self.custom_craftablestub_update_prompt ]]( player ) )
2557 initial_current_weapon = player getCurrentWeapon();
2559 if ( current_weapon.isheroweapon || current_weapon.isgadget )
2561 self.hint_string =
"";
2571 if ( !isdefined( player.current_craftable_pieces[slot] ) )
2573 self.hint_string = &
"ZOMBIE_BUILD_PIECE_MORE";
2579 self.hint_string = &
"ZOMBIE_BUILD_PIECE_WRONG";
2585 assert ( isdefined( level.zombie_craftableStubs[
self.equipname ].str_to_craft ),
"Missing craftable hint" );
2587 self.hint_string = level.zombie_craftableStubs[
self.equipname ].str_to_craft;
2593 self.hint_string = &
"ZOMBIE_BUILD_PIECE_ONLY_ONE";
2599 self.hint_string = &
"ZOMBIE_BUILD_PIECE_HAVE_ONE";
2603 self.hint_string =
self.trigger_hintstring;
2609 self.hint_string = &
"ZOMBIE_GO_TO_THE_BOX_LIMITED";
2612 else if (
IS_TRUE(
self.str_taken ) )
2614 self.hint_string = &
"ZOMBIE_GO_TO_THE_BOX";
2618 self.hint_string =
self.trigger_hintstring;
2622 self.hint_string =
"";
2635 self endon(
"kill_choose_open_craftable" );
2637 n_playernum = player GetEntityNumber();
2638 self.b_open_craftable_checking_input =
true;
2642 hintTextHudElem = newclientHudElem( player );
2643 hintTextHudElem.alignX =
"center";
2644 hintTextHudElem.alignY =
"middle";
2645 hintTextHudElem.horzAlign =
"center";
2646 hintTextHudElem.vertAlign =
"middle";
2647 hintTextHudElem.y = 95;
2649 if ( player IsSplitScreen() )
2651 hintTextHudElem.y = -50;
2654 hintTextHudElem.foreground =
true;
2655 hintTextHudElem.font =
"default";
2656 hintTextHudElem.fontScale = 1.1;
2657 hintTextHudElem.alpha = 1;
2658 hintTextHudElem.color = ( 1.0, 1.0, 1.0 );
2659 hintTextHudElem setText( &
"ZOMBIE_CRAFTABLE_CHANGE_BUILD" );
2661 if ( !isdefined(
self.openCraftableHudElem ) )
2663 self.openCraftableHudElem = [];
2666 self.openCraftableHudElem[ n_playernum ] = hintTextHudElem;
2671 while ( isdefined(
self.playertrigger[ n_playernum ] ) && !
self.crafted )
2673 if ( player ActionSlotOneButtonPressed() )
2675 self.n_open_craftable_choice++;
2678 else if ( player ActionSlotTwoButtonPressed() )
2680 self.n_open_craftable_choice--;
2686 if (
self.n_open_craftable_choice >=
self.a_uts_open_craftables_available.size )
2688 self.n_open_craftable_choice = 0;
2690 else if (
self.n_open_craftable_choice < 0 )
2692 self.n_open_craftable_choice =
self.a_uts_open_craftables_available.size - 1;
2698 self.equipname =
self.a_uts_open_craftables_available[
self.n_open_craftable_choice ].equipname;
2699 self.hint_string =
self.a_uts_open_craftables_available[
self.n_open_craftable_choice ].hint_string;
2700 self.playertrigger[ n_playernum ] SetHintString(
self.hint_string );
2701 b_got_input =
false;
2708 self.openCraftableHudElem[ n_playernum ].alpha = 1;
2712 self.openCraftableHudElem[ n_playernum ].alpha = 0;
2718 self.b_open_craftable_checking_input =
false;
2719 self.openCraftableHudElem[ n_playernum ]
destroy();
2720 self.openCraftableHudElem[ n_playernum ] = undefined;
2737 self.a_uts_open_craftables_available = [];
2739 foreach ( uts_craftable
in level.a_uts_craftables )
2745 if (
IS_TRUE( uts_craftable.craftableStub.is_open_table ) &&
2746 !
IS_TRUE( uts_craftable.crafted ) &&
2747 uts_craftable.craftableSpawn.craftable_name !=
"open_table" &&
2751 self.a_uts_open_craftables_available[
self.a_uts_open_craftables_available.size] = uts_craftable;
2758 if (
self.a_uts_open_craftables_available.size < 2 )
2760 self notify(
"kill_choose_open_craftable" );
2761 self.b_open_craftable_checking_input =
false;
2762 n_entitynum = player GetEntityNumber();
2764 if ( isdefined(
self.openCraftableHudElem ) &&
2765 isdefined(
self.openCraftableHudElem[ n_entitynum ] ) )
2767 self.openCraftableHudElem[ n_entitynum ]
destroy();
2768 self.openCraftableHudElem[ n_entitynum ] = undefined;
2772 switch (
self.a_uts_open_craftables_available.size )
2775 if ( !isdefined( player.current_craftable_pieces[slot] ) )
2777 self.hint_string = &
"ZOMBIE_BUILD_PIECE_MORE";
2786 self.n_open_craftable_choice = 0;
2787 self.equipname =
self.a_uts_open_craftables_available[
self.n_open_craftable_choice ].equipname;
2795 if ( !
self.b_open_craftable_checking_input )
2808 self.hint_string = &
"ZOMBIE_GO_TO_THE_BOX_LIMITED";
2811 else if (
IS_TRUE(
self.bought ) )
2813 self.hint_string = &
"ZOMBIE_GO_TO_THE_BOX";
2816 else if (
IS_TRUE(
self.str_taken ) )
2818 self.hint_string = &
"ZOMBIE_GO_TO_THE_BOX";
2822 self.hint_string =
self.trigger_hintstring;
2850 if ( isdefined(
self.screecher ) )
2855 if ( !
self UseButtonPressed() )
2860 if ( craftableSpawn.stub.useTime > 0 && isdefined( slot ) && !craftableSpawn
craftable_is_piece_crafting(
self.current_craftable_pieces[slot] ) )
2867 if ( craftableSpawn.stub.script_unitrigger_type ==
"unitrigger_radius_use" )
2870 porigin =
self GetEye();
2871 radius_sq = ( 1.5 * 1.5 ) * craftableSpawn.stub.radius * craftableSpawn.stub.radius;
2873 if ( Distance2DSquared( torigin, porigin ) > radius_sq )
2880 if ( !isdefined( trigger ) || !trigger IsTouching(
self ) )
2896 self endon(
"entering_last_stand" );
2897 self endon(
"death" );
2898 self endon(
"disconnect" );
2899 self endon(
"craftable_progress_end" );
2901 while ( isdefined(
self ) && getTime() - start_time < craft_time )
2903 progress = ( getTime() - start_time ) / craft_time;
2925 self.useBarText setText( &
"ZOMBIE_BUILDING" );
2927 if ( isdefined(
self ) && isdefined( start_time ) && isdefined( craft_time ) )
2943 if ( !isdefined(
self ) )
2946 if ( isdefined( player.craftableAudio ) )
2948 player.craftableAudio
delete();
2949 player.craftableAudio = undefined;
2960 if ( !isdefined(
self.useTime ) )
2962 self.useTime = int( 3 * 1000 );
2965 self.craft_time =
self.useTime;
2966 self.craft_start_time = getTime();
2967 craft_time =
self.craft_time;
2968 craft_start_time =
self.craft_start_time;
2970 if ( craft_time > 0 )
2975 orgweapon = player GetCurrentWeapon();
2976 build_weapon = GetWeapon(
"zombie_builder" );
2977 player GiveWeapon( build_weapon );
2978 player SwitchToWeapon( build_weapon );
2980 if ( isdefined( slot ) )
2992 if ( isdefined( level.craftable_craft_custom_func ) )
2994 player thread [[level.craftable_craft_custom_func]](
self.stub );
2998 while ( isdefined(
self ) && player
player_continue_crafting(
self.stub.craftableSpawn, slot ) && getTime() -
self.craft_start_time <
self.craft_time )
3003 player notify(
"craftable_progress_end" );
3007 player TakeWeapon( build_weapon );
3009 if (
IS_TRUE( player.is_drinking ) )
3017 if ( isdefined(
self ) &&
3019 (
self.craft_time <= 0 || getTime() -
self.craft_start_time >=
self.craft_time ) )
3021 if ( isdefined( slot ) )
3030 self notify(
"craft_succeed" );
3035 if ( isdefined( player.craftableAudio ) )
3037 player.craftableAudio
delete();
3038 player.craftableAudio = undefined;
3041 if ( isdefined( slot ) )
3050 self notify(
"craft_failed" );
3057 self endon(
"kill_trigger" );
3058 self endon(
"craft_succeed" );
3059 self endon(
"craft_failed" );
3063 PlayFX( level._effect[
"building_dust"], player GetPlayerCameraPos(), player.angles );
3075 if ( retval ==
"craft_succeed" )
3088 self notify(
"craftable_place_think" );
3089 self endon(
"craftable_place_think" );
3090 self endon(
"kill_trigger" );
3092 player_crafted = undefined;
3094 while ( !
IS_TRUE(
self.stub.crafted ) )
3096 self waittill(
"trigger", player );
3098 if ( isdefined( level.custom_craftable_validation ) )
3100 valid =
self [[ level.custom_craftable_validation ]]( player );
3108 if ( player !=
self.parent_player )
3113 if ( isdefined( player.screecher_weapon ) )
3128 self.stub.hint_string =
"";
3129 self SetHintString(
self.stub.hint_string );
3131 if ( isdefined(
self.stub.onCantUse ) )
3133 self.stub [[
self.stub.onCantUse ]]( player );
3138 if ( isdefined(
self.stub.onBeginUse ) )
3140 self.stub [[
self.stub.onBeginUse ]]( player );
3144 team = player.pers[
"team"];
3146 if ( isdefined(
self.stub.onEndUse ) )
3148 self.stub [[
self.stub.onEndUse ]]( team, player,
result );
3156 if ( isdefined(
self.stub.onUse ) )
3158 self.stub [[
self.stub.onUse ]]( player );
3162 player_crafted = player;
3163 self.stub.hint_string = prompt;
3164 self SetHintString(
self.stub.hint_string );
3170 if ( isdefined(
self.stub.craftableStub.onFullyCrafted ) )
3172 b_result =
self.stub [[
self.stub.craftableStub.onFullyCrafted ]]();
3180 if ( isdefined( player_crafted ) )
3182 player_crafted playsound(
"zmb_craftable_complete" );
3192 if (
self.stub.persistent ==
UNCRAFT )
3200 if ( isdefined( player_crafted ) )
3207 self.stub.hint_string = &
"ZOMBIE_GO_TO_THE_BOX_LIMITED";
3208 self SetHintString(
self.stub.hint_string );
3212 if (
IS_TRUE(
self.stub.str_taken ) )
3214 self.stub.hint_string = &
"ZOMBIE_GO_TO_THE_BOX";
3215 self SetHintString(
self.stub.hint_string );
3219 if ( isdefined(
self.stub.model ) )
3221 self.stub.model NotSolid();
3222 self.stub.model show();
3227 self waittill(
"trigger", player );
3229 if( isdefined(
self.stub.bought) &&
self.stub.bought == 1 )
3234 if ( isdefined( player.screecher_weapon ) )
3239 current_weapon = player GetCurrentWeapon();
3245 if ( current_weapon.isheroweapon || current_weapon.isgadget )
3255 if ( isdefined( level.custom_craftable_validation ) )
3257 valid =
self [[ level.custom_craftable_validation ]]( player );
3265 if ( !
IS_TRUE(
self.stub.crafted ) )
3267 self.stub.hint_string =
"";
3268 self SetHintString(
self.stub.hint_string );
3272 if ( player !=
self.parent_player )
3283 self.stub.bought = 1;
3285 if ( isdefined(
self.stub.model ) )
3294 if ( isdefined( level.zombie_include_craftables[
self.stub.equipname ].onBuyWeapon ) )
3296 self [[level.zombie_include_craftables[
self.stub.equipname ].onBuyWeapon]]( player );
3302 self.stub.hint_string = &
"ZOMBIE_GO_TO_THE_BOX_LIMITED";
3306 self.stub.hint_string = &
"ZOMBIE_GO_TO_THE_BOX";
3309 self SetHintString(
self.stub.hint_string );
3320 if ( hide && isdefined( level.custom_craftable_validation ) )
3322 visible =
self [[ level.custom_craftable_validation ]]( player );
3325 if ( visible && isdefined(
self.stub.model ) )
3327 self.stub.model NotSolid();
3328 self.stub.model show();
3333 self waittill(
"trigger", player );
3335 if ( isdefined( player.screecher_weapon ) )
3340 if ( isdefined( level.custom_craftable_validation ) )
3342 valid =
self [[ level.custom_craftable_validation ]]( player );
3350 if ( !
IS_TRUE(
self.stub.crafted ) )
3352 self.stub.hint_string =
"";
3353 self SetHintString(
self.stub.hint_string );
3357 if ( player !=
self.parent_player )
3378 if ( isdefined( level.zombie_craftable_persistent_weapon ) )
3380 if (
self [[level.zombie_craftable_persistent_weapon]]( player ) )
3386 if ( isdefined( level.zombie_custom_equipment_setup ) )
3388 if (
self [[level.zombie_custom_equipment_setup]]( player ) )
3397 player GiveWeapon(
self.stub.weaponname );
3399 player notify(
self.stub.weaponname.name +
"_pickup_from_table" );
3401 if ( isdefined( level.zombie_include_craftables[
self.stub.equipname ].onBuyWeapon ) )
3403 self [[level.zombie_include_craftables[
self.stub.equipname ].onBuyWeapon]]( player );
3406 else if (
self.stub.weaponname !=
"keys_zm" )
3408 player setactionslot( 1,
"weapon",
self.stub.weaponname );
3411 if ( isdefined( level.zombie_craftableStubs[
self.stub.equipname ].str_taken ) )
3413 self.stub.hint_string = level.zombie_craftableStubs[
self.stub.equipname ].str_taken;
3417 self.stub.hint_string =
"";
3420 self SetHintString(
self.stub.hint_string );
3427 self.stub.hint_string =
"";
3428 self SetHintString(
self.stub.hint_string );
3436 self moveto(
self.origin + ( 0, 0, 40 ), 3 );
3437 direction =
self.origin;
3438 direction = ( direction[1], direction[0], 0 );
3440 if ( direction[1] < 0 || ( direction[0] > 0 && direction[1] > 0 ) )
3442 direction = ( direction[0], direction[1] * -1, 0 );
3444 else if ( direction[0] < 0 )
3446 direction = ( direction[0] * -1, direction[1], 0 );
3449 self Vibrate( direction, 10, 0.5, 4 );
3450 self waittill(
"movedone" );
3454 PlayFX( level._effect[
"poltergeist"],
self.origin );
3460 foreach ( stub
in level.a_uts_craftables )
3462 if ( stub.equipname == equipname )
3480 if ( isdefined( stub ) )
3482 craftable = stub.craftableSpawn;
3483 craftable.crafted =
false;
3484 craftable.stub.crafted =
false;
3485 craftable notify(
"uncrafted" );
3486 level.craftables_crafted[ craftable.craftable_name ] =
false;
3487 level notify( craftable.craftable_name +
"_uncrafted" );
3489 for ( i = 0; i < craftable.a_pieceSpawns.size; i++ )
3491 craftable.a_pieceSpawns[i].crafted =
false;
3493 if ( isdefined( craftable.a_pieceSpawns[i].tag_name ) )
3495 craftable.stub.model NotSolid();
3497 if ( !
IS_TRUE( craftable.a_pieceSpawns[i].crafted ) )
3499 craftable.stub.model HidePart( craftable.a_pieceSpawns[i].tag_name );
3503 craftable.stub.model show();
3504 craftable.stub.model ShowPart( craftable.a_pieceSpawns[i].tag_name );
3510 craftable.a_pieceSpawns[i]
piece_spawn_at( origin, angles, use_random_start );
3514 if ( isdefined( craftable.stub.model ) )
3516 craftable.stub.model Ghost();
3527 if ( isdefined( stub ) )
3529 craftable = stub.craftableSpawn;
3530 craftable.crafted =
false;
3531 craftable.stub.crafted =
false;
3532 craftable notify(
"uncrafted" );
3533 level.craftables_crafted[ craftable.craftable_name ] =
false;
3534 level notify( craftable.craftable_name +
"_uncrafted" );
3536 for ( i = 0; i < craftable.a_pieceSpawns.size; i++ )
3538 craftable.a_pieceSpawns[i].crafted =
false;
3540 if ( isdefined( craftable.a_pieceSpawns[i].tag_name ) )
3542 craftable.stub.model NotSolid();
3544 if ( !
IS_TRUE( craftable.a_pieceSpawns[i].crafted ) )
3546 craftable.stub.model HidePart( craftable.a_pieceSpawns[i].tag_name );
3550 craftable.stub.model show();
3551 craftable.stub.model ShowPart( craftable.a_pieceSpawns[i].tag_name );
3555 ang = RandomFloat( 360 );
3556 h = 0.25 + RandomFloat( 0.5 );
3557 dir = ( Sin( ang ), Cos( ang ), h );
3558 self thread
player_throw_piece( craftable.a_pieceSpawns[i], origin, speed * dir, return_to_spawn, return_time );
3561 craftable.stub.model Ghost();
3570 foreach ( craftable
in level.zombie_include_craftables )
3572 if ( isdefined( craftable.triggerThink ) )
3574 craftable [[craftable.triggerThink]]();
3583 a_trigs = GetEntArray(
"open_craftable_trigger",
"targetname" );
3585 foreach ( trig
in a_trigs )
3589 unitrigger_stub.require_look_at =
false;
3590 unitrigger_stub.require_look_toward =
true;
3613 trig = GetEnt( trigger_targetname,
"targetname" );
3615 if ( !isdefined( trig ) )
3620 unitrigger_stub = spawnstruct();
3622 unitrigger_stub.craftableStub = level.zombie_include_craftables[ equipname ];
3624 unitrigger_stub.link_parent = parent;
3625 unitrigger_stub.origin_parent = trig;
3626 unitrigger_stub.trigger_targetname = trigger_targetname;
3629 unitrigger_stub.origin = trig.origin;
3630 unitrigger_stub.angles = trig.angles;
3631 unitrigger_stub.equipname = equipname;
3632 unitrigger_stub.weaponname = weaponname;
3633 unitrigger_stub.trigger_hintstring = trigger_hintstring;
3634 unitrigger_stub.delete_trigger = delete_trigger;
3635 unitrigger_stub.crafted =
false;
3636 unitrigger_stub.persistent = persistent;
3637 unitrigger_stub.useTime = int( 3 * 1000 );
3644 tmins = trig GetMins();
3645 tmaxs = trig GetMaxs();
3646 tsize = tmaxs-tmins;
3648 if ( isdefined( trig.script_length ) )
3650 unitrigger_stub.script_length = trig.script_length;
3654 unitrigger_stub.script_length = tsize[1];
3657 if ( isdefined( trig.script_width ) )
3659 unitrigger_stub.script_width = trig.script_width;
3663 unitrigger_stub.script_width = tsize[0];
3666 if ( isdefined( trig.script_height ) )
3668 unitrigger_stub.script_height = trig.script_height;
3672 unitrigger_stub.script_height = tsize[2];
3675 if ( isdefined( trig.radius ) )
3677 unitrigger_stub.radius = trig.radius;
3681 unitrigger_stub.radius = 64;
3684 unitrigger_stub.target = trig.target;
3685 unitrigger_stub.targetname = trig.targetname +
"_trigger";
3687 unitrigger_stub.script_noteworthy = trig.script_noteworthy;
3688 unitrigger_stub.script_parameters = trig.script_parameters;
3690 unitrigger_stub.cursor_hint =
"HINT_NOICON";
3692 if ( isdefined( level.zombie_craftableStubs[ equipname ].str_to_craft ) )
3694 unitrigger_stub.hint_string = level.zombie_craftableStubs[ equipname ].str_to_craft;
3697 unitrigger_stub.script_unitrigger_type =
"unitrigger_radius_use";
3698 unitrigger_stub.require_look_at =
true;
3706 unitrigger_stub.piece_trigger = trig;
3707 trig.trigger_stub = unitrigger_stub;
3713 if ( delete_trigger )
3718 level.a_uts_craftables[level.a_uts_craftables.size] = unitrigger_stub;
3719 return unitrigger_stub;
3741 player notify(
"event_ended" );
3746 if ( isdefined(
self.craftableStub.onBeginUse ) )
3748 self [[
self.craftableStub.onBeginUse ]]( player );
3751 if ( isdefined( player ) && !isdefined( player.craftableAudio ) )
3753 player.craftableAudio =
spawn(
"script_origin", player.origin );
3754 player.craftableAudio PlayLoopSound(
"zmb_craftable_loop" );
3760 if ( !isdefined( player ) )
3765 if ( isdefined( player.craftableAudio ) )
3767 player.craftableAudio
delete();
3768 player.craftableAudio = undefined;
3771 if ( isdefined(
self.craftableStub.onEndUse ) )
3773 self [[
self.craftableStub.onEndUse ]]( team, player,
result );
3776 player notify(
"event_ended" );
3781 if ( isdefined(
self.craftableStub.onCantUse ) )
3783 self [[
self.craftableStub.onCantUse ]]( player );
3789 if ( isdefined(
self.craftableStub.onUsePlantObject ) )
3791 self [[
self.craftableStub.onUsePlantObject ]]( player );
3795 player notify (
"bomb_planted" );
3803 if ( !isdefined( level.zombie_craftableStubs ) )
3810 if ( isdefined(
self.zombie_weapon_upgrade ) && isdefined( level.zombie_craftableStubs[
self.zombie_weapon_upgrade ] ) )
3817 if ( isdefined(
self.script_noteworthy ) &&
self.script_noteworthy ==
"specialty_weapupgrade" )
3819 if (
IS_TRUE( level.craftables_crafted[
"pap" ] ) )
3832 self.a_pieceSpawns--;
3837 if (
self.a_pieceSpawns <= 0 )
3848 assert( isdefined( level.zombie_craftableStubs[ craftable_name ] ), craftable_name +
" was not included or is not part of the zombie weapon list." );
3850 return level.zombie_craftableStubs[ craftable_name ].str_to_craft;
3855 craftable endon(
"death" );
3857 self waittill(
"disconnect" );
3859 if ( isdefined( self_notify ) )
3861 self notify( self_notify );
3866 if ( isdefined( craftable.stub ) )
3869 craftable.stub = undefined;
3872 if ( isdefined( craftable ) )
3901 if ( isdefined(
self.current_craftable_pieces ) && isdefined(
self.current_craftable_pieces[slot] ) )
3903 if (
self.current_craftable_pieces[slot].craftablename == craftable_name &&
3904 self.current_craftable_pieces[slot].modelname == piece_name )
3911 if ( isdefined( level.a_uts_craftables ) )
3913 foreach ( craftable_stub
in level.a_uts_craftables )
3915 if ( craftable_stub.craftableStub.name == craftable_name )
3918 foreach ( piece
in craftable_stub.craftableSpawn.a_pieceSpawns )
3920 if ( piece.pieceName == piece_name )
3922 if (
IS_TRUE( piece.in_shared_inventory ) )
3941 if ( isdefined( level.a_uts_craftables ) )
3943 foreach ( craftable_stub
in level.a_uts_craftables )
3945 if ( craftable_stub.craftableStub.name == craftable_name )
3948 if (
IS_TRUE( craftable_stub.crafted ) )
3954 foreach ( piece
in craftable_stub.craftableSpawn.a_pieceSpawns )
3956 if ( piece.pieceName == piece_name )
3979 if ( !isdefined( piece ) || !isdefined( piece.craftablename ) )
3985 if (isDefined(piece.piecestub) && isDefined(piece.piecestub.hash_id))
3989 if ( isdefined( piece.piecestub.vox_id ) )
3991 if (
IS_TRUE( piece.piecestub.b_one_time_vo ) )
3993 if ( !isdefined(
self.a_one_time_piece_pickup_vo ) )
3995 self.a_one_time_piece_pickup_vo = [];
4003 if ( IsInArray(
self.a_one_time_piece_pickup_vo, piece.piecestub.vox_id ) )
4008 self.a_one_time_piece_pickup_vo[
self.a_one_time_piece_pickup_vo.size] = piece.piecestub.vox_id;
4021 if ( !isdefined( craftable ) || !isdefined( craftable.craftable_name ) )
4026 bname = craftable.craftable_name;
4028 if ( isdefined( craftable.stat_name ) )
4030 bname = craftable.stat_name;
4041 level notify( bname +
"_crafted",
self );
4046 if ( !isdefined( craftable ) || !isdefined( craftable.craftable_name ) )
4051 bname = craftable.craftable_name;
4053 if ( isdefined( craftable.stat_name ) )
4055 bname = craftable.stat_name;
4061 if (isDefined(craftable.stub) && isDefined(craftable.stub.craftablestub) && isDefined(craftable.stub.craftablestub.hash_id))
4066 if( !isdefined(craftable.stub.craftablestub.no_challenge_stat) || (craftable.stub.craftablestub.no_challenge_stat==
false) )
4071 if ( isdefined( craftable.stub.craftablestub.vox_id ) )
4073 if ( isdefined( level.zombie_custom_craftable_built_vo ) )
4075 self thread [[ level.zombie_custom_craftable_built_vo ]]( craftable.stub );
4084 if ( !isdefined( craftable ) )
4090 if (isDefined(craftable.stub) && isDefined(craftable.stub.craftablestub) && isDefined(craftable.stub.craftablestub.hash_id))
4095 if ( !isdefined( stat_name ) )
4102 if ( isdefined( craftable.stub.craftablestub.vox_id ) )
4114 if ( !isdefined( equipment ) )
4119 craftable_name = undefined;
4121 if ( isdefined( equipment.name ) )
4126 if ( !isdefined( craftable_name ) )
4133 if (isDefined(equipment.stub) && isDefined(equipment.stub.craftablestub) && isDefined(equipment.stub.craftablestub.hash_id))
4153 self endon(
"disconnect" );
4154 self.craftable_timer =
true;
4156 self.craftable_timer =
false;
4161 self endon(
"disconnect" );
4162 self.craftable_pickedup_timer =
true;
4164 self.craftable_pickedup_timer =
false;
4170 if ( !isdefined( equipment ) )
4175 if ( equipment ==
"equip_turbine_zm" || equipment ==
"equip_turret_zm" || equipment ==
"equip_electrictrap_zm" || equipment ==
"riotshield_zm" || equipment ==
"alcatraz_shield_zm" || equipment ==
"tomb_shield_zm" )
4192 if ( !isdefined( craftable_name ) )
4199 vo_name = undefined;
4201 if ( craftable_name == level.riotshield_name )
4203 vo_name =
"craft_plc_shield";
4206 if ( !isdefined( vo_name ) )
4218 DEFAULT(level.craftables_stats_recorded,[]);
4219 level.craftables_stats_recorded[str_craftable] = b_record;
4224 if ( !isdefined( piece_name ) || ( piece_name ==
"sq_common" ) || ( piece_name ==
"keys_zm" ) )
4229 if (
IS_TRUE( level.zm_disable_recording_stats ) ||
IS_TRUE( level.zm_disable_recording_buildable_stats ) )
4234 DEFAULT(level.craftables_stats_recorded,[]);
4235 if ( !
IS_TRUE(level.craftables_stats_recorded[piece_name]) )
4240 self AddDStat(
"buildables", piece_name, stat_name, value );
4288 if ( isdefined( craftable_name ) )
4290 switch ( craftable_name )
4292 case "equip_riotshield_zm":
4293 return "riotshield_zm";
4295 case "equip_turbine_zm":
4298 case "equip_turret_zm":
4301 case "equip_electrictrap_zm":
4302 return "electric_trap";
4304 case "equip_springpad_zm":
4305 return "springpad_zm";
4307 case "equip_slipgun_zm":
4308 return "slipgun_zm";
4312 return craftable_name;
4320 foreach ( uts_craftable
in level.a_uts_craftables )
4322 if ( uts_craftable.craftableStub.name == str_craftable )
4324 if ( isdefined( uts_craftable.model ) )
4326 return uts_craftable.model;
4341 foreach ( uts_craftable
in level.a_uts_craftables )
4343 if ( uts_craftable.craftableStub.name == str_craftable )
4345 foreach ( pieceSpawn
in uts_craftable.craftableSpawn.a_pieceSpawns )
4347 if ( pieceSpawn.pieceName == str_piece )
4368 if ( isdefined( pieceSpawn ) )
4381 if ( isdefined( pieceSpawn ) )
4390 DEFAULT(
self.current_craftable_pieces, [] );
4392 foreach ( slot, self_piece
in self.current_craftable_pieces )
4394 if( piece_to_remove.pieceName === self_piece.pieceName && piece_to_remove.craftableName === self_piece.craftableName )
4397 self.current_craftable_pieces[ slot ] = undefined;
4398 self notify(
"craftable_piece_released" + slot );
4407 foreach ( uts_craftable
in level.a_uts_craftables )
4409 if ( uts_craftable.craftableStub.name == str_craftable )
4411 foreach ( pieceSpawn
in uts_craftable.craftableSpawn.a_pieceSpawns )
4413 if ( pieceSpawn.pieceName == str_piece && isdefined( pieceSpawn.model ) )
4415 return pieceSpawn.model;
4430 self notify(
"player_show_craftable_parts_ui" );
4431 self endon(
"player_show_craftable_parts_ui" );
4435 if( isdefined( str_crafted_clientuimodel ) )
4451 self endon(
"disconnect" );
4454 wait n_show_ui_duration;