Index: /nikanabo/current/bsl/mybackup/nobackup.txt
===================================================================
--- /nikanabo/current/bsl/mybackup/nobackup.txt	(revision 185)
+++ /nikanabo/current/bsl/mybackup/nobackup.txt	(revision 185)
@@ -0,0 +1,15 @@
+The name of this file indicates the 
+backup state of your level logic.
+
+backupok.txt
+	Your level logic is backed up here.
+	You can install scripted mods safely.
+
+nobackup.txt
+	Your level logic is not backed up.
+	Please run a backup from Oni\nikanabo
+	wbackup.bat	for Windows
+	xbackup.sh	for Mac/Linux
+
+You may delete the backed up logic if you 
+want. Do NOT delete this file, though...
Index: /nikanabo/current/bsl/mybackup/readme.txt
===================================================================
--- /nikanabo/current/bsl/mybackup/readme.txt	(revision 185)
+++ /nikanabo/current/bsl/mybackup/readme.txt	(revision 185)
@@ -0,0 +1,3 @@
+User level logic is backed up here.
+BSL mods should always check for 
+this backup before installing.
Index: /nikanabo/current/bsl/mybackup/winstall.bat
===================================================================
--- /nikanabo/current/bsl/mybackup/winstall.bat	(revision 185)
+++ /nikanabo/current/bsl/mybackup/winstall.bat	(revision 185)
@@ -0,0 +1,12 @@
+echo off
+IF NOT EXIST backupok.txt (
+    echo Level logic not backed up.
+) ELSE (
+    echo Restoring user level logic...
+    cd ..\..\..\GameDataFolder
+    rmdir /s /q IGMD
+    xcopy ..\nikanabo\bsl\mybackup\IGMD IGMD /s /k /i
+    cd ..\nikanabo\bsl\mybackup
+    echo User level logic restored.
+)
+PAUSE
Index: /nikanabo/current/bsl/mybackup/xinstall.sh
===================================================================
--- /nikanabo/current/bsl/mybackup/xinstall.sh	(revision 185)
+++ /nikanabo/current/bsl/mybackup/xinstall.sh	(revision 185)
@@ -0,0 +1,11 @@
+#!/bin/sh
+if [ ! -e backupok.txt ]
+    echo "User level logic not backed up."
+else
+    echo "Restoring user level logic..."
+    cd ../../../GameDataFolder
+    rm -rf IGMD
+    cp -r ../nikanabo/bsl/mybackup/IGMD .
+    cd ../nikanabo/bsl/mybackup
+    echo "User level logic restored."
+fi
Index: /nikanabo/current/bsl/onilight/IGMD/Airport/airport.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/Airport/airport.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/Airport/airport.bsl	(revision 185)
@@ -0,0 +1,514 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+console_deactivate 4
+if(save_point > 1) chr_delete civ_victim_1
+trigvolume_enable bayparticles1 0
+trigvolume_enable bayparticles1_copy 0
+trigvolume_enable exhaust 0
+trigvolume_enable exhaust_copy 0
+trigvolume_enable save_game_2 0
+#used
+console_deactivate 2
+door_lock 3
+particle fx1 do start
+particle fx2 do start
+particle fx3 do start
+particle fx4 do start
+particle fx5 do start
+particle fx6 do start
+particle exhaust create
+particle tarmacfire do start
+trigvolume_enable stop_booth_music_tv 1
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_asian
+sound_music_stop atm_gr06
+sound_music_stop mus_fitec_hd
+}
+
+#tv25 to tv41
+func void fire_damage(string ai_name)
+{	
+chr_poison (ai_name, 5, 30, 30);
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+particle tctf1 do start
+particle auto1 do start
+particle auto1fire do start
+particle auto1spark do start
+particle door1spark do start
+trigvolume_enable hidden1 1
+trigvolume_enable hidden2 1
+playback 0 IntroKonoko01
+chr_inv_reset 0
+ai2_spawn IntroStriker01
+ai2_spawn IntroStriker02	
+objective_set 1 silent
+target_set 1095 30
+sleep 1
+sound_music_start mus_asian 0.8 2.0
+sound_dialog_play_block c00_01_22shinatama
+sound_dialog_play c00_01_28shinatama
+}
+
+#tv 17 and 18 - across the street near the burning car
+func void hidden_civilian1(string ai_name)
+{
+ai2_spawn hidden_civ_1
+}
+
+#hit func of IntroStriker01
+func void hide_1(string char_index)
+{
+ai2_spawn civ_victim_5
+playback_block civ_victim_5 civ_victim5_flee interp 30
+ai2_dopath civ_victim_5 civ_victim_5
+}
+
+#lose func of IntroStriker01
+func void striker_lullaby_1(string ai_name)
+{
+striker_lullaby_2
+}
+
+#lose func of IntroStriker02
+func void striker_lullaby_2(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	if(save_point eq 3)
+		{
+		particle door3_locklight01 do start
+		door_unlock 14
+		}
+	music_stop
+	}
+}
+
+#tv 22 - in some distance after the 1st passage 
+func void panic1a(string char_index)
+{
+ai2_spawn civ_victim_6
+playback civ_victim_6 civ_victim6_flee interp 30
+ai2_spawn civ_victim_4
+playback civ_victim_4 civ_victim4_flee interp 30
+sleep 30
+ai2_spawn Intro_Striker_4
+playback Intro_Striker_4 striker4_advance interp 30
+ai2_spawn Intro_Comguy_1
+}
+
+#tv10 - after the 2nd passage
+func void panic1b(string char_index)
+{
+ai2_passive Intro_Striker_4 1
+ai2_spawn civ_victim_2
+ai2_spawn civ_victim_3
+playback civ_victim_3 civ_victim3_flee interp 30
+sleep 120
+ai2_spawn Intro_Striker_3
+ai2_attack Intro_Striker_3 civ_victim_2
+ai2_spawn Friend_Thug_1
+ai2_spawn Neutral_Thug_1
+ai2_spawn Neutral_Thug_3
+chr_delete civ_victim_4
+chr_delete civ_victim_6
+}
+
+#tv11 - after the 3rd passage
+func void horror_1(string char_index)
+{
+ai2_passive Intro_Striker_4 0
+ai2_spawn civ_victim_10
+ai2_spawn civ_victim_11
+ai2_spawn civ_victim_20
+ai2_spawn civ_victim_21
+}
+
+#console1
+func void change_terminaldoor_light(void)
+{
+particle door1_locklight01 do start
+door_unlock 3
+music_stop
+}
+
+#tv13 - after door 2
+func void ambush_striker_1(string char_index)
+{
+ai2_spawn Terminal_Striker_1
+ai2_spawn Terminal_Striker_2
+ai2_spawn mad_bomber_1
+obj_create 991 992
+}
+
+#hit func of Terminal_Striker_1
+func void civ_victim_20s_flee(string char_index)
+{
+ai2_dopath civ_victim_20 civ20s_flee1
+ai2_dopath civ_victim_21 civ20s_flee2
+}
+
+#tv14 - in some distance after door 3
+func void mad_bomber_bait(string char_index)
+{
+ai2_dopath mad_bomber_1 bomber_flee 1
+}
+
+func void patrolscript0200(string char_index)
+{
+chr_delete mad_bomber_1
+}
+
+#tv4 - in some distance after tv14
+func void LoadingBay1(string char_index)
+{
+ai2_spawn LoadingBay_Thug_1
+ai2_spawn LoadingBay_Thug_2
+ai2_spawn LoadingBay_Striker_2
+ai2_spawn LoadingBay_Comguy_1
+objective_set 2 silent
+sound_dialog_play c00_01_19shinatama
+}
+
+#tv15 - after tv14 in front of the ramp
+func void bomber_boom(string char_index)
+{
+particle bomb1 do explode
+obj_kill 991 992
+sleep 300
+particle bomb1 stop
+}
+
+#tv8 - the complete floor of the hall
+func void set_target_3(string chr_index)
+{
+particle door1_locklight01 do stop
+door_lock 3
+particle tctf1 do stop
+particle auto1 do stop
+particle auto1fire do stop
+particle auto1spark do stop
+particle door1spark do stop
+chr_delete civ_victim_1
+chr_delete civ_victim_2
+chr_delete civ_victim_3
+chr_delete civ_victim_5
+chr_delete civ_victim_10
+chr_delete civ_victim_11
+chr_delete civ_victim_20
+chr_delete civ_victim_21
+target_set 1109 30
+sound_dialog_play c00_01_26shinatama
+}
+
+##########
+### SP2 ###
+##########
+
+#tv3 - after the passage from the hall to the runway
+func void save_point_2(string player_name)
+{
+if(save_point eq 2)
+	{
+	trigvolume_enable bomberboom 0
+	trigvolume_enable madbomberbait 0
+	trigvolume_enable trigger_volume_03 0
+	target_set 1109 30
+	objective_set 2 silent
+	sleep 1
+	sound_dialog_play_block c00_01_19shinatama
+	sound_dialog_play c00_01_26shinatama
+	}
+else save_game 2 autosave
+ai2_spawn Tarmac_Striker_1
+ai2_spawn Tarmac_Striker_2
+ai2_spawn Tarmac_Striker_3
+ai2_spawn Tarmac_Striker_4
+ai2_spawn Tarmac_Friend_1
+ai2_spawn LoadingBay_Striker_1
+sound_music_start atm_gr06 1
+var_counter = -4
+}
+
+#lose func of Tarmac_Striker_3
+func void progress_check_1(string ai_name)
+{
+progress_check_4
+}
+
+#lose func of Tarmac_Striker_2
+func void progress_check_2(string ai_name)
+{
+progress_check_4
+}
+
+#tv19 - on the left side; over the complete runway from left to right; in front of the nose of the airplane
+func void back9a(string ai_name)
+{
+ai2_spawn hidden_striker1
+}
+
+#tv23 - on the right side; over the complete runway from left to right; under the engines of the airplane 
+# (entry func: bay1_particles; exit func: bay2_particles); I've disabled it
+#tv22 - after tv23 (entry func: bay2_particles; exit func: bay1_particles); I've disabled it
+
+#tv20 - in front of the first shack; over the complete runway from left to right
+func void back9b(string ai_name)
+{
+ai2_spawn hidden_striker2
+}
+
+#tv9 - big block; where the to ways down to the hall starts to the windows
+func void set_target_4(string chr_index)
+{
+target_set 1112 30
+sound_dialog_play c00_01_25shinatama
+}
+
+#tv6 - in front of the passage to the hall
+func void BayTwo1(string char_index)
+{
+ai2_dopath Tarmac_Striker_2 come_to_me 1
+ai2_dopath Tarmac_Striker_3 come_to_me 1
+ai2_dopath mad_bomber_2 come_to_me 1
+ai2_spawn BayTwo_Striker_1
+ai2_spawn hidden_friend2
+ai2_spawn mad_bomber_2
+music_stop
+}
+
+#lose func of mad_bomber_2
+func void progress_check_3(string ai_name)
+{
+progress_check_4
+}
+
+#lose func of BayTwo_Striker_1
+func void progress_check_4(string ai_name)
+{
+var_counter = var_counter + 1
+}
+
+#tv42 - after tv6 (entry func: exhaust_off; exit func: exhaust_on); I've disabled it
+#tv43 - after tv42 (entry func: exhaust_on; exit func: exhaust_off); I've disabled it
+#tv16 - at the end of the ramp; in front of door 6 (entry func: set_target_5; inside func: save_point_3); I've disabled it
+
+##########
+### SP3 ###
+##########
+
+#tv44 - at the same place as tv16
+func void second_coming(string ai_name)
+{
+if(var_counter eq 0)
+	{
+	if(save_point eq 3)
+		{
+		trigvolume_enable back9 0
+		trigvolume_enable back9_copy 0
+		trigvolume_enable bomberboom 0
+		trigvolume_enable madbomberbait 0
+		trigvolume_enable tarmac 0
+		trigvolume_enable trigger_volume_03 0
+		trigvolume_enable trigger_volume_08 0
+		trigvolume_enable trigger_volume_10 0
+		trigvolume_enable trigger_volume_11 0
+		objective_set 2 silent
+		}
+	else save_game 3 autosave
+	trigvolume_enable secondcoming 0
+	ai2_spawn TerminalTwo_Striker_1
+	ai2_spawn TerminalTwo_Striker_2
+	door_unlock 6
+	particle door7_locklight01 do start
+	particle lock2_locklight01 do start
+	target_set 1115 30
+	sleep 1
+	sound_dialog_play c00_01_24shinatama
+	}
+else
+	{
+	ai2_dopath Tarmac_Striker_2 come_to_me 1
+	ai2_dopath Tarmac_Striker_3 come_to_me 1
+	ai2_dopath mad_bomber_2 come_to_me 1
+	}
+}
+
+func void patrolscript000(string ai_name)
+{
+particle lock2_locklight01 do start
+door_unlock 6
+}
+
+#tv1 - after door 7
+func void Booth(string wazzzup)
+{
+ai2_spawn BoothStriker01
+ai2_spawn BoothStriker02
+playback BoothStriker01 BoothStriker01
+playback BoothStriker02 BoothStriker02
+sound_music_start mus_asian 0.8
+target_set 0 0
+door_lock 10
+}
+
+#lose func of BoothStriker01
+func void console_2_activate(string char_index)
+{
+console_activate 2
+}
+
+#console 2
+func void change_door2_light(void)
+{
+door_lock 7
+particle door7_locklight01 do stop
+particle door2_locklight01 do start
+console_deactivate 2
+objective_set 3 silent
+target_set 1139 30
+sound_dialog_play_block c00_01_18shinatama
+sound_dialog_play c00_01_28shinatama
+}
+
+#tv5 - after door 10
+func void Repair1(string char_index)
+{
+ai2_spawn Repair_Striker_1
+ai2_spawn Repair_Comguy_1
+ai2_spawn alamo_thug_1	
+}
+
+#tv24 - after door 11
+func void stop_booth_music(string who)
+{
+music_stop
+}
+
+#tv21 - at the beginning of the stairs to door 13
+func void Repair2(string char_index)
+{
+ai2_spawn Repair_Striker_2
+ai2_spawn Repair_Comguy_2	
+}
+
+#console 3
+func void final_ambush(string char_index)
+{
+sound_music_start mus_fitec_hd 0.91
+particle door3_locklight01 do start
+door_unlock 14
+ai2_spawn finalam_striker_1
+ai2_spawn finalam_striker_2
+ai2_setmovementmode finalam_striker_1 walk
+ai2_setmovementmode finalam_striker_2 walk
+playback finalam_striker_1 finalam_striker1
+playback finalam_striker_2 finalam_striker2
+sleep 240
+particle door3_locklight01 do stop
+door_lock 14
+ai2_dopath finalam_striker1 finalam_1 1
+ai2_dopath finalam_striker2 finalam_2 1
+}
+
+#for the open door func see func: striker_lullaby_2
+#tv12 - on the stairs to door 12 (entry func: i_uh_heheheh); it's disabled and I didn't enabled it
+
+#tv7 - after door 14
+func outro(string wazzup)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level_4a(void)
+{
+text_console level_4a
+console_reset 7
+}
+
+func void level_4b(void)
+{
+text_console level_4b
+console_reset 7
+}
+
+func void level_4c(void)
+{
+text_console level_4c
+console_reset 8
+}
Index: /nikanabo/current/bsl/onilight/IGMD/Airport_III/airport2.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/Airport_III/airport2.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/Airport_III/airport2.bsl	(revision 185)
@@ -0,0 +1,930 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3)
+	{
+	restore_game
+	sleep 1
+	if(trigvolume_count(5) eq 0) fork save_point_2
+	}
+if(save_point eq 4) restore_game
+if(save_point eq 5) fork save_point_5
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable ratend 0
+trigvolume_enable trigger_volume_03 0
+trigvolume_enable trigger_volume_04 0
+trigvolume_enable trigger_volume_40 0
+trigvolume_enable trigger_volume_41_copy 0
+trigvolume_enable unfinishedbusiness 0
+#used
+door_lock 35
+particle gas2 do stop
+particle gaslight1 do stop
+trig_hide 1
+trig_hide 2
+trig_hide 3
+trig_hide 4
+trigvolume_enable rappel_point 0
+trigvolume_enable trigger_volume_08 1
+trigvolume_enable tripwire 1
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+if(save_point eq 5) save_game 5 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_om03
+sound_music_stop atm_gr09
+sound_music_stop mus_asian
+sound_music_stop atm_cl09
+sound_music_stop mus_space01
+}
+
+#tv43, 46 and 47
+func void fire_damage(string ai_name)
+{	
+chr_poison(ai_name, 5, 30, 30);
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+playback 0 IntroKonokoSet	
+sleep 5
+ai2_spawn Start_Friend_1
+ai2_spawn Start_Striker_5
+ai2_makeaware Start_Striker_5 Start_Friend_1
+particle room1 do start
+sleep 15
+sound_dialog_play c00_01_28shinatama
+sleep 30
+objective_set 1 silent
+target_set 7124 30
+sound_music_start mus_om03
+}
+
+func void patrolscript0200(string char_index)
+{
+playback_block Start_Friend_1 roll fromhere
+ai2_dopath Start_Friend_1 Start_Friend_1b 1
+ai2_setjobstate Start_Friend_1
+}
+
+#tv9 - in the middle of the passage from the start room to the hall
+func void Start1(string char_index)
+{
+ai2_spawn Start_Striker_1
+ai2_spawn Start_Striker_2
+ai2_spawn Start_Comguy_1
+}
+
+#tv11- at the end of the passage
+func void mad_bomber1(string ai_name)
+{
+ai2_spawn mad_bomber1
+sleep 150
+particle bomb1 do explode
+particle squib1a do explode
+particle squib1b do explode
+sleep 60
+particle bomb2 do explode
+particle squib2 do explode
+sleep 30
+particle bomb_damage1 do start
+}
+
+#lose func of Start_Striker_5 and Start_Comguy_1 and Hangar1_A_Striker_3
+func void striker_lullaby_1(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	music_stop
+	var_counter = 0
+	}
+}
+
+#tv14 - in some distance in front of the corner of the right wall; from left to right
+func void victim_thug1(string ai_name)
+{
+ai2_spawn victim_thug1
+ai2_spawn cruel_striker1
+}
+
+#console11
+func void lock2(string ai_name)
+{
+particle lock2_locklight01 do start
+trigvolume_enable hidden_friends1 1
+music_stop
+}
+
+#tv15 - in the middle of the passage to door 41
+func void hidden_thugs(string ai_name)
+{
+ai2_spawn Start_Friend_2
+ai2_spawn Start_Friend_3
+}
+
+#console 12
+func void lock1(void)
+{
+particle lock1_locklight01 do start
+target_set 7125 30
+}
+
+##########
+### SP2 ###
+##########
+
+#tv1 - in some distance after door 11
+func void tarmac(string ai_name)
+{
+if(save_point ne 2)
+	{
+	fork remove_ai
+	save_game 2 autosave
+	particle lock1_locklight01 do stop
+	door_close 11
+	door_lock 11
+	particle room1 do stop
+	particle bomb_damage1 do stop
+	}
+particle compound create
+ai2_spawn tarmac_striker_1
+ai2_spawn tarmac_striker_2
+ai2_spawn tarmac_striker_3
+ai2_spawn tarmac_tanker_1
+ai2_spawn tarmac_tanker_2
+ai2_spawn tarmac_commguy_1
+objective_set 2 silent
+target_set 7037 30
+sleep 1
+sound_music_start atm_gr09 0.75
+sound_dialog_play c00_01_18shinatama
+}
+
+#tv18 - big box around the entrance of the area which is fenced in (where the mad bomber waits)
+func void striker_tee_off(string ai_name)
+{
+ai2_dopath tarmac_striker_4 tarmac_striker_3b 1
+}
+
+#tv19 - compled area which is fenced in (where the mad bomber waits)
+#hit func of tarmac_striker_3
+func void tanker_backup(string ai_name)
+{
+ai2_dopath tarmac_tanker_2 tarmac_tanker_2b 1
+}
+
+#tv17 - after door 46; from left to right
+func void unlock_commguy(string ai_name)
+{
+ai2_dopath tarmac_commguy_1 tarmac_commguy_2 1
+ai2_dopath tarmac_tanker_2 tarmac_tanker_2c 1
+music_stop
+}
+
+#console 1
+func void Hangar1_A(void)
+{
+particle lock3_locklight01 do start
+door_unlock 12
+target_set 7085 30
+}
+
+#tv12 and 45 - in some distance after door 12
+func void muro_bait(string ai_name)
+{
+trigvolume_enable murobait_a 0
+trigvolume_enable murobait_b 0
+particle compound kill
+door_close 12
+door_lock 12
+ai2_spawn muro1
+ai2_spawn escort_striker1
+ai2_spawn escort_striker2
+playback muro1 muro1 interp 30
+playback escort_striker1 escort_striker1 interp 30
+playback escort_striker2 escort_striker2 interp 30
+sound_music_start mus_asian 0.75
+particle garage1_locklight02 do start
+door_open 26
+door_jam 26
+ai2_spawn Hangar1_A_Striker_1
+ai2_spawn Hangar1_A_Striker_2
+ai2_spawn Hangar1_A_Striker_3
+playback Hangar1_A_Striker_2 hangar1_striker2 interp 30
+playback Hangar1_A_Striker_3 hangar1_striker3 interp 30	
+playback Hangar1_A_Striker_1 hangar1_striker1 interp 30
+sleep 30
+sound_dialog_play c00_01_20shinatama
+objective_set 3 silent
+target_set 0 0
+sleep 600
+chr_delete muro1
+chr_delete escort_striker1
+chr_delete escort_striker2
+}
+
+#lose func of Hangar1_A_Striker_1
+func void striker_lullaby_2(string ai_name)
+{
+striker_lullaby_1
+}
+
+### WAY TO THE GAS TUNNEL ###
+
+#console13
+func void rat_door(string ai_name)
+{
+particle lock9_locklight02 do start
+door_unlock 24
+}
+
+#tv48 - after door 26
+func void low_target_clear(string ai_name)
+{
+target_set 0 0
+}
+
+#tv49 - after tv48
+func void low_target_set(string ai_name)
+{
+target_set 7085 30
+}
+
+#tv2 - in some distance after tv49
+func void hangar1a(string char_index)
+{
+ai2_spawn Hangar1_B_Striker_1
+ai2_spawn Hangar1_B_Striker_4
+}
+
+#lose func of Hangar1_B_Striker_1 and Hangar1_B_Striker_4
+func void hangar1d_var(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	particle garage2_locklight02 do start
+	door_unlock 19
+	door_open 19
+	door_jam 19
+	ai2_spawn hangar1d_enemy_1
+	ai2_spawn hangar1d_enemy_2
+	}
+}
+
+#lose func of hangar1d_enemy_1 and hangar1d_enemy_2
+func void hangar1f_var(string ai_name)
+{
+var_counter = var_counter + 1
+if (var_counter eq 4)
+	{
+	particle garage3_locklight02 do start
+	door_unlock 20
+	door_open 20
+	door_jam 20
+	ai2_spawn hangar1f_enemy_1
+	ai2_spawn hangar1f_enemy_3
+	ai2_spawn rat_thug_4
+	var_counter = 0
+	}
+}
+
+#tv39 - after door 20 (entry func: skip_ratscene); I've disabled it
+
+#hit func of hangar1f_enemy_3
+func void hangar1d_backup(string ai_name)
+{
+ai2_spawn hangar1f_enemy_2
+}
+
+func void patrolscript0500(string ai_name)
+{
+playback_block hangar1f_enemy_2 bomber_jump interp 30
+}
+
+#tv31 - after the beginning of the ramp
+func void gas_trig_show(string ai_name)
+{
+trig_show 1
+trig_show 2
+trig_show 3
+trig_show 4
+console_deactivate 14
+console_deactivate 15
+door_open 48
+door_jam 48
+}
+
+### WAY TO THE ROOF ###
+
+#tv13 - from the left wall (at the end of the right side of door 26) to the right wall
+func void hangar1b(string ai_name)
+{
+ai2_spawn superball_striker
+}
+
+#tv50 - at the beginning of the first plattform; at the end of the first ramp
+func void high_target_clear(string ai_name)
+{
+target_set 0 0
+}
+
+#tv51 - after tv50
+func void high_target_set(string ai_name)
+{
+target_set 7126 30
+}
+
+#console 8
+func void lock5(void)
+{
+particle lock5c_locklight01 do start
+lock_check
+}
+
+#tv30 - after the room with console 3; left side; at the end of the ramp
+func void hangar1c(string char_index)
+{
+ai2_spawn Hangar1_B_Striker_5
+ai2_spawn Hangar1_B_Striker_9
+ai2_spawn Hangar1_A_Tanker_1
+ai2_spawn Hangar1_B_Comguy_12
+}
+
+#console 3
+func void lock5a_var(string ai_name)
+{
+particle lock5a_locklight01 do start
+lock_check
+}
+
+#tv4 - the platform with door 21 and door 22; first half of the platform (tv without any func); I've disabled it
+
+#console 33
+func void lock5b_var(string ai_name)
+{
+particle lock5b_locklight01 do start
+lock_check
+}
+
+func void lock_check(void)
+{
+var_counter2 = var_counter2 + 1
+if(var_counter2 eq 1) music_stop
+if(var_counter2 eq 3)
+	{
+	door_unlock 21
+	door_unlock 22
+	roof_guys
+	}
+}
+
+func void roof_guys(void)
+{
+#particles
+particle carpool create
+particle carpool do start
+particle roof2 do start
+particle roof3 do start
+#roof1
+ai2_spawn ahah_badman_1
+ai2_spawn ahah_badman_2
+ai2_spawn Roof1_Striker_1
+ai2_spawn Roof1_Striker_2
+#roof2
+ai2_spawn carpool_striker_1
+ai2_spawn Roof2_Striker_1
+ai2_spawn Roof2_Striker_2
+ai2_spawn Roof2_Striker_3
+#tv
+trigvolume_enable trigger_volume_08 0
+}
+
+##########
+### SP3 ###
+##########
+
+### GAS TUNNEL ###
+
+#tv5 - in some distance after door 24
+func void save_point_3(string ai_name)
+{
+if(save_point eq 3)
+	{
+	gas_trig_show
+	objective_set 3 silent
+	target_set 7085 30
+	}
+else
+	{
+	fork remove_ai
+	save_game 3 autosave
+	particle lock9_locklight02 do stop
+	door_close 24
+	door_lock 24
+	}
+ai2_spawn Rat_Tanker_1
+ai2_spawn Rat_Comguy_1
+sleep 1
+sound_music_start atm_cl09 0.75
+trigvolume_enable save2 0
+trigvolume_enable save3 0
+}
+
+#tv28 - the complete volume of the tunnel (tv name: gas)
+func void poison_konoko(string ai_name)
+{	
+chr_poison(0, 10, 60, 90);
+}
+
+#fired off by touching the triggers (lasers)
+func void gas(string ai_name)
+{
+particle gas1 do start
+particle gas2 do start
+particle gaslight1 do start
+console_activate 14
+console_activate 15
+door_unjam 48
+door_close 48
+door_jam 48
+trigvolume_enable gas 1
+}
+
+#console 14 and console 15
+func void gas_off(string ai_name)
+{
+particle gas1 do stop
+particle gas2 do stop
+particle gaslight1 do stop
+console_reset 14
+console_reset 15
+console_deactivate 14
+console_deactivate 15
+door_unjam 48
+door_open 48
+door_jam 48
+trigvolume_enable gas 0
+}
+
+#tv27 - in some distance in front of door 48 (entry func: Rat_Guards); I've disabled it
+
+#tv29 - after door 48
+func void gas_kill(string ai_name)
+{
+particle gas1 do stop
+particle gas2 do stop
+particle gaslight1 do stop
+door_unjam 48
+door_close 48
+trig_hide 1
+trig_hide 2
+trig_hide 3
+trig_hide 4
+}
+
+#tv32 - in some distance in front of door 35
+func void gas_trig_hide(string ai_name)
+{
+roof_guys
+}
+
+### ROOF ###
+
+#tv26 - long volume after door 21 and door 22
+func void save_point_2(string ai_name)
+{
+if(save_point eq 3)
+	{
+	fork roof_guys
+	objective_set 3 silent
+	}
+else 
+	{
+	save_game 3 autosave
+	particle lock5a_locklight01 do stop
+	particle lock5b_locklight01 do stop
+	particle lock5c_locklight01 do stop
+	door_close 21
+	door_close 22
+	door_lock 21
+	door_lock 22
+	}
+target_set 7085 30
+trigvolume_enable save2 0
+trigvolume_enable save3 0
+sleep 1
+sound_music_start atm_cl09 1.0
+}
+
+#tv21 - complete left end of the roof
+#tv20 - at the beginning of the cul-de-sac
+func void secret_striker(string char_index)
+{
+ai2_spawn secret_striker_1
+}
+
+#notice func of secret_striker_1
+func void secret_tanker(string char_index)
+{
+ai2_spawn secret_tanker_1
+}
+
+#tv22 - complete front end of the roof
+#tv23 - complete right end of the roof
+#tv24 - at the roof of the gas tunnel; from the left to the right; start left: at the beginning of the first short ramp
+func void low_roadies_1(string ai_name)
+{
+ai2_spawn Back_Striker_1
+ai2_spawn Back_Striker_2
+ai2_spawn Back_Striker_3
+ai2_spawn Back_Thug_1
+}
+
+#notice func of Back_Striker_3
+func void sos_2(string char_index)
+{
+ai2_spawn sos_badman_2
+}
+
+#tv25 - at the end of the underpass of the gas tunnel
+func void low_roadies_2(string ai_name)
+{
+ai2_spawn Back_Tanker_1
+ai2_spawn Back_Thug_2
+ai2_spawn Back_Thug_3
+}
+
+### BOTH WAYS FUSE ###
+
+func void carpool_backup(string char_index)
+{
+ai2_spawn carpool_striker_2
+}
+
+#tv42 - huge box around the carpool (entry func: carpool_start; exit func: carpool_stop); I've disabled it
+
+#tv6 - on the roof of the underpass to console 10; at the beginning (top) of the ramp
+func void Back3(string char_index)
+{
+ai2_spawn Roof3_Striker_1
+ai2_spawn Roof3_Striker_2
+ai2_spawn Roof3_Tanker_1
+}
+
+#hit func of Roof3_Tanker_1
+func void roof3_backup1(string char_index)
+{
+ai2_dopath Roof3_Striker_1 Roof3_Striker_1b 1
+}
+
+#tv33 - huge box around the underpass to console 10; includes the roof of the underpass
+func void back_compound(string char_index)
+{
+ai2_spawn compound_tanker_1
+ai2_spawn compound_bomber_1
+}
+
+#tv41 - huge wall from left to right over the complete area below and the roof; starts in some distance after the stiarway to door 27
+func void remote_parking(string ai_name)
+{
+ai2_spawn hostage_thug_1
+ai2_spawn hostage_thug_2
+ai2_spawn hostage_thug_3
+ai2_spawn squad_tanker_1
+ai2_spawn squad_tanker_2
+var_counter2 = 10
+}
+
+#lose func of squad_tanker_1
+func void remote_backup_1(string ai_name)
+{
+ai2_spawn hostage_striker_1
+}
+
+#lose func of squad_tanker_2
+func void remote_backup_2(string ai_name)
+{
+ai2_spawn hostage_striker_2
+}
+
+##########
+### SP4 ###
+##########
+
+#console 10
+func void save_point_4(string ai_name)
+{
+trigvolume_enable trigger_volume_08 1
+particle lock6_locklight01 do start
+door_unlock 27
+if(save_point eq 4)
+	{
+	console_deactivate 10
+	particle carpool create
+	particle carpool do start
+	particle roof2 do start
+	particle roof3 do start
+	trigvolume_enable backcompound 0	
+	trigvolume_enable hidden1a 0
+	trigvolume_enable hidden1b 0
+	trigvolume_enable lowroad1 0
+	trigvolume_enable lowroad2 0
+	trigvolume_enable lowroad3 0
+	trigvolume_enable lowroad4 0
+	trigvolume_enable remote 0
+	trigvolume_enable save2 0
+	trigvolume_enable trigger_volume_07 0
+	}
+else
+	{
+	fork remove_ai
+	music_stop
+	fade_out 0 0 0 30
+	sleep 30
+	chr_teleport 0 2020
+	chr_peace 0
+	fade_in 30
+	save_game 4 autosave
+	}
+target_set 7060 30
+objective_set 4 silent
+sound_dialog_play c00_01_19shinatama
+}
+
+#tv7 - in front of door 27
+func void Office1(string char_index)
+{
+if(var_counter2 ne 10) fork save_point_4
+ai2_spawn Office1_Comguy_1
+ai2_spawn Office1_Comguy_11
+ai2_spawn Office2_Striker_1
+ai2_spawn Office2_Striker_3
+ai2_spawn Office3_Tanker_12
+ai2_spawn neutral_1
+ai2_spawn neutral_2
+sleep 1
+sound_music_start atm_gr09
+}
+
+#tv44 - around the box with the lsi
+func void objective_check(string ai_name)
+{
+if(chr_has_lsi(0))
+	{	
+	trigvolume_enable objectivecheck 0
+	objective_set 5 silent
+	target_set 7127 30
+	particle lock6_locklight01 do stop
+	door_lock 27
+	particle carpool do stop
+	particle carpool kill
+	particle roof2 do stop
+	particle roof3 do stop
+	}
+}
+
+#tv36 - in the middle of the stairs to door 33
+func void lsi_check_1(string ai_name)
+{
+if(chr_has_lsi(0))
+	{
+	trigvolume_enable tripwire 1
+	music_stop
+	}
+}
+
+#tv34 - in some distance in front of door 36
+func void ambush(string ai_name)
+{
+ai2_spawn ambush_striker_1
+if(save_point ne 5)
+	{
+	particle lock7_locklight01 do start
+	door_unlock 36
+	ai2_spawn ambush_commguy_1
+	sleep 220
+	ai2_doalarm ambush_commguy_1 4
+	}
+sleep 1
+sound_music_start mus_space01 0.75
+}
+
+##########
+### SP5 ###
+##########
+
+#tv8 - after door 36
+func void save_point_5(string ai_name)
+{
+trigvolume_enable hangar2_setup 0
+if(save_point eq 5)
+	{
+	restore_game
+	ambush
+	objective_set 5 silent
+	}
+else
+	{
+	save_game 5 autosave
+	particle lock7_locklight01 do stop
+	door_close 36
+	door_lock 36
+	}
+particle muroplane_prop do start
+particle rotorwash do start
+ai2_spawn Hangar2_tanker_1
+ai2_spawn alarm_striker_1
+target_set 1054 30
+}
+
+#console 4
+func void raise_alarm(string char_index)
+{
+ai2_dopath alarm_striker_1 alarm_striker_1a 1
+fork alarm_sound_script
+}
+
+func void alarm_sound_script(void)
+{
+sound_ambient_start alarm_loop
+sleep 900
+sound_ambient_stop alarm_loop
+}
+
+#tv35 - in front of door 42
+func void alarm_patrol(string char_index)
+{
+ai2_dopath alarm_striker_1 alarm_striker_1b 1
+}
+
+#tv37 - in some distance after door 42
+func void final_muro(string char_index)
+{
+ai2_spawn muro2
+ai2_spawn escort_striker3
+ai2_spawn escort_striker4
+playback escort_striker3 final_escort3
+playback escort_striker4 final_escort4
+playback muro2 final_muro
+sleep 960
+chr_delete muro2
+chr_delete escort_striker3
+sleep 60
+chr_delete escort_striker4
+}
+
+#tv38 - on the last but one platform; at the beginning of the last part of the ramp
+func void Hangar2b(string char_index)
+{
+ai2_spawn Hangar2_Striker_3
+ai2_spawn Hangar2_Striker_4
+ai2_spawn Hangar2_Striker_5
+}
+
+#lose func of Hangar2_Striker_5
+func void striker_showdown_1(string ai_name)
+{
+striker_showdown_3
+}
+
+#lose func of Hangar2_Striker_4
+func void striker_showdown_2(string ai_name)
+{
+striker_showdown_3
+}
+
+#lose func of Hangar2_Striker_3
+func void striker_showdown_3(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 3)
+	{
+	trigvolume_enable rappel_point 1
+	particle rappel create
+	target_set 1054 30
+	music_stop
+	}
+}
+
+#tv10 - at the rappel point
+func void lsi_check_2(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level6a(void)
+{
+text_console level_6a
+console_reset 16
+}
+
+func void level6b(void)
+{
+text_console level_6b
+console_reset 9
+}
+
+func void level6c(void)
+{
+text_console level_6c
+console_reset 13
+}
+
+func void level6d(void)
+{
+text_console level_6d
+console_reset 17
+}
+
+func void level6e(void)
+{
+text_console level_6e
+console_reset 5
+}
+
+func void level6f(void)
+{
+text_console level_6f
+console_reset 2
+}
Index: /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/training.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/training.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/training.bsl	(revision 185)
@@ -0,0 +1,1139 @@
+#################
+### VARIABLES ###
+#################
+
+var int rating = 0;
+var int var_training_counter;
+var int var_training_counter2;
+var int var_training_counter3;
+
+#############
+### START ###
+#############
+
+func void deactivate_training_stuff(void)
+{
+#used
+co_message_display = 1
+env_show 2010 0
+particle forcefield1 do start
+particle forcefield2 do start
+particle steam start
+trigvolume_enable tv1 0
+trigvolume_enable tv2 0	
+trigvolume_enable tv3 0
+trigvolume_enable tv4 0
+trigvolume_enable tv5 0
+trigvolume_enable tv6 0
+trigvolume_enable tv7 0
+trigvolume_enable tv8 0
+trigvolume_enable tv9 0
+trigvolume_enable tv10 0
+trigvolume_enable tv11 0
+trigvolume_enable tv12 0
+trigvolume_enable tv13 0
+trigvolume_enable tv14 0
+trigvolume_enable tv15 0
+trigvolume_enable tv16 0
+trigvolume_enable tv17 0
+trigvolume_enable tv74 0
+trigvolume_enable tv75 0
+trigvolume_enable tv_end 0
+trigvolume_enable tv_move4 0
+trigvolume_enable tv_review 0
+trigvolume_enable tv_train_door 0
+trigvolume_enable trigger_volume_71 0
+ui_show_element left 0
+ui_show_element right 0
+}
+
+###############
+### TRAINING ###
+###############
+
+### MOVEMENT ###
+
+#tv20 - at the start point
+func void train_movement(string ai_name)
+{
+trigvolume_enable tv_train_movement 0
+fork deactivate_training_stuff
+splash_screen training_splash_screen
+fade_out 0 0 0 0
+lock_keys
+lock_keys keys_pause
+lock_keys keys_action
+lock_keys keys_movement
+fade_in 60
+sleep 10
+sound_music_start atm_gr06 0
+sound_music_volume atm_gr06 0.7 3.0
+fork lights
+message xwelcome 240
+sound_dialog_play c00_01_29shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play c00_01_30shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play c00_01_32shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play_block c00_01_33shinatama
+sound_dialog_play_block pause
+message xdash1
+fork encourage_dash
+chr_wait_animation 0 KONSPRrun_lt KONSPRrun_rt
+var_training_counter2 = 1
+message_remove
+sleep 60
+message xdash2 180
+sound_dialog_play c00_01_37shinatama
+sleep 180
+message xgotrack
+sound_dialog_play_block c00_01_40shinatama
+particle obj_start create
+trigvolume_enable tv_move4 1
+}
+
+#tv50 - in front of console 10 (func: move2); I've disabled it
+
+func void lights(void)
+{
+particle t17 create
+sleep 60
+particle t16 create
+sleep 60
+particle t15 create
+sleep 60
+particle t14 create
+sleep 60
+particle t13 create
+sleep 60
+particle t12 create
+sleep 60
+particle t11 create
+sleep 60
+particle t10 create
+sleep 60
+particle t9 create
+sleep 60
+particle t8 create
+sleep 60
+particle t7 create
+sleep 60
+particle t6 create
+sleep 60
+particle t5 create
+sleep 60
+particle t4 create
+sleep 60
+particle t3 create
+sleep 60
+particle t2 create
+sleep 60
+particle t1 create
+}
+
+func void encourage_dash(string ai_name)
+{
+sleep 600
+if(var_training_counter2 ne 1)
+	{
+	sound_dialog_play c00_01_39shinatama
+	message xencouragedash
+	rating = rating + 1
+	}
+}
+
+#tv51 - where you start your dash
+func void move4(string ai_name)
+{
+message_remove xgotrack
+var_training_counter = 0
+trigvolume_enable tv1 1
+trigvolume_enable tv2 1	
+trigvolume_enable tv3 1
+trigvolume_enable tv4 1
+trigvolume_enable tv5 1
+trigvolume_enable tv6 1
+trigvolume_enable tv7 1
+trigvolume_enable tv8 1
+trigvolume_enable tv9 1
+trigvolume_enable tv10 1
+trigvolume_enable tv11 1
+trigvolume_enable tv12 1
+trigvolume_enable tv13 1
+trigvolume_enable tv14 1
+trigvolume_enable tv15 1
+trigvolume_enable tv16 1
+trigvolume_enable tv17 1
+particle obj_start kill
+sound_dialog_play_interrupt c00_01_41shinatama
+sleep 60
+message xrun
+particle obj_end create
+trigvolume_enable tv_end 1
+}
+
+#tv34 - next to the 1st red light
+func void track17(string ai_name)
+{
+particle t17 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv33 - next to the 2nd red light
+func void track16(string ai_name)
+{
+fork speed_timer
+particle t16 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv35 - next to the 3rd red light
+func void track15(string ai_name)
+{
+particle t15 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv37 - next to the 4th red light
+func void track14(string ai_name)
+{
+particle t14 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv38 - next to the 5th red light
+func void track13(string ai_name)
+{
+particle t13 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv39 - next to the 6th red light
+func void track12(string ai_name)
+{
+particle t12 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv40 - next to the 7th red light
+func void track11(string ai_name)
+{
+particle t11 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv41 - next to the 8th red light
+func void track10(string ai_name)
+{
+particle t10 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv36 - next to the 9th red light
+func void track9(string ai_name)
+{
+particle t9 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv42 - next to the 10th red light
+func void track8(string ai_name)
+{
+particle t8 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv43 - next to the 11th red light
+func void track7(string ai_name)
+{
+particle t7 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv44 - next to the 12th red light
+func void track6(string ai_name)
+{
+particle t6 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv45 - next to the 13th red light
+func void track5(string ai_name)
+{
+particle t5 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv46 - next to the 14th red light
+func void track4(string ai_name)
+{
+particle t4 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv47 - next to the 15th red light
+func void track3(string ai_name)
+{
+particle t3 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv48 - next to the 16th red light
+func void track2(string ai_name)
+{
+particle t2 kill
+var_training_counter = var_training_counter + 1
+}
+
+#tv49 - next to the 17th red light
+func void track1(string ai_name)
+{
+particle t1 kill
+var_training_counter = var_training_counter + 1
+}
+
+func void speed_timer(void)
+{
+sleep 540
+var_training_counter3 = 1
+}
+
+#tv52 - at the end of the dash course; in some distance after tv49
+func void track_end(string ai_name)
+{
+particle obj_end kill
+message_remove
+sleep 60
+if(var_training_counter eq 17)
+	{
+	if(var_training_counter3 eq 1)
+		{
+		rating = rating + 1
+		sound_dialog_play_block c00_01_11shinatama
+		message xgoodbutslow 120
+		sleep 120
+		}
+	else
+		{
+		sound_dialog_play_block c00_01_42shinatama
+		message xgreat 120
+		sleep 120
+		}
+	message xendbasic 240
+	sound_dialog_play_block c00_01_44shinatama
+	sleep 240
+	message xgodoor
+	sound_dialog_play c00_01_48shinatama
+	trigvolume_enable tv_train_door 1
+	particle obj1 create
+	}
+if(var_training_counter < 17)
+	{
+	if(var_training_counter3 eq 1)
+		{
+		rating = rating + 2
+		sound_dialog_play_block c00_01_43shinatama
+		message xslowtoo 360
+		sleep 360
+		}
+	else
+		{
+		rating = rating + 1
+		sound_dialog_play_block c00_01_43shinatama
+		message xpractice 360
+		sleep 360
+		}
+	fork try_it_again
+	}
+}
+
+func void try_it_again(void) 
+{
+var_training_counter2 = 0
+var_training_counter3 = 0
+sleep 60
+particle obj_start create
+message xgotrack
+particle t17 kill
+particle t16 kill
+particle t15 kill
+particle t14 kill
+particle t13 kill
+particle t12 kill
+particle t11 kill
+particle t10 kill
+particle t9 kill
+particle t8 kill
+particle t7 kill
+particle t6 kill
+particle t5 kill
+particle t4 kill
+particle t3 kill
+particle t2 kill
+particle t1 kill
+particle t17 create
+particle t16 create
+particle t15 create
+particle t14 create
+particle t13 create
+particle t12 create
+particle t11 create
+particle t10 create
+particle t9 create
+particle t8 create
+particle t7 create
+particle t6 create
+particle t5 create
+particle t4 create
+particle t3 create
+particle t2 create
+particle t1 create
+trigvolume_reset tv1 
+trigvolume_reset tv2 
+trigvolume_reset tv3 
+trigvolume_reset tv4 
+trigvolume_reset tv5 
+trigvolume_reset tv6 
+trigvolume_reset tv7 
+trigvolume_reset tv8 
+trigvolume_reset tv9 
+trigvolume_reset tv10 
+trigvolume_reset tv11 
+trigvolume_reset tv12 
+trigvolume_reset tv13 
+trigvolume_reset tv14 
+trigvolume_reset tv15 
+trigvolume_reset tv16 
+trigvolume_reset tv17
+trigvolume_reset tv_end
+trigvolume_reset tv_move4
+}
+
+#tv53 - in front of console 11 (func: review); I've disabled it
+
+#tv22 - in front of door 98
+func void train_door(string ai_name)
+{
+message_remove
+sleep 60
+particle obj1 kill
+message unlock_door1 240
+particle door1_locklight02 do start
+door_unlock 98
+}
+
+### JUMP ###
+
+#tv25 - after door 98
+func void train_jump(string ai_name)
+{
+var_training_counter = 0
+var_training_counter2 = 0
+var_training_counter3 = 0
+lock_keys keys_inventory
+message_remove
+sound_dialog_play_interrupt c00_01_49shinatama
+sleep 60
+message jump_basic 180
+sleep 180
+lock_keys keys_jump
+message c01_50_06
+chr_wait_animtype 0 jump
+message_remove c01_50_06
+sleep 60
+sound_dialog_play c00_01_08shinatama
+message c01_50_07 		
+chr_wait_animation 0 KONOKOjump_fw_start KONOKOjump_lt_start KONOKOjump_rt_start KONOKOjump_bk_start
+message_remove c01_50_07
+sleep 60
+sound_dialog_play c00_01_02shinatama
+message jump_basic2 180
+sleep 180
+message jump1
+sound_dialog_play c00_01_50shinatama
+particle forcefield1 do stop
+particle obj2 create
+env_show 2011 0
+}
+
+#tv54 - on the box with the energy cell
+func void powerup(string ai_name)
+{
+fork pickup_powerup
+sleep 80
+sound_dialog_play_interrupt c00_01_46shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play c00_01_47shinatama
+sound_dialog_play_block pause
+sleep 30
+if(var_training_counter ne 1) sound_dialog_play c00_01_50shinatama
+}
+
+func void pickup_powerup(void)
+{
+chr_wait_animtype 0 Pickup_Object
+rating = rating - 1
+sleep 80
+message xpower1 300
+}
+
+### CROUCH ###
+
+#tv21 - after the forcefield
+func void train_crouch(string ai_name)
+{
+trigvolume_enable trigger_volume_62 0
+message_remove
+var_training_counter = 1
+particle door1_locklight02 do stop
+door_lock 98
+particle obj2 kill
+sleep 60
+sound_dialog_play_interrupt c00_01_01shinatama
+ai2_spawn demo1
+ai2_spawn demo2
+ai2_spawn demo3
+chr_nocollision demo1 1
+chr_nocollision demo2 1 
+chr_nocollision demo3 1
+ai2_dopath demo1 pdemo1
+ai2_dopath demo2 pdemo2
+ai2_dopath demo3 pdemo3
+ai2_setjobstate demo1
+ai2_setjobstate demo2
+ai2_setjobstate demo3
+lock_keys keys_crouch
+message shift 120
+sleep 120
+sound_dialog_play c00_01_51shinatama
+message xinterrupt 120
+sleep 120
+message xfite
+particle fight create
+trigvolume_enable trigger_volume_71 1
+}
+
+#tv66 - on the box which is in front of the window
+func void t71(string ai_name)
+{
+var_training_counter = 0
+particle fight kill
+message_remove xfite
+chr_nocollision demo1 0
+chr_nocollision demo2 0 
+chr_nocollision demo3 0
+env_show 2010 1
+chr_changeteam demo1 Syndicate
+chr_changeteam demo2 Syndicate
+}
+
+#lose func of demo1 and demo2
+func void demo_over(string ai_name)
+{
+var_training_counter = var_training_counter + 1
+if(var_training_counter eq 2)
+	{
+	ai2_dopath demo3 pdemo4
+	ai2_setjobstate demo3
+	sleep 90
+	message xresume 180
+	sound_dialog_play c00_01_53shinatama
+	sound_dialog_play_block pause
+	if(var_training_counter < 10) crouch2
+	}
+}
+
+#lose func of demo3
+func void demo3dies(string ai_name)
+{
+var_training_counter = 10
+chr_changeteam demo1 Konoko
+chr_changeteam demo2 Konoko
+sleep 60
+message xresume 180
+sound_dialog_play c00_01_52shinatama
+sound_dialog_play_block pause
+crouch2
+}
+
+func void crouch2(string ai_name)
+{
+var_training_counter = 0
+message c01_50_09
+chr_wait_animtype 0 crouch_run crouch_run_backwards crouch_run_sidestep_left crouch_run_sidestep_right
+sleep 60
+message_remove c01_50_09
+sleep 60
+message c01_50_10 240
+sound_dialog_play_block c00_01_54shinatama
+sleep 240
+message c01_50_11
+chr_wait_animation 0 KONCOMcrouch_fw KONCOMcrouch_rt KONCOMcrouch_lt KONOKOcrouch_fw KONOKOss_lt_slide KONOKOss_rt_slide KONOKOrun_bk_slide
+message_remove c01_50_11
+sleep 60
+sound_dialog_play_block c00_01_05shinatama
+sound_dialog_play_block pause
+sleep 30
+message back
+chr_wait_animtype 0 crouch_back
+message_remove back
+sleep 60
+sound_dialog_play_block c00_01_07shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play_block c00_01_55shinatama
+sound_dialog_play_block pause
+message c01_50_16 
+chr_wait_animstate 0 run_slide
+message_remove c01_50_16
+sleep 60
+sound_dialog_play_block c00_01_06shinatama
+sound_dialog_play_block pause
+sleep 30
+message jump_flip
+message c01_50_19
+chr_wait_animtype 0 flip
+message_remove
+sleep 60
+sound_dialog_play_block c00_01_03shinatama
+sound_dialog_play_block pause
+particle forcefield2 do stop
+env_show 2012 0
+sleep 60
+sound_dialog_play_block c00_01_61shinatama
+message c01_50_23 	
+particle obj3 create
+sleep 600
+if(var_training_counter ne 1)
+	{
+	rating = rating + 1
+	sound_dialog_play_block c00_01_62shinatama
+	sound_dialog_play_block pause
+	message_remove c01_50_23
+	sleep 60
+	message jump_encourage 300
+	sleep 300
+	message c01_50_23
+	sleep 900
+	}
+if(var_training_counter ne 1)
+	{
+	rating = rating + 1	
+	message_remove c01_50_23 
+	sleep 60
+	sound_dialog_play_block c00_01_63shinatama
+	particle obj3 kill
+	sleep 30
+	particle obj4 create
+	message jump_encourage2
+	}
+}
+
+### FIGHT ###
+
+#tv23 - after the forcefield
+func void train_fighting(string ai_name)
+{
+var_training_counter = 1
+music_stop
+particle obj3 kill
+particle obj4 kill
+trig_deactivate 1
+trig_deactivate 2
+trig_deactivate 3
+message_remove
+sleep 60
+sound_dialog_play_interrupt c00_01_64shinatama
+message begin_fight 240
+sleep 240
+lock_keys keys_attack
+message xpunch
+chr_wait_animtype 0 punch
+message_remove xpunch
+sleep 60
+message xkick
+chr_wait_animtype 0 kick
+message_remove xkick
+sleep 60
+sound_dialog_play_block c00_01_65shinatama
+message punch
+chr_wait_animtype 0 punch2
+message_remove punch
+sleep 60
+message c01_50_27 180
+sound_dialog_play_interrupt c00_01_66shinatama
+sound_dialog_play_block pause
+var_training_counter = 0
+message c01_50_29
+fork wait_for_combo
+chr_wait_animtype 0 ppk
+var_training_counter = 1
+message_remove
+sleep 60
+message xppk
+sound_dialog_play_interrupt c00_01_07shinatama
+sleep 30
+message_remove xppk
+sound_dialog_play_block c00_01_70shinatama
+sound_dialog_play_block pause
+sleep 30
+sound_dialog_play_block c00_01_71shinatama
+message xspar2
+ai2_spawn dum_hit_flash
+chr_lock_active dum_hit_flash
+chr_death_lock dum_hit_flash 1
+particle door2_locklight02 do start
+door_unlock 99
+}
+
+func void wait_for_combo(string ai_name)
+{
+sleep 600
+if(var_training_counter eq 0)
+	{
+	rating =  rating + 1
+	message_remove c01_50_29
+	sound_dialog_play_block c00_01_68shinatama
+	sleep 60
+	}
+if(var_training_counter eq 0)
+	{
+	message c01_50_29b 240
+	sleep 240
+	}
+if(var_training_counter eq 0) message c01_50_29
+}
+
+### FIGHT AIGAINST NEUTRAL DRONE ###
+
+#tv27 - after door 99
+func void train_hit_flash(string ai_name)
+{
+sound_music_start atm_ft68 0
+sound_music_volume atm_ft68 0.75 3.0
+message_remove xspar2
+sleep 60
+sound_dialog_play_block c00_01_77shinatama
+message start_hit
+ai2_makeignoreplayer dum_hit_flash 1
+}
+
+#tv68 - the field with the drone (exit func)
+func void flash_path(string ai_name)
+{
+sleep 90
+ai2_dopath dum_hit_flash patrol_dum_hit_flash
+}
+
+#hit func of dum_hit_flash
+func void hurt_dummy1(string ai_name)
+{
+particle steam stop
+particle door2_locklight02 do stop
+door_lock 99
+message_remove start_hit
+sleep 60
+ai2_dopath dum_hit_flash patrol_dum_hit_flash
+ai2_setjobstate dum_hit_flash
+message c01_50_35 240
+sleep 240
+message blueflash 240
+sleep 240
+message c01_50_37 240
+sleep 240
+message c01_50_38 240
+sleep 240
+sound_dialog_play_block c00_01_78shinatama
+sleep 360
+message goto_throw
+particle door3_locklight02 do start
+door_unlock 100
+ai2_spawn dum_train_throw
+chr_lock_active dum_train_throw
+chr_death_lock dum_train_throw 1
+ai2_makeignoreplayer dum_train_throw 1
+}
+
+#lose func of dum_hit_flash
+func void regen1(string ai_name)
+{
+message_remove blueflash
+message_remove c01_50_37
+message_remove c01_50_38
+sleep 60
+message xregen1 180
+sleep 180
+chr_set_health dum_hit_flash 50
+ai2_dopath dum_hit_flash patrol_dum_hit_flash
+ai2_setjobstate dum_hit_flash
+}
+
+### THROW ###
+
+#tv26 - after door 100
+func void train_throw(string ai_name)
+{
+var_training_counter = 0
+message_remove
+sleep 60
+sound_dialog_play_interrupt c00_01_79shinatama
+ai2_dopath dum_train_throw patrol_train_throw2
+ai2_setjobstate dum_train_throw
+message c01_50_41
+chr_wait_animtype 0 throw_forward_punch throw_forward_kick run_throw_forward_punch run_throw_forward_kick 
+message_remove c01_50_41
+sleep 60
+message xthrow1 300
+sleep 300
+message xthrow2 300
+sleep 300
+sound_dialog_play c00_01_48shinatama
+message goto_block
+sleep 60
+door_unlock 101
+particle door4_locklight02 do start
+particle door4b_locklight02 do start
+ai2_spawn dum_train_block
+ai2_makeignoreplayer dum_train_block 1
+chr_invincible 0 1
+}
+
+#tv67 - the field with the drone
+func void throw_path(string ai_name)
+{
+sleep 90
+ai2_dopath dum_train_throw patrol_train_throw2
+}
+
+#hit func of dum_train_throw
+func void lockthrow(void)
+{
+particle door3_locklight02 do stop
+door_lock 100
+}
+
+#lose func of dum_train_throw
+func void regen2(string ai_name)
+{
+sleep 60
+message xregen1 180
+sleep 180
+chr_set_health dum_train_throw 50
+ai2_dopath dum_train_throw patrol_train_throw2
+ai2_setjobstate dum_train_throw
+}
+
+### BLOCK ###
+
+#tv24 - after door 101
+func void train_block(string ai_name)
+{
+message_remove goto_block
+sound_dialog_play_block c00_01_72shinatama
+sound_dialog_play_block pause
+sound_dialog_play_block c00_01_73shinatama
+if(var_training_counter ne 1) message c01_50_33
+}
+
+#tv29 - the field with the drone (entry func)
+func void train_block2(string ai_name)
+{	
+var_training_counter = 1
+ai2_makeignoreplayer dum_train_block 0
+ai2_dopath dum_train_block patrol_56b
+ai2_setjobstate dum_train_block
+if(var_training_counter2 ne 1) go_on
+}
+
+func void go_on(void)
+{
+var_training_counter2 = 1
+message_remove c01_50_33
+door_lock 101
+door_close 101
+particle door4_locklight02 do stop
+chr_delete dum_train_throw
+chr_delete dum_hit_flash
+chr_delete demo1
+chr_delete demo2
+chr_delete demo3
+sleep 60
+message c01_50_32 300
+sound_dialog_play_block c00_01_74shinatama
+sound_dialog_play_pause 
+sleep 30
+sound_dialog_play_block c00_01_75shinatama
+message xblocking2 300
+sound_dialog_play_pause 
+sleep 30
+sound_dialog_play_block c00_01_76shinatama
+sleep 120
+ai2_makeignoreplayer dum_train_block 1
+ai2_dopath dum_train_block patrol_56b
+ai2_setjobstate dum_train_block 
+sound_dialog_play_block c00_01_83shinatama
+door_unlock 102
+particle door5_locklight02 do start
+message goto_shoot
+chr_inv_reset 0
+music_stop
+sleep 60
+ai2_spawn dum_train_shoot
+ai2_spawn dum_train_shoot2
+ai2_passive dum_train_shoot 1
+ai2_passive dum_train_shoot2 1
+chr_invincible dum_train_shoot 1
+chr_invincible dum_train_shoot2 1
+chr_invincible 0 0
+}
+
+#tv29 - the field with the drone (exit func)
+func void block_path(string ai_name)
+{
+var_training_counter = 0
+message xdronedeactive 180
+ai2_makeignoreplayer dum_train_block 1
+ai2_dopath dum_train_block patrol_56
+}
+
+#lose func of dum_train_block
+func void disable_tv46(void)
+{
+message_remove c01_50_33
+trigvolume_enable trigger_volume_46 0
+}
+
+#tv78 - in front of door 102
+func void block_path2(string ai_name)
+{
+ai2_makeignoreplayer dum_train_block 1
+ai2_dopath dum_train_block patrol_56
+}
+
+### SHOOT ###
+
+#tv28 - after door 102
+func void train_shoot(string ai_name)
+{
+var_training_counter = 0
+var_training_counter2 = 0
+fork wait_for_reload
+message_remove xdronedeactive
+particle g_tap1 create
+sleep 7
+weapon_spawn w1_tap 7042
+wp_disable_fade = 1
+message_remove goto_shoot
+sleep 60
+lock_keys keys_reload
+sound_dialog_play_interrupt c00_01_84shinatama
+sound_dialog_play_pause 
+chr_wait_animtype 0 Pickup_Pistol Pickup_Pistol_Mid 
+particle door5_locklight02 do stop
+door_lock 102
+trigvolume_enable tv74 1
+trigvolume_enable tv75 1
+ui_show_element left 1
+sleep 60
+message c01_50_54
+sound_dialog_play_block c00_01_85shinatama
+chr_wait_animtype 0 Autopistol_Recoil
+sleep 120
+message_remove c01_50_54
+}
+
+func void wait_for_reload(void)
+{
+chr_wait_animtype 0 reload_pistol reload_rifle
+var_training_counter2 = var_training_counter2 + 1
+if(var_training_counter2 > 1) rating = rating + 1
+sleep 180
+if(save_point eq 0) fork wait_for_reload
+}
+
+#tv69 - the complete room
+func void need_ammo(string ai_name)
+{
+trigvolume_enable tv74 0
+if(chr_has_empty_weapon(0) eq 1)
+	{
+	if(var_training_counter eq 0 and var_training_counter3 ne 1) need_red_clips
+	if(var_training_counter eq 1 and var_training_counter3 ne 1) need_green_cells
+	}
+sleep 60
+if(var_training_counter ne 10) trigvolume_enable tv74 1
+}
+
+func void need_red_clips(void)
+{
+var_training_counter3 = 1
+if(var_training_counter2 eq 0)
+	{
+	message_remove xkeepshoot
+	sound_dialog_play_interrupt c00_01_87shinatama
+	message c01_50_61
+	}
+particle g_tap1 create
+sleep 7
+powerup_spawn ammo 7042
+if(var_training_counter2 eq 0)
+	{
+	chr_wait_animtype 0 Pickup_Object_Mid Pickup_Object
+	message_remove c01_50_61
+	sleep 60
+	message xreload
+	chr_wait_animtype 0 reload_pistol
+	message_remove xreload
+	sleep 60
+	message xkeepshoot
+	}
+if(var_training_counter2 > 0) chr_wait_animtype 0 reload_pistol
+var_training_counter3 = 0
+}
+
+func void need_green_cells(void)
+{
+var_training_counter3 = 1
+particle g_phr1 create
+sleep 7
+powerup_spawn cell 7044
+chr_wait_animtype 0 reload_riffle
+var_training_counter3 = 0
+}
+
+#tv70 - the complete room
+func void targets_gone(string ai_name)
+{
+trigvolume_enable tv75 0
+if(env_broken(3001, 3018) eq 18) targets_are_gone
+else
+	{
+	sleep 60
+	trigvolume_enable tv75 1
+	}
+}
+
+func void targets_are_gone(void)
+{
+var_training_counter = 1
+message_remove xkeepshoot
+particle g_phr1 create
+sleep 7
+weapon_spawn w3_phr 7045
+sound_dialog_play_interrupt c00_01_86shinatama
+sound_dialog_play_block pause
+message c01_50_51
+message c01_50_53
+sound_dialog_play_block c00_01_88shinatama
+chr_wait_animtype 0 Pickup_Rifle Pickup_Rifle_Mid 
+message_remove
+sleep 30
+ai2_passive dum_train_shoot 0
+sound_dialog_play_interrupt c00_01_89shinatama
+ai2_dopath dum_train_shoot patrol_train_shoot
+ai2_setjobstate dum_train_shoot
+chr_invincible dum_train_shoot 0
+}
+
+#lose func of dum_train_shoot
+func void droid1_gone(string ai_name)
+{
+sound_dialog_play_block c00_01_90shinatama
+sound_dialog_play_block pause
+sleep 30
+ai2_passive dum_train_shoot2 0
+ai2_dopath dum_train_shoot2 patrol_train_shoot2
+ai2_setjobstate dum_train_shoot2
+chr_invincible dum_train_shoot2 0
+}
+
+#lose func of dum_train_shoot2
+func void droid2_gone(string ai_name)
+{
+var_training_counter = 10
+message_remove
+if(rating < 1) message poopy 300
+if(rating eq 1) message poopy2 300
+if(rating eq 2) message poopy3 300
+if(rating eq 3) message poopy4 300
+if(rating eq 4) message poopy5 300
+if(rating eq 5) message poopy6 300
+if(rating > 5) message poopy7 300
+sound_dialog_play_block c00_01_91shinatama
+sound_dialog_play_block pause
+wp_disable_fade = 0
+lock_keys keys_all
+sleep 60
+fade_out 0 0 0 30
+sleep 30
+ui_show_element right 1
+save_point = 1
+fork remove_ai
+fork start
+fade_in 30
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+#console 11
+func void review2(string ai_name)
+{
+text_console level_1c
+console_reset 11
+}
+
+#console 18
+func void console_jump(string ai_name)
+{
+text_console level_1g
+console_reset 18
+}
+
+#console 17
+func void console_escape(string ai_name)
+{
+text_console level_1h
+console_reset 17
+}
+
+#console 16
+func void console_attack(string ai_name)
+{
+text_console level_1i
+console_reset 16
+}
+
+#console 15
+func void console_flash(string ai_name)
+{
+text_console level_1j
+console_reset 15
+}
+
+#console 14
+func void console_throw(string ai_name)
+{
+text_console level_1k
+console_reset 14
+}
+
+#console 13
+func void console_block(string ai_name)
+{
+text_console level_1l
+console_reset 13
+}
+
+#console 12
+func void lastreview(string ai_name)
+{
+text_console level_1f
+console_reset 12
+}
Index: /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/warehouse.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/warehouse.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/EnvWarehouse/warehouse.bsl	(revision 185)
@@ -0,0 +1,631 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = .15
+gl_fog_blue = .15
+gl_fog_green = .15
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+if(save_point > 0) start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+splash_screen warehouse_splash_screen
+if(save_point eq 1) save_point = 2
+if(save_point eq 2) fork intro
+if(save_point eq 3) restore_game
+if(save_point eq 4) restore_game
+if(save_point eq 5) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable tv_train_movement 0
+console_deactivate 4
+trigvolume_enable alarm_trigvol 0
+trigvolume_enable mid_warehouse_target 0
+trigvolume_enable setup_bay3_tv 0
+trigvolume_enable trigger_volume_01 0
+trigvolume_enable trigger_volume_06 0
+trigvolume_enable trigger_volume_63 0
+trigvolume_enable trigger_volume_64 0
+trigvolume_enable trigger_volume_65 0
+trigvolume_enable trigger_volume_68 0
+trigvolume_enable trigger_volume_70 0
+trigvolume_enable trigger_volume_76 0
+trigvolume_enable trigger_volume_77 0
+trigvolume_enable trigger_volume_80 0
+trigvolume_enable tv_66 0
+#used
+door_unlock 108
+env_show 2010 0
+obj_create 20 20
+trigvolume_enable gotLSI_tv 0
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+if(save_point eq 5) save_game 5 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+#training
+sound_music_stop atm_gr06
+sound_music_stop atm_ft68
+#warehoue
+sound_music_volume mus_ambgrv1 0.0 2.0
+sound_music_stop mus_ambgrv1
+sound_music_stop atm_low1
+sound_music_volume mus_chase 0.0 3.0
+sound_music_stop mus_chase
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+playback 0 SwingKonokoSet
+chr_inv_reset 0
+ai2_spawn A_t48
+objective_set 1 silent
+}
+
+#tv55 - the complete area of the platform where Konoko starts (no funcs); I've disabled it
+#lose func of A_t48 (func: t48_dead); I don't use it
+
+#console 1
+func void unlock6(string ai_name)
+{
+particle d1_locklight01 do start
+door_unlock 6
+target_set 44 30
+ai2_spawn A_t50
+trigvolume_enable trigger_volume_65 1
+}
+
+#tv57 - in front of door 6 (entry func: t65; exit func: t65b); I've diabled it
+
+### FIRST HALL - GROUND FLOOR ###
+
+#tv56 - after door 6 (entry func: t64); I've diabled it
+#tv72 - right side; in the right corner (entry func: t77); I've diabled it
+
+#tv12 - left side; after the box near the left wall
+func void rat3(void)
+{
+particle rat3 pulse
+}
+
+#tv11 - in front of door 16; right side; around the small drum
+func void bug0(void)
+{
+particle bug0 pulse
+}
+
+### FIRST HALL - FIRST FLOOR ###
+
+#console 2
+func void unlock1(string ai_name)
+{
+particle lock1_locklight01 do start
+door_unlock 15
+door_unlock 16
+target_set 33 15
+sleep 120
+ai2_spawn Bay1_Thug_1
+}
+
+### FIRST HALL - SECOND FLOOR ###
+
+#tv74 - on the top of the crane cabin
+func void t02(string ai_name)
+{
+ai2_spawn secret2
+ai2_dopath A_t50 patrol_secret1
+ai2_setjobstate A_t50
+fork health_check
+}
+
+func void health_check(void)
+{
+chr_wait_health secret2 0
+train_fathealth
+}
+
+#tv58 - in front of door 4 (entry func: t01); I've disabled it
+
+### SECOND HALL - GROUND FLOOR ###
+
+#tv80 - the complete volume of the hall (no funcs); I've disabled it
+
+#tv1 - high box after door 16 and door 15
+func void intro_enemies(string ai_name)
+{
+ai2_spawn Bay2_Thug_1
+ai2_spawn Bay2_Thug_2
+sound_music_start mus_ambgrv1 0
+sound_music_volume mus_ambgrv1 0.75 3.0
+}
+
+#lose func of Bay2_Thug_1
+func void train_fathealth(string ai_name)
+{
+if(var_counter eq 0)
+	{
+	var_counter = 1
+	sleep 90
+	sound_dialog_play c00_01_93shinatama
+	sound_dialog_play_block pause
+	sleep 40
+	sound_dialog_play c00_01_94shinatama
+	}
+}
+
+#tv19 - after one third of the hall; from left to right; ends right in some distance in front of door 18
+func void rat1(void)
+{
+particle rat1 pulse
+}
+
+#tv13 - after door 18
+func void bug8(void)
+{
+particle bug8 pulse
+}
+
+#console 3
+func void unlock2(string ai_name)
+{
+particle lock2_locklight01 do start
+door_unlock 24
+door_unlock 26
+target_set 84 15
+music_stop
+}
+
+#tv4 - in front of door 26 and door 24 (entry func: setup_bay3); I've disabled it
+
+### SECOND HALL - FIRST FLOOR ###
+
+#nothing here; no second floor
+
+### THIRD HALL - GROUND FLOOR ###
+
+#tv15 - after door 26; right side; in front of the first box
+func void rat6(void)
+{
+particle rat6 pulse
+}
+
+#tv14 - next to tv15; in front of the second box
+func void bug4(void)
+{
+particle bug4 pulse
+}
+
+#tv16 - in some distance after door 31
+func void rat4(void)
+{
+particle rat4 pulse
+}
+
+### THIRD HALL - FIRST FLOOR ###
+
+#tv5 - around Chung
+func void Chung(void)
+{
+sound_music_start atm_low1 0.7
+trigvolume_enable gotLSI_tv 1
+target_set 1 0
+}
+
+#tv30 - around the lsi
+func void checkLSI(string ai_name)
+{
+trigvolume_enable gotLSI_tv 0
+if(chr_has_lsi(0) eq 1)
+	{
+	particle lock3_locklight01 do start
+	door_unlock 37
+	music_stop
+	ai2_spawn Ambush_Striker_1
+	ai2_spawn Mid_Thug_1
+	ai2_spawn Mid_Thug_2
+	objective_set 2 silent
+	target_set 7053 30
+	var_counter = 0
+	}
+if(chr_has_lsi(0) eq 0)
+	{
+	sleep 60
+	trigvolume_enable gotLSI_tv 1
+	}
+}
+
+### THIRD HALL - SECOND FLOOR ###
+
+#tv75 - in front of door 32
+func void t05(string ai_name)
+{
+ai2_spawn ambush_striker
+}
+
+##########
+### SP2 ###
+##########
+
+#tv59 - after door 37
+func void s2(string player_name)
+{
+if(save_point eq 3)
+	{
+	ai2_spawn Mid_Thug_1
+	ai2_spawn Mid_Thug_2
+	objective_set 2 silent
+	target_set 7053 30
+	}
+else save_game 3 autosave
+}
+
+#tv76 - in front of door 36
+func void t09(string ai_name)
+{
+target_set 62 30
+}
+
+#tv63 - after door 35
+func void t07(string ai_name)
+{
+ai2_spawn Top_Thug_5
+}
+
+#tv64 - after door 34; near the end of the way; near the corner of the left wall
+func void t69(string ai_name)
+{
+ai2_spawn Top_Striker_1
+ai2_spawn Top_Comguy_1
+ai2_spawn Top_Thug_3
+}
+
+#tv6 - in front of door 61
+func void spawn_mid2(string ai_name)
+{
+ai2_spawn Mid2_Striker_1
+ai2_spawn Mid2_Striker_2
+target_set 66 15
+}
+
+#console 5
+func void unlock4(string ai_name)
+{
+particle lock4_locklight01 do start
+door_unlock 65
+target_set 7054 15
+}
+
+##########
+### SP3 ###
+##########
+
+#tv62 - after door 65 (entry func: s3); I've disabled it
+
+#tv2 - after door 65; nearly at the same position as tv62
+func void train_alarm(string ai_name)
+{
+if(save_point eq 4)
+	{
+	objective_set 2 silent
+	target_set 7054 15
+	}
+else
+	{
+	fork remove_ai
+	save_game 4 autosave
+	door_lock 60
+	}
+ai2_spawn Bay4_Comguy_1
+}
+
+### FIRST HALL - GROUND FLOOR ###
+
+#tv18 - in front of door 68
+func void rat5(void)
+{
+particle rat5 pulse
+}
+
+#console 7 ==> see second floor
+
+### FIRST HALL - FIRST FLOOR ###
+
+#hit func of Bay4_Comguy_1
+func void hurt1(string ai_name)
+{
+ai2_makeignoreplayer Bay4_Comguy_1 1
+ai2_doalarm Bay4_Comguy_1 6
+ai2_dopath Bay4_Comguy_1 Run_To_Alarm
+ai2_setjobstate Bay4_Comguy_1
+sleep 60
+sound_dialog_play c00_01_96shinatama
+}
+
+func void patrolscript0001(string ai_name)
+{
+ai2_doalarm Bay4_Comguy_1 6
+}
+
+### FIRST HALL - SECOND FLOOR ###
+
+#console 7
+func void unlock5(string ai_name)
+{
+particle lock4_locklight01 do stop
+door_lock 65
+particle lock5_locklight01 do start
+door_unlock 73
+door_unlock 74
+door_unlock 81
+door_unlock 82
+target_set 72 30
+console_deactivate 7
+var_counter = 1
+}
+
+#tv7 - in front of console 6 (entry func: alarm_warning; exit func: alarm_warningb); I've disabled it
+
+#console 6
+func void alarm_trig(string ai_name)
+{
+fork do_alarm_sound
+if(var_counter eq 0) unlock5
+ai2_makeignoreplayer Bay4_Comguy_1 0
+ai2_dopath Bay4_Comguy_1 patrol_42
+ai2_setjobstate Bay4_Comguy_1 
+ai2_spawn Alarm_Bay4_Striker_1
+chr_teleport Alarm_Bay4_Striker_1 7033
+ai2_attack Alarm_Bay4_Striker_1 char_0
+ai2_spawn Alarm_Bay4_Striker_2
+chr_teleport Alarm_Bay4_Striker_2 7033
+ai2_attack Alarm_Bay4_Striker_2 char_0
+}
+
+func void do_alarm_sound(void)
+{
+sound_ambient_start alarm_loop
+sleep 900
+sound_ambient_stop alarm_loop
+}
+
+#console 4 (func: unlock_alarm); I've disabled it
+
+### SECOND HALL - GROUND FLOOR ###
+
+#tv31 - high box after door 73 and door 74
+func void t47(string ai_name)
+{
+ai2_spawn Bay5_Thug_1
+ai2_spawn Bay5_Thug_2
+}
+
+### SECOND HALL - FIRST FLOOR ###
+
+#nothing, no second floor
+
+### THIRD HALL - GROUND FLOOR ###
+
+#tv32 - after door 81
+func void spawn_bay6_bot(string ai_name)
+{
+trigvolume_enable spawn_bay6_top_tv 0
+ai2_spawn Bay6_Striker_1b
+ai2_spawn Bay6_Neutral_1b
+ai2_spawn Bay6_Neutral_2
+ai2_spawn guard1
+train_neutral
+}
+
+func void train_neutral(string ai_name)
+{
+target_set 92 15
+sound_dialog_play c00_01_97shinatama
+}
+
+### THIRD HALL - FIRST FLOOR ###
+
+#tv60 - complete volume of the first floor (no funcs); I've disabled it
+
+#tv3 - after door 82
+func void spawn_bay6_top(string ai_name)
+{
+trigvolume_enable spawn_bay6_bot_tv 0
+ai2_spawn Bay6_Striker_1
+ai2_spawn Bay6_Neutral_1
+ai2_spawn Bay6_Neutral_2
+ai2_spawn guard1
+train_neutral
+}
+
+#tv79 - after door 87
+func void t10(string ai_name)
+{
+ai2_makeignoreplayer Bay6_Neutral_1 1
+ai2_makeignoreplayer Bay6_Neutral_1b 1
+ai2_dopath Bay6_Neutral_1 Bay6_Thug_1
+ai2_dopath Bay6_Neutral_1b Bay6_Thug_1_copy
+sleep 240
+ai2_makeignoreplayer Bay6_Neutral_1 0
+ai2_makeignoreplayer Bay6_Neutral_1b 0	
+}
+
+### THIRD HALL - SECOND FLOOR ###
+
+#tv61 - after door 88
+func void t67(string ai_name)
+{
+chr_changeteam guard1 Syndicate
+}
+
+#neutral func of Bay6_Neutral_2
+func void gotoconsole(string ai_name)
+{
+console_activate 9
+sleep 7
+ai2_doalarm Bay6_Neutral_2 9
+sleep 180
+trigvolume_enable trigger_volume_06 1
+}
+
+#tv77 - around console 9 (exit func: t06); I've disabled it
+
+#console 9
+func void open_warehouse(string ai_name)
+{
+if(save_point eq 4)
+	{
+	particle lock7_locklight01 do start
+	door_unlock 86
+	ai2_spawn Final_Thug_1
+	ai2_spawn Final_Thug_2
+	ai2_spawn Final_Thug_3
+	ai2_spawn Final_Thug_5
+	ai2_dopath Bay6_Neutral_2 Open_Warehouse
+	ai2_setjobstate Bay6_Neutral_2
+	objective_set 3 silent
+	target_set 93 15
+	}
+particle bigdoor_locklight02 do start
+ai2_spawn WH_Thug_A
+ai2_dopath WH_Thug_A WH_Thug_A
+ai2_setjobstate WH_Thug_A
+ai2_spawn WH_Striker_B
+ai2_dopath WH_Striker_B WH_Striker_B
+ai2_setjobstate WH_Striker_B
+ai2_spawn WH_Striker_C
+ai2_spawn WH_Striker_D
+ai2_dopath WH_Striker_D WH_Striker_D
+ai2_setjobstate WH_Striker_D
+}
+
+#tv8 - in front of door 48 (entry func: train_timer); I've diabled it
+
+##########
+### SP4 ###
+##########
+
+#tv73 - after door 48
+func void s4(string ai_name)
+{
+if(save_point eq 5) open_warehouse
+else save_game 5 autosave
+objective_set 4 silent
+target_set 96 15
+sleep 1
+timer_start 180 you_lose
+sound_music_start mus_chase 0
+sound_music_volume mus_chase 0.50 1.0
+sound_dialog_play c00_01_95shinatama
+sound_dialog_play_block pause
+sound_music_volume mus_chase 0.75 1.0
+}
+
+#tv17 - after door 48; right next to the box at 10 past 12
+func void rat2(void)
+{
+particle rat2 pulse
+}
+
+#tv9 - after door 56
+func void stair1_target(string ai_name)
+{
+target_set 31 15
+}
+
+#tv10 - in front of door 58
+func void stair2_target(string ai_name)
+{
+target_set 81 15
+}
+
+#tv71 - big box around console 8 (no funcs); I've disabld it
+#tv65 - not so big box around console 8 (inside func: t70); I've disabld it
+
+#lose func of WH_Striker_C
+func void end_striker(string ai_name)
+{
+music_stop
+}
+
+#console 8
+func void end_console(string ai_name)
+{
+timer_stop
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void console_evidence1(string ai_name)
+{
+text_console level_1a
+console_reset 19
+}
+
+func void console_evidence2(string ai_name)
+{
+text_console level_1b
+console_reset 20
+}
Index: /nikanabo/current/bsl/onilight/IGMD/compound/compound.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/compound/compound.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/compound/compound.bsl	(revision 185)
@@ -0,0 +1,961 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+var int var_counter3 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3) fork load_s3
+if(save_point eq 4) fork grif
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable trigger_volume_01 0
+trigvolume_enable trigger_volume_01_copy 0
+trigvolume_enable trigger_volume_01_copy2 0
+trigvolume_enable trigger_volume_04 0
+trigvolume_enable trigger_volume_04_copy 0
+trigvolume_enable trigger_volume_04_copy_copy 0
+trigvolume_enable trigger_volume_04_copy2 0
+trigvolume_enable trigger_volume_09 0
+trigvolume_enable trigger_volume_11 0
+trigvolume_enable trigger_volume_15 0
+trigvolume_enable trigger_volume_25 0
+trigvolume_enable trigger_volume_26 0
+trigvolume_enable trigger_volume_27 0
+trigvolume_enable trigger_volume_44 0
+trigvolume_enable trigger_volume_45 0
+trigvolume_enable attack_1tv 0
+door_lock 35
+door_lock 36
+door_lock 37
+door_lock 39
+door_lock 40
+door_lock 41
+#used
+trigvolume_enable trigger_volume_10 0
+trigvolume_enable trigger_volume_12 0
+trigvolume_enable trigger_volume_21 0
+trigvolume_enable trigger_volume_21_copy 0
+trigvolume_enable trigger_volume_31 0
+trigvolume_enable trigger_volume_33 0
+trigvolume_enable attack_2tv 0
+trigvolume_enable attack_3tv 0
+trigvolume_enable attack_3tv_copy 0
+trigvolume_enable attack_4tv 0
+env_shade 912 913 .4 .4 .4
+env_show 911 0
+env_show 914 0
+env_show 915 0
+env_show 916 0
+env_show 151 0
+env_show 152 0
+env_show 153 0
+env_show 154 0
+env_show 155 0
+env_show 156 0
+env_show 157 0
+env_show 158 0
+env_show 159 0
+env_show 251 0
+env_show 252 0
+env_show 253 0
+env_show 254 0
+env_show 255 0
+env_show 256 0
+env_show 257 0
+env_show 258 0
+env_show 259 0
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+weapon_reset
+powerup_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_om01
+sound_music_stop mus_main03_hd
+sound_music_stop mus_asianb
+}
+
+#tv38 and tv40
+func void deathfall(void)
+{
+cm_detach
+sleep 30
+chr_set_health 0 0
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+particle snow1 do start
+particle snow2 do start
+particle snow3 do start
+playback 0 IntroKonokoSet
+chr_set_health 0 400
+ai2_spawn A_S1
+ai2_spawn A_S2
+ai2_spawn A_E3
+ai2_spawn A_E5
+ai2_spawn A_E5b
+ai2_dopath A_S1 patrol_01b
+ai2_setjobstate A_S1
+objective_set 1 silent
+sleep 1
+sound_music_start mus_om01 .9
+}
+
+#tv1 - from an imaginary line (from the end of the rigt fence to the left fence) to the fence behind you
+# (enter func: snow1_start, leave func: snow1_stop); I've disabled it
+#tv3 - after tv1, ends in front of door 2 (enter func: snow2_start, leave func: snow2_stop); I've disabled it
+#tv2 - huge box right on tv3 (enter func: snow3_start, leave func: snow3_stop); I've disabled it
+
+#tv39 - in front of the imaginary line of tv1
+func void t38(string ai_name)
+{
+ai2_spawn A_E4
+ai2_spawn A_Sb63
+ai2_spawn A_E6
+ai2_spawn A_Sb7
+ai2_spawn new_2
+}
+
+#tv6 - in front of the truck entrance door with the blue lights (func: peak_start); I've disabled it
+#tv4 - after the truck entrance door with the blue lights (func: peak_stop); I've disabled it
+#tv5 - in front of the truck entrance door with the red lights (func: peak_start); I've disabled it
+#tv7 - after the truck entrance door with the red lights (func: peak_stop); I've disabled it
+
+#tv31 - after door 2
+func void set_objective_2(string ai_name)
+{
+ai2_spawn B_Sr9
+ai2_spawn B_Eb11
+ai2_spawn B_Eb16
+ai2_spawn B_Esb15
+particle door12_locklight01 do start
+objective_set 2 silent
+target_set 558 30
+music_stop
+}
+
+#hit func of A_Sb7
+func void run1(string ai_name)
+{
+ai2_doalarm A_Sb7 1
+ai2_dopath A_Sb7 patrol_00
+}
+
+func void patrolscript0054(string ai_name)
+{
+ai2_doalarm A_Sb7 1
+}
+
+#console1
+func void run1_alarm(string ai_name)
+{
+fork do_alarm_sound
+ai2_dopath A_E3 patrol_49	
+ai2_dopath A_E4 patrol_49
+ai2_dopath A_E5 patrol_49
+ai2_dopath A_E6 patrol_49
+ai2_spawn B_Sr9
+sleep 7
+ai2_dopath B_Sr9 patrol_10
+ai2_spawn B_Eb11
+sleep 60
+ai2_dopath B_Eb11 patrol_10
+}
+
+func void do_alarm_sound(void)
+{
+sound_ambient_start alarm_loop
+sleep 900
+sound_ambient_stop alarm_loop
+}
+
+func void patrolscript0080(string ai_name)
+{
+ai2_tripalarm 1 char_0
+}
+
+#tv9 - in front of console6, from the left wall trough the room to the right wall (func: t9); I've disabled it)
+
+##########
+### SP2 ###
+##########
+
+#tv37 - after door 12
+func void s2(string ai_name)
+{
+if(save_point eq 2)
+	{
+	objective_set 2 silent
+	target_set 558 30
+	}
+else
+	{
+	fork remove_ai
+	save_game 2 autosave
+	particle snow1 do stop
+	particle snow2 do stop
+	particle snow3 do stop
+	}
+ai2_spawn C_Sr17
+ai2_spawn C_Sr18
+ai2_spawn C_Sr19
+ai2_spawn C_Sb75
+ai2_spawn C_Sb76
+ai2_spawn C_Sb78
+ai2_dopath C_Sr17 patrol_17
+ai2_setjobstate C_Sr17
+ai2_dopath C_Sr18 patrol_18
+ai2_setjobstate C_Sr18
+}
+
+#tv9 - after the left passageway
+#tv27 - after door 13
+func void t8(string ai_name)
+{
+particle door12_locklight01 do stop
+door_lock 12
+ai2_spawn C_Tb20
+ai2_spawn C_Eb29
+ai2_spawn C_Eb30
+ai2_spawn C_Eb21
+ai2_spawn C_Eb22
+ai2_spawn C_N23
+ai2_spawn C_N24
+}
+
+### POSSIBILITY 1 - YOU FALL DOWN ###
+
+#console4
+func void unlock_stairs2(string ai_name)
+{
+unlock_stairs_both
+ai2_spawn C_b74
+ai2_spawn C_Eb73
+chr_teleport C_b74 224
+chr_teleport C_Eb73 237
+ai2_dopath C_b74 patrol_80
+ai2_dopath C_Eb73 patrol_80
+}
+
+func void unlock_stairs_both(string ai_name)
+{
+music_stop
+particle stair_locklight01 do start
+door_unlock 10
+door_unlock 15
+door_unlock 16
+door_unlock 17
+ai2_spawn S_Tr41
+trigvolume_enable trigger_volume_10 1
+trigvolume_enable trigger_volume_12 1
+console_deactivate 3
+console_deactivate 4
+}
+
+#tv26 - between door 16 and door 17, in the middle of the staircase (func: t27); I've disabled it
+
+#tv11 - on the left side after door 17
+func void t12(string ai_name)
+{
+t10
+}
+
+#tv24 - the complete way from after door 18 to the room with door 14 (no func); I've disabled it
+
+### POSSIBILITY 2 - YOU DON'T FALL DOWN ###
+
+#tv23 - the complete way from after door 19 to the room with door 13 (no func); I've disabled it
+
+#console5
+func void unlock44(string ai_name)
+{
+ai2_spawn C_Er79
+door_unlock 44
+particle d1_locklight01 do start
+sound_music_start mus_main03_hd
+target_set 559 30
+}
+
+#console3
+func void unlock_stairs(string ai_name)
+{
+unlock_stairs_both
+target_set 1 0
+}
+
+#tv25 - after door 15
+func void t11(string ai_name)
+{
+ai2_dopath C_Sb25 patrol_48
+sleep 60
+ai2_dopath C_Sb26 patrol_48
+sleep 60
+ai2_dopath C_Eb27 patrol_48
+}
+
+#t10 - on the right side after door 44
+func void t10(string ai_name)
+{
+trigvolume_enable trigger_volume_10 0
+trigvolume_enable trigger_volume_12 0
+obj_create 51 59
+env_anim 51 59
+sleep 10
+sound_ambient_start c05_26_17_trucka
+sleep 270
+env_setanim 51 truckbackstop
+env_setanim 52 truckcabstop
+env_setanim 53 truckdoorstop
+env_setanim 54 truckdoor2stop
+env_setanim 55 truckwheel03stop
+env_setanim 56 truckwheel04stop
+env_setanim 57 truckwheel05stop
+env_setanim 58 truckwheel06stop
+env_setanim 59 truckwheel07stop
+ai2_spawn ParkStriker
+chr_lock_active ParkStriker
+chr_envanim ParkStriker ParkStrikeBox01 norotation
+sleep 40
+sound_ambient_start c05_31_21_brake_doorsa
+sleep 60
+chr_animate ParkStriker STRIKElev7_Park
+ai2_spawn C_Sb25
+ai2_spawn C_Sb26
+ai2_spawn C_Eb27
+playback C_Sb25 truckers
+sleep 40
+playback C_Sb26 truckers
+sleep 30
+playback C_Eb27 truckers
+sleep 60
+obj_kill 51 59
+env_show 151 1
+env_show 152 1
+env_show 153 1
+env_show 154 1
+env_show 155 1
+env_show 156 1
+env_show 157 1
+env_show 158 1
+env_show 159 1
+sound_music_start mus_asianb
+particle obj1 create
+target_set 511 30
+objective_set 3 silent
+sleep 480
+ai2_dopath C_Sb25 patrol_48
+sleep 60
+ai2_dopath C_Sb26 patrol_48
+sleep 60
+ai2_dopath C_Eb27 patrol_48
+}
+
+#tv28 - the complete ground floor; used to count the enemies inside; see next func
+
+#tv22 - in front of the driver's door of the truck
+func void runTruck(string ai_name)
+{
+trigvolume_enable trigger_volume_23 0
+if(chr_has_lsi(0) and trigvolume_count(29) eq 0)
+	{
+	music_stop
+	fade_out 0 0 0 30
+	sleep 30
+	fork remove_ai
+	particle obj1 kill
+	load_s3
+	playback 0 TruckExitKonoko
+	fade_in 30
+	if(save_point ne 3) save_game 3 autosave
+	}
+else
+	{
+	sleep 60
+	trigvolume_enable trigger_volume_23 1
+	}
+}
+
+##########
+### SP3 ###
+##########
+
+func void load_s3(void)
+{
+if(save_point eq 3) restore_game
+env_show 251 1
+env_show 252 1
+env_show 253 1
+env_show 254 1
+env_show 255 1
+env_show 256 1
+env_show 257 1
+env_show 258 1
+env_show 259 1
+env_show 911 1
+env_show 912 0
+env_show 913 0
+env_show 914 1
+env_show 915 1
+env_show 916 1
+ai2_spawn D_R33
+objective_set 4 silent
+target_set 501 30
+}
+
+#tv12 - at the beginning of the stairs, which are in front of door 24
+func void t13(string ai_name)
+{
+ai2_spawn E_Er34
+sleep 60
+door_unlock 24
+particle purple_locklight01 do start
+ai2_dopath E_Er34 patrol_34
+ai2_setjobstate E_Er34
+ai2_spawn E_Eb35
+}
+
+#tv15 - after door 24
+func void t16(string ai_name)
+{
+ai2_spawn E_Nr36
+ai2_spawn E_Nb37
+ai2_spawn E_Nb38
+ai2_spawn E_Nr39
+door_unlock 22
+particle purple3_locklight01 do start
+target_set 1 0
+}
+
+### 2ND FLOOR ###
+
+#tv13 - in front of door 33
+func void t14(string ai_name)
+{
+ai2_spawn E_N35
+ai2_spawn E_Tr40
+}
+
+#tv14 - in front of door 30 (func: t15); I've disabled it
+#tv44 - in front of door 25 (func: t45); I've disabled it
+#tv45 - in front of door 27 (func: t45); I've disabled it
+
+#console200 - room with door 30 (right side)
+func void purple2_unlock(string ai_name)
+{
+particle purple2_locklight01 do start
+door_unlock 20
+door_unlock 21
+door_unlock 22
+door_unlock 23
+door_unlock 24
+door_unlock 25
+door_unlock 26
+door_unlock 27
+door_unlock 28
+trigvolume_enable trigger_volume_21 1
+trigvolume_enable trigger_volume_21_copy 1
+console_deactivate 100
+console_deactivate 200
+if(var_counter ne 10) target_set 556 30
+}
+
+#tv20 - after door 25
+func void t21(string ai_name)
+{
+t22
+}
+
+#tv21 - after door 27
+func void t22(string ai_name)
+{
+trigvolume_enable trigger_volume_21 0
+trigvolume_enable trigger_volume_21_copy 0
+sound_music_start mus_main03_hd
+particle mainchamber_locklight01 do start
+door_unlock 18
+door_unlock 19
+ai2_spawn D_R31
+ai2_spawn D_R32
+ai2_spawn D_E83
+door_open 18
+door_open 19
+sleep 180
+door_close 18
+door_close 19
+door_lock 18
+door_lock 19
+particle mainchamber_locklight01 do stop
+sleep 420
+music_stop
+}
+
+### 3RD FLOOR ###
+
+#tv18 - in front of door 34
+func void t19(string ai_name)
+{
+ai2_spawn E_Er45
+ai2_spawn E_N43
+}
+
+#tv16 - in front of door 31
+func void t17(string ai_name)
+{
+ai2_spawn E_Nr46
+}
+
+### 1ST FLOOR ###
+
+#tv19 - in front of door 32
+func void t20(string ai_name)
+{
+ai2_spawn E_N44
+}
+
+#tv17 - in front of door 29
+func void t18(string ai_name)
+{
+ai2_spawn E_R46
+}
+
+#console100 - room with door 29 (right side)
+func void purple2_unlock_b(string ai_name)
+{
+purple2_unlock
+if(var_counter ne 1 or var_counter ne 11 or var_counter ne 101) target_set 555 30
+trigvolume_enable trigger_volume_21 0
+trigvolume_enable trigger_volume_21_copy 0
+}
+
+### TEXT CONSOLES ###
+
+#console301 - 3rd floor - room with door 34 (left side)
+func void console301(string ai_name)
+{
+console300
+}
+
+#console300 - 3rd floor - room with door 31 (right side)
+func void console300(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 1 or var_counter eq 101) target_set 556 30
+if(var_counter eq 11) target_set 555 30
+if(var_counter eq 111) target_set 547 30
+console_deactivate 300
+console_deactivate 301
+ConsoleText
+}
+
+#console201 - 2nd floor - room with door 33 (left side)
+func void console200(string ai_name)
+{
+var_counter = var_counter + 10
+if(var_counter eq 10 or var_counter eq 110) target_set 557 30
+if(var_counter eq 11) target_set 555 30
+if(var_counter eq 111) target_set 547 30
+ConsoleText
+}
+
+#console101 - 1st floor - room with door 32 (left side)
+func void console101(string ai_name)
+{
+var_counter = var_counter + 100
+if(var_counter eq 100 or var_counter eq 101) target_set 556 30
+if(var_counter eq 110) target_set 557 30
+if(var_counter eq 111)
+target_set 547 30
+ConsoleText
+}
+
+func void ConsoleText(void)
+{
+if(var_counter eq 1 or var_counter eq 10 or var_counter eq 100)
+	{
+	text_console level_19a
+	sound_dialog_play c15_57_01konoko
+	}
+if(var_counter eq 11 or var_counter eq 101 or var_counter eq 110)
+	{
+	text_console level_19b
+	sound_dialog_play c15_57_02konoko
+	}
+if(var_counter eq 111)
+	{
+	text_console level_19c
+	sound_dialog_play c15_57_03konoko
+	trigvolume_enable attack_1tv 1
+	trigvolume_enable attack_2tv 1
+	trigvolume_enable attack_3tv 1
+	trigvolume_enable attack_3tv_copy 1
+	trigvolume_enable attack_4tv 1
+	objective_set 5 silent
+	sleep 60
+	sound_music_start mus_main03_hd
+	var_counter = 0
+	}
+}
+
+### ALL CONSOLES ACTIVATED ###
+
+#tv37 - 3rd floor - after door 34 (left side)
+func void attack_4(string ai_name)
+{
+attack_3
+}
+
+#tv34 - floor 3 - after door 31 (right side)
+func void attack_2(string ai_name)
+{
+attack_3
+}
+
+#tv33 - 1st floor - after door 29 (right side) (func: attack_1); I've disabled it
+
+#tv46 - 2nd floor - after door 34 (left side)
+#tv35 - 1st floor - after door 32 (left side)
+func void attack_3(string ai_name)
+{
+trigvolume_enable attack_2tv 0
+trigvolume_enable attack_3tv 0
+trigvolume_enable attack_3tv_copy 0
+trigvolume_enable attack_4tv 0
+particle F_locklight01 do start
+door_unlock 43
+ai2_spawn F_Eb43
+ai2_spawn F_Eb44
+ai2_spawn F_Eb47
+ai2_dopath F_Eb43 patrol_43
+ai2_setjobstate F_Eb43
+sleep 30
+ai2_dopath F_Eb44 patrol_44
+ai2_setjobstate F_Eb44
+sleep 30
+ai2_dopath F_Eb47 patrol_47
+ai2_setjobstate F_Eb47
+music_stop
+ai2_dopath F_Eb43 patrol_43b
+ai2_setjobstate F_Eb43
+ai2_dopath F_Eb44 patrol_44b
+ai2_setjobstate F_Eb44
+ai2_dopath F_Eb47 patrol_47b
+ai2_setjobstate F_Eb47
+trigvolume_enable trigger_volume_33 1
+}
+
+#tv32 - in front of door 43
+func void t33(string ai_name)
+{
+sound_dialog_play c15_57_04konoko
+ai2_spawn F_Er86
+ai2_spawn F_Nr87
+target_set 258 30
+}
+
+#tv41 - in front of the 1st staircase
+func void t41(string ai_name)
+{
+ai2_spawn F_Er59
+}
+
+#tv42 - after the 1st staircase
+func void t42(string ai_name)
+{
+ai2_spawn F_Nr60
+}
+
+#tv43 - in front of the 2nd staircase
+func void t43(string ai_name)
+{
+ai2_spawn F_R61
+ai2_spawn F_Er88
+ai2_spawn F_C62
+ai2_makeignoreplayer F_C62 1
+}
+
+#tv29 - at the mezzanine of the 3rd staircase
+func void t30(string ai_name)
+{
+ai2_makeignoreplayer F_C62 0
+ai2_spawn F_Er89
+}
+
+#hit func of F_C62
+func void comalarm(string ai_name)
+{
+ai2_tripalarm 2 char_0
+}
+
+#console2
+func void fconsole_ok(string ai_name)
+{
+text_console level_19d
+particle green create
+particle green2 create
+particle green3 create
+trigvolume_enable trigger_volume_31 1
+objective_set 6 silent
+target_set 502 30
+}
+
+#tv30 - complete dish platform
+func void t31(string ai_name)
+{
+target_set 1 0
+fade_out 0 0 0 30
+sleep 30
+fork remove_ai
+particle green kill
+particle green2 kill
+particle green3 kill
+playback 0 GrifKonokoSet
+grif
+fade_in 30
+if(save_point ne 4) save_game 4 autosave
+}
+
+##########
+### SP4 ###
+##########
+
+func void grif(void)
+{
+if(save_point eq 4) restore_game
+env_show 301 0
+env_show 302 0
+env_show 303 0
+env_show 304 0
+env_show 305 0
+env_show 306 0
+env_show 307 0
+env_show 308 0
+env_show 309 0
+env_show 401 1
+env_show 402 1
+env_show 403 1
+env_show 404 1
+env_show 405 1
+env_show 406 1
+env_show 407 1
+env_show 408 1
+env_show 409 1
+ai2_spawn Muro
+chr_boss_shield Muro
+chr_set_health Muro 500
+ai2_spawn GrifElite01
+ai2_spawn GrifElite02
+ai2_spawn GrifElite03
+ai2_dopath GrifElite01 patrol_513
+ai2_dopath GrifElite02 patrol_514
+ai2_dopath GrifElite03 patrol_518
+if(did_kill_griffen() eq 0)
+	{
+	ai2_boss_battle = 1	
+	ai2_spawn Griffin
+	ai2_spawn GrifOps01
+	ai2_spawn GrifOps02
+	ai2_spawn GrifOps03
+	ai2_dopath GrifOps01 patrol_521
+	ai2_dopath GrifOps02 patrol_515
+	ai2_dopath GrifOps03 patrol_517
+	sleep 1
+	fork wait_to_help
+	}
+if(did_kill_griffen() eq 1)
+	{
+	ai2_boss_battle = 0
+	sleep 1
+	fork heli
+	}
+particle dishpulse do start
+particle sturm_ambient do start
+sound_ambient_start mc_dish_loop 0.6
+sound_music_start mus_ot
+objective_set 6 silent
+}
+
+func void heli(void)
+{
+sound_ambient_start c07_17_19heli
+sleep 480
+obj_create 901 906
+env_anim 901 906
+ai2_spawn GrifOps01
+ai2_spawn GrifOps02
+ai2_spawn GrifOps03
+chr_envanim GrifOps01 GrifOps01Box01
+chr_envanim GrifOps02 GrifOps02Box01
+chr_envanim GrifOps03 GrifOps03Box01
+chr_animate GrifOps01 STRIKEcrouch_idle 400
+chr_animate GrifOps02 STRIKEcrouch_idle 400
+chr_animate GrifOps03 STRIKEcrouch_idle 400
+sleep 290
+env_setanim 901 heli_doors_rt08
+env_setanim 902 heli_doors_lt08
+env_setanim 903 heli_rotorblades08
+env_setanim 904 heli_body08
+env_setanim 905 heli_canopy08
+env_setanim 906 heli_interior08
+chr_envanim GrifOps01 GrifOps01Box02 norotation
+chr_envanim GrifOps02 GrifOps02Box02 norotation
+chr_envanim GrifOps03 GrifOps03Box02 norotation
+chr_animate GrifOps01 STRIKElev7_Ops01
+chr_animate GrifOps02 STRIKElev7_Ops02
+chr_animate GrifOps03 STRIKElev7_Ops03
+chr_changeteam GrifOps01 Syndicate
+chr_changeteam GrifOps02 Syndicate
+chr_changeteam GrifOps03 Syndicate
+ai2_attack GrifOps01 char_0
+ai2_attack GrifOps02 char_0
+ai2_attack GrifOps03 char_0
+sleep 600
+obj_kill 901 906
+}
+
+func void wait_to_help(void)
+{
+chr_wait_health Muro 200
+ai2_boss_battle = 0
+var_counter3 = 1
+attack_konoko
+}
+
+#lose func of GrifOps01, GrifOps02, GrifOps03 and Griffin
+func void swat_dies(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 4) attack_konoko
+}
+
+func void attack_konoko(void)
+{
+ai2_attack GrifElite01 char_0
+ai2_attack GrifElite02 char_0
+ai2_attack GrifElite03 char_0
+ai2_attack GrifElite04 char_0
+ai2_attack GrifElite05 char_0
+ai2_attack GrifElite06 char_0
+}
+
+#lose func of GrifElite03
+func void check_death1a(string ai_name)
+{
+ai2_spawn GrifElite04
+ai2_passive GrifElite04 1
+playback_block GrifElite04 GrifWave2_Run1
+ai2_passive GrifElite04 0
+if(var_counter3 eq 1) ai2_attack GrifElite04 char_0
+if(var_counter3 eq 0) ai2_makeaware GrifElite04 char_0
+}
+
+#lose func of GrifElite02
+func void check_death1b(string ai_name)
+{
+ai2_spawn GrifElite05
+ai2_passive GrifElite05 1
+playback_block GrifElite05 GrifWave2_Run1
+ai2_passive GrifElite05 0
+if (var_counter3 eq 1) ai2_attack GrifElite05 char_0
+if (var_counter3 eq 0) ai2_makeaware GrifElite05 char_0
+}
+
+#lose func of GrifElite04 and GrifElite05
+func void final_round(string ai_name)
+{
+var_counter2 = var_counter2 + 1
+if(var_counter2 eq 1)
+	{
+	ai2_spawn GrifElite06
+	ai2_passive GrifElite06 1
+	playback_block GrifElite06 GrifWave2_Run3
+	ai2_passive GrifElite06 0
+	if(var_counter3 eq 1) ai2_attack GrifElite06 char_0
+	if(var_counter3 eq 0) ai2_makeaware GrifElite06 char_0
+	}
+}
+
+#lose func of Muro
+func void check_death2(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void console_truckinfo(void)
+{
+text_console level_19e
+console_reset 6
+}
Index: /nikanabo/current/bsl/onilight/IGMD/dream_lab/dream_lab.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/dream_lab/dream_lab.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/dream_lab/dream_lab.bsl	(revision 185)
@@ -0,0 +1,553 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable ambush1a_copy 0
+#used
+trigvolume_enable splash_trigger 0
+env_show 1976 0
+door_lock 1
+door_lock 3
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_volume mus_om01 0.0 1.0
+sound_music_stop mus_om01
+sound_music_stop atm_gr09
+sound_music_stop mus_wls
+sound_music_stop atm_ft81
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+env_show 200 0
+env_show 201 0
+env_show 227 0
+env_show 231 1
+env_show 232 1
+env_show 999 0
+ai2_spawn IntroMuro
+playback IntroMuro IntroMuroSet
+ai2_passive IntroMuro 1
+playback 0 IntroKonokoSet
+particle fog_floor1 do start
+particle fog_floor2a do start
+trigvolume_enable shinatama1a 1
+trigvolume_enable shinatama1b 1
+objective_set 1 silent
+sleep 1
+sound_music_start mus_om01 .75
+}
+
+#tv12 - after the crossing from the lab to the romm where Muro waits
+func void murofog(void)
+{
+ai2_passive IntroMuro 0
+env_show 201 1
+env_show 999 1
+env_show 250 0
+env_show 252 0
+}
+
+#lose func of IntroMuro
+func void murodeath(void)
+{
+env_show 999 0
+env_show 1010 0
+chr_unstoppable IntroMuro 1
+chr_animate IntroMuro COMCOMlev13_death 120
+sleep 20
+chr_delete IntroMuro
+music_stop
+sound_music_start atm_gr09 0.75
+particle fog_floor1 do start
+particle fog_floor2a do start
+ai2_spawn ghost_1
+ai2_spawn ghost_2
+objective_set 1 silent
+}
+
+#tv13 - after the crossing from room to the hall
+func void bring_the_wall(string char)
+{
+trigvolume_enable shinatama1a 1
+trigvolume_enable shinatama1b 1
+env_show 1010 1
+}
+
+#tv17 - around ghost_1
+func void ghost_1(string ai_name)
+{
+chr_delete ghost_1
+}
+
+#tv2 - after tv17 from the left to the right
+func void shinatama_1a(string ai_name)
+{
+sound_dialog_play c12_63_01shinatama
+ai2_spawn shinatama_1a
+ai2_lookatme shinatama_1a
+}
+
+#tv16- around ghost_2; after tv2
+func void ghost_2(string ai_name)
+{
+chr_delete ghost_2
+}
+
+#tv3 - in some distance after tv16 (inside func); from the left to the right; 
+func void shinatama_1b(string ai_name)
+{
+ai2_dopath shinatama_1a shinatama_flee_1
+}
+
+func void patrolscript0100(string ai_name)
+{
+chr_delete shinatama_1a
+door_lock 7
+}
+
+#tv3 (leave func)
+func void mini_strike(string ai_name)
+{
+ai2_spawn mini_strike_1
+ai2_spawn mini_strike_2
+ai2_spawn mini_strike_3
+ai2_spawn mini_strike_4
+chr_delete ghost_1
+chr_delete ghost_2
+}
+
+#hit func of mini_strike_1
+func void mini_strike_flee_1(string ai_name)
+{
+ai2_dopath mini_strike_1 mini_strike_flee_1
+}
+
+#hit func of mini_strike_2
+func void mini_strike_flee_2(string ai_name)
+{
+ai2_dopath mini_strike_2 mini_strike_flee_2
+}
+
+#hit func of mini_strike_3
+func void mini_strike_flee_3(string ai_name)
+{
+ai2_dopath mini_strike_3 mini_strike_flee_3
+}
+
+#hit func of mini_strike_4
+func void mini_strike_flee_4(string ai_name)
+{
+ai2_dopath mini_strike_4 mini_strike_flee_4
+}
+
+func void patrolscript0001(string ai_name)
+{
+chr_nocollision mini_strike_1 1
+playback_block mini_strike_1 cheese1 interp 30
+chr_delete mini_strike_1
+}
+func void patrolscript0002(string ai_name)
+{
+chr_nocollision mini_strike_2 1
+playback_block mini_strike_2 cheese2 interp 30
+chr_delete mini_strike_2
+}
+
+func void patrolscript0003(string ai_name)
+{
+chr_nocollision mini_strike_3 1
+playback_block mini_strike_3 cheese3 interp 30
+chr_delete mini_strike_3
+}
+
+func void patrolscript0004(string ai_name)
+{
+chr_nocollision mini_strike_4 1
+playback_block mini_strike_4 cheese4 interp 30
+chr_delete mini_strike_4
+}
+
+func void patrolscript0110(string ai_name)
+{
+chr_delete mini_strike_1
+}
+
+func void patrolscript0111(string ai_name)
+{
+chr_delete mini_strike_2
+}
+
+func void patrolscript0112(string ai_name)
+{
+chr_delete mini_strike_3
+}
+
+func void patrolscript0113(string ai_name)
+{
+chr_delete mini_strike_4
+}
+
+#lose func of mini_strike_3
+func void bighead_1a_var(string ai_name)
+{
+bighead_1d_var
+}
+
+#lose func of mini_strike_4
+func void bighead_1b_var(string ai_name)
+{
+bighead_1d_var
+}
+
+#lose func of mini_strike_2
+func void bighead_1c_var(string ai_name)
+{
+bighead_1d_var
+}
+
+#lose func of mini_strike_1
+func void bighead_1d_var(string ai_name)
+{
+var_counter2 = var_counter2 + 1
+if(var_counter2 eq 4)
+	{
+	sleep 60
+	chr_big_head = 1
+	timer_start 120
+	sleep 7200
+	chr_big_head = 0
+	}
+}
+
+#tv14 - at the beginning of the stairs (enter func: fog_floor1off, leave func: fog_floor1on); I've disabled it
+
+#tv5 - in front of the end of the stairs
+func void ambush_1a(string ai_name)
+{
+chr_delete shinatama_1a
+ai2_spawn ambush_tanker_1a
+ai2_spawn ambush_tanker_1b
+music_stop
+sound_music_start mus_wls .75
+door_open 8
+door_jam 8
+}
+
+#lose func of ambush_tanker_1a
+func void tanker_1_var(string ai_name)
+{
+tanker_2_var
+}
+
+#lose func of ambush_tanker_1b
+func void tanker_2_var(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	music_stop
+	sound_music_start atm_ft81 .75
+	door_unlock 9
+	var_counter = 0
+	}
+}
+
+#tv1 - after door 9
+func void shinatama_2(string ai_name)
+{
+sound_dialog_play c12_63_03shinatama
+ai2_spawn shinatama_2
+chr_lock_active shinatama_2
+ai2_spawn liliput_striker_1
+ai2_spawn liliput_striker_2
+ai2_spawn liliput_striker_3
+door_unjam 8
+door_lock 11
+particle fog_floor2a do stop
+particle fog_floor2b do start
+}
+
+func void patrolscript0101(string ai_name)
+{
+chr_delete shinatama_2
+}
+
+#tv19 - in front of door 11
+func void red_retreat(string ai_name)
+{
+ai2_makeignoreplayer ambush_red_1 1
+ai2_makeignoreplayer ambush_red_2 1
+ai2_dopath ambush_red_1 red_retreat_1 1
+ai2_dopath ambush_red_2	red_retreat_2 1
+}
+
+func void patrolscript0007(string ai_name)
+{
+ai2_makeignoreplayer ambush_red_1 0
+ai2_makeignoreplayer ambush_red_2 0
+}
+
+#tv8 - after door 11
+func void ambush_2(string ai_name)
+{
+ai2_spawn ambush_red_1
+music_stop
+sound_music_start mus_wls .75
+}
+
+#hit func of ambush_red_1
+func void red_1_var(string ai_name)
+{
+ai2_spawn ambush_red_2
+door_unlock 1
+chr_delete mini_strike_1
+chr_delete mini_strike_2
+chr_delete mini_strike_3
+chr_delete mini_strike_4
+}
+
+#lose func of ambush_red_1
+func void redmusic_1_var(string ai_name)
+{
+redmusic_2_var
+}
+
+#lose func of ambush_red_2
+func void redmusic_2_var(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	music_stop
+	sound_music_start atm_gr09 0.75
+	door_unlock 2
+	var_counter = 0
+	}
+}
+
+#tv4 - in the middle between door 1 and door 2
+func void shinatama_3(string ai_name)
+{
+sound_dialog_play c12_63_04shinatama
+particle fog_room1 do start
+ai2_spawn shinatama_3
+ai2_spawn shin_striker_1
+ai2_spawn shin_striker_2
+ai2_spawn shin_striker_3
+ai2_spawn shin_striker_4
+}
+
+func void patrolscript0102(string ai_name)
+{
+chr_delete shinatama_3
+sleep 400
+chr_delete shin_striker_1
+chr_delete shin_striker_2
+chr_delete shin_striker_3
+chr_delete shin_striker_4
+}
+
+##########
+### SP2 ###
+##########
+
+#tv6 and tv15 - in a small distance after door 2
+func void room_1(string ai_name)
+{
+if(save_point eq 2)
+	{
+	particle fog_floor1 do start
+	particle fog_room1 do start
+	}
+else
+	{
+	fork remove_ai
+	save_game 2 autosave
+	particle fog_floor2b do stop
+	music_stop
+	}
+door_lock 2
+ai2_spawn griffin
+chr_lock_active griffin
+playback griffin GrifGriffinSet
+objective_set 2 silent
+trigvolume_enable room1a 0
+trigvolume_enable room1b 0
+trigvolume_enable shinatama3 0
+sleep 1
+sound_music_start mus_wls .75
+}
+
+#hit func of griffin
+func void swat_1_var(string ai_name)
+{
+door_unlock 2
+ai2_spawn griffin_b1
+ai2_spawn griffin_b2
+}
+
+#lose func of griffin
+func void griffindeath(void)
+{
+chr_unstoppable griffin 1
+chr_animate griffin COMCOMlev13_death 120
+sleep 20
+chr_delete griffin
+door_unlock 3
+}
+
+#tv20 - in the middle between door 3 and door 4
+func void show_the_acid(string char)
+{
+sound_music_volume mus_wls 0 2	
+music_stop
+sound_music_start atm_gr09 0.75
+particle fog_floor1 do stop
+env_show 1976 1
+trigvolume_enable splash_trigger 1
+door_close 3
+door_lock 3
+trig_activate 1
+}
+
+#tv9 - in some distance after door 4
+func void laser_cutscene(string ai_name)
+{
+door_lock 4
+ai2_spawn laser_ops_1
+playback_block laser_ops_1 lstriker_1 interp 30
+trigvolume_enable lasercutscene 0
+}
+
+#tv11 - complete volume under the acid texture
+func void splash(string character)
+{
+if(chr_is_player(character) eq 1)
+	{
+	chr_animate 0 KONOKOacid
+	cm_detach
+	sleep 10
+	sound_impulse_play konoko_gruesome_death
+	sleep 30
+	chr_set_health 0 0
+	}
+else
+	{
+	chr_animate(character, KONOKOacid);
+	sleep 10
+	chr_set_health(character, 0);
+	}
+}
+
+#tv10 - in the middle between door 5 and door 6
+func void shinatama_nograv(string ai_name)
+{
+particle fog_room1 do stop
+particle fog_room2 do start
+door_unlock 6
+door_lock 5
+}
+
+#tv7 - in front of door 6
+func void room2_music(string ai_name)
+{
+sound_music_volume atm_ft81 0 2
+music_stop
+sound_music_start mus_wls .75
+}
+
+#tv18 - after door 6
+func void room_2(string ai_name)
+{
+door_close 6
+door_lock 6
+ai2_spawn evilkonoko
+chr_lock_active evilkonoko
+playback evilkonoko Kon2Konoko02Set
+chr_animate evilkonoko KONOKOpowerup 0
+chr_set_health evilkonoko 400
+trigvolume_enable room2 0
+trig_activate 0
+env_show 1976 0
+}
+
+#lose func of evilkonoko
+func void you_win(string char_index)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
Index: /nikanabo/current/bsl/onilight/IGMD/lab/lab.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/lab/lab.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/lab/lab.bsl	(revision 185)
@@ -0,0 +1,643 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = .30
+gl_fog_blue = .15
+gl_fog_green = .17
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+if(save_point eq 0) save_point = 1 
+if(save_point eq 1) fork intro
+if (save_point eq 2) restore_game
+if (save_point eq 3) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable floor1 0
+trigvolume_enable save_1_trig 0
+trigvolume_enable save_3_trig 0
+trigvolume_enable sapperdamageon 0
+trigvolume_enable trigger_volume_36 0
+trigvolume_enable trigger_volume_36_copy 0
+trigvolume_enable trigger_volume_36_copy_copy 0
+#used
+trigvolume_enable outro_volume_1 0
+trigvolume_enable attack_trigger 0
+trigvolume_enable final_ambush 0
+env_show 776 0
+env_show 777 0
+obj_create 2 7
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_main01_hd
+sound_music_stop mus_main03
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+ai2_spawn Barabus
+ai2_attack Barabus konoko
+playback 0 IntroKonoko01
+chr_inv_reset 0
+env_show 8 1
+env_show 9 1
+env_show 10 1
+objective_set 1 silent
+sleep 1
+sound_music_start mus_main01_hd 0.8
+}
+
+#tv31 - at the place, where Konoko gets off the bike (inside func: save_game_1); I've disabled it
+
+#lose func of Barabus
+func void rocket(void)
+{
+music_stop
+chr_animate Barabus STRIKEknockdown1
+fade_out 0 0 0 30
+sleep 30
+chr_animate_block Barabus BARABlev3_rocket
+chr_envanim Barabus RocketBox01
+sound_ambient_start c01_00_02barjet
+particle lock99_locklight01 do start
+door_unlock 43
+objective_set 2 silent
+target_set 143 30
+fade_in 30
+sleep 360
+chr_delete Barabus
+sleep 600
+sound_dialog_play c00_01_98shinatama
+}
+
+#tv22 - if you look to the gate, on the left, around the place where you find the plasma gun
+func void spawn_right_patrol(string ai_name)
+{
+ai2_spawn right_patrol_striker_1
+}
+
+#tv23 - between the last pillar and the 5 glass doors
+func void spawn_back_patrol(string ai_name)
+{
+ai2_spawn back_patrol_striker_1
+ai2_spawn back_patrol_striker_2
+}
+
+#tv21 - if you look to the gate, on the right, nearly at the end of the way
+func void spawn_left_patrol(string ai_name)
+{
+ai2_spawn left_patrol_striker_1
+}
+
+#tv8 - in front of door 43 (func: spawn_floor1_guards); I've disabled it
+
+##########
+### SP2 ###
+##########
+
+### GROUND FLOOR ###
+
+#tv33 - after door 43
+func void turnoffcompass(string ai_name)
+{
+if(save_point ne 2)
+	{
+	save_game 2 autosave	
+	target_set 143 0
+	}
+ai2_spawn Floor1_Striker_1
+ai2_spawn Floor1_Striker_2
+ai2_spawn Floor1_Sci_1
+ai2_spawn Floor1_Sci_2
+ai2_spawn Floor1_Sci_3
+ai2_spawn Floor1_Sci_4
+objective_set 3 silent
+tr_write_animation KONCOMpunch_heavy tramph.txt
+}
+
+#tv35 - complete room with console 2 (no funcs); I've disabled it
+
+#console 2
+func void unlock_floor1_doors(string ai_name)
+{
+particle lock1_locklight01 do start
+particle lock4a_locklight01 do start
+door_unlock 3
+door_unlock 8
+door_unlock 11
+door_unlock 14
+door_unlock 17
+door_unlock 20
+door_unlock 23
+door_unlock 26
+check_doors
+}
+
+#tv3 - long box in some distance after door 3, door 14, door 20 and door 26
+func void spawn_floor1_striker_11(string ai_name)
+{
+ai2_spawn Floor1_Striker_11
+ai2_spawn Floor1_Striker_12
+}
+
+#tv4 - long box in some distance after door 8, door 11, door 17 and door 23
+func void spawn_floor1_striker_10(string ai_name)
+{
+ai2_spawn Floor1_Striker_10
+ai2_spawn Floor1_Striker_12
+}
+
+#tv1 - in front of the stairs
+func void spawn_floor2_guards(string ai_name)
+{
+ai2_spawn Floor2_Striker_2
+ai2_spawn Floor2_Striker_3
+ai2_spawn Floor2_Striker_4
+sleep 15
+ai2_spawn Floor2_Striker_1
+ai2_doalarm Floor2_Striker_1 3
+sleep 15
+ai2_spawn Floor2_Sci_1
+ai2_spawn Floor2_Sci_2
+ai2_spawn Floor2_Sci_3
+ai2_spawn Floor2_Sci_4
+ai2_spawn Floor2_Sci_5
+}
+
+#tv10 - on the platform between the ground floor and the first floor
+func void set_target_4(string chr_index)
+{
+sound_dialog_play c00_01_26shinatama
+target_set 253 30
+}
+
+### FIRST FLOOR ###
+
+#tv36 - complete room with console 3 (no funcs); I've disabled it
+
+#console 3
+func void unlock_floor2_doors(void)
+{
+trigvolume_enable attack_trigger 1
+particle lock2_locklight01 do start
+particle lock4b_locklight01 do start
+door_unlock 2
+door_unlock 9
+door_unlock 12
+door_unlock 15
+door_unlock 18
+door_unlock 21
+door_unlock 24
+door_unlock 27
+check_doors
+sleep 60
+ai2_dopath Floor2_Striker_1 Floor2_Stk_1
+ai2_setjobstate Floor2_Striker_1
+}
+
+#tv24 - after door 6; outside of the room with console 3 (tv name: attack_trigger)
+func void commence_attack(string ai_name)
+{
+ai2_setalert Floor2_Striker_2 high
+ai2_setalert Floor2_Striker_3 high
+ai2_setalert Floor2_Striker_4 high
+ai2_dopath Floor2_Striker_1 Floor2_Stk_1
+ai2_dopath Floor2_Striker_2 scram_path
+ai2_dopath Floor2_Striker_3 attack_path_1
+ai2_dopath Floor2_Striker_4 attack_path_2
+ai2_setjobstate Floor2_Striker_1
+ai2_setjobstate Floor2_Striker_2
+ai2_setjobstate Floor2_Striker_3
+ai2_setjobstate Floor2_Striker_4
+ai2_attack Floor2_Striker_4 Floor2_Sci_4
+ai2_attack Floor2_Striker_3 Floor2_Sci_1
+}
+
+#lose func of Floor2_Sci_4
+func void death_sentence_1(string ai_name)
+{
+ai2_attack Floor2_Striker_4 Floor2_Sci_5
+}
+
+#lose func of Floor2_Sci_1
+func void death_sentence_2(string ai_name)
+{
+ai2_attack Floor2_Striker_3 Floor2_Sci_2
+}
+
+#lose func of Floor2_Sci_2
+func void death_sentence_3(string ai_name)
+{
+ai2_attack Floor2_Striker_3 Floor2_Sci_3
+}
+
+#tv2 - in front of the stairs
+func void spawn_floor3_guards(string ai_name)
+{
+ai2_spawn Floor3_Striker_1
+ai2_spawn Floor3_Striker_2
+ai2_spawn Floor3_Striker_3
+ai2_spawn Floor3_Comguy_1
+}
+
+#tv11 - on the platform between the first and the second floor
+func void set_target_5(string chr_index)
+{
+sound_dialog_play c00_01_28shinatama
+target_set 254 30
+}
+
+### SECOND FLOOR ###
+
+#tv37 - complete room with console 4 (no funcs); I've disabled it
+
+#console 4
+func void unlock_floor3_doors(string ai_name)
+{
+particle lock3_locklight01 do start
+particle lock4c_locklight01 do start
+door_unlock 1
+door_unlock 10
+door_unlock 13
+door_unlock 16
+door_unlock 19
+door_unlock 22
+door_unlock 25
+door_unlock 28
+check_doors
+}
+
+### ROOF ###
+
+#tv12 - in front of door 4
+func void set_objective_4(string chr_index)
+{
+sound_dialog_play c00_01_19shinatama
+objective_set 4 silent
+target_set 110 30
+}
+
+#tv30 - in some distance after the ramp to the lower roof; box from left to right
+func void roof_surprise(string ai_name)
+{
+ai2_dopath Roof_Striker_3 Roof_Striker_3b
+ai2_setjobstate Roof_Striker_3
+}
+
+#tv5 - after door 39
+func void spawn_tower_guards(string ai_name)
+{
+ai2_spawn Tower_Striker_1
+ai2_spawn Tower_Striker_2
+}
+
+#tv18 - after door 41; on the right side
+func void tower_lock_1(string chr_index)
+{
+ai2_spawn Tower_MB_1
+particle sapper do start
+music_stop
+}
+
+#tv17 - right next to the furniture in the middle of the tower; from left to right (entry func: sapper_damage_on); I've disabled it
+
+#lose func of Tower_MB_1
+func void bomber(void)
+{
+fade_out 0 0 0 30
+sleep 30
+chr_delete Tower_MB_1
+fork remove_ai
+particle sapper do stop
+chr_teleport 0 99
+chr_facetoflag 0 90
+fade_in 30
+}
+
+##########
+### SP3 ###
+##########
+
+### LOBBY - GROUND FLOOR ###
+
+#tv9 - in front of door 35; in the elevator shaft
+func void spawn_lobby_tctf(string ai_name)
+{
+if(save_point ne 3)
+	{
+	sleep 30
+	save_game 3 autosave
+	}
+env_show 540 0
+env_show 777 1
+env_show 778 0
+ai2_spawn Lobby_TCL_1
+ai2_spawn Lobby_TCL_2
+ai2_spawn Lobby_TCS_1
+objective_set 5 silent
+target_set 142 30
+}
+
+#tv34 - after door 35 (inside func: save_game_3); I've disabled it
+
+#tv13 - big box from door 59 and door 60 to the opposite wall; includes console 1
+func void spawn_lobby_synd(string ai_name)
+{
+ai2_spawn Lobby_Striker_1
+ai2_spawn Lobby_Striker_2
+ai2_spawn Lobby_Striker_3
+ai2_spawn Lobby_Striker_4
+}
+
+#hit func of Lobby_TCL_1
+func void Lobby_Hurt_TCL_1(string ai_name)
+{
+ai2_dopath Lobby_TCL_1 Lobby_Hurt_TCL_1
+}
+
+#hit func of Lobby_TCL_2
+func void Lobby_Hurt_TCL_2(string ai_name)
+{
+sleep 120
+ai2_dopath Lobby_TCL_2 Lobby_Hurt_TCL_2
+}
+
+#tv32 - at the end of the stairs to the lower floor with console 11; big box from left to right
+func void backdoor(string ai_name)
+{
+ai2_spawn backdoor_striker_1
+ai2_spawn backdoor_striker_3
+}
+
+#console 11
+func void passage_1(string ai_name)
+{
+particle lock69a_locklight01 do start
+check_doors
+}
+
+### LOBBY - FIRST FLOOR ###
+
+#tv28 - long box; starts in some after door 53 and ends in front of console 9
+func void spawn_lively_2(string ai_name)
+{
+ai2_spawn lively_striker_2
+}
+
+#console 9
+func void passage_2(string ai_name)
+{
+particle lock69b_locklight01 do start
+check_doors
+}
+
+#tv26 - in some distance after door 37
+func void spawn_opposite_striker_1(string ai_name)
+{
+ai2_spawn opposite_striker_1
+}
+
+#tv27 - in some distance after door 31
+func void spawn_opposite_striker_2(string ai_name)
+{
+ai2_spawn opposite_striker_2
+}
+
+### LOBBY - SECOND FLOOR ###
+
+#tv25 - around the green energy clip; in the room with door 46
+func void spawn_lively_1(string ai_name)
+{
+ai2_spawn lively_striker_1
+}
+
+#tv29 - at the end of the room with door 29; from left to right; includes the hypo
+func void spawn_lively_3(string ai_name)
+{
+ai2_spawn lively_striker_3
+ai2_spawn lively_striker_4
+}
+
+#console 8
+func void passage_3(string ai_name)
+{
+particle lock69c_locklight01 do start
+check_doors
+}
+
+func void check_doors(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 3)
+	{
+	if(save_point eq 2)
+		{
+		door_unlock 4
+		ai2_spawn Roof_Striker_1
+		ai2_spawn Roof_Striker_2
+		ai2_spawn Roof_Striker_3
+		sound_music_start mus_main03
+		}
+	if(save_point eq 3)
+		{
+		door_unlock 48
+		sound_music_start mus_main03 1.0
+		}
+	var_counter = 0
+	}
+}
+
+#tv20 - in front of door 48
+func void miseenscene_start(string ai_name)
+{
+particle scene create
+ai2_spawn scene_thug_1
+ai2_spawn scene_thug_2
+}
+
+#tv6 - in the middle between door 48 and door 55
+func void spawn_vats(string ai_name)
+{
+ai2_spawn Vat_Striker_1
+ai2_spawn Vat_Striker_2
+ai2_spawn Vat_Striker_3
+ai2_spawn Vat_Striker_4
+ai2_spawn Vat_Striker_5
+}
+
+#console 10 (text console)
+func void day_264(string ai_name)
+{
+ai2_idle scene_thug_1
+ai2_movetoflag scene_thug_1 7010
+ai2_setmovementmode scene_thug_1 run
+sleep 300
+particle day264 create
+particle dayafter create
+particle dayafter do start
+chr_animate scene_thug_1 STRIKEknockdown3
+ai2_dopath scene_thug_1 scene_flee_1
+ai2_dopath scene_thug_2 scene_flee_2
+sleep 300
+ai2_spawn arcy
+sleep 1000
+chr_delete scene_thug_1
+chr_delete scene_thug_2
+sleep 500
+chr_delete arcy
+}
+
+#tv19 - in front of door 55
+func void set_objective_6(string chr_index)
+{
+sound_dialog_play c00_01_22shinatama
+objective_set 6 silent
+target_set 256 30
+}
+
+### HALL ###
+
+#tv16 - the complete acid volume
+func void fallinthevat(string character)
+{
+if(chr_is_player(character) eq 1)
+	{
+  	cm_detach
+    	chr_animate 0 KONOKOacid
+	sleep 10
+	sound_impulse_play konoko_gruesome_death
+	chr_set_health 0 0
+	}
+else
+	{
+	chr_animate(character, KONOKOacid);
+	sleep 10
+	chr_set_health(character, 0);
+  	}
+}
+
+#console 5
+func void unlock_end_door(string ai_name)
+{
+trigvolume_enable final_ambush 1
+particle lockend_locklight02 do start
+door_unlock 56
+target_set 52 30
+ai2_spawn Vat_MB_1
+}
+
+#tv7 - in some distance in front three pillars; from left to right
+func void final_ambush(string ai_name)
+{
+ai2_spawn Ambush_Striker_1
+ai2_spawn Ambush_Striker_2
+}
+
+#hit func of Ambush_Striker_1
+func void gethelp(string ai_name)
+{
+trigvolume_enable outro_volume_1 1
+particle lock177_locklight01 do start
+door_unlock 49
+door_unlock 50
+ai2_attack Ambush_Striker_2 Konoko
+music_stop
+}
+
+#tv14 - after door 50
+#tv15 - after door 49
+func void outro(void)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level3a(string chr_index)
+{
+text_console level_3a
+console_reset 7
+}
+
+func void level3b(string chr_index)
+{
+text_console level_3b
+console_reset 6
+}
+
+func void level3c(string chr_index)
+{
+text_console level_3c
+console_reset 1
+}
+
+func void level3d(string chr_index)
+{
+text_console level_3d
+day_264
+}
Index: /nikanabo/current/bsl/onilight/IGMD/manplant/manplant.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/manplant/manplant.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/manplant/manplant.bsl	(revision 185)
@@ -0,0 +1,539 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = .15
+gl_fog_blue = .15
+gl_fog_green = .15
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(void)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3) restore_game
+if(save_point eq 4) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+trigvolume_setscript save_point4 sp4 entry
+#not used
+trigvolume_enable alarm_1 0
+trigvolume_enable brain_commguy_1 0
+trigvolume_enable febtober2 0
+trigvolume_enable flyway_1 0
+trigvolume_enable Griffin 0
+trigvolume_enable hidden_1a 0
+trigvolume_enable hidden_1b 0
+trigvolume_enable lowthug_1 0
+trigvolume_enable new_target_3 0
+trigvolume_enable nook_1 0
+trigvolume_enable nookright 0
+trigvolume_enable outro1 0
+trigvolume_enable plasma_striker_1 0
+trigvolume_enable sound_off 0
+trigvolume_enable trigger_active_1 0
+trig_deactivate 201
+trig_deactivate 202
+trig_deactivate 203
+trig_deactivate 204
+trig_deactivate 2012
+trig_deactivate 2022
+particle lock_1_locklight01 do start
+particle lock_1b_locklight01 do start
+env_show 555 0
+door_lock 1
+#used
+trigvolume_enable febtober 0
+trigvolume_enable tech_1 0
+trig_hide 205
+trig_hide 2013
+trig_hide 2023
+trig_hide 2032
+trig_hide 2042
+obj_create 1201 1208
+env_anim 1201 1208
+door_unlock 3
+door_lock 4
+door_lock 9
+door_lock 21
+console_deactivate 6
+}
+
+func void you_lose(void)
+{
+fade_out 0 0 0 30 
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_fiteb_hd
+sound_music_stop atm_low_perc1
+sound_music_stop atm_cl12
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+chr_inv_reset 0
+ai2_spawn nookleft_thug_1
+ai2_spawn nookright_thug_1
+ai2_spawn ambush_striker_1
+ai2_spawn ambush_striker_2
+ai2_spawn ambush_striker_3
+ai2_spawn partner_cop_1
+ai2_spawn partner_cop_2
+ai2_attack partner_cop_1 ambush_striker_1
+ai2_attack partner_cop_2 ambush_striker_3
+ai2_makeaware nookleft_thug_1 konoko
+ai2_makeaware nookright_thug_1 konoko
+objective_set 1 silent
+target_set 38 30
+sleep 1
+sound_music_start mus_fiteb_hd 0.75
+sound_dialog_play c00_01_22shinatama
+}
+
+#tv3 - after door 3 (entry func: nookright); I've disabled it
+#tv1 - between door 2 and door 4 (entry func: nook_1); I've disabled it
+
+#lose func of ambush_striker_1
+func void striker_lullaby_1(void)
+{
+striker_lullaby_3
+}
+
+#lose func of ambush_striker_2
+func void striker_lullaby_2(void)
+{
+striker_lullaby_3
+}
+
+#lose func of ambush_striker_3
+func void striker_lullaby_3(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 3)
+	{
+	particle foyer_right_locklight01 do start
+	door_unlock 21
+	trigvolume_enable tech_1 1
+	var_counter = 0
+	music_stop
+	}
+}
+
+#tv2 - in front of door 21
+func void tech_1(void)
+{
+ai2_spawn tech_thug_1
+ai2_spawn tech_thug_1a
+ai2_dopath partner_cop_1 cop_backup_1a 1
+ai2_dopath partner_cop_2 cop_backup_1b 1
+}
+
+#tv28 - after door 21 (func: all_music_counters); I've disabled it
+#tv25 - complete room (func: feb_tober2); I've disabled it
+
+#console1
+func void door_1(void)
+{
+door_lock 8
+door_lock 15
+ai2_spawn plasma_striker_1
+particle febtober1_locklight01 do start
+particle lock_1a_locklight01 do start
+particle save1a_locklight01 do start
+door_unlock 19
+target_set 123 30
+}
+
+#tv5 - after door 19
+func void bait_1(void)
+{
+ai2_spawn bait_commguy_1
+ai2_spawn tech_thug_2
+sleep 120
+ai2_doalarm bait_commguy_1 15
+sound_music_start atm_low_perc1 1.00
+particle save1b_locklight01 do start
+door_unlock 11
+ai2_dopath partner_cop_1 cop_backup_2a 1
+ai2_dopath partner_cop_2 cop_backup_2b 1
+}
+
+#tv13 - after door 13 (enter func: plasma_striker_1, loop func: calling_all_cars); I've disabled it
+#tv6 - after door 12 (func: calling_all_cars2); I've disabled it
+
+#console15
+func void alarm_1(void)
+{
+ai2_spawn hall_striker_2
+sound_ambient_start alarm_loop
+sleep 900
+sound_ambient_stop alarm_loop
+}
+
+##########
+### SP2 ###
+##########
+
+#tv18 - after door 11
+func void tech_ambush_1(void)
+{
+if(save_point eq 2)
+	{
+	door_lock 8
+	door_lock 15
+	ai2_spawn plasma_striker_1
+	particle save1b_locklight01 do start
+	door_unlock 11
+	objective_set 1 silent
+	target_set 38 30
+	sleep 1
+	sound_music_start atm_low_perc1 1.00
+	sound_dialog_play c00_01_22shinatama
+	}
+else save_game 2 autosave
+ai2_spawn hall_striker_1
+door_lock 10
+door_lock 12
+}
+
+#console3
+func void door_2(void)
+{
+particle febtober1_locklight01 do start
+particle lock88_locklight02 do start
+door_unlock 10
+door_unlock 23
+ai2_spawn patrol_striker_2
+console_activate 4 1
+target_set 124 30
+sound_dialog_play c00_01_27shinatama
+}
+
+#tv7 - in front of door 7
+func void cruel_1(void)
+{
+ai2_spawn cruel_commguy_1
+ai2_spawn victim_femsci_1
+}
+
+#console4
+func void door_3(void)
+{
+music_stop
+particle lock_3_locklight01 do start
+door_unlock 4
+ai2_spawn tech_thug_3
+objective_set 2 silent
+target_set 128 30
+sound_dialog_play c00_01_26shinatama
+}
+
+#tv4 - in some distance in front of door 23 (func: flyway_1); I've disabled it
+
+#tv19 - after door 23
+func void new_target_1(void)
+{
+sound_music_start atm_cl12 0.75
+target_set 54 30
+}
+
+#tv15 - at the beginning of the stairs after door 24
+func void beaters_1(void)
+{
+chr_delete plasma_striker_1
+door_unlock 8
+door_unlock 15
+ai2_spawn scram_striker_1
+ai2_spawn beater_thug_1
+particle vent01 start
+}
+
+#lose func of beater_thug_1
+func void beater_thug_2(void)
+{
+ai2_spawn beater_thug_2
+}
+
+#lose func of scram_striker_1
+func void backup_2(void)
+{
+ai2_spawn backup_thug_2
+ai2_tripalarm 2 0
+}
+
+#tv16 - in front of door 16 (enter func: scramble_sound_off, loop func: Griffin_1); I've disabled it
+#tv10 - after door 16 (enter func: set_objective_3, inside func: lowthug_1, leave func: disable_obj_trig_1); I've disabled it
+
+##########
+### SP3 ###
+##########
+
+#tv26 - in some distance in front of door 15
+func void save_point_3(void)
+{
+if(save_point ne 3)
+	{
+	fork remove_ai
+	save_game 3 autosave
+	particle vent01 do stop
+	music_stop
+	}
+particle hlock_1_locklight01 do start
+door_unlock 22
+particle vent02 do start
+trig_activate 2
+door_close 16
+door_lock 16
+trigvolume_enable febtober 1
+ai2_spawn hidden_sci_1
+ai2_spawn low_thug_1
+ai2_spawn low_thug_2
+objective_set 3 silent
+target_set 127 30
+sleep 1
+sound_dialog_play c00_01_18shinatama
+}
+
+#tv8 - in front of door 22  (func: hidden_1b); I've disabled it
+#tv9 - after door 22  
+
+#console7
+func void guardroom_1(void)
+{
+particle guardroom_1_locklight01 do start
+door_unlock 14
+ai2_spawn patrol_striker_3
+ai2_spawn brain_commguy_1
+ai2_spawn brain_commguy_2
+console_deactivate 6
+target_set 65 30
+}
+
+#tv13 - at the beginning of the upper way, next to where the stairs ends (func: trigger_active_1); I've disabled it
+
+#tv24 - after the railing
+func void feb_tober(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+chr_teleport 0 41
+chr_facetoflag 0 126
+fade_in 30
+trigvolume_reset febtober
+}
+
+#tv11 - after door 14 (func: brain_commguy_1); I've disabled it
+
+#console8
+func void brainlock_1(void)
+{
+ai2_spawn low_striker_1
+ai2_spawn low_striker_2
+console_activate 6
+target_set 126 30
+}
+
+#tv12 - after door 8
+func void low_striker_1(string ai_name)
+{
+ai2_spawn low_striker_1
+ai2_spawn low_striker_2
+}
+
+#tv20 - in front of the furniture with console6 (func: new_target_3); I've disabled it
+
+#console6
+func void trigger_deactivate_4(void)
+{
+particle guardroom_2_locklight01 do start
+door_unlock 9
+trig_deactivate 4
+console_activate 5
+target_set 125 30
+}
+
+#console5
+func void hidden_1(void)
+{
+particle brainlock_1_locklight02 do start
+door_unlock 6
+target_set 129 30
+trigvolume_enable cruel_striker_1 1
+}
+
+#tv21 - in front of door 6
+func void cruel_striker_1(void)
+{
+ai2_spawn cruel_striker_1
+ai2_spawn victim_mansci_1
+brain_start
+}
+
+func void brain_start(void)
+{
+particle brainlock_2_locklight01 do start
+particle brain do start
+particle brain1 do start
+trig_show 205
+trig_show 2013
+trig_show 2023
+trig_show 2032
+trig_show 2042
+trig_speed 205 .4
+trig_speed 2013 .4
+trig_speed 2023 .4
+trig_speed 2032 .4
+trig_speed 2042 .4
+}
+
+#called up, after you have talked to the scientist
+func void flee(void)
+{
+chr_talk victim_mansci_1 c02_62_11sci 0 0
+ai2_dopath victim_mansci_1 victim_2
+sleep 300
+objective_set 4 silent
+sound_dialog_play c00_01_20shinatama
+}
+
+#tv17 - in front of the beginning of the stairs (func: outro); not used
+
+##########
+### SP4 ###
+##########
+
+#tv27 - after door 26
+func void sp4(void)
+{
+if(save_point eq 4)
+	{
+	brain_start
+	objective_set 4 silent
+	sleep 1
+	sound_dialog_play c00_01_20shinatama	
+	}
+else
+	{
+	save_game 4 autosave
+	fork remove_ai
+	particle brainlock_1_locklight02 do stop
+	door_lock 6
+	particle vent02 stop
+	}
+turret_deactivate 20
+particle brainlock_3_locklight01 do start
+door_unlock 27
+sound_ambient_start deadlybrain_sound 1.0
+sound_music_start mus_cool4_hd 1
+}
+
+#tv22 - in some distance after door 27
+#tv23 - in some distance after door 27 on the right side
+func void lockit(void)
+{
+particle brainlock_3_locklight01 do stop
+door_close 27
+door_jam 27
+}
+
+#console21, console22, console23 and console24
+func void brain_counter(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 4)
+	{
+	fade_out 0 0 0 30
+	sleep 30
+	win
+	}
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level2a(string chr_index)
+{
+text_console level_2a
+console_reset 2
+}
+
+func void level2b(string chr_index)
+{
+text_console level_2b
+console_reset 12
+}
+
+func void level2c(string chr_index)
+{
+text_console level_2c
+console_reset 13
+}
+
+func void level2d(string chr_index)
+{
+text_console level_2d
+console_reset 14
+}
+
+func void level2e(string chr_index)
+{
+text_console level_2e
+console_reset 11
+}
Index: /nikanabo/current/bsl/onilight/IGMD/neuro/neuro.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/neuro/neuro.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/neuro/neuro.bsl	(revision 185)
@@ -0,0 +1,925 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = .15
+gl_fog_blue = .15
+gl_fog_green = .15
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+menu2
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(void)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if (save_point eq 2) restore_game
+if (save_point eq 3) restore_game
+if (save_point eq 4) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable ending 0
+trigvolume_enable ending2 0
+trigvolume_enable sensor 0
+trigvolume_enable final_sensor 0
+trigvolume_enable spawn_kerr_trig 0
+trigvolume_enable trap_music 0
+trigvolume_enable tv_check_outro 0
+trigvolume_enable tv_vat_monologue_1 0
+trigvolume_enable tv_vat_monologue_2 0
+trigvolume_enable lab1 0
+trigvolume_enable lab1_copy 0
+trigvolume_enable lab1_copy_copy 0
+trigvolume_enable lab1_copy_copy2 0
+trigvolume_enable lab1_copy_copy3 0
+trigvolume_enable lab1_copy_copy4 0
+trigvolume_enable lab1_copy_copy5 0
+trigvolume_enable lab1_copy_copy6 0
+trigvolume_enable lab1_copy_copy7 0
+trigvolume_enable lab1_copy_copy8 0
+trigvolume_enable lab1_copy_copy9 0
+trigvolume_enable lab1_copy_copy10 0
+trigvolume_enable lab1_copy_copy3_copy 0
+trigvolume_enable lab1_copy_copy3_copy2 0
+trigvolume_enable lab1_copy_copy3_copy3 0
+trigvolume_enable lab1_copy_copy3_copy4 0
+trigvolume_enable trigger_volume_02 0
+trigvolume_enable trigger_volume_08_copy 0
+trigvolume_enable trigger_volume_19 0
+trigvolume_enable trigger_volume_19_copy2 0
+trigvolume_enable trigger_volume_19_copy3 0
+trigvolume_enable trigger_volume_19_copy4 0
+trigvolume_enable trigger_volume_19_copy5 0
+trigvolume_enable trigger_volume_19_copy6 0
+trigvolume_enable trigger_volume_19_copy3_copy 0
+trigvolume_enable trigger_volume_19_copy6_copy 0
+trigvolume_enable trigger_volume_19_copy6_copy2 0
+trigvolume_enable trigger_volume_19_copy7 0
+trigvolume_enable trigger_volume_19_copy8 0
+trigvolume_enable trigger_volume_37 0
+trigvolume_enable trigger_volume_37_copy 0
+trigvolume_enable trigger_volume_37_copy_copy 0
+trigvolume_enable trigger_volume_37_copy_copy_copy 0
+trigvolume_enable trigger_volume_37_copy_copy_copy2 0
+trigvolume_enable trigger_volume_37_copy2 0
+trigvolume_enable trigger_volume_37_copy3 0
+trigvolume_enable trigger_volume_37_copy4 0
+trigvolume_enable trigger_volume_45 0
+trigvolume_enable trigger_volume_45_copy 0
+trigvolume_enable trigger_volume_45_copy_copy 0
+trigvolume_enable trigger_volume_45_copy_copy2 0
+trigvolume_enable trigger_volume_45_copy_copy3 0
+trigvolume_enable trigger_volume_45_copy_copy4 0
+trigvolume_enable trigger_volume_45_copy_copy5 0
+trigvolume_enable trigger_volume_45_copy_copy6 0
+trigvolume_enable trigger_volume_53_copy 0
+trigvolume_enable trigger_volume_53_copy_copy 0
+trigvolume_enable trigger_volume_68 0
+trigvolume_enable trigger_volume_69 0
+trigvolume_enable trigger_volume_69_copy 0
+trigvolume_enable trigger_volume_69_copy2 0
+#used
+trigvolume_enable chase_trigger 0
+trigvolume_enable end 0
+trigvolume_enable Setup_Security_Trig 0
+trigvolume_enable trigger_volume_02 0
+trig_deactivate 2
+trig_deactivate 3
+trig_deactivate 4
+obj_create 71 74
+obj_create 401 409
+env_anim 401 409
+env_show 823 0
+console_deactivate 9
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_space01
+sound_music_stop mus_xtr1
+}
+
+##########
+### SP1 ###
+##########
+
+#tv55 - in some distance after the door 9 (fake door) (func: start_trap_music); I've disabled it
+
+func void intro(void)
+{
+playback 0 IntroKonstart
+particle lock100_locklight01 do stop
+door_lock 11
+ai2_spawn OutroTCTF2
+chr_changeteam OutroTCTF2 TCTF
+ai2_spawn Start_Lite_1
+ai2_spawn IntroTCTF02
+chr_teleport OutroTCTF2 1010
+chr_teleport Start_Lite_1 1010
+chr_teleport IntroTCTF02 1010
+ai2_lookatme OutroTCTF2
+ai2_lookatme Start_Lite_1
+ai2_lookatme IntroTCTF02
+env_show 271 1
+env_show 272 1
+env_shade 271 272 .4 .4 .2
+objective_set 1 silent
+target_set 1261 30
+sleep 1
+sound_music_start mus_space01 0.8
+ai2_attack OutroTCTF2 Konoko
+ai2_attack Start_Lite_1 Konoko
+ai2_attack IntroTCTF02 Konoko
+fork wait1
+fork wait2
+fork wait3
+}
+
+func void wait1(void)
+{
+chr_wait_health OutroTCTF2 0
+check_counter
+}
+
+func void wait2(void)
+{
+chr_wait_health Start_Lite_1 0
+check_counter
+}
+
+func void wait3(void)
+{
+chr_wait_health IntroTCTF02 0
+check_counter
+}
+
+func void check_counter(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 3)
+	{
+	trigvolume_enable trigger_volume_02 1
+	particle lock99_locklight02 do start
+	door_unlock 11
+	var_counter = 0
+	music_stop
+	}
+}
+
+#tv1 - in front of door 11 (func: Setup_Pod1); I've disabled it
+
+##########
+### SP2 ###
+##########
+
+#tv54 - after door 11
+func void autosave_1(string player_name)
+{
+if(save_point eq 2)
+	{
+	objective_set 1 silent
+	target_set 1261 30
+	}
+else save_game 2 autosave
+ai2_spawn Pod1_Scientist_1
+ai2_spawn Pod1_Scientist_2
+ai2_spawn Pod1_TCL_1
+ai2_spawn Pod1_TCL_2
+ai2_spawn Pod1_TCL_3
+particle lab1 do start
+particle lab2 do start
+particle lab3 do start
+}
+
+func void patrolscript0001(string ai_name)
+{
+playback_block Pod1_TCL_1 alarm1 interp 20
+}
+
+func void patrolscript0002(string ai_name)
+{
+playback_block Pod1_TCL_2 alarm2 interp 20
+}
+
+#tv20 - in front of door 15 (func: lab1_stop); I've disabled it
+#tv19 - after door 15 (func: lab1_start); I've disabled it
+#tv28 - in front of door 14 (func: lab1_stop); I've disabled it
+#tv27 - after door 14 (func: lab1_start); I've disabled it
+#tv31 - in front of door 19 (func: lab1_start); I've disabled it
+#tv32 - after door 19 (func: lab1_stop); I've disabled it
+#tv24 - in front of door 18 (func: lab1_start); I've disabled it
+#tv33 - after door 18 (func: lab1_stop); I've disabled it
+#tv34 - in front of door 16 (enter func: lab1_stop, leave func: lab2_start); I've disabled it
+#tv25 - after door 16 (func: lab1_start); I've disabled it
+#tv23 - in front of door 17 (enter func: lab1_stop, leave func: lab2_start); I've disabled it
+#tv22 - after door 17 (func: lab1_start); I've disabled it
+#tv26 - in front of door 13 (func: lab1_start); I've disabled it
+#tv29 - after door 13 (func: lab1_stop); I've disabled it
+#tv21 - in front of door 12 (func: lab1_start); I've disabled it
+#tv30 - after door 12 (func: lab1_stop); I've disabled it
+
+#console1
+func void Pod1_UnlockDoors(string ai_name)
+{
+particle lock1_locklight01 do start
+door_unlock 20
+door_unlock 21
+door_unlock 22
+door_unlock 23
+particle lock99_locklight02 do stop
+door_lock 11
+particle alarm1_emlight01 do stop
+console_reset 10
+}
+
+#hit func of Pod1_TCL_1
+func void Pod1_RTAlarm_A(string ai_name)
+{
+ai2_doalarm Pod1_TCL_1 10
+}
+
+#hit func of Pod1_TCL_2
+func void Pod1_RTAlarm_B(string ai_name)
+{
+ai2_doalarm Pod1_TCL_2 10
+}
+
+#console10
+func void Pod1_Alarm(string ai_name)
+{
+door_unlock 11
+particle lock99_locklight02 do start
+sleep 180
+ai2_spawn Pod1_BOL_Alarm_1
+ai2_spawn Pod1_BOL_Alarm_2
+ai2_spawn pod1_a_1
+ai2_spawn pod1_a_2
+ai2_setalert Pod1_TCL_1 combat
+ai2_setalert Pod1_TCL_2 combat 
+ai2_setalert Pod1_TCL_3 combat
+ai2_setalert Pod1_BOL_Alarm_1 combat 
+ai2_setalert Pod1_BOL_Alarm_2 combat
+ai2_dopath Pod1_TCL_1 Pod1_Final_Guard_A
+ai2_dopath Pod1_TCL_2 Pod1_Final_Guard_B
+ai2_dopath Pod1_TCL_3 Pod1_Final_Guard_C
+ai2_dopath Pod1_Scientist_1 Pod1_Final_Sci_A
+ai2_dopath Pod1_Scientist_2 Pod1_Final_Sci_B
+ai2_setjobstate Pod1_TCL_1
+ai2_setjobstate Pod1_TCL_2
+ai2_setjobstate Pod1_TCL_3
+ai2_setjobstate Pod1_Scientist_1
+ai2_setjobstate Pod1_Scientist_2
+ai2_tripalarm 11 Konoko
+particle lock1_locklight01 do stop
+door_lock 20
+door_lock 21
+door_lock 22
+door_lock 23
+particle alarm1_emlight01 do start
+console_reset 1
+Pod_Alarm_Sound
+}
+
+#for the Pod_Alarm_Sound func see pod2 section
+
+#tv2 - huge box in front of door 20, door 21, door 22 and door 23
+func void Pod2_Setup(string ai_name)
+{
+trig_activate 2
+ai2_spawn Pod2_TCL_1
+ai2_spawn Pod2_TCL_2
+ai2_spawn Pod2_Sci_1
+particle lock2_locklight01 do stop
+}
+
+func void patrolscript0003(string ai_name)
+{
+playback_block Pod2_TCL_1 pod2alarm1 interp 20
+}
+
+func void patrolscript0004(string ai_name)
+{
+playback_block Pod2_TCL_2 pod2alarm2 interp 20
+}
+
+#tv36 - in front of door 27 (enter func: lab2_start, leave func: lab3_stop); I've disabled it
+#tv40 - after of door 27 (enter func: lab2_stop, leave func: lab3_start); I've disabled it
+#tv39 - in front of door 26 (enter func: lab2_start, leave func: lab3_stop); I've disabled it
+#tv35 - after of door 26 (enter func: lab2_stop, leave func: lab3_start); I've disabled it
+#tv38 - in front of door 25 (enter func: lab2_start, leave func: lab3_stop); I've disabled it
+#tv41 - after of door 25 (enter func: lab2_stop, leave func: lab3_start); I've disabled it
+#tv37 - in front of door 24 (enter func: lab2_start, leave func: lab3_stop); I've disabled it
+#tv42 - after of door 24 (enter func: lab2_stop, leave func: lab3_start); I've disabled it
+
+#console2
+func void Pod2_UnlockDoors(string ai_name)
+{
+door_unlock 28
+door_unlock 29
+door_unlock 30
+door_unlock 31
+door_lock 11
+particle lock99_locklight02 do stop
+particle alarm2_emlight01 do stop
+particle lock2_locklight01 do start
+console_reset 11
+}
+
+#hit func of Pod2_TCL_1
+func void Pod2_RTAlarm_A(string ai_name)
+{
+ai2_doalarm Pod2_TCL_1 11
+}
+
+#hit func of Pod2_TCL_2
+func void Pod2_RTAlarm_B(string ai_name)
+{
+ai2_doalarm Pod2_TCL_2 11
+}
+
+#console11
+func void Pod2_Alarm(string ai_name)
+{
+door_unlock 11
+particle lock99_locklight02 do start
+sleep 180
+ai2_spawn Pod2_BOL_Alarm_1
+ai2_spawn pod2_a_1
+ai2_spawn pod2_a_2
+ai2_setalert Pod2_TCL_1 high 
+ai2_setalert Pod2_TCL_2 high 
+ai2_setalert Pod2_BOS_1 high 
+ai2_dopath Pod2_TCL_1 Pod2_End_TCL_1
+ai2_dopath Pod2_TCL_2 Pod2_End_TCL_2
+ai2_dopath Pod2_BOS_1 Pod2_End_BOS_1
+ai2_dopath Pod2_Sci_1 Pod2_End_Sci_1
+ai2_setjobstate Pod2_TCL_1
+ai2_setjobstate Pod2_TCL_2
+ai2_setjobstate Pod2_BOS_1
+ai2_setjobstate Pod2_Sci_1
+ai2_tripalarm 12 Konoko
+particle lock2_locklight01 do stop
+particle alarm2_emlight01 do start
+door_lock 28
+door_lock 29
+door_lock 30
+door_lock 31
+console_reset 2
+Pod_Alarm_Sound
+}
+
+func void Pod_Alarm_Sound(void)
+{
+sound_ambient_start alarm_loop
+sleep 900
+sound_ambient_stop alarm_loop
+}
+
+#tv3 - huge box in front of door 28, door 29, door 30 and door 31
+func void Pod3_Setup(string ai_name)
+{
+ai2_spawn Pod3_BOS_1
+ai2_spawn Pod3_BOS_2
+ai2_spawn Pod3_BOL_1
+trigvolume_enable Kerr_trig 1
+}
+
+#tv44 - in front of door 35 (func: lab3_start); I've disabled it
+#tv46 - after of door 35 (enter func: lab3_stop); I've disabled it
+#tv48 - in front of door 34 (func: lab3_start); I've disabled it
+#tv47 - after of door 34 (enter func: lab3_stop); I've disabled it
+#tv50 - in front of door 33 (func: lab3_start); I've disabled it
+#tv45 - after of door 33 (enter func: lab3_stop); I've disabled it
+#tv49 - in front of door 32 (func: lab3_start); I've disabled it
+#tv43 - after of door 32 (enter func: lab3_stop); I've disabled it
+#tv9 - huge box from after door 33 and door 34 to the end of the room, where you find Kerr (no funcs); not used
+#tv75 - in front of door 59 (func KerrSpawn); I've disabled it
+
+#tv67 - complete room after door 59
+func void Kerr(void)
+{
+trigvolume_enable Kerr_trig 0
+if(save_point eq 3)
+	{
+	particle lab3 do start
+	load_s3
+	}
+else console_activate 13
+}
+
+func void patrolscript0009(string ai_name)
+{
+patrolscript0010
+}
+
+func void patrolscript0010 (string ai_name)
+{
+particle lock99_locklight02 do start
+door_unlock 11
+sleep 540
+particle lock99_locklight02 do stop
+door_lock 11
+}
+
+##########
+### SP3 ###
+##########
+
+#console13
+func void Kerr_Console(string ai_name)
+{
+give_powerup hypo 2
+if(save_point ne 3) save_game 3 autosave
+trig_deactivate 2
+load_s3
+particle lock1_locklight01 do stop
+particle lock2_locklight01 do stop
+door_lock 28
+door_lock 29
+door_lock 30
+door_lock 31
+particle lab1 do stop
+particle lab2 do stop
+}
+
+func void load_s3(void)
+{
+particle lock4_locklight02 do start
+door_unlock 58
+objective_set 2 silent
+target_set 366 30
+}
+
+#tv4 - on the gangway in front of door 58
+func void Setup_Lab(string ai_name)
+{
+ai2_spawn CS_ScanOps01
+ai2_spawn LabHall_BOL_1
+ai2_spawn LabHall_BOL_2
+ai2_spawn LabHall_BOL_3
+ai2_spawn LabHall_BOL_4
+ai2_spawn LabHall_BOL_5
+ai2_spawn Hall_TCS_33
+ai2_spawn Lab1_Sci_1
+ai2_spawn Lab1_Sci_2
+ai2_spawn Lab2_Sci_1
+ai2_spawn Lab2_Sci_2
+ai2_spawn Lab3_Sci_1
+ai2_spawn Lab3_Sci_2
+particle part1 do start
+particle part2 do start
+}
+
+#tv52 - huge box after door 58 from the wall to the stairs; 1st and 2nd floor (enter func: part1_begin, leave func: part1_stop); I'vedisabled it
+#tv51 - after tv52 (enter func: part2_start, leave func: part2_stop); I'vedisabled it
+#tv14 - in front of door 6 and door 7 (func: spawn_kerr); I've disabled it
+#tv71 - in front of door 7 (no func); I've disabled it
+#tv73 - in front of door 7 (func: play_vat_monologue); I've disabled it
+#tv69 - in front of door 6 (no func); I've disabled it
+#tv74 - in front of door 6 (func: play_vat_monologue); I've disabled it
+#tv68 - complete scan lab (no func); I've disabled it
+
+#console5
+func void Lab_Console_3(string ai_name)
+{
+ai2_spawn lab_BOS_3
+ai2_tripalarm 1 Konoko
+particle lock5c_locklight01 do start
+particle labalarm3 do start
+door_check
+}
+
+#console4
+func void Lab_Console_2(string ai_name)
+{
+ai2_spawn lab_BOS_2
+ai2_tripalarm 1 Konoko
+particle lock5b_locklight01 do start
+particle labalarm2 do start
+door_check
+}
+
+#console3
+func void Lab_Console_1(string ai_name)
+{
+ai2_spawn lab_BOS_1
+ai2_tripalarm 1 Konoko
+particle lock5a_locklight01 do start
+particle labalarm1 do start
+door_check
+}
+
+func void door_check(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 1)
+	{
+	particle lock4_locklight02 do stop
+	door_lock 58
+	target_set 1009 30
+	particle lab3 do stop
+	}
+if(var_counter eq 3)
+	{
+	door_unlock 6
+	door_unlock 7
+	var_counter = 0
+	}
+}
+
+##########
+### SP4 ###
+##########
+
+#tv11 - complete scan lab
+func void scanner_start(void)
+{
+trigvolume_enable trigger_volume_13 0
+if(save_point eq 4)
+	{
+	ai2_spawn CS_ScanOps01
+	particle lock5a_locklight01 do start
+	particle lock5b_locklight01 do start
+	particle lock5c_locklight01 do start
+	door_unlock 6
+	door_unlock 7
+	console_deactivate 3
+	console_deactivate 4
+	console_deactivate 5
+	particle part1 do start
+	particle part2 do start
+	}
+else save_game 4 autosave
+objective_set 3 silent
+target_set 346 30
+sleep 1
+sound_music_start mus_xtr1 0.7
+}
+
+#lose func of CS_ScanOps01
+func void play_vat_monologue(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 1) sound_dialog_play c13_66_01konoko
+}
+
+#console14
+func void Lab_Unlock_Door_5(string ai_name)
+{
+particle lock6_locklight02 do start
+door_unlock 1
+trigvolume_enable chase_trigger 1
+trigvolume_enable Setup_Security_Trig 1
+ai2_spawn Scan_BOS_1
+ai2_spawn Scan_BOS_2
+ai2_spawn Scan_BOS_3
+ai2_spawn Scan_BOS_4
+chr_teleport LabHall_BOL_5 272
+chr_teleport Hall_TCS_33 7018
+ai2_forget LabHall_BOL_5
+ai2_forget Hall_TCS_33
+ai2_dopath LabHall_BOL_1 Scan_BOL_1
+ai2_dopath LabHall_BOL_2 Scan_BOL_2
+ai2_dopath LabHall_BOL_3 Scan_BOL_3
+ai2_dopath LabHall_BOL_4 Scan_BOL_4
+ai2_dopath LabHall_BOL_5 Scan_BOL_5
+ai2_dopath Hall_TCS_33 Scan_Hall_TCS_33
+ai2_setjobstate LabHall_BOL_1
+ai2_setjobstate LabHall_BOL_2
+ai2_setjobstate LabHall_BOL_3
+ai2_setjobstate LabHall_BOL_4
+ai2_setjobstate Hall_TCS_33
+fork get_her
+}
+
+func void get_her(string ai_name)
+{
+sleep 1800
+ai2_tripalarm 5 Konoko
+ai2_dopath LabHall_BOL_1 get_her_1
+ai2_dopath LabHall_BOL_2 get_her_2
+ai2_setjobstate LabHall_BOL_1
+ai2_setjobstate LabHall_BOL_2
+sleep 1800
+ai2_tripalarm 7 Konoko
+ai2_dopath LabHall_BOL_3 Scan_BOL_3
+ai2_dopath LabHall_BOL_4 Scan_BOL_4
+ai2_setjobstate LabHall_BOL_3
+ai2_setjobstate LabHall_BOL_4
+sleep 1800
+ai2_tripalarm 9 Konoko
+ai2_dopath Scan_BOS_1 get_her_1
+ai2_dopath Scan_BOS_2 get_her_2
+ai2_setjobstate Scan_BOS_1
+ai2_setjobstate Scan_BOS_2
+sleep 1800
+ai2_tripalarm 11 Konoko
+ai2_dopath Scan_BOS_3 get_her_3
+ai2_dopath Scan_BOS_4 get_her_4
+ai2_setjobstate Scan_BOS_3
+ai2_setjobstate Scan_BOS_4
+}
+
+#tv80 - in some distance after door 3
+func void chase_after_scan(string ai_name)
+{
+play_vat_monologue
+ai2_dopath Scan_BOS_3 chase_after_3
+ai2_dopath Scan_BOS_4 chase_after_4
+ai2_setjobstate Scan_BOS_3
+ai2_setjobstate Scan_BOS_4
+ai2_tripalarm 11 Konoko
+sleep 1200
+ai2_dopath Scan_BOS_1 chase_after_1
+ai2_dopath Scan_BOS_2 chase_after_2
+ai2_setjobstate Scan_BOS_1
+ai2_setjobstate Scan_BOS_2
+ai2_tripalarm 9 Konoko
+}
+
+#tv12 - in front of door 1
+func void Setup_Security(string ai_name)
+{
+trigvolume_enable Ambush_Trigger_1 1
+ai2_spawn Sec_BOL_1
+ai2_spawn Sec_BOS_1
+ai2_spawn Sec_BOS_2
+trig_activate 3
+trig_activate 4
+music_stop
+}
+
+#console86
+func void Unlock_Door_7(string ai_name)
+{
+particle lock7_locklight02 do start
+door_unlock 54
+target_set 360 30
+var_counter = 0
+}
+
+#tv5 - in the middle between door 54 and door 36
+func void Sec_Ambush_1(string ai_name)
+{
+fork remove_ai
+trig_deactivate 3
+trig_deactivate 4
+turret_deactivate 2
+turret_deactivate 3
+particle lock8_locklight02 do start
+door_unlock 36
+door_unlock 37
+particle lock7_locklight02 do stop
+door_lock 54
+ai2_spawn Sec_Ambush_BOS_1
+ai2_spawn Sec_Ambush_BOL_1
+ai2_attack Sec_Ambush_BOS_1 Konoko
+ai2_attack Sec_Ambush_BOL_1 Konoko
+sleep 120
+particle lock8_locklight02 do stop
+door_lock 36
+particle part1 do stop
+particle part2 do stop
+}
+
+#tv72 - in front of door 36 (func: closethedoor); I've disabled it
+
+#tv6 - in front of tv72
+func void Setup_Final(string ai_name)
+{
+ai2_spawn Final_BOS_1
+ai2_spawn Final_BOL_1
+ai2_spawn Final_Thug_1
+ai2_spawn Final_Thug_2
+}
+
+#lose func of Sec_Ambush_BOS_1
+func void nextwave_1(string ai_name)
+{
+nextwave_2
+}
+
+#lose func of Sec_Ambush_BOS_2
+func void nextwave_2(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2)
+	{
+	particle vat1 do start
+	particle vat2 do start
+	particle vat3 do start
+	particle vat4 do start
+	particle lock8_locklight02 do start
+	door_unlock 36
+	door_unlock 37
+	ai2_spawn Sec_Ambush_BOS_2
+	ai2_spawn Sec_Ambush_BOL_2
+	ai2_attack Sec_Ambush_BOS_2 Konoko
+	ai2_attack Sec_Ambush_BOL_2 Konoko
+	var_counter = 0
+	}
+}
+
+#tv13 - in the middle of the next room, from left to right
+func void set_objective_4(string chr_index)
+{
+objective_set 4 silent
+target_set 222 30
+}
+
+#tv57 - in some distance in front of door 37 (func: vat1_start); I've disabled it
+
+#tv56 - after door 37
+func void BeginVat(void)
+{
+sound_dialog_play c13_66_02konoko
+ai2_attack Final_BOL_1 Konoko
+}
+
+#tv79 - in front of tv58
+func void mid_guards(string ai_name)
+{
+ai2_spawn Final_BOL_2
+ai2_spawn Final_Thug_9
+ai2_attack Final_BOL_2 Konoko
+}
+
+#tv58 - in front of tv62 (func: vat2_stop); I've disabled it
+#tv62 - in front of door 38 and door 39 (func: vat2_start); I've disabled it
+
+#tv18 - complete room, where you find console7
+func void CraneTalk(void)
+{
+sound_dialog_play c13_66_03konoko
+}
+
+#console7 and console8
+func void FTS(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2) console_activate 9
+}
+
+#tv60 - in front of door 42 and door 43 (func: vat1_start); I've disabled it
+#tv59 - after door 42 and door 43 (func: vat1_stop); I've disabled it
+#tv61 - in front of tv64 (func: vat3_stop); I've disabled it
+#tv64 - in front of door 44 and door 45 (func: vat3_start); I've disabled it
+
+#tv76 - in front of tv63
+func void end_guards(string ai_name)
+{
+ai2_spawn end_guard_1
+ai2_spawn end_guard_2
+ai2_spawn Final_Thug_10
+}
+
+#tv63 - in front of door 48 and door 49 (func: vat2_start); I've disabled it
+#tv65 - after door 48 and door 49 (func: vat2_stop); I've disabled it
+#tv77 - complete last platform (no func); I've disabled it
+#tv78 - complete last platform (func: check_outro); I've disabled it
+#tv7 - complete last platform (no func); I've disabled it
+#tv8 - after door 51 (no func); I've disabled it
+#tv18 - at the end of the last platform, in front of the crusher (func: vat3_start); I've disabled it
+#tv66 - after tv18 (func: vat3_stop); I've disabled it
+
+#console9
+func void final_check_for_crane(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+### ACID FUNCTIONS ###
+
+#tv10 - 1st acid basin
+func void Acid01(string character)
+{
+var_counter2 = 1
+acid(character)
+}
+
+#tv15 - 2nd acid basin
+func void Acid02(string character)
+{
+var_counter2 = 2
+acid(character)
+}
+
+#tv16 - 3rd acid basin
+func void Acid03(string character)
+{
+var_counter2 = 3
+acid(character)
+}
+
+#tv53 - 4th acid basin
+func void acid04(string character)
+{
+var_counter2 = 4
+acid(character)
+}
+
+func void acid(string character)
+{
+if(chr_is_player(character) eq 1)
+	{
+	chr_animate(character, KONOKOacid);
+	input 0
+	if(var_counter2 eq 1) cm_interpolate AcidCam01 500
+	if(var_counter2 eq 2) cm_interpolate AcidCam01 400
+	if(var_counter2 eq 3) cm_interpolate AcidCam01 200
+	if(var_counter2 eq 4) cm_interpolate AcidCam01 0
+	sleep 5
+	chr_invincible(character, 1);
+	if(var_counter2 eq 1) sleep 525
+	if(var_counter2 eq 2) sleep 430
+	if(var_counter2 eq 3) sleep 230
+	if(var_counter2 eq 4) sleep 40
+	trigvolume_enable LastVat 0
+	chr_animate(character, KONOKOlev14_grinder);
+	chr_envanim(character, GrinderKonBox01, norotation);
+	sleep 60
+	sound_ambient_start c13_47_11_bonecrunch
+	sleep 10
+	sound_impulse_play konoko_gruesome_death
+	sleep 75
+	}
+else
+	{
+	chr_animate(character, KONOKOacid);
+	sleep 10
+	}
+chr_set_health(character, 0);
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level_14a(void)
+{
+text_console level_14a
+console_reset 12
+}
+
+func void level_14b(void)
+{
+text_console level_14b
+console_reset 6
+}
Index: /nikanabo/current/bsl/onilight/IGMD/power/power.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/power/power.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/power/power.bsl	(revision 185)
@@ -0,0 +1,721 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+var int var_counter3 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game	
+if(save_point eq 3) fork load_s3
+if(save_point eq 4) restore_game
+if(save_point eq 5) fork load_s5
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable trigger_volume_08_copy 0
+trigvolume_enable trigger_volume_09 0
+trigvolume_enable trigger_volume_10_copy 0
+trigvolume_enable trigger_volume_10_copy_copy 0
+trigvolume_enable trigger_volume_11_copy 0
+trigvolume_enable trigger_volume_11_copy_copy 0
+trigvolume_enable trigger_volume_14 0
+#used
+env_show 802 0
+env_show 822 0
+particle power1 do start
+particle power2 do start
+trigvolume_enable trigger_volume_02 0
+trigvolume_enable trigger_volume_06 0
+trigvolume_enable trigger_volume_12 0
+trigvolume_enable trigger_volume_13 0
+trigvolume_enable trigger_volume_40 0
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+if(save_point eq 5) save_game 5 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_main01
+sound_music_stop mus_sad1
+sound_music_stop mus_space01
+sound_music_stop mus_asian
+sound_music_stop mus_fiteb
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+playback 0 IntroKonokoSet01
+ai2_spawn A1_intro01
+ai2_spawn A1_intro02
+ai2_spawn A1_bluedoorstriker
+objective_set 1 silent
+target_set 5007 30
+sleep 1
+sound_music_start mus_main01 .75
+}
+
+#lose func of A1_intro01 and A1_intro02
+func void die_for_art(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2) music_stop
+}
+
+#console1
+func void target02(string ai_name)
+{
+particle blue_locklight01 do start
+particle b2_locklight01 do start
+target_set 2001 30
+trigvolume_enable trigger_volume_12 1
+music_stop
+}
+
+#tv12 - in front of door 30
+func void target03(string ai_name)
+{
+ai2_spawn A1_s_red01
+ai2_spawn A1_s_red02
+target_set 5007 30
+}
+
+#called up, when A1_s_red02 gives you the hypo
+func void change_patrol(string ai_name)
+{
+ai2_dopath A1_s_red02 patrol_45
+ai2_setjobstate A1_s_red02
+}
+
+#tv4 - in front of door 31
+func void tv04(string ai_name)
+{
+ai2_spawn A2_s_tank01
+ai2_spawn A2_s_blue13
+ai2_spawn A2_s_blue01
+ai2_spawn A2_s_blue03
+ai2_spawn A2_s_red03
+ai2_spawn char_1
+ai2_spawn A2_s_tank02
+}
+
+#tv3 - in front of door 33
+func void tv03(string ai_name)
+{
+ai2_spawn A2_s_blue09
+}
+
+#tv34 - at the beginning of the first pillar, which is nearby to the room with console3
+func void tv34(string ai_name)
+{
+ai2_spawn A2_s_red04 
+}
+
+#console3
+func void ontv02(string ai_name)
+{
+trigvolume_enable trigger_volume_02 1
+particle el_red1 kill
+particle el_1_locklight01 do start
+target_set 108 30
+}
+
+#called up, when A2_s_red04 gives you the w4_psm
+func void spawn_sniper1(string ai_name)
+{
+ai2_spawn sniper1
+ai2_makeignoreplayer sniper1 1
+playback_block sniper1 sniper1_jump
+ai2_makeignoreplayer sniper1 0
+ai2_dopath sniper1 patrol_52
+ai2_setjobstate sniper1
+sleep 600
+ai2_makeignoreplayer sniper1 1
+ai2_dopath sniper1 patrol_53
+ai2_setjobstate sniper1
+}
+
+#hit func of sniper1
+func void hurt_sniper1(string ai_name)
+{
+ai2_makeignoreplayer sniper1 1
+ai2_dopath sniper1 patrol_53
+ai2_setjobstate sniper1
+}
+
+#in some distance after the room with console3, in front of the elevator
+func void tv33(string ai_name)
+{
+ai2_makeignoreplayer A2_s_red04 1
+ai2_dopath A2_s_red04 patrol_54
+ai2_setjobstate A2_s_red04
+}
+
+#tv2 - flat box on the elevator platform
+func void tv02(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+fork remove_ai
+obj_kill 801
+playback 0 Elev1KonokoSet
+load_s2
+fade_in 30
+var_counter = 0
+}
+
+func void load_s2(void)
+{
+env_show 802 1
+ai2_spawn B1_s_blue05
+ai2_spawn B1_s_green01
+ai2_spawn new_dummy1
+ai2_spawn C1_blue22
+ai2_spawn C2_blue25
+ai2_dopath B1_s_blue05 patrol_08_blue05b
+ai2_setjobstate B1_s_blue05
+chr_teleport B1_s_blue05 1046
+objective_set 1 silent
+target_set 1083 30
+sleep 1
+sound_music_start mus_sad1 0.3
+sound_music_volume mus_sad1 0.8 2
+}
+
+##########
+### SP2 ###
+##########
+
+#tv35 - after the elevator platform
+func void s2(string ai_name)
+{
+if(save_point eq 2)
+	{
+	fork remove_ai
+	load_s2
+	}
+else save_game 2 autosave
+}
+
+#console12
+func void target06(string ai_name)
+{
+particle green_locklight01 do start
+target_set 2005 30
+trigvolume_enable trigger_volume_13 1
+}
+
+#tv13 - in front of door 34
+func void target05(string ai_name)
+{
+ai2_spawn B1_s_Red01
+target_set 133 30
+music_stop
+}
+
+#tv1 - in front of door 35
+func void tv01(string ai_name)
+{
+ai2_spawn whiteneut
+ai2_spawn C1_blue22
+ai2_spawn B2_s_blue06
+ai2_spawn B2_s_blue07
+ai2_spawn B2_s_blue08
+ai2_spawn B2_s_tank04
+}
+
+#console4
+func void target08(string ai_name)
+{
+particle white_locklight01 do start
+target_set 3001 30
+}
+
+#tv14 - in front of door 36 (the same func as tv13, so I've disabled it)
+
+#tv5 - in front of door 37
+func void tv05(string ai_name)
+{
+ai2_spawn B3_s_green02
+ai2_spawn C1_blue20
+}
+
+#tv15 - at the end of the both ways after door 37
+func void target10(string ai_name)
+{
+target_set 5008 30
+}
+
+#tv16 - at the end of the passageway to the other side
+func void target11(string ai_name)
+{
+target_set 5009 30
+}
+
+#tv42 - huge box around the complete ways to the 2nd elevator (only used as a chara counter, see next funcs)
+
+#lose func of C2_blue25 and respawn1
+func void script_respawn1(void)
+{
+if(trigvolume_count(42) eq 0)
+	{
+	var_counter2 = var_counter2 + 1
+	if(var_counter2 eq 1)
+		{
+		ai2_spawn respawn1
+		chr_giveweapon respawn1 w7_scc
+		}
+	if(var_counter2 eq 2)
+		{
+		ai2_spawn respawn1
+		chr_giveweapon respawn1 w3_phr
+		ai2_dopath patrol_08_blue05
+		ai2_setjobstate respawn1
+		}
+	if(var_counter2 eq 3)
+		{
+		ai2_spawn respawn1
+		chr_giveweapon respawn1 w2_sap
+		}
+	}
+}
+
+#lose func of C1_blue20 and respawn2
+func void script_respawn2(void)
+{
+if(trigvolume_count(42) eq 0)
+	{
+	var_counter3 = var_counter3 + 1
+	if(var_counter3 eq 1)
+		{
+		ai2_spawn respawn2
+		chr_giveweapon respawn2 w3_phr
+		}
+	if(var_counter3 eq 2)
+		{
+		ai2_spawn respawn2
+		chr_giveweapon respawn2 w2_sap
+		ai2_dopath patrol_19_blue20b
+		ai2_setjobstate respawn2
+		}
+	if(var_counter3 eq 3)
+		{
+		ai2_spawn respawn2
+		chr_giveweapon respawn2 w2_sap
+		}
+	}
+}
+
+#lose func of C1_blue22
+func void script_respawn3(void)
+{
+if(trigvolume_count(42) eq 0) ai2_spawn C1_red21
+}
+
+#tv37 - box around the place, where you find the 2nd mercury bow
+func void t37(string ai_name)
+{
+ai2_spawn new_1
+ai2_spawn new_2
+}
+
+#tv38 - about in the middle
+func void t38(string ai_name)
+{
+ai2_spawn new_3
+ai2_spawn new_4
+}
+
+#console6
+func void ontv06(string ai_name)
+{
+trigvolume_enable trigger_volume_06 1
+particle el_2_locklight01 do start
+target_set 119 30
+}
+
+##########
+### SP3 ###
+##########
+
+#tv6 -  flat box on the elevator platform
+func void tv06(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+fork remove_ai
+load_s3
+chr_teleport 0 120
+chr_facetoflag 0 120
+fade_in 30
+if(save_point ne 3) save_game 3 autosave
+}
+
+func void load_s3(void)
+{
+if(save_point eq 3)
+	{
+	fork remove_ai
+	restore_game
+	}
+obj_kill 821
+env_show 822 1
+ai2_spawn D1_neut05
+objective_set 2 silent
+target_set 128 30
+sleep 1
+sound_music_start mus_space01 0.75
+}
+
+#console7
+func void target14(string ai_name)
+{
+particle red_locklight01 do start
+target_set 2085 30
+}
+
+#tv20 - in front of door 38
+func void tv25(string ai_name)
+{
+ai2_spawn D1_red30
+ai2_spawn D1_neut02
+ai2_spawn D2_blue60
+ai2_spawn D1_neut10
+ai2_spawn new_5
+ai2_spawn D2_blue61
+music_stop
+}
+
+#called up, after you have talked to the guy
+func void power_deactivate(void)
+{	
+ai2_doalarm D1_neut02 9
+ai2_dopath D1_neut02 patrol_80
+ai2_setjobstate D1_neut02
+}
+
+#console9
+func void power_lull_1(string ai_name)
+{	
+music_stop
+ai2_neutralbehavior D1_neut02 none
+target_set 125 30
+sound_music_start mus_asian .75
+particle power1 do stop
+timer_start 20 power_lull_1b
+}
+
+func void power_lull_1b(void)
+{	
+music_stop
+particle power1 do start
+sleep 300
+console_reset 9
+}
+
+#tv17 - at the end of the pipe
+func void target13(string ai_name)
+{
+target_set 128 30
+}
+
+##########
+### SP4 ###
+##########
+
+#tv30 - in front of door 23
+func void s4(string ai_name)
+{
+if(save_point eq 4)
+	{
+	fork remove_ai
+	load_s4
+	}
+else save_game 4 autosave
+}
+
+func void load_s4(void)
+{
+particle red_locklight01 do start
+ai2_spawn D2_blue61
+ai2_spawn D2_blue60
+ai2_spawn new_5
+ai2_spawn D1_neut10
+trigvolume_enable trigger_volume_17 0
+trigvolume_enable trigger_volume_25 0
+trigvolume_enable trigger_volume_30 0
+objective_set 2 silent
+target_set 128 30
+}
+
+#tv39 - box around the place, where D1_neut10 gives you a hypo
+func void t39(string ai_name)
+{
+trigvolume_enable trigger_volume_40 1
+}
+
+#tv40 - in the middle between tv39 and door 22
+func void t40(string ai_name)
+{
+ai2_spawn new_6
+ai2_spawn new_7
+}
+
+#console10
+func void target17(string ai_name)
+{
+particle yellow_locklight01 do start
+target_set 3094 30
+}
+
+#tv41 - in front of door 24
+func void spawn2tube(string ai_name)
+{
+ai2_spawn D2_red62
+ai2_spawn D2_tank63
+ai2_spawn new_8
+ai2_spawn sci_maniac
+}
+
+#console11
+func void power_lull_2(string ai_name)
+{	
+sound_music_start mus_asian .75
+particle power2 do stop
+ai2_spawn new_10
+ai2_spawn new_67
+ai2_spawn D3_tank65
+timer_start 20 power_lull_2b
+}
+
+func void power_lull_2b(void)
+{	
+music_stop
+particle power2 do start
+sleep 300
+console_reset 11
+}
+
+#tv19 - on the pipe, in some distance in front of the platform with console13
+func void target19(string ai_name)
+{
+target_set 5010 30
+}
+
+### POSSIBILITY 1: YOU RUN TO THE END OF THE PIPE ###
+
+#tv36 - box around the place, where you find the w5_sbg
+func void t36(string ai_name)
+{
+ai2_spawn sbg_1
+ai2_spawn sbg_2
+ai2_spawn sbg_3
+}
+
+### POSSIBILITY 2: YOU JUMP TO THE PLATFORM WITH CONSOLE 13 ###
+
+#tv7 - at the beginning of the staircase
+func void tv07(string ai_name)
+{
+chr_delete new_1
+chr_delete new_2
+chr_delete new_3
+chr_delete new_4
+chr_delete new_5
+chr_delete new_6
+chr_delete new_7
+chr_delete new_8
+chr_delete sci_maniac
+chr_delete D1_blue50
+chr_delete D2_blue60
+chr_delete D2_blue61
+chr_delete D1_neut02
+chr_delete D1_neut05
+chr_delete D1_neut10
+chr_delete D1_red30
+chr_delete D2_red62
+chr_delete D3_red66
+chr_delete D2_tank63
+chr_delete D3_tank65
+ai2_spawn F_friend
+ai2_spawn F_blue73
+ai2_spawn F_blue1
+target_set 5006 30
+}
+
+##########
+### SP5 ###
+##########
+
+#console8
+func void unlock_bwhite(string ai_name)
+{
+if(save_point ne 5) save_game 5 autosave
+particle bwhite_locklight01 do start
+objective_set 3 silent
+}
+
+func void load_s5(void)
+{
+if(save_point eq 5)
+	{
+	fork remove_ai
+	restore_game
+	}
+particle bwhite_locklight01 do start
+door_unlock 4
+ai2_spawn F_blue1
+console_deactivate 8
+trigvolume_enable trigger_volume_07 0
+objective_set 3 silent
+target_set 5006 30
+var_counter = 1
+}
+
+#tv10 - in front of door 3
+func void tv10(string ai_name)
+{
+ai2_spawn F_blue69
+ai2_spawn F_blue2
+}
+
+#tv11 - in front of door 2
+func void tv11(string ai_name)
+{
+ai2_spawn F_tank70
+}
+
+#tv8 - in front of door 1
+func void tv08(string ai_name)
+{
+ai2_spawn end01
+ai2_spawn end02
+ai2_spawn end03
+sleep 60
+ai2_dopath F_tank70 patrol_5004
+ai2_setjobstate F_tank70
+ai2_dopath F_blue69 patrol_5005
+ai2_setjobstate F_blue69
+ai2_dopath F_blue2 patrol_5004
+ai2_setjobstate F_blue2
+ai2_dopath F_blue1 patrol_5006
+ai2_setjobstate F_blue1
+ai2_dopath F_blue73 patrol_5006
+ai2_setjobstate F_blue73
+ai2_attack F_tank70 char_0
+ai2_attack F_blue69 char_0
+ai2_attack F_blue2 char_0
+ai2_attack F_blue1 char_0
+ai2_attack F_blue73 char_0
+sound_music_start mus_fiteb .75
+}
+
+#tv29 - after door 1
+func void tv29(string ai_name)
+{
+sound_music_start mus_fiteb .75
+}
+
+#lose func of end01, end02, end03, F_blue1, F_blue2, F_blue69, F_blue73 and F_tank70 
+func check_death(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 8)
+	{
+	fade_out 0 0 0 30
+	sleep 30
+	win
+	}
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void console_pipe(void)
+{
+text_console level_9d
+console_reset 13
+}
+
+func void text9a(void)
+{
+text_console level_9a
+console_reset 2
+}
+
+func void text9b(void)
+{
+text_console level_9b
+console_reset 5
+}
+
+func void text9c(void)
+{
+text_console level_9c
+console_reset 14
+}
Index: /nikanabo/current/bsl/onilight/IGMD/power_II/power2.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/power_II/power2.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/power_II/power2.bsl	(revision 185)
@@ -0,0 +1,730 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) fork intro
+if(save_point eq 1) restore_game
+if(save_point eq 2) fork save_point_2
+if(save_point eq 3) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable crossfire 0
+trigvolume_enable open_ambush_1 0
+trigvolume_enable save2 0
+trigvolume_enable save_point3 0
+trigvolume_enable setobjective_4 0
+trigvolume_enable setobjective_5 0
+trigvolume_enable strikerguards 0
+trigvolume_enable room1_copy_copy 0
+trigvolume_enable room1_copy2 0
+trigvolume_enable room2 0
+trigvolume_enable room2_copy 0
+trigvolume_enable room2_stop 0
+trigvolume_enable room2_stop_copy2 0
+trigvolume_enable room2_stop_copy_copy 0
+trigvolume_enable room2_stop_copy 0
+trigvolume_enable room3_stop 0
+trigvolume_enable room3_stop_copy 0
+trigvolume_enable room3_particle_control 0
+trigvolume_enable room4_copy 0
+trigvolume_enable room4_copy_copy 0
+trigvolume_enable trigger_volume_07 0
+trigvolume_enable trigger_volume_11_copy 0
+trigvolume_enable trigger_volume_16_copy3 0
+trigvolume_enable trigger_volume_16_copy_copy2 0
+trigvolume_enable trigger_volume_16_copy2_copy2 0
+trigvolume_enable trigger_volume_16_copy_copy_copy2 0
+trigvolume_enable trigger_volume_16_copy2_copy_copy 0
+trigvolume_enable trigger_volume_16_copy_copy_copy_copy 0
+trigvolume_enable trigger_volume_36 0
+trigvolume_enable trigger_volume_39 0
+#used
+obj_create 81 82
+env_shade 777 777 .4 .4 .4
+env_show 778 0
+chr_delete ShinShin
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_trt
+sound_music_stop atm_cl09
+sound_music_stop atm_cl10
+sound_music_stop atm_cl11
+sound_music_stop atm_cl12
+sound_music_stop mus_amasian
+}
+
+#tv66, tv67 and tv68 - called up, if you fall from a pipe
+func void dont_even_try_it(string ai_name)
+{
+chr_set_health 0 0
+}
+
+##########
+### SP0 ###
+##########
+
+func void intro(void)
+{
+particle room1 do start
+particle room2 do start
+particle room3 do start
+ai2_spawn ambush_striker_10
+ai2_spawn ambush_striker_11
+playback 0 IntroKonoko01
+objective_set 1 silent
+sleep 1
+sound_music_start mus_trt
+}
+
+#tv1 - big long box around the railing and the beginning of the stairway
+func void p1(string ai_name)
+{
+music_stop
+sound_music_start atm_cl09 1.0
+ai2_spawn A1_sr01
+ai2_spawn A1_t02
+ai2_lookatme A1_sr01
+ai2_lookatme A1_t02
+sleep 120
+door_lock 1
+door_lock 2
+}
+
+#lose func of A1_t02
+func void backup_1(string ai_name)
+{
+ai2_spawn backup_striker1
+particle blast1_locklight01 do start
+door_unlock 1
+door_open 1
+}
+
+#lose func of A1_sr01
+func void backup_2(string ai_name)
+{
+ai2_spawn backup_striker2
+particle blast2_locklight01 do start
+door_unlock 2
+door_open 2
+}
+
+#tv41 - long box in middle of the 1st hall (proceed from the left to the right side); not used, or better: does not work
+
+#tv2 - after door 1 and door 2
+func void p2(string ai_name)
+{
+ai2_spawn A2_r03
+playback A2_r03 redjump
+ai2_lookatme A2_r03
+ai2_spawn aerial_red_2
+ai2_passive aerial_red_2 1
+playback aerial_red_2 redjump2
+ai2_passive aerial_red_2 0
+ai2_lookatme aerial_red_2
+ai2_spawn red_guard_1
+ai2_dopath A1_sr01 patrol_31
+ai2_dopath A1_t02 patrol_31
+ai2_setjobstate A1_sr01
+ai2_setjobstate A1_t02 patrol_31
+ai2_spawn ShinShin force
+playback ShinShin ShinShinSet
+ai2_setmovementmode ShinShin creep
+ai2_passive ShinShin 1
+ai2_makeblind ShinShin 1
+ai2_makedeaf ShinShin 1
+chr_lock_active ShinShin
+chr_unstoppable ShinShin 1
+chr_invincible ShinShin 1
+chr_nocollision ShinShin 1
+}
+
+#tv34 - complete volume of the 2nd hall - enter func
+func void t43(string ai_name)
+{
+var_counter = 1
+}
+
+#tv34 - complete volume of the 2nd hall - leave func
+func void t43b(string ai_name)
+{
+var_counter = 0
+}
+
+#tv63 - long box in middle of the 2nd hall (proceed from the left to the right side)
+func void come_to_me(string ai_name)
+{
+ai2_dopath ambush_striker1 come_to_me 1
+ai2_dopath ambush_striker2 come_to_me 1
+ai2_dopath A1_t02 come_to_me 1
+ai2_dopath A1_sr01 come_to_me 1
+}
+
+#tv65 - complete second half of the 2nd hall; only used to check, if there are still enemies in it or not; see next func
+
+#tv3 - big field around shinatama
+func void shin_check(string ai_name)
+{
+trigvolume_enable trigger_volume_03 0
+if(trigvolume_count(32) eq 0) Shin
+else
+	{
+	sleep 60
+	trigvolume_enable trigger_volume_03 1
+	}
+}
+
+#tv54 - complete volume of the 2nd hall too; used to delete all enemies inside; see next func
+
+func void Shin(void)
+{
+music_stop
+sound_music_start atm_cl10 0.0
+sound_music_volume atm_cl10 1 5
+objective_set 2 silent
+target_set 7020 60
+particle blast1_locklight01 do stop
+particle blast2_locklight01 do stop
+door_lock 1
+door_lock 2
+particle room1 do stop
+particle room2 do stop
+particle Shindoor_locklight01 do start
+door_unlock 3
+particle room4 do start
+ai2_spawn A2_sb04
+sound_dialog_play c09_31_27shinatama
+sound_dialog_play_block pause
+sleep 600
+sound_dialog_play c09_31_28shinatama
+sleep 600
+sound_dialog_play c09_31_29shinatama
+sleep 330
+sound_dialog_play_block pause
+sleep 15
+music_stop
+sound_ambient_start c06_45_04_explo
+sleep 10
+particle ShinBomb do explode
+trigvolume_kill 64
+if(var_counter ne 0) chr_set_health 0 0
+else 
+	{
+	fade_out 1 1 1 30
+	sleep 2
+	fade_in 30
+	door_lock 3
+	particle Shindoor_locklight01 do stop
+	objective_set 3 silent
+	target_set 0 0
+	}
+}
+
+#tv4 - in front of door 3
+func void p5(string ai_name)
+{
+ai2_spawn A3_n05
+ai2_spawn A3_sb06
+}
+
+##########
+### SP1 ###
+##########
+
+#tv69 - in some distance afer door 3
+func void new_save1(string ai_name)
+{
+if(save_point eq 1)
+	{
+	p5
+	particle room4 do start
+	objective_set 3 silent
+	}
+else save_game 1 autosave
+particle Shindoor_locklight01 do stop
+door_close 3
+door_lock 3
+particle room3 do stop
+}
+
+#called up, after you've talked to the guy
+func void do_console_1(string ai_name)
+{
+ai2_doalarm A3_n05 1
+}
+
+#console1
+func void pipe1a(string ai_name)
+{	
+ai2_passive A3_n05 1
+particle room4 do stop
+timer_start 30 pipe1b
+sound_music_start atm_cl11
+}
+
+func void pipe1b(void)
+{	
+particle room4 do start
+console_reset 1
+music_stop
+}
+
+#tv29 - on the pipe, in some distance after door 4 (func: p36); I've disabled it
+
+#tv28 - after door 9
+func void killmuro(string ai_name)
+{
+music_stop
+ai2_spawn A4_n07
+}
+
+#tv5 - in front of door 10
+func void p6(string ai_name)
+{
+ai2_spawn A4_sr08
+ai2_spawn B1_c07
+}
+
+#tv6 - after door 13 and door 14, not used (func: p7)
+
+#tv7 - in the middle of the stairs from 1st floor to 2nd floor
+func void p8(string ai_name)
+{
+trigvolume_enable trigger_volume_08 0
+ai2_spawn B2_sb09
+ai2_spawn B2_n10
+}
+
+#tv49 - after door 11 and door 12
+func void p9(string ai_name)
+{
+ai2_spawn C1_c16
+ai2_spawn C1_t11	
+ai2_spawn C1_sb12
+ai2_spawn C1_t13	
+ai2_spawn C2_sg15
+ai2_spawn C2_sr17
+ai2_spawn C2_sb14
+ai2_spawn C2_t19
+}
+
+#console6
+func void zap_cinematic(string ai_name)
+{
+particle doorA_locklight01 do start
+particle doorB_locklight01 do start
+door_unlock 15
+ai2_spawn vat_bot_1
+ai2_spawn vat_bot_2
+ai2_spawn vat_bot_3
+ai2_spawn vat_bot_4
+ai2_spawn vat_bot_5
+chr_weapon_immune vat_bot_1
+chr_weapon_immune vat_bot_2
+chr_weapon_immune vat_bot_3
+chr_weapon_immune vat_bot_4
+chr_weapon_immune vat_bot_5
+particle vatroom1 do start
+particle zap1 create
+particle zap2 create
+particle zap3 create
+trigvolume_enable save2 1
+sleep 1
+sound_music_start atm_cl12 0.75
+}
+
+##########
+### SP2 ###
+##########
+
+#tv25 - after door 15
+func void save_point_2(string ai_name)
+{
+if(save_point eq 2)
+	{
+	restore_game
+	zap_cinematic
+	objective_set 4 silent
+	}
+else save_game 2 autosave
+particle doorA_locklight01 do stop
+door_close 15
+door_lock 15
+particle room4 do stop
+}
+
+#tv64 - complete volume of the vat room (from the floor, where Konoko stands nearly to the ceiling)
+func void zap_start(string ai_name)
+{
+trigvolume_enable zap1 0
+if(var_counter eq 0)
+	{
+	particle zap1 do start
+	sleep 120
+	particle zap1 do stop
+	}
+if(var_counter eq 0)
+	{
+	particle zap2 do start
+	sleep 120
+	particle zap2 do stop
+	}
+if(var_counter eq 0)
+	{
+	particle zap3 do start
+	sleep 120
+	particle zap3 do stop
+	}
+sleep 60
+trigvolume_enable zap1 1
+}
+
+#1st console 4
+func void zap_timer_1(string ai_name)
+{
+var_counter = 1
+timer_start 15 zap_start_again
+}
+
+#tv60 - passage to the 1st console 4
+func void change_patrol_1(string ai_name)
+{
+ai2_dopath vat_bot_2 vat_bot_2b 1
+}
+
+#2nd console 4
+func void zap_timer_2(string ai_name)
+{
+var_counter = 1
+timer_start 10 zap_start_again
+}
+
+#tv61 - passage to the 2nd console 4
+func void change_patrol_2(string ai_name)
+{
+ai2_dopath vat_bot_3 vat_bot_3b 1
+} 
+
+#3rd console 4
+func void zap_timer_3(string ai_name)
+{
+var_counter = 1
+timer_start 5 zap_start_again
+}
+
+#tv62 - passage to the 3rd console 4
+func void change_patrol_3(string ai_name)
+{
+ai2_dopath vat_bot_5 vat_bot_5b 1
+}
+
+func void zap_start_again(string ai_name)
+{
+var_counter = 0
+console_reset 4
+}
+
+#tv35 to tv40 - called up, if a chara falls into the acid
+func void splash(string character)
+{
+if(chr_is_player(character) eq 1)
+	{
+  	cm_detach
+    	chr_animate 0 KONOKOacid
+	sleep 10
+	sound_impulse_play konoko_gruesome_death
+	chr_set_health 0 0
+	}
+else
+	{
+	chr_animate(character, KONOKOacid);
+	sleep 10
+	chr_set_health(character, 0);
+  	}
+}
+
+#after door 16
+func void red_ambush(string ai_name)
+{
+music_stop
+ai2_spawn ambush_red_1
+}
+
+#tv10 - after door 19 and door 20
+func void p10(string ai_name)
+{
+ai2_spawn D1_sr20
+ai2_spawn D1_sb21
+particle doorB_locklight01 do stop
+door_lock 16
+particle zap1 kill
+particle zap2 kill
+particle zap3 kill
+particle vatroom1 do stop
+trigvolume_enable strikerguards 1
+}
+
+#tv9 - long box (from the left side to the right side) in some distance in front of door 21
+func void striker_guards(string ai_name)
+{
+ai2_spawn striker_guard_1
+ai2_spawn striker_guard_2
+particle room6 do start
+}
+
+#tv51 - in front of door 21 (func: striker_guards); I've disabled it
+#tv31 - in front of door 21 too (func: p11); I've disabled it too
+#tv50 - after door 21 (func: cross_fire); I've disabled it
+
+#tv10 - after door 22
+func void p12(string ai_name)
+{
+ai2_spawn D2_sg24
+ai2_spawn D2_f25
+ai2_spawn D2_sb26
+playback D2_sb26 piperun
+ai2_spawn pipe_guard_1
+ai2_spawn pipe_guard_2
+}
+
+#console8
+func void pipe2a(void)
+{	
+particle room6 do stop
+timer_start 30 pipe2b
+sound_music_start atm_cl11
+}
+
+func void pipe2b(void)
+{	
+music_off
+particle room6 do start
+console_reset 8
+}
+
+#tv58 - after door 27
+func void pipe2_music_off(void)
+{	
+music_stop
+particle save3_locklight01 do start
+}
+
+#tv11 - in front of door 28
+func void p13(string ai_name)
+{
+ai2_spawn E1_sr28
+ai2_spawn E1_sb29
+ai2_spawn E1_sr30
+ai2_spawn ambush_comguy_1
+ai2_spawn E1_n31
+ai2_spawn E1_n32
+ai2_spawn E1_n37
+particle pipe3 do create
+particle pipe3 do start
+}
+
+#tv33 - after door 33 (funcs: p11 and save_point_3); I've disabled it
+
+##########
+### SP3 ###
+##########
+
+#tv 32 - in some distance after door 28
+func void p11b(string ai_name)
+{
+trigvolume_enable p11b_vol 0
+if(save_point eq 3) p13
+else save_game 3 autosave
+particle save3_locklight01 do stop
+door_close 28
+door_lock 28
+objective_set 5 silent
+particle room6 do stop
+}
+
+#lose func of E1_sr30
+func void warnbigroom(string ai_name)
+{
+ai2_makeaware E1_sr28 char_0
+ai2_makeaware E1_sb29 char_0
+}
+
+#tv48 - 1st floor, at the beginning of the stairs to the 2nd floor
+func void spawn_EC_guards(string ai_name)
+{
+ai2_spawn E1_sb29
+ai2_spawn E1_c33
+ai2_spawn E1_c40
+ai2_spawn E1_f34
+ai2_spawn E1_f40
+ai2_spawn E1_f35
+}
+
+#tv53 - at the same place as tv48 (func: set_objective_5); I've disabled it
+
+#tv59 - 3rd floor, at the beginning of the stairs to the 4th floor
+func void final_guards(string ai_name)
+{
+ai2_spawn final_guard_1
+ai2_spawn final_guard_2
+}
+
+#console14
+func void tctf_control(string ai_name)
+{
+sound_music_start mus_amasian 1.0
+particle elev1_locklight01 do start
+particle elev2_locklight01 do start
+door_unlock 37
+door_unlock 38
+ai2_spawn E2_sr38
+ai2_spawn E2_sr39
+}
+
+#tv30 - in front of door 37 (func: p39); I've disabled it
+
+#tv12 - after door 37
+func void elevator(void)
+{
+fade_out 0 0 0 30
+sleep 30
+fork_rmove_ai
+env_show 778 1
+env_shade 778 778 .3 .3 .3
+ai2_spawn F_r40
+playback 0 ElevatorTop
+fade_in 30
+fork wait_for_help
+}
+
+func void wait_for_help(void)
+{
+chr_wait_health F_r40 70
+ai2_spawn TCTF1051
+ai2_spawn TCTF1052
+ai2_spawn TCTF1053
+ai2_spawn TCTF1054
+chr_lock_active 1051
+chr_lock_active 1052
+chr_lock_active 1053
+chr_lock_active 1054
+chr_changeteam TCTF1051 TCTF
+chr_changeteam TCTF1052 TCTF
+chr_changeteam TCTF1053 TCTF
+chr_changeteam TCTF1054 TCTF
+playback TCTF1051 OutroSwatEnter
+ai2_attack TCTF1053 char_0
+sleep 60
+playback TCTF1052 OutroSwatEnter
+ai2_attack TCTF1054 char_0
+sleep 50
+playback TCTF1053 OutroLiteEnter
+ai2_attack TCTF1051 char_0
+sleep 70
+playback TCTF1054 OutroLiteEnter
+ai2_attack TCTF1052 char_0
+}
+
+#console15
+func void pipe3(void)
+{	
+sound_music_volume mus_amasian 0 2
+music_stop
+particle pipe3 kill
+sound_music_start atm_cl11
+timer_start 20 pipe3b
+}
+
+func void pipe3b(void)
+{	
+music_stop
+particle pipe3 do create
+particle pipe3 do start
+console_reset 15
+}
+
+#tv13 - after door 39; circa after a quarter of the lenght of the pipe
+func void outro(void)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level10a(string chr_index)
+{
+text_console level_10a
+console_reset 2
+}
+
+func void level10b(string chr_index)
+{
+text_console level_10b
+console_reset 7
+}
Index: /nikanabo/current/bsl/onilight/IGMD/roof/roof.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/roof/roof.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/roof/roof.bsl	(revision 185)
@@ -0,0 +1,779 @@
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) fork load_s2
+if(save_point eq 3) fork load_s3
+if(save_point eq 4) fork load_s4_all
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable trigger_volume_02 0
+trigvolume_enable trigger_volume_03 0
+trigvolume_enable trigger_volume_04 0
+trigvolume_enable trigger_volume_04_copy 0
+trigvolume_enable trigger_volume_05 0
+trigvolume_enable trigger_volume_06 0
+trigvolume_enable trigger_volume_07 0
+trigvolume_enable trigger_volume_07_copy 0
+trigvolume_enable trigger_volume_08 0
+trigvolume_enable trigger_volume_08_copy2 0
+trigvolume_enable trigger_volume_08_copy2_copy 0
+trigvolume_enable trigger_volume_08_copy2_copy_copy 0
+trigvolume_enable trigger_volume_10_copy 0
+trigvolume_enable trigger_volume_10_copy_copy 0
+trigvolume_enable trigger_volume_11 0
+trigvolume_enable trigger_volume_23 0
+trigvolume_enable trigger_volume_23_copy 0
+trigvolume_enable trigger_volume_26 0
+trigvolume_enable trigger_volume_29_copy 0
+trigvolume_enable trigger_volume_30 0
+trigvolume_enable trigger_volume_31 0
+trigvolume_enable trigger_volume_32 0
+trigvolume_enable trigger_volume_33 0
+trigvolume_enable trigger_volume_35 0
+trigvolume_enable trigger_volume_44 0
+trigvolume_enable trigger_volume_46 0
+trigvolume_enable trigger_volume_46_copy 0
+trigvolume_enable trigger_volume_46_copy2 0
+trigvolume_enable trigger_volume_46_copy3 0
+trigvolume_enable trigger_volume_46_copy_copy 0
+trigvolume_enable trigger_volume_46_copy4 0
+trigvolume_enable trigger_volume_46_copy4_copy 0
+trigvolume_enable trigger_volume_52 0
+trigvolume_enable trigger_volume_56 0
+trigvolume_enable trigger_volume_60 0
+trigvolume_enable trigger_volume_61 0
+trigvolume_enable trigger_volume_65 0
+trigvolume_enable trigger_volume_77 0
+trigvolume_enable trigger_volume_78 0
+trigvolume_enable trigger_volume_80 0
+trigvolume_enable trigger_volume_83 0
+trigvolume_enable trigger_volume_84 0
+#used
+env_show 31 0
+env_show 41 0
+env_shade 1500 1501 .9 .8 .9
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_cool19
+sound_music_stop mus_atm_cl12lp
+sound_music_stop mus_low1
+sound_music_stop mus_fitec
+}
+
+#tv63 to tv73
+func void deathfall(void)
+{
+sleep 30
+cm_detach
+sleep 30
+chr_set_health 0 0
+}
+
+##########
+### SP1 ###
+##########
+
+### 1ST ROOF ###
+
+func void intro(void)
+{
+playback 0 IntroKonoko
+if(save_point ne 1) save_game 1 autosave
+chr_envanim_stop IntroNinja
+chr_teleport IntroNinja 600
+chr_facetoflag IntroNinja 600
+chr_animate IntroNinja NINCOMcrouch_idle
+ai2_passive IntroNinja 1
+ai2_setmovementmode IntroNinja creep
+sleep 40
+playback_block IntroNinja IntroNinja
+ai2_passive IntroNinja 0
+ai2_attack IntroNinja 0
+ai2_setalert A_Sr9 combat
+ai2_setjobstate A_Sr9
+objective_set 1 silent
+target_set 7006 0
+}
+
+#tv29 - crossing point to the lower floor
+func void t22(string ai_name)
+{
+ai2_dopath IntroNinja patrol_39
+ai2_setjobstate IntroNinja
+}
+
+#tv32 - box on the right side (enter func: t33in, levae func: t33out); I've disabled it
+#tv31 - box on the left side (enter func: t32in, levae func: t32out); I've disabled it
+
+#tv1 - above the abyss
+func void t1(string ai_name)
+{
+ai2_dopath IntroNinja patrol_40
+ai2_setjobstate IntroNinja
+ai2_dopath A_N1 patrol_02
+ai2_setjobstate A_N1
+ai2_dopath A_Sr9 patrol_09
+ai2_setjobstate A_Sr9
+ai2_spawn A_N7
+ai2_spawn A_N8
+}
+
+func void patrolscript0001(string ai_name)
+{
+playback_block IntroNinja ninja_jump5 interp 30
+}
+
+func void patrolscript0022(string ai_name)
+{
+playback_block IntroNinja ninja_jump4 interp 20
+}
+
+func void patrolscript0002(string ai_name)
+{
+playback_block A_N1 ninja_jump interp 30
+}
+
+func void patrolscript0005(string ai_name)
+{
+playback_block A_T4 tanker1 interp 20
+}
+
+func void patrolscript0004(string ai_name)
+{
+playback_block A_T6 tanker2 interp 20
+}
+
+### 2ND ROOF ###
+
+#tv55 - after the abyss, at the beginning of the 2nd roof (enter func: t57, leave func: t57b); I've disabled it
+
+### 3RD ROOF ###
+
+#tv56 - after the abyss, at the beginning of the 3rd roof
+func void t58(string ai_name)
+{
+sound_music_start mus_cool19 0.0
+sound_music_volume mus_cool19 0.75 3.0
+ai2_dopath IntroNinja patrol_51
+ai2_setjobstate IntroNinja
+ai2_dopath A_N1 patrol_50
+ai2_setjobstate A_N1
+ai2_dopath A_Sr9 patrol_49
+ai2_setjobstate A_Sr9
+ai2_spawn A_C5
+ai2_spawn A_Sr3
+ai2_spawn A_T4
+ai2_spawn A_T6
+particle b01_rain1 do start
+particle b01_rain2 do start
+particle b01_rain3 do start
+}
+
+#tv35 - after tv56 (func: rain1); I've disabled it
+
+### 4TH ROOF ###
+
+#tv4 - at the right side of the mast (func: t3); I've disabled it
+#tv2 - at the left side of the mast (func: t2); I've disabled it
+
+### 5TH ROOF ###
+
+#tv57 - after the abyss, at the beginning of the 5th roof (enter func: t59, leave func: t59b); I've disabled it
+#tv5 - on the right side after tv59 (func: t5); I've disabled it
+#tv4 - on the left side after tv59 (func: t4); I've disabled it
+#lose func of A_T4 and A_T6: music_stop
+#tv6 - around the place, where you find the hypo (func: t6); I've disabled it
+#tv7 - in front of the staircase to the higher floor (funnc: b01); not used
+#tv30 - under the passageway; near the place, where you find the shield (func: t31); I've disabled it
+#tv33 - after tv7 (func: t7); I've disabled it
+#tv34 - after tv33, on the right side after the staircase (func: b02); not used
+#tv8 - in front of tv38 (func: rain1); I've disabled it
+#tv37 - in front of tv38 (func: rain2); I've disabled it
+
+#tv36 - in front of the passage, from the left side to the right side
+func void t8(string ai_name)
+{
+music_stop
+chr_delete IntroNinja
+chr_delete A_N1
+chr_delete A_Sr9
+ai2_spawn B_Sr10
+ai2_spawn B_Sr10a
+ai2_spawn B_R11
+ai2_spawn B_R12a
+ai2_spawn B_Sr12
+ai2_spawn B_T13
+ai2_dopath A_T6 patrol_42
+ai2_setjobstate A_T6
+ai2_dopath A_T4 patrol_42
+ai2_setjobstate A_T4
+ai2_setjobstate A_Sr3
+ai2_setjobstate A_C5
+ai2_dopath A_N7 patrol_45
+ai2_setjobstate A_N7
+ai2_dopath A_N8 patrol_45
+ai2_setjobstate A_N8
+}
+
+func void patrolscript0011(string ai_name)
+{
+playback_block B_T13 tanker_jump interp 30
+}
+
+#tv39 - in the middle of the passage, from the left side to the right side (func: rain2); I've disabled it)
+#tv38 - in the middle of the passage, after tv39, from the left side to the right side (func: rain3); I've disabled it)
+
+#tv80 - after the passage, from the left side to the right side
+func void runup(void)
+{
+ai2_dopath B_Sr10 patrol_10z
+ai2_setjobstate B_Sr10
+particle b02_rain1 do start
+particle b02_rain2 do start
+particle b02_rain3 do start
+}
+
+### 6TH ROOF ###
+
+#tv9 - at the beginning of the 6th roof, from the left side to the right side
+func void t10(string ai_name)
+{
+sound_dialog_play c11_39_03konoko
+ai2_spawn B_SuperNinja
+chr_boss_shield B_SuperNinja
+chr_unstoppable B_SuperNinja 1
+chr_neutral B_SuperNinja 1
+playback_block B_SuperNinja superninja1 interp 20
+sleep 60
+chr_delete B_SuperNinja
+}
+
+#tv85 - at the same place as tv9 (enter func: t83, leave func: t83b); I've disabled it
+#tv41 - after tv85, from the left side to the right side (func: rain4); I've disabled it
+#tv40 - in some distance after tv 85, from the left side to the right side (enter func: rain5, leave func: t77); I've disabled it
+#tv58 - at the end of the 6th roof, where you can jump to the 7th roof (eneter func: t60, leave func: t60b); I've disabled it
+
+### 7TH ROOF ###
+
+#t42 - at the beginning of the 7th roof
+func void t11(string ai_name)
+{
+ai2_spawn C_N17
+ai2_spawn C_N18
+ai2_dopath B_T13 patrol_41
+ai2_setjobstate B_T13
+particle el1_locklight01 do start
+particle b03_rain1 do start
+particle b03_rain2 do start
+particle b03_rain3 do start
+}
+
+#tv10 - after tv42 (func: rain6); I've disabled it
+
+#tv74 - around the entrance of the elavator and in the elevator; used to count the enemies inside it; see next func
+
+#tv11 - in the middle of the elevator
+func void t12(string ai_name)
+{
+trigvolume_enable trigger_volume_12 0
+if(trigvolume_count(62) eq 0) Elevator
+else
+	{
+	sleep 60
+	trigvolume_enable trigger_volume_12 1
+	}
+}
+
+##########
+### SP2 ###
+##########
+
+func void Elevator(void)
+{
+sound_dialog_play c11_39_02konoko
+fade_out 0 0 0 30
+sleep 30
+load_s2
+chr_facetoflag 0 44
+chr_teleport 0 44
+fade_in 30
+}
+
+func void load_s2(void)
+{
+fork remove_ai
+if(save_point eq 2) restore_game
+ai2_spawn C_Sr15
+ai2_spawn C_T16
+ai2_spawn C_R55
+ai2_spawn C_N57
+ai2_spawn D_C19
+ai2_spawn D_Sb20
+ai2_spawn D_R21
+env_show 31 1
+objective_set 1 silent
+target_set 47 0
+}
+
+### 1ST ROOF ###
+
+func void patrolscript0077(string ai_name)
+{
+ai2_dopath D_R21 patrol_21
+ai2_setjobstate D_R21
+}
+
+#tv12 - after door 3
+func void s2(string ai_name)
+{
+if(save_point eq 2) 
+	{
+	particle b03_rain1 do start
+	particle b03_rain2 do start
+	particle b03_rain3 do start
+	}
+else
+	{
+	save_game 2 autosave
+	particle b01_rain1 do stop
+	particle b01_rain2 do stop
+	particle b01_rain3 do stop
+	particle b02_rain1 do stop
+	particle b02_rain2 do stop
+	particle b02_rain3 do stop
+	}	
+}
+
+#tv75 - after the stairs to the higher floor (func: t65); I've disabled it
+
+### 2ND ROOF ###
+
+#tv43 - complete 2nd roof (func: rain7); I've disabled it
+#tv48 - above the abyss, crossing from the 2nd roof to the 3rd roof (func: rain9); I've disabled it
+
+### 3RD ROOF ###
+
+#tv17 - at the beginning of the 3rd roof
+func void t18(string ai_name)
+{
+sound_music_start mus_atm_cl12lp 0.0
+sound_music_volume mus_atm_cl12lp 0.75 3.0
+particle b04_rain1 do start
+particle b04_rain2 do start
+particle b04_rain3 do start
+particle b04_rain4 do start
+particle b04_rain5 do start
+particle b04_rain6 do start
+}
+
+#tv48 - at the same place as tv17 (func: rain9); I've disabled it
+#tv45 - in some distance after tv48 (func: rain10); I've disabled it
+#tv46 - in some distance after tv45 (func: rain11); I've disabled it
+#tv47 - in some distance after tv46 (func: rain12); I've disabled it
+#tv53 - in some distance after tv47 (func: rain12); I've disabled it
+#tv49 - in some distance after tv53 (func: rain13); I've disabled it
+#tv76 - in some distance in front of of the end of the right "colonnade" (func: t77); I've disabled it
+#tv77 - at the end of the left "colonnade" (func: t78); I've disabled it
+
+#tv13 - at the end of the 3rd roof
+func void t14(string ai_name)
+{
+music_stop
+ai2_spawn D_Sb22
+ai2_spawn D_Sb23
+ai2_spawn D_Sr24
+ai2_spawn D_Sr38
+ai2_spawn D_C60
+ai2_dopath D_Sb20 patrol_35
+target_set 1 0
+particle b06_rain1 do start
+particle b06_rain2 do start
+particle b06_rain3 do start
+particle b06_rain4 do start
+particle b06_rain5 do start
+particle b06_rain6 do start
+}
+
+### 4TH ROOF ###
+
+func void patrolscript0014(string ai_name)
+{
+playback_block D_Sb20 striker_jump interp 20
+}
+
+#tv27 - ground floor, left passage, some distance after the beginning of the 2nd "block" (func: t30); I've disabled it
+
+#after the beginning of the center passage
+func void t19(string ai_name)
+{
+sound_music_start mus_low1 0.0
+sound_music_start mus_low1 0.75 3
+ai2_spawn D_N25
+ai2_spawn C_R61
+}
+
+#t19 - at the end of the center passage, after the left corner
+func void t20(string ai_name)
+{
+music_stop
+ai2_spawn D_Sr26
+ai2_spawn D_Sr27
+ai2_spawn D_T28
+}
+
+#tv54 - at the beginning of the stairs, where the tanker waits (func: cloudkiller); not used
+
+#t14 - next to last floor of the stairs
+func void t15(string ai_name)
+{
+powerup_spawn lsi 605
+ai2_spawn E_N14
+ai2_spawn E_N14a
+ai2_passive E_N14 1
+ai2_spawn NinjaZip
+ai2_passive NinjaZip 1
+chr_unstoppable NinjaZip 1
+playback NinjaZip NinjaZipSet
+playback E_N14 Ninja02Set
+}
+
+#tv15 - after the stairs 
+func void NinjaZip(void)
+{
+chr_envanim NinjaZip ZipNinjaBipBox norotation
+chr_animate NinjaZip NINJAlev12_zip
+obj_create 72
+env_anim 72
+sleep 60
+playback E_N14 Ninja02Jump
+sleep 80
+ai2_passive E_N14 0
+sleep 100
+playback NinjaZip NinjaZipLeave
+sleep 120
+chr_delete NinjaZip
+objective_set 2 silent
+target_set 7006 0
+}
+
+#tv84 - around the place, where you find the zipline rider
+func void t28(string ai_name)
+{
+chr_wait_animtype char_0 Pickup_Object
+particle obj_zip create
+}
+
+#tv87 - at the end of the secret way
+func void t85(string ai_name)
+{
+ai2_spawn sbg_ninja
+}
+
+#tv16 - at the place with the yellow flashing circle
+func void t17(string ai_name)
+{
+if(chr_has_lsi(0)) KonokoZip
+}
+
+func void KonokoZip(void)
+{
+particle obj_zip kill
+chr_envanim 0 ZipKonBipBox norotation
+chr_animate 0 KONOKOlev12_zip
+obj_create 71
+env_anim 71
+sleep 55
+sound_ambient_start c08_11_19zip
+sleep 235
+obj_kill 72
+chr_peace 0
+objective_set 3 silent
+target_set 7006 0
+chr_delete D_C19
+chr_delete D_C60
+chr_delete D_N25
+chr_delete D_R21
+chr_delete D_Sb20
+chr_delete D_Sb22
+chr_delete D_Sb23
+chr_delete D_Sr24
+chr_delete D_Sr26
+chr_delete D_Sr27
+chr_delete D_Sr38
+particle b04_rain1 do stop
+particle b04_rain2 do stop
+particle b04_rain3 do stop
+particle b04_rain4 do stop
+particle b04_rain5 do stop
+particle b04_rain6 do stop
+}
+
+func void load_s3(void)
+{
+restore_game
+particle b06_rain1 do start
+zip_rider
+}
+
+func void zip_rider(void)
+{
+ai2_spawn E_N14
+ai2_spawn E_N14a
+obj_create 71
+env_anim 71
+chr_envanim_block E_N14a ZipKonBipBox norotation
+chr_animate_block E_N14a KONOKOlev12_zip
+sleep 60
+obj_create 72
+env_anim 72
+chr_envanim_block E_N14 ZipKonBipBox norotation
+chr_animate_block E_N14 KONOKOlev12_zip
+sleep 230
+ai2_attack E_N14a char_0
+sleep 60
+obj_kill 71
+ai2_attack E_N14 char_0
+}
+
+##########
+### SP3 ###
+##########
+
+### 1ST ROOF ###
+
+#tv59 - the place, where you arrive with your zip rider (func: set_objective_2); I've disabled it
+
+#tv78 - after tv59
+func void s3(string ai_name)
+{
+if(save_point ne 3)
+	{
+	save_game 3 autosave
+	zip_rider
+	}
+objective_set 3 silent
+target_set 7006 0
+}
+
+#tv24 - in some distance after tv59 (func: rain17); I've disabled it
+
+#tv28 - at the beginning of the passageway
+func void t9(string ai_name)
+{
+ai2_spawn E_C62
+playback E_C62 com
+ai2_spawn E_N37
+ai2_makeignoreplayer E_N37 1
+playback_block E_N37 ninja_jump2
+ai2_makeignoreplayer E_N37 0
+ai2_attack E_N37 char_0
+}
+
+#tv50 - at the beginning of the passageway (func: rain18); I've disabled it
+
+#tv20 - at the same place as tv50
+func void t21(string ai_name)
+{
+sound_dialog_play c11_39_04konoko
+ai2_spawn E_N29
+ai2_spawn E_Sb31
+ai2_spawn E_Sr63
+ai2_spawn E_Sr64
+ai2_spawn E_R65
+ai2_spawn E_SuperNinja
+chr_boss_shield E_SuperNinja
+chr_unstoppable E_SuperNinja
+playback_block E_SuperNinja superninja2 interp 20
+sleep 60
+chr_delete E_SuperNinja
+}
+
+#tv79 - around the place, where you find the hypo (func: t80); I've disabled it
+
+### 2ND ROOF ###
+
+#tv26 - on the next to last floor
+func void t29(string ai_name)
+{
+sound_dialog_play c11_39_05konoko
+}
+
+#tv86 - at the beginning of the highest floor (enter func: t84, leave func: t84b); I've disabled it
+#tv51 - at the same place as tv86 (func: rain19); I've disabled it
+
+#tv83 - after the beginning of the stairs
+func void t95(string ai_name)
+{
+sound_dialog_play c11_39_06konoko
+ai2_spawn E_Sr30
+}
+
+#tv52 - at the end of the small passage after the end of the stairs (func: rain20); I've disabled it
+#tv21 - after tv52 (func: t23); I've disabled it
+
+#tv83 - at the 1st corner (beside the "block", where the sniper with the mercury bow stands on)
+func void t96(string ai_name)
+{
+sound_dialog_play c11_39_07konoko
+}
+
+#tv23 - at the 2nd corner
+func void t25(string ai_name)
+{
+ai2_spawn E_Sr33
+ai2_dopath E_Sr30 patrol_34
+ai2_setjobstate E_Sr30
+}
+
+#tv22 - at the 3rd corner
+func void t24(string ai_name)
+{
+sound_dialog_play c11_39_08konoko
+ai2_spawn E_R32
+ai2_dopath E_Sr33 patrol_34
+ai2_setjobstate E_Sr33
+door_lock 6
+}
+
+#tv61 - complete area between the 3rd corner and the 4th corner; used to count the enemies inside it; see next func
+
+#tv60 - in front of the doors of the elevator
+func void t63(string ai_name)
+{
+trigvolume_enable trigger_volume_63 0
+if (trigvolume_count(64) eq 0) door_unlock 6
+else
+	{
+	sleep 60
+	trigvolume_enable trigger_volume_63 1
+	}
+}
+
+#tv25 - in the middle of the elevator
+func void ninja(void)
+{
+fade_out 0 0 0 30
+sleep 30
+sound_dialog_play c11_39_09konoko
+chr_facetoflag 0 9523
+chr_teleport 0 9523
+obj_kill 72
+door_lock 2
+load_s4_part1
+fade_in 30
+load_s4_part2
+}
+
+##########
+### SP4 ###
+##########
+
+func void load_s4_all(void)
+{
+load_s4_part1
+load_s4_part2
+}
+
+func void load_s4_part1(void)
+{
+fork remove_ai
+particle wind do start
+ai2_spawn OutroNinja
+chr_boss_shield OutroNinja
+chr_nocollision OutroNinja 1
+playback OutroNinja SuperNinjaSet
+}
+
+func void load_s4_part2(void)
+{
+if(save_point eq 4) 
+	{
+	restore_game
+	particle b06_rain6 do start
+	objective_set 3 silent
+	}
+else
+	{
+	particle b06_rain1 do stop
+	particle b06_rain2 do stop
+	particle b06_rain3 do stop
+	particle b06_rain4 do stop
+	particle b06_rain5 do stop
+	save_game 4 autosave
+	}
+sleep 1
+sound_music_start mus_fitec
+chr_animate OutroNinja NINCOMteleport_in 47
+sleep 40
+playback OutroNinja SuperNinjaDone
+chr_animate OutroNinja NINCOMteleport_out 31
+chr_nocollision OutroNinja 0
+}
+
+func void outro(void)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
Index: /nikanabo/current/bsl/onilight/IGMD/state/state.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/state/state.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/state/state.bsl	(revision 185)
@@ -0,0 +1,530 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0 
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable Cut_dog 0
+trigvolume_enable trigger_volume_07 0
+trigvolume_enable trigger_volume_11 0
+trigvolume_enable trigger_volume_12 0
+trigvolume_enable trigger_volume_14 0
+trigvolume_enable trigger_volume_15 0
+#used
+trigvolume_enable Cut_outro 0
+trigvolume_enable shut_off_vault_music 0
+trigvolume_enable ninja_ambush_bot_trig 0
+trigvolume_enable ninja_ambush_top_trig 0
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_main02
+sound_music_stop mus_lz
+sound_music_stop mus_heart
+sound_music_stop mus_main02_hd
+}
+
+#tv13, tv14, tv15, tv19 and tv 20
+func void spawn_outside_left_snipers(string ai_name)
+{
+ai2_spawn flOUTSIDE_A_sniper_1
+ai2_spawn flOUTSIDE_A_sniper_2
+ai2_spawn flOUTSIDE_B_sniper_1
+ai2_spawn flOUTSIDE_C_sniper_1
+}
+
+#tv16, tv17 and tv18
+func void spawn_outside_right_snipers(string ai_name)
+{
+ai2_spawn flOUTSIDE_D_sniper_1
+ai2_spawn flOUTSIDE_D_sniper_2
+ai2_spawn flOUTSIDE_E_sniper_1
+ai2_spawn flOUTSIDE_E_sniper_2
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+particle lock99_locklight01 do start
+ai2_spawn IntroSec1
+ai2_spawn IntroSec2
+ai2_spawn neutral_1
+ai2_spawn fl2_secguard_1
+powerup_spawn ammo 131
+powerup_spawn hypo 132
+objective_set 1 silent
+target_set 127 30
+sleep 1
+sound_music_start mus_main02_hd 1.0
+}
+
+#lose func of IntroSec2
+func void die_for_art_1(string ai_name)
+{
+die_for_art_2
+}
+
+#lose func of IntroSec1
+func void die_for_art_2(string ai_name)
+{
+var_counter = var_counter + 1
+if(var_counter eq 2) music_stop
+}
+
+### GROUND FLOOR ###
+
+#tv7 - after door 59
+func void save_game_1(string ai_name)
+{
+ai2_spawn fl1_secguard_1
+ai2_spawn fl1_secguard_2
+ai2_spawn fl1_secguard_4
+}
+
+#hit func of neutral_1
+func void do_neutral_1_run(string ai_name)
+{
+ai2_neutralbehavior neutral_1 none
+ai2_setmovementmode neutral_1 run_noaim
+ai2_dopath neutral_1 neutral_1_run
+ai2_setjobstate neutral_1
+}
+
+#console2
+func void change_fl2_lights(string ai_name)
+{
+particle lock1_locklight01 do start
+particle lock2_locklight01 do start
+door_unlock 54
+objective_set 2 silent
+}
+
+### 1ST FLOOR ###
+
+#tv2 - after door 67, the complete room plus all rooms behind it
+func void fl2_spawn_secguard_3(string ai_name)
+{
+ai2_spawn fl2_secguard_3
+ai2_spawn fl2_secguard_6
+ai2_spawn fl2_balcony_1
+}
+
+#tv1 - after door 75, the complete room plus all rooms behind it
+func void fl2_spawn_secguard_2(string ai_name)
+{
+ai2_spawn fl2_secguard_2
+ai2_spawn fl2_secguard_7
+ai2_spawn fl2_balcony_2
+ai2_spawn neutral_2
+ai2_spawn neutral_4
+}
+
+#hit func of neutral_2
+func void do_neutral_2_run(string ai_name)
+{
+ai2_neutralbehavior neutral_2 none
+ai2_dopath neutral_2 neutral_2_run
+ai2_setjobstate neutral_2
+}
+
+#console3
+func void change_fl3_lights(string ai_name)
+{
+particle lock3_locklight01 do start
+ai2_spawn fl3_mook_1
+ai2_spawn fl3_mook_2
+}
+
+### 2ND FLOOR ###
+
+#tv6 - in front of door 68 and door 76
+func void spawn_fl3_guards(string ai_name)
+{
+ai2_spawn fl3_secguard_1
+ai2_spawn fl3_secguard_2
+ai2_spawn fl3_secguard_6
+ai2_spawn flROOF_sniper_1
+ai2_spawn Roof_BOSWAT_1
+ai2_spawn neutral_3
+ai2_spawn neutral_6
+objective_set 3 silent
+var_counter = 0
+}
+
+#hit func of neutral_3
+func void do_neutral_3_run(string ai_name)
+{
+ai2_neutralbehavior neutral_3 none
+ai2_dopath neutral_3 neutral_3_run
+ai2_setjobstate neutral_3
+}
+
+#console4
+func void seclock2(string ai_name)
+{
+particle lock5b_locklight01 do start
+console_check
+}
+
+#console82
+func void seclock3(string ai_name)
+{
+particle lock5c_locklight01 do start
+console_check
+}
+
+#console88
+func void seclock1(string ai_name)
+{
+particle lock5a_locklight01 do start
+console_check
+}
+
+func void console_check(void)
+{
+var_counter = var_counter + 1
+if(var_counter eq 1) sound_music_start mus_lz 0.75
+if(var_counter eq 3)
+	{
+	music_stop
+	door_unlock 23
+	door_unlock 42
+	}
+}
+
+### ROOF ###
+
+#console5
+func void DataArchiveUnlock(string ai_name)
+{
+sound_music_start mus_heart
+particle lock4_locklight01 do start
+door_unlock 7
+ai2_spawn fl1_target_1
+ai2_spawn fl2_target_2
+objective_set 4 silent
+target_set 267 30
+trigvolume_enable shut_off_vault_music 1
+}
+
+### BACK TO GROUND FLOOR ###
+
+#tv22 - between door 7 and door 14
+func void all_music_counters(void)
+{
+music_stop
+}
+
+##########
+### SP2 ###
+##########
+
+### BASMENT ###
+
+#tv24 - after door 15 (which is on the left side)
+func void save_game_2_right(string player_name)
+{
+save_game_2_left
+}
+
+#tv23 - after door 5 (which is on the right side)
+func void save_game_2_left(string player_name)
+{
+if(save_point eq 2) fork load_s2
+else
+	{
+	save_game 2 autosave
+	fork remove_ai
+	}
+trigvolume_enable save_trig_left 0
+trigvolume_enable save_trig_right 0
+ai2_spawn flBASEMENT_guard_1
+ai2_spawn flBASEMENT_guard_2
+console_activate 1
+console_activate 6
+}
+
+func void load_s2(void)
+{
+particle lock1_locklight01 do start
+particle lock2_locklight01 do start
+particle lock3_locklight01 do start
+particle lock4_locklight01 do start
+particle lock5a_locklight01 do start
+particle lock5b_locklight01 do start
+particle lock5c_locklight01 do start
+particle lock99_locklight01 do start
+door_unlock 5
+door_unlock 7
+door_unlock 14
+door_unlock 15
+door_unlock 23
+door_unlock 42
+door_unlock 54
+door_unlock 59
+door_unlock 67
+door_unlock 68
+door_unlock 75
+door_unlock 76
+trig_activate 1
+trig_activate 2
+console_deactivate 2
+console_deactivate 3
+console_deactivate 5
+console_deactivate 4
+console_deactivate 11
+console_deactivate 82
+console_deactivate 88
+trigvolume_enable trigger_volume_09 0
+trigvolume_enable trigger_volume_08 0
+trigvolume_enable trigger_volume_02 0
+trigvolume_enable trigger_volume_01 0
+ai2_spawn neutral_1
+ai2_spawn neutral_2
+ai2_spawn neutral_3
+ai2_spawn neutral_4
+ai2_spawn neutral_5
+ai2_spawn neutral_6
+ai2_neutralbehavior neutral_1 none
+ai2_neutralbehavior neutral_2 none
+ai2_neutralbehavior neutral_3 none
+objective_set 4 silent
+target_set 267 30
+}
+
+#console6
+func void hall_1(string ai_name)
+{
+particle lock6_locklight01 do start
+door_unlock 3
+door_unlock 22
+door_unlock 38
+door_unlock 77
+trig_deactivate 1
+trig_deactivate 2
+}
+
+#console1
+func void unlock_secret_1(string ai_name)
+{
+console_activate 7
+ai2_spawn secret_guard_1
+ai2_spawn secret_guard_2
+trig_activate 12
+trig_activate 13
+trig_activate 14
+door_unlock 82
+objective_set 5 silent
+target_set 1030 30
+}
+
+#tv8 - in front of door 3 and door 77
+func void spawn_flRAMP_guards(string ai_name)
+{
+particle lock46_locklight01 do start
+ai2_spawn flRAMP_guard_1
+ai2_spawn flRAMP_guard_2
+}
+
+### BACK TO 2ND FLOOR ###
+
+#console7
+func void unlock_secret_2(string ai_name)
+{
+particle lock7_locklight01 do start
+door_unlock 34
+door_unlock 36
+trig_deactivate 12
+trigvolume_enable ninja_ambush_top_trig 1
+trigvolume_enable ninja_ambush_bot_trig 1
+}
+
+#tv29 - after door 3 and door 77
+#tv25 - after door 22 and door 38
+func void ninja_ambush(string ai_name)
+{
+trigvolume_enable ninja_ambush_top_trig 0	
+trigvolume_enable ninja_ambush_bot_trig 0	
+ai2_spawn ambush_ninja_1
+ai2_spawn creepy_ninja_1
+ai2_spawn creepy_ninja_3
+}
+
+### NEXT PART OF THE BUILDING - 1ST FLOOR ###
+
+#console8
+func void upstairs(string ai_name)
+{
+particle lock23_locklight01 do start
+particle lock65_locklight01 do start
+door_unlock 8
+door_unlock 9
+door_unlock 35
+trig_deactivate 13
+trig_deactivate 14
+ai2_spawn creepy_ninja_5
+ai2_spawn creepy_ninja_6
+}
+
+### 2ND FLOOR ###
+
+#tv4 - in front of door 37
+func void window_ninja(string ai_name)
+{
+trigvolume_enable Cut_outro 0
+ai2_spawn creepy_ninja_4
+chr_teleport creepy_ninja_4 289
+ai2_lookatme creepy_ninja_4
+chr_animate creepy_ninja_4 NINJArun_kick
+chr_create 1030 start
+chr_neutral 1030 1
+playback 1030 WindowNinjaSet
+sound_music_start mus_pursuit_hd
+obj_create 481 481
+obj_show 481 481
+env_anim 481 481
+env_setanim 481 Disk02
+chr_envanim 1030 WindowNinjaBox01 norotation
+chr_animate 1030 NINJAlev11_window
+sleep 185
+sound_impulse_play glass_big
+particle WindowCharge do explode
+sleep 60
+chr_delete 1030
+ai2_spawn WindowNinjaRun
+ai2_passive WindowNinjaRun 1
+chr_unstoppable WindowNinjaRun 1
+chr_lock_active WindowNinjaRun
+playback WindowNinjaRun WindowNinjaRun
+obj_kill 481 481
+target_set 1030 0
+sleep 210
+playback WindowNinjaRun JumpNinjaSet
+#sleep 10
+#playback WindowNinjaRun JumpNinjaSet
+}
+
+### OUTSIDE ON THE ROOF ###
+
+#tv27 - complete roof
+func void check_outro(string ai_name)
+{
+trigvolume_enable tv_check_outro 0
+if(trigvolume_count(24) eq 0)
+	{
+	trigvolume_enable Cut_outro 1
+	particle obj2 create
+	target_set 126 30
+	}
+else
+	{
+	sleep 60
+	trigvolume_enable tv_check_outro 1
+	}
+}
+
+#tv28 - complete roof too; used to count the enemies inside it; see func above
+
+#tv21 - after the window, from the first left box to the right wall
+func void FaceSet(string ai_name)
+{
+playback WindowNinjaRun
+ai2_spawn FaceNinja
+ai2_spawn FaceNinja2
+playback FaceNinja FaceNinjaSet
+playback FaceNinja FaceNinjaJump
+}
+
+#tv26 - passage between the two boxes
+func void JumpNinja(string ai_name)
+{
+chr_nocollision WindowNinjaRun 1
+chr_animate WindowNinjaRun KONOKOlev11_jump -1
+sleep 135
+chr_delete WindowNinjaRun
+}
+
+#tv5 - the place with the yellow flashing circle
+func void outro(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void grifftext(string chr_index)
+{
+text_console level_11a
+console_reset 9
+}
Index: /nikanabo/current/bsl/onilight/IGMD/tctf/tctf.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/tctf/tctf.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/tctf/tctf.bsl	(revision 185)
@@ -0,0 +1,1180 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3) restore_game
+if(save_point eq 4) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable t86 0
+trigvolume_enable trigger_volume_99 0
+#used
+env_show 97 0
+env_show 98 0
+env_show 321 0
+env_show 322 0
+env_show 323 0
+env_show 324 0
+env_show 325 0
+env_show 398 0
+env_show 601 0
+env_show 602 0
+trig_deactivate 1
+trig_deactivate 2
+trig_deactivate 3
+trig_deactivate 4
+trig_deactivate 5
+trig_deactivate 6
+trig_deactivate 7
+trig_deactivate 8
+trig_deactivate 9
+trig_deactivate 10
+trig_deactivate 60
+trig_deactivate 61
+trig_deactivate 62
+trig_deactivate 63
+trig_deactivate 64
+trig_deactivate 65
+trig_deactivate 70
+trig_deactivate 71
+trig_deactivate 72
+trig_deactivate 73
+trig_deactivate 74
+trig_deactivate 75
+trig_deactivate 98
+trig_deactivate 99
+trig_deactivate 100
+trig_deactivate 101
+trig_deactivate 302
+trig_deactivate 303
+trig_deactivate 310
+trig_deactivate 320
+trig_deactivate 400
+trig_deactivate 500
+trig_deactivate 501
+trig_deactivate 502
+trig_deactivate 503
+trig_deactivate 510
+trig_deactivate 511
+trig_deactivate 512
+trig_deactivate 520
+trig_deactivate 521
+trig_deactivate 522
+trigvolume_enable z_40t 0
+trigvolume_enable zz_40t 0
+trigvolume_enable zzz_40t 0
+trigvolume_enable zzzz_40t 0
+trigvolume_enable tv_61t 0
+trigvolume_enable trigger_volume_81 0
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_asianb
+sound_music_stop mus_pursuit
+sound_music_stop mus_om01
+}
+
+#tv86 to tv97
+func void fire_damage(string ai_name)
+{
+chr_poison(ai_name, 5, 30, 30);
+}
+
+##########
+### SP1 ###
+##########
+
+### GARAGE - GROUND FLOOR ###
+
+func void intro(void)
+{
+env_show 99 1
+env_show 101 1
+env_show 103 1
+env_show 104 1
+env_show 105 1
+env_show 106 1
+env_show 107 1
+env_show 108 1
+env_show 110 1
+env_show 111 1
+env_show 112 1
+env_show 321 1
+env_show 322 1
+env_show 323 1
+env_show 324 1
+env_show 325 1
+env_shade 321 325 .6 .6 .6
+env_show 444 1
+ai2_spawn lobby_striker_01
+ai2_spawn lobby_striker_02
+ai2_spawn lobby_striker_03
+playback 0 IntroKonoko
+particle smoke do start
+particle security_locklight01 do start
+particle LobbyWall do explode
+objective_set 1 silent
+target_set 323 30
+sleep 1
+sound_dialog_play c07_22_01konoko
+sound_music_start mus_asianb
+}
+
+#tv9 - left ramp between ground floor and 1st floor
+func void spawnG3_11(string ai_name)
+{
+ai2_spawn garage_striker_07
+ai2_passive garage_striker_07 1
+ai2_spawn garage_striker_08
+playback garage_striker_07 garage_taunt
+ai2_passive garage_striker_07 0
+}
+
+#tv12 - left ramp between ground floor and 1st floor, after tv9
+func void killG2_08(string ai_name)
+{
+trigvolume_enable trigger_volume_G2_08 0 
+}
+
+#tv7 - right ramp between ground floor and 1st floor
+func void spawnG2_7(string ai_name)
+{
+ai2_spawn garage_striker_01
+ai2_spawn garage_striker_02
+}
+
+#tv13 - right ramp between ground floor and 1st floor, after tv7
+func void killG2_10(string ai_name)
+{
+trigvolume_enable trigger_volume_G2_10 0 
+}
+
+#tv50 - ground floor, crossing from garage to building (big box in front of door 4 and 7)
+func void tv_50(string ai_name)
+{
+ai2_spawn l_s99
+ai2_spawn l_s98
+music_stop
+}
+
+### GARAGE - 1ST FLOOR ###
+
+#tv10 - left ramp between 1st floor and 2nd floor
+func void spawnG3_12(string ai_name)
+{
+if (var_counter eq 0)
+	{
+	ai2_spawn garage_striker_09
+	ai2_spawn garage_striker_10
+	}
+if (var_counter ne 0)
+	{
+	ai2_spawn garage_striker_09
+	}
+}
+
+#tv15 - left ramp between 1st floor and 2nd floor, after tv10
+func void killG3_12(string ai_name)
+{
+trigvolume_enable trigger_volume_G3_12 0 
+}
+
+#tv8 - right ramp between 1st floor and 2nd floor
+func void spawnG3_8(string ai_name)
+{
+if (var_counter eq 0)
+	{
+	ai2_spawn garage_striker_03
+	ai2_makeignoreplayer garage_striker_03 1
+	ai2_spawn garage_striker_04
+	ai2_spawn garage_striker_05
+	ai2_lookatme garage_striker_04
+	ai2_lookatme garage_striker_05
+	playback_block garage_striker_03 garage_jump
+	ai2_makeignoreplayer garage_striker_03 0
+	}
+if (var_counter ne 0)
+	{
+	ai2_spawn garage_striker_03
+	ai2_makeignoreplayer garage_striker_03 1
+	playback_block garage_striker_03 garage_jump
+	ai2_makeignoreplayer garage_striker_03 0
+	}
+}
+
+#tv14 - right ramp between 1st floor and 2nd floor, after tv8
+func void killG3_11(string ai_name)
+{
+trigvolume_enable trigger_volume_G3_11 0 
+}
+
+#tv21 - 1st floor, crossing from garage to building (big box in front of door 5 and 8)
+func void g_23(string ai_name)
+{
+ai2_spawn L2s_01
+ai2_spawn L2s_02
+ai2_spawn L2s_03
+ai2_spawn L2tctf_01
+ai2_spawn L2tctf_02
+music_stop
+trigvolume_enable trigger_volume_w_39 0
+}
+
+##tv31 - 1st floor, crossing from garage to building (box in front of door 2)
+func void p_31(string ai_name)
+{
+trigvolume_enable trigger_volume_L2_4 1
+}
+
+### GARAGE - 2ND FLOOR ###
+
+#tv11 - 2nd floor, crossing from garage to building (big box in front of door 6 and 9)
+func void c_13(string ai_name)
+{
+ai2_spawn lobby_striker_20
+ai2_spawn lobby_striker_21
+ai2_spawn lobby_fodder01
+ai2_spawn lobby_striker_05
+trigvolume_enable vv_38t 0
+trigvolume_enable a_18t 0
+music_stop
+}
+
+### ENTRANCE HALL - GROUND FLOOR ###
+
+#tv6 - in front of door 10
+func void spawnL1_6(string ai_name)
+{
+ai2_spawn lobby_striker_06
+trigvolume_enable tv_50t 0
+}
+
+#tv38 - after the passageway to the entrance hall with the van
+func void x_05(string ai_name)
+{
+ai2_spawn l_c01
+ai2_lookatme l_c01
+ai2_passive l_c01 1
+playback l_c01 lobby_runout
+ai2_passive l_c01 0
+trigvolume_enable trigger_volume_L1_6_9 0
+}
+
+#tv39 - in the passageway from the entrance hall with the van (near door 19)
+func void y_32(string ai_name)
+{
+ai2_spawn l_t01
+playback l_t01 lobby_backroll
+sleep 15
+ai2_spawn l_s02
+ai2_spawn l_s03
+trigvolume_enable tv_47t 0
+}
+
+#tv46 - after door 29
+func void tv_46(string ai_name)
+{
+ai2_spawn l_s24
+ai2_spawn l_t23
+trigvolume_enable tv_47t 1
+ai2_dopath l_t01 l_t01_06
+ai2_setjobstate l_t01
+}
+
+#tv47 - in some distance after door 22
+func void tv_47(string ai_name)
+{
+ai2_spawn l_s27
+}
+
+#tv66 - near door 26 and 31
+func void room1_stop(string ai_name)
+{
+particle room1 do stop
+}
+
+#tv67 - near door 26 and 31, after tv66
+func void room1_start(string ai_name)
+{
+particle room1 do start
+particle smoke do start
+}
+
+#tv45 - after door 31
+func void tv_45(string ai_name)
+{
+ai2_spawn a_v1
+ai2_spawn l_s22
+ai2_spawn l_s23
+ai2_dopath l_t01 l_t01_03
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_05
+ai2_setjobstate l_t23
+}
+
+#tv44 - after door 26
+func void tv_44(string ai_name)
+{
+ai2_spawn l_c10
+ai2_dopath l_t01 l_t01_02
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_03
+ai2_setjobstate l_t23
+}
+
+#console1
+func void goAttack(string ai_name)
+{
+music_stop
+trigvolume_enable tv_57t 1
+chr_delete l_c01
+chr_delete l_s98
+chr_delete l_s99
+chr_delete lobby_striker_01
+chr_delete lobby_striker_02
+chr_delete garage_striker_01
+chr_delete garage_striker_02
+chr_delete garage_striker_03
+chr_delete garage_striker_04
+chr_delete garage_striker_05
+chr_delete garage_striker_06
+chr_delete garage_striker_07
+chr_delete garage_striker_08
+chr_delete garage_striker_09
+chr_delete garage_striker_10
+ai2_spawn tanker_stairdoor
+particle stair_lock_locklight01 do start
+objective_set 2 silent
+target_set 1111 30
+sound_dialog_play c00_01_27shinatama
+}
+
+#tv57 - huge box after door 19, 20 and 24
+func void tv57(string ai_name)
+{
+sound_music_start mus_pursuit 0
+sound_music_volume mus_pursuit 0.75 3.0
+target_set 59 30
+sleep 180
+sound_dialog_play c00_01_105shinatama
+}
+
+### Pathfinding ###
+
+#lose func of l_s02 and l_s03
+func void unlock_follow(void)
+{
+var_counter2 = var_counter2 + 1
+if(var_counter2 eq 2)
+	{
+	trigvolume_enable z_40t 1
+	trigvolume_enable zz_40t 1
+	trigvolume_enable zzz_40t 1
+	trigvolume_enable zzzz_40t 1
+	trigvolume_enable tv_61t 1
+	}
+}
+
+func void patrolscript2222(void)
+{
+ai2_lookatchar l_t01 char_0
+ai2_lookatchar l_t23 char_0
+}
+
+#tv42 - in front of door 19
+func void z04(string ai_name)
+{
+ai2_dopath l_t01 l_t01_06
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_06
+ai2_setjobstate l_t23
+}
+
+#tv41 - after door 22
+func void z02(string ai_name)
+{
+ai2_dopath l_t01 l_t01_04
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_02
+ai2_setjobstate l_t23
+}
+
+#tv40 - near door 29
+func void z03(string ai_name)
+{
+ai2_dopath l_t01 l_t01_05
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_01
+ai2_setjobstate l_t23
+}
+
+#tv43 - in front of door 26 and 31, after tv67
+func void z01(string ai_name)
+{
+ai2_dopath l_t01 l_t01_01
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_04
+ai2_setjobstate l_t23
+}
+
+#tv101 - staircase, between ground floor and 1st floor
+func void z05(string ai_name)
+{
+ai2_dopath l_t01 l_t01_07
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_07
+ai2_setjobstate l_t23
+}
+
+### ENTRANCE HALL - 1ST FLOOR ###
+
+#tv37 - after door 20
+func void w_39(string ai_name)
+{
+ai2_spawn s2_t01
+ai2_spawn s2_t02
+ai2_spawn s2_s01
+ai2_spawn s2_s02
+ai2_spawn s2_s03
+ai2_spawn s2_s05
+ai2_spawn s2_t05
+trigvolume_enable g_23t 0
+}
+
+#tv34 - after the passageway to the footbridge (left side after door 20)
+func void u_36(string ai_name)
+{
+ai2_spawn cat1_02
+trigvolume_enable trigger_volume_L2_4 0
+}
+
+#tv5 - other side of the footbridge
+func void spawnL2_4(string ai_name)
+{
+ai2_spawn lobby_striker_04
+playback lobby_striker_04 lobbystriker_roll
+trigvolume_enable u_36t 0
+}
+
+#tv30 - next to tv5, staircase between 1st floor and 2nd floor (func: p_31t); not used
+
+#tv23 - in some distance after door 98
+func void i_24(string ai_name)
+{
+trigvolume_enable j_25t 0
+trigvolume_enable h_06t 0
+}
+
+#tv24 - after tv23
+func void j_25(string ai_name)
+{
+ai2_spawn L2s_11
+}
+
+#tv22 - after tv24
+func void h_06(string ai_name)
+{
+ai2_spawn L2s_10
+ai2_spawn Ls_15
+ai2_spawn Ltctf_55
+ai2_dopath L2tctf_01 patrol_L2_13
+ai2_dopath L2tctf_02 patrol_L2_13
+}
+
+#tv33 - in some distance near door 33
+func void t_35(string ai_name)
+{
+trigvolume_enable s_34t 0
+}
+
+#tv32 - after tv 33
+func void s_34(string ai_name)
+{
+ai2_spawn Lcom_01
+}
+
+#tv27 - after door 33
+func void m_28(string ai_name)
+{
+ai2_spawn Lv_40
+ai2_spawn Lv_41
+ai2_spawn Lc_43
+ai2_spawn Ls_44
+trigvolume_enable s_34t 1
+}
+
+#called up, after you've talked to the female cop
+func void femcop_holster(string ai_name)
+{
+chr_forceholster Lc_43 1
+}
+
+#tv29 - after door 37
+func void o_30(string ai_name)
+{
+ai2_spawn Ls_60
+ai2_spawn a_v2
+}
+
+#tv28 - after door 32
+func void n_29(string ai_name)
+{
+ai2_spawn Lc_50
+ai2_spawn Ls_51
+ai2_spawn Ls_12
+}
+
+### Pathfinding ###
+
+#tv61 - big box in front of door 98
+func void z06(string ai_name)
+{
+ai2_dopath l_t01 l_t01_08
+ai2_setjobstate l_t01
+ai2_dopath l_t23 l_t23_08
+ai2_setjobstate l_t23
+}
+
+### ENTRANCE HALL - 2ND FLOOR ###
+
+#tv20 - in front of door 24
+func void f_22(string ai_name)
+{
+ai2_spawn lobby_striker_05
+trigvolume_enable vv_38t 0
+ai2_spawn lobby_striker_20
+ai2_spawn lobby_fodder01
+ai2_spawn lobby_striker_21
+}
+
+#tv18 - after door 24
+func void d_20(string ai_name)
+{
+ai2_spawn l2_s46
+ai2_spawn l2_s44
+playback_block l2_s44 lobby_roll3
+}
+
+#tv35 - after the passageway to the footbridge (left side after door 24)
+func void v_37(string ai_name)
+{
+ai2_spawn cat1_01
+trigvolume_enable vv_38t 0
+}
+
+#tv36 - other side of the footbridge
+func void vv_38(string ai_name)
+{
+ai2_spawn lobby_striker_05
+ai2_spawn lobby_striker_20
+ai2_spawn lobby_striker_21
+ai2_spawn lobby_fodder01
+trigvolume_enable v_37t 0
+}
+
+#tv19 - entrance to the room on the right side near door 24
+func void e_21(string ai_name)
+{
+ai2_spawn lobby_striker_34
+ai2_spawn lobby_victim05
+ai2_spawn lobby_victim06
+trigvolume_enable l_27t 0
+}
+
+#tv25 - in the room, around the place where the female civ gives you the w6_vdg
+func void k_26(string ai_name)
+{
+trigvolume_enable l_27t 1
+}
+
+#tv26 - at the same place as tv19 (entrance to the room)
+func void l_27(string ai_name)
+{
+ai2_spawn L3s_40
+ai2_spawn L3s_41
+}
+
+#tv68 - in front of door 99
+func void a_18(string ai_name)
+{
+trigvolume_enable b_19t 0
+trigvolume_enable c_13t 0
+}
+
+#tv17 - after door 99, after tv68
+func void b_19(string ai_name)
+{
+ai2_spawn lobby_striker_30
+ai2_spawn lobby_striker_31
+playback lobby_striker_31 lobby_roll2
+trigvolume_enable d_20t 0
+}
+
+#tv69 - near door 40, in front of tv16
+func void room2_stop(string ai_name)
+{
+particle room2 stop
+}
+
+#tv16 - near door 40, after tv69
+func void room2_start(string ai_name)
+{
+particle room2 start
+}
+
+#tv49 - after door 40
+func void tv_49(string ai_name)
+{
+ai2_spawn l2_s47
+}
+
+#tv71 - near door 38, in front of tv70
+func void room3_stop(string ai_name)
+{
+particle room3 stop
+}
+
+#tv70 - near door 38, after tv71
+func void room3_start(string ai_name)
+{
+particle room3 start
+}
+
+#tv48 - after door 38
+func void tv_48(string ai_name)
+{
+ai2_spawn l2_s46
+}
+
+#console2
+func void floor4_lock(void)
+{
+music_stop
+particle floor4_lock_locklight01 do start
+target_set 60 30
+sound_dialog_play c00_01_28shinatama
+}
+
+### ENTRANCE HALL - 3RD FLOOR ###
+
+#tv51 - after door 28
+func void tv_51(string ai_name)
+{
+ai2_spawn l4_red1
+ai2_spawn l4_t1
+ai2_spawn l4_s1
+ai2_spawn l4_s67
+ai2_spawn l4_t2
+ai2_spawn l4_s2
+ai2_spawn l4_s3
+ai2_spawn l4_f1
+ai2_spawn l4_f2
+ai2_spawn l4_f3
+ai2_spawn l4_c66
+ai2_kill l4_f1
+ai2_kill l4_f2
+ai2_kill l4_f3
+ai2_kill l4_c66
+}
+
+#tv79 - after door 41
+func void music_kidnap(void)
+{
+sleep 1
+sound_music_start mus_om01 0.0
+sound_music_volume mus_om01 0.75 3.0
+#this music stopped in ta2_54 script
+}
+
+##########
+### SP2 ###
+##########
+
+### GROUND FLOOR ###
+
+#tv58 - after the end of the stairs
+func void tv_58(string ai_name)
+{
+if(save_point eq 2) music_kidnap
+else save_game 2 autosave
+fork remove_ai
+trigvolume_enable tv_58t 0
+trigvolume_enable trigger_volume_80 0
+door_lock 41
+particle security_locklight01 do stop
+objective_set 3 silent
+target_set 60 30
+var_counter = 0
+}
+
+#tv52 - in front of door 42
+func void tv_52(string ai_name)
+{
+particle smoke do stop
+ai2_spawn a_t03
+ai2_passive a_t03 1
+playback a_t03 atrium_run
+sleep 7
+ai2_spawn a_t06
+sleep 7
+ai2_spawn a_s02
+sleep 7
+ai2_spawn a_s03
+sleep 7
+ai2_spawn a_red1
+ai2_passive a_t03 0
+chr_set_health a_t05 900
+chr_set_health a_t06 900
+chr_set_health a_s02 900
+chr_set_health a_s03 900
+}
+
+#tv72 - at the beginning of the stairs to the 2nd floor
+func void room4_start(string ai_name)
+{
+particle room4 start
+}
+
+### 2ND FLOOR ###
+
+#tv53 - at the end of the stairs to the 2nd floor
+func void ta_53(string ai_name)
+{
+ai2_spawn a_t05
+ai2_dopath a_s03 patrol_7043
+ai2_setjobstate a_s03
+ai2_dopath a_s02 patrol_7030
+ai2_setjobstate a_s02
+ai2_dopath a_t06 patrol_7034
+ai2_setjobstate a_t06
+ai2_dopath a_t05 patrol_7042
+ai2_setjobstate a_t05
+chr_set_health a_t05 40
+chr_set_health a_t06 30
+chr_set_health a_s02 80
+chr_set_health a_s03 80
+}
+
+### 1ST FLOOR ###
+
+#tv56 - at the end of the gangway from the 2nd floor to the 1st floor 
+func void ta_53b(string ai_name)
+{
+chr_set_health a_t05 80
+chr_set_health a_t06 60
+chr_set_health a_s02 70
+chr_set_health a_s03 80
+}
+
+#tv75 - after the end of the gangway from the 2nd floor to the 1st floor
+func void room6_start(string ai_name)
+{
+particle room6 do start
+}
+
+#tv83 - after the middle of the floor, in front of tv73
+func void room4_stop(string ai_name)
+{
+particle room4 do stop
+}
+
+#tv73 - after tv83 (func: room3_stop, already used above)
+
+### 3RD FLOOR ###
+
+#tv59 - after the end of the gangway from the 2nd floor to the 3rd floor
+func void room5_stop(string ai_name)
+{
+particle room5 stop
+}
+
+#tv81 - in front of tv74
+func void room5_start(string ai_name)
+{
+particle room5 start
+}
+
+#tv74 - in front of tv
+func void room6_stop(string ai_name)
+{
+particle room6 stop
+}
+
+#tv82 - in front of the beginning of the gangway from the 3rd floor to the 4th floor (func: room4_stop, already used above)
+
+### 4TH FLOOR ###
+
+#tv98 - after the end of the gangway from the 3rd floor to the 4th floor
+func void new_atrium(string ai_name)
+{
+ai2_spawn a_s07
+ai2_spawn a_s05
+ai2_spawn a_v3
+}
+
+#tv77 - complete room, which contains the console8 (func: check_death); I've disabled it
+
+### 5TH FLOOR ###
+
+#tv54 - after the end of the gangway from the 4th floor to the 5th floor
+func void ta2_54(string ai_name)
+{
+ai2_spawn a2_t1
+ai2_spawn a2_red1
+ai2_spawn LSI
+ai2_kill LSI
+sleep 240
+corpse_reset
+music_stop
+}
+
+#tv103 - the complete room, where you get the laser torch
+func void t103(string ai_name)
+{
+trigvolume_enable trigger_volume_103 0
+if (chr_has_lsi(0))
+	{
+	trigvolume_enable trigger_volume_81 1
+	objective_set 4 silent
+	particle obj1 create
+	target_set 9999 30
+	 }
+else
+	{
+	sleep 60
+	trigvolume_enable trigger_volume_103 1
+	}
+}
+
+#tv80 - small flat box on the roof of the elevator
+func void ta_62(string ai_name)
+{
+trigvolume_enable trigger_volume_81 0
+particle obj1 kill
+ai2_kill
+fade_out 0 0 0 30
+sleep 30
+playback 0 ElevatorEndSet
+fade_in 30
+}
+
+##########
+### SP3 ###
+##########
+
+### GROUND FLOOR ###
+
+#tv55 - after the elevator shaft
+func void tsh_55(string ai_name)
+{
+if(save_point ne 3) save_game 3 autosave
+trigvolume_enable tsh_55t 0
+ai2_spawn sh_tank1
+ai2_spawn sh_red1
+ai2_spawn sh_s3
+ai2_spawn sh_s4
+ai2_spawn sh_s4b
+objective_set 5 silent
+target_set 58 30
+env_show 501 0
+env_show 502 0
+env_show 503 0
+env_show 504 0
+env_show 601 1
+env_show 602 1
+sleep 120
+ai2_attack sh_s3 char_0
+}
+
+#tv85 - at the same place as tv55 (func: s3; I've moved the save_game command to tv55, so this tv isn't any longer in use)
+
+#console3
+func void shin_lock(void)
+{
+particle shin_lock_locklight01 do start
+particle roof_locklight01 do start
+}
+
+#tv104 - on the balustrade, near door 14
+func void t102(string ai_name)
+{
+ai2_spawn mbo_sniper
+ai2_spawn mbo_target
+}
+
+#tv76 - staircase, platform between ground floor and 1st floor
+func void t62(string ai_name)
+{
+ai2_spawn sh_s1
+ai2_spawn sh_s2
+ai2_spawn sh_s6
+}
+
+### 1ST FLOOR ###
+
+#tv78 - staircase, platform between 1st floor and 2nd floor
+func void t72(string ai_name)
+{
+ai2_spawn sh_com1
+ai2_spawn sh_tank2
+ai2_spawn sh_s9
+}
+
+### 2ND FLOOR ###
+
+#tv101 - after door 56
+func void t98(string ai_name)
+{
+ai2_spawn a_v4
+}
+
+#tv60 - staircase, platform between 2nd floor and roof, in front of tv100
+func void tsh_60(string ai_name)
+{
+ai2_spawn sh_s12
+ai2_spawn sh_s12b
+helicopter
+}
+
+func void helicopter(void)
+{
+obj_create 901 906
+particle EndDust create
+}
+
+#tv100 - after tv60
+func void t100(string ai_name)
+{
+ai2_spawn roof_tctf1
+ai2_spawn sh_s12c
+}
+
+##########
+### SP4 ###
+##########
+
+#tv63, if you leave the building on the right side
+func void tr_65(string ai_name)
+{
+tr_67
+}
+
+#tv62, if you leave the building on the left side
+func void tr_64(string ai_name)
+{
+tr_67
+}
+
+#tv64 - after the window, which is behind the tctf cop
+func void tr_66(string ai_name)
+{
+tr_67
+}
+
+#tv65 - after the other window on this side
+func void tr_67(string ai_name)
+{
+trigvolume_enable tsh_60t 0
+trigvolume_enable tr_64t 0
+trigvolume_enable tr_65t 0
+trigvolume_enable tr_66t 0
+trigvolume_enable tr_67t 0
+if(save_point eq 4) helicopter
+else save_game 4 autosave
+objective_set 5 silent
+target_set 1 0
+sleep 1
+sound_ambient_start c08_heli 1.0
+fork helicopter_sound_stop
+chr_create 1019 start
+chr_create 1020 start
+chr_create 1021 start
+chr_changeteam 1019 Syndicate
+chr_changeteam 1020 Syndicate
+chr_changeteam 1021 Syndicate
+chr_envanim 1019 HeliOutroShinBox01
+chr_envanim 1020 HeliOutroStrBox01
+chr_envanim 1021 HeliOutroStrBox02
+chr_animate 1019 SHINATstand_heli 1000
+chr_animate 1020 STRIKEstand_heli 1000
+chr_animate 1021 STRIKEcrouch_idle 1000
+env_anim 901 906
+particle EndDust kill
+ai2_spawn barabus
+chr_boss_shield barabus
+ai2_lookatchar barabus 0
+sound_music_start mus_asianb 0
+sound_music_volume mus_asianb 2
+sleep 600
+chr_delete 1019
+chr_delete 1020
+chr_delete 1021
+sleep 600
+obj_kill 901 906
+sound_ambient_stop c08_heli
+}
+
+func void helicopter_sound_stop(void)
+{
+sleep 680
+sound_ambient_volume c08_heli 0.0 12
+}
+
+#tv1 and tv84 - the side after the window, which is behind the tctf cop
+func void BarabasSouth(string barabas)
+{
+sound_ambient_start c11_10_14bar_jet
+playback barabus BarabasSouth
+ai2_barabbas_retrievegun barabus
+sleep 60
+chr_envanim barabus BarabasSouthBox norotation
+chr_animate barabus BARABsouth
+}
+
+#tv4 - the next side, if you go anticlockwise
+func void BarabasEast(string barabas)
+{
+sound_ambient_start c11_10_14bar_jet
+playback barabus BarabasEast
+ai2_barabbas_retrievegun barabus
+sleep 60
+chr_envanim barabus BarabasEastBox norotation
+chr_animate barabus BARABeast
+}
+
+#tv2 - the next side, if you go anticlockwise
+func void BarabasNorth(string barabas)
+{
+sound_ambient_start c11_10_14bar_jet
+playback barabus BarabasNorth
+ai2_barabbas_retrievegun barabus
+sleep 60
+chr_envanim barabus BarabasNorthBox norotation
+chr_animate barabus BARABnorth
+}
+
+#tv3 - the next side, if you go anticlockwise
+func void BarabasWest(string barabas)
+{
+sound_ambient_start c11_10_14bar_jet
+playback barabus BarabasWest
+ai2_barabbas_retrievegun barabus
+sleep 60
+chr_envanim barabus BarabasWestBox norotation
+chr_animate barabus BARABwest
+}
+
+#lose func of barabus
+func void final(void)
+{
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void level_8a(void)
+{
+text_console level_8a
+console_reset 17
+}
+
+func void level_8b(void)
+{
+text_console level_8b
+console_reset 12
+}
+
+func void level_8c(void)
+{
+text_console level_8c
+console_reset 14
+}
+
+func void level_8d(void)
+{
+text_console level_8d
+console_reset 16
+}
+
+func void level_8e(void)
+{
+text_console level_8e
+console_reset 15
+}
+
+func void level_8f(void)
+{
+text_console level_8f
+console_reset 13
+}
Index: /nikanabo/current/bsl/onilight/IGMD/tctf_ii/tctf2.bsl
===================================================================
--- /nikanabo/current/bsl/onilight/IGMD/tctf_ii/tctf2.bsl	(revision 185)
+++ /nikanabo/current/bsl/onilight/IGMD/tctf_ii/tctf2.bsl	(revision 185)
@@ -0,0 +1,982 @@
+#################
+### VARIABLES ###
+#################
+
+var int var_counter = 0;
+var int var_counter2 = 0;
+var int var_counter3 = 0;
+
+############
+### MAIN ###
+############
+
+func void main(void)
+{
+gl_fog_red = 0
+gl_fog_blue = 0
+gl_fog_green = 0
+gl_fog_start = .995
+gs_farclipplane_set 5000
+ui_suppress_prompt = 1
+chr_auto_aim_dist = 0
+start
+}
+
+#############
+### START ###
+#############
+
+func void start(string ai_name)
+{
+fork deactivate_stuff
+if(save_point eq 0) save_point = 1
+if(save_point eq 1) fork intro
+if(save_point eq 2) restore_game
+if(save_point eq 3) restore_game
+if(save_point eq 4) restore_game
+if(save_point eq 5) restore_game
+sleep 5
+fork sp_all
+}
+
+func void deactivate_stuff(void)
+{
+#not used
+trigvolume_enable shinzom_voice1 0
+trigvolume_enable shinzom_voice2 0
+trigvolume_enable shinzom_voice3 0
+trigvolume_enable shinzom_voice4 0
+trigvolume_enable trigger_volume_03 0
+trigvolume_enable trigger_volume_04 0
+trigvolume_enable trigger_volume_04_copy 0
+trigvolume_enable trigger_volume_04_copy_copy 0
+trigvolume_enable trigger_volume_05 0
+trigvolume_enable trigger_volume_07b 0
+trigvolume_enable trigger_volume_10 0
+trigvolume_enable trigger_volume_12 0
+trigvolume_enable trigger_volume_14 0
+trigvolume_enable trigger_volume_16 0
+trigvolume_enable trigger_volume_20 0
+trigvolume_enable trigger_volume_34 0
+trigvolume_enable trigger_volume_37 0
+trigvolume_enable trigger_volume_38 0
+trigvolume_enable trigger_volume_41 0
+trigvolume_enable trigger_volume_44 0
+trigvolume_enable trigger_volume_45 0
+trigvolume_enable trigger_volume_46 0
+trigvolume_enable trigger_volume_49 0
+trigvolume_enable trigger_volume_51 0
+trigvolume_enable trigger_volume_52 0
+trigvolume_enable trigger_volume_54 0
+trigvolume_enable trigger_volume_55 0
+trigvolume_enable trigger_volume_56 0
+trigvolume_enable trigger_volume_57 0
+trigvolume_enable trigger_volume_61 0
+trigvolume_enable trigger_volume_67 0
+trig_deactivate 10
+trig_deactivate 91
+trig_deactivate 92
+trig_deactivate 93
+trig_deactivate 94
+trig_deactivate 910
+trig_deactivate 210
+trig_deactivate 310
+trig_deactivate 410
+trig_deactivate 510
+trig_deactivate 214
+trig_deactivate 314
+trig_deactivate 414
+trig_deactivate 514
+trig_deactivate 2101
+trig_deactivate 3101
+trig_deactivate 4101
+trig_deactivate 5101
+env_show 403 0
+env_show 1010 0
+door_lock 4
+door_lock 5
+door_lock 6
+door_lock 7
+door_lock 8
+door_lock 9
+console_deactivate 3
+console_deactivate 399
+console_deactivate 400
+console_deactivate 401
+console_deactivate 402
+#used
+trigvolume_enable trigger_volume_06 0
+trigvolume_enable trigger_volume_29 0
+trigvolume_enable trigger_volume_35 0
+trigvolume_enable trigger_volume_39 0
+if(save_point ne 0 and save_point ne 1) deactivate_sp1
+if(save_point ne 2) deactivate_sp2
+if(save_point ne 3) deactivate_sp3
+env_shade 321 325 .3 .3 .3
+env_show 171 0
+env_show 172 0
+env_show 173 0
+env_show 174 0
+door_lock 42
+}
+
+func void deactivate_sp1(void)
+{
+trig_deactivate 60
+trig_deactivate 61
+trig_deactivate 62
+trig_deactivate 63
+trig_deactivate 64
+trig_deactivate 65
+trig_deactivate 70
+trig_deactivate 71
+trig_deactivate 72
+trig_deactivate 73
+trig_deactivate 74
+trig_deactivate 75
+}
+
+func void deactivate_sp2(void)
+{
+trig_deactivate 6
+trig_deactivate 7
+trig_deactivate 98
+trig_deactivate 99
+}
+
+func void deactivate_sp3(void)
+{
+trig_deactivate 1
+trig_deactivate 2
+trig_deactivate 3
+trig_deactivate 4
+trig_deactivate 5
+trig_deactivate 8
+trig_deactivate 100
+trig_deactivate 101
+trig_deactivate 302
+trig_deactivate 303
+trig_deactivate 315
+trig_deactivate 320
+trig_deactivate 500
+trig_deactivate 501
+trig_deactivate 502
+trig_deactivate 503
+trig_deactivate 400
+trig_deactivate 510
+trig_deactivate 511
+trig_deactivate 512
+trig_deactivate 520
+trig_deactivate 521
+trig_deactivate 522
+}
+
+func void you_lose(string ai_name)
+{
+fade_out 0 0 0 30
+sleep 30
+lose
+}
+
+####################################
+### SEVERAL TIMES USED FUNCTIONS ###
+####################################
+
+func void sp_all(void)
+{
+co_message_display = 0
+if(save_point eq 1) save_game 1 autosave
+if(save_point eq 2) save_game 2 autosave
+if(save_point eq 3) save_game 3 autosave
+if(save_point eq 4) save_game 4 autosave
+if(save_point eq 5) save_game 5 autosave
+sleep 180
+co_message_display = 1
+}
+
+func void remove_ai(void)
+{
+ai2_kill
+sleep 60
+powerup_reset
+weapon_reset
+sleep 240
+corpse_reset
+}
+
+func void music_stop(void)
+{
+sound_music_stop mus_main03
+sound_music_stop mus_wls
+sound_music_stop mus_trt
+sound_music_stop mus_sv
+}
+
+##########
+### SP1 ###
+##########
+
+func void intro(void)
+{
+particle roof_doors_locklight01 do start
+particle griffin_locklight01 do start
+door_unlock 61
+door_unlock 67
+door_unlock 71
+chr_teleport 0 19
+chr_inv_reset 0
+ai2_spawn l1
+ai2_spawn l3
+ai2_spawn l7
+ai2_spawn A_L8
+ai2_spawn A_L12
+ai2_spawn A_L18
+ai2_spawn A_L19
+ai2_spawn A_Lbo13
+objective_set 1 silent
+target_set 590 30
+sleep 1
+sound_music_start mus_main03 1.0
+}
+
+#tv1 - the complete volume between the doors 61, 63, 67 and 68
+func void t2(string ai_name)
+{
+trigvolume_enable trigger_volume_61 0
+ai2_spawn n5
+ai2_spawn A_Sbo14
+ai2_dopath A_Sbo14 patrol_14
+ai2_setjobstate A_Sbo14
+ai2_spawn A_Sbo15
+sleep 30
+ai2_dopath A_Sbo15 patrol_14
+ai2_setjobstate A_Sbo15
+music_stop
+}
+
+#neutral func of n5
+func void outta_sight(string ai_name)
+{
+ai2_dopath n5 patrol_99
+ai2_setjobstate n5
+}
+
+#tv61 - at the same place as tv1 (entry func: t61); I've disabled it
+
+#console 5
+func void roof(string ai_name)
+{
+trigvolume_enable trigger_volume_06 1
+particle roof_locklight01 do start
+ai2_spawn A_T25
+}
+
+#console 12
+func void roof_door2(string ai_name)
+{
+particle roof_door2_locklight01 do start
+ai2_spawn A_n17
+ai2_dopath A_n17 patrol_16
+ai2_setjobstate A_n17
+}
+
+#tv3 - long box behind door 63 and the windows (entry func: t4); I've disabled it
+#tv4 - long box behind door 68 and the windows (entry func: t4); I've disabled it
+#tv66 - long box behind the windows on the elevator side (entry func: t4); I've disabled it
+#tv67 - long box behind the windows on the opposite side of tv66 (entry func: t4); I've disabled it
+#tv2 - after door 59 (entry func: t3); I've disabled it
+
+#tv5 - after door 58
+func void t6(string ai_name)
+{
+ai2_spawn A_L20
+ai2_spawn A_L21
+target_set 593 30
+trig_activate 6
+}
+
+##########
+### SP2 ###
+##########
+
+#tv46 - on the platform between the stairs to the hall
+func void s2(string ai_name)
+{
+if(save_point eq 2)
+	{
+	objective_set 1 silent
+	target_set 593 30
+	}
+else
+	{
+	fork remove_ai
+	save_game 2 autosave
+	particle roof_locklight01 do stop
+	door_lock 59
+	trig_activate 7
+	trig_activate 98
+	trig_activate 99
+	deactivate_sp1
+	}
+particle shin_lock_locklight01 do start
+door_unlock 14
+door_unlock 48
+ai2_spawn B_S22
+}
+
+### HALL - 2ND FLOOR ###
+
+#tv6 - near the end of the stairs
+func void t7(string ai_name)
+{
+ai2_dopath B_S22 patrol_23
+ai2_setjobstate B_S22
+ai2_spawn B_N28
+ai2_dopath B_N28 patrol_42
+ai2_setjobstate B_N28
+ai2_spawn B_Lbo26
+playback_block B_Lbo26 run1 interp 20
+sleep 20
+ai2_dopath B_Lbo26 patrol_27
+ai2_setjobstate B_Lbo26
+}
+
+#hit func of B_S22
+func void B_S22_run (string ai_name)
+{
+ai2_dopath B_S22 patrol_24
+ai2_setjobstate B_S22
+}
+
+func void patrolscript0001(void)
+{
+playback_block B_S22 taunt1 interp 20
+}
+
+#tv12 - at the same place as tv6 (entry func: t7b); Ive disabled it
+
+#tv7 - after door 54 and the window next to it
+func void t8(string ai_name)
+{
+ai2_spawn B_L41
+ai2_spawn B_S36
+ai2_makeignoreplayer B_S36 0
+ai2_spawn B_S37
+ai2_makeignoreplayer B_S37 0
+ai2_spawn B_Sbo38
+ai2_makeignoreplayer B_Sbo38 0
+sound_music_start mus_wls 1.0
+sound_dialog_play c14_54_24konoko
+sound_dialog_play_block pause
+objective_set 2 silent
+}
+
+#tv59 - behind door 56 and the window next to it
+func void t59(string ai_name)
+{
+ai2_spawn B_L30
+ai2_spawn B_L95
+ai2_spawn B_Lbo27
+}
+
+#tv11 - after the right furniture in the room with door 64 (entry func: t12); I've disabled it
+
+#tv37 - on the platform between the stairs
+func void t43(string ai_name)
+{
+ai2_spawn B_S29
+ai2_spawn B_S43
+ai2_spawn B_S96
+}
+
+### HALL - 1ST FLOOR ###
+
+#tv68 - behind door 60 and the window next to it (entry func: t67); I've disabled it
+#tv8 - behind door 55 and the window next to it (entry func: t10); I've disabled it
+#tv34 - in front of door 50 and the window next to it (entry func: t38); I've disabled it
+
+#tv60 - on the platform between the stairs
+func void t60(string ai_name)
+{
+ai2_spawn B_C32
+ai2_spawn B_C33
+ai2_spawn B_C34
+}
+
+### HALL - GROUND FLOOR ###
+
+#tv9 - after door 48
+func void t11(string ai_name)
+{
+trigvolume_enable trigger_volume_11_copy 0
+t11_funcs
+}
+
+#tv25 - big volume on the ground
+func void t11b(string ai_name)
+{
+trigvolume_enable trigger_volume_11 0
+t11_funcs
+}
+
+func void t11_funcs(void)
+{
+ai2_dopath B_S36 patrol_38
+ai2_setjobstate B_S36
+ai2_spawn B_Lbo76
+ai2_spawn B_C32
+ai2_spawn B_C33
+ai2_spawn B_C34
+music_stop
+}
+
+#tv69 - in front of the wall with the high window next to door 48
+func void t68(string ai_name)
+{
+ai2_spawn mbo_femcop
+}
+
+#tv40 - after door 14 (no funcs); I've disabled it
+#tv42 - on the platform between the stairs (entry func: t45); I've disabled it
+
+##########
+### SP3 ###
+##########
+
+#tv44 - at the same place as tv42
+func void save3_and_spine(string ai_name)
+{
+if(save_point eq 3) objective_set 2 silent
+else
+	{
+	fork remove_ai
+	save_game 3 autosave
+	particle shin_lock_locklight01 do stop
+	door_lock 14
+	deactivate_sp2
+	trig_activate 1
+	trig_activate 2
+	trig_activate 3
+	trig_activate 4
+	trig_activate 5
+	trig_activate 8
+	trig_activate 100
+	trig_activate 101
+	trig_activate 302
+	trig_activate 303
+	trig_activate 400
+	trig_activate 500
+	trig_activate 501
+	trig_activate 502
+	trig_activate 503
+	trig_activate 510
+	trig_activate 511
+	trig_activate 512
+	trig_activate 520
+	trig_activate 521
+	trig_activate 522
+	trig_activate 315
+	trig_activate 320
+	}
+ai2_spawn C_C47
+ai2_spawn C_C65
+ai2_spawn C_L50
+ai2_spawn C_L51
+ai2_spawn C_N48
+ai2_spawn C_N55
+ai2_spawn C_N60
+ai2_spawn C_Sbo44
+ai2_spawn C_Sbo93
+ai2_makeignoreplayer C_C65 1
+ai2_makeignoreplayer C_L50 1
+ai2_makeignoreplayer C_L51 1
+ai2_makeignoreplayer C_N55 1
+particle spine1 do start
+particle spine2 do start
+particle spine3 do start
+particle spinesound1 do start
+particle spinesound2 do start
+particle spinesound3 do start
+target_set 587 30
+sleep 1
+sound_music_start mus_trt 0.8
+}
+
+#tv39 - in some diastance after tv44 (entry func: t45b); I've disabled it
+
+### ATRIUM - 7TH FLOOR ###
+
+#tv13 - in the middle between the end of the stairs and the entrance of the room with console 10 (entry func: t14); I've disabled it
+#tv49 - medium volume around console 10 (no funcs); I've disabled it
+
+#neutral func of C_N48
+func void patrolscript0098(string ai_name)
+{	
+ai2_doalarm C_N48 10
+}
+
+#tv48 - in front of console 10
+func void t40(string ai_name)
+{
+trigvolume_enable trigger_volume_40 0
+var_counter = 1
+check_consoles
+}
+
+#console 10
+func void powersub1(string ai_name)
+{
+if(var_counter eq 0)
+	{
+	trigvolume_enable trigger_volume_40 0
+	var_counter2 = var_counter2 + 1
+	}
+var_counter3 = var_counter3 + 1
+particle spine1 do stop
+particle spinesound1 do stop
+if(var_counter3 eq 1 or var_counter3 eq 101) target_set 594 30
+if(var_counter3 eq 11) target_set 595 30
+if(var_counter3 eq 111) power_off
+}
+
+#tv14 at the beginning of the ramp
+func void t15(string ai_name)
+{
+ai2_lookatme C_L51
+ai2_dopath C_L51 patrol_51
+ai2_setjobstate C_L51
+ai2_makeignoreplayer C_L51 0
+sleep 90
+ai2_lookatme C_L50
+ai2_dopath C_L50 patrol_50
+ai2_setjobstate C_L50 
+ai2_makeignoreplayer C_L50 0
+}
+
+### ATRIUM - 6TH FLOOR ###
+
+#tv15 - long box along in front of the windows and the entrance of the first room (entry func: t16); I've disabled it
+
+#tv58 - long box behind the windows and the entrance of the second room
+func void t58(string ai_name)
+{
+ai2_spawn C_Lbo53
+ai2_spawn C_Sbo52
+}
+
+### ATRIUM - 5TH FLOOR ###
+
+#tv16 - in the first room around C_N55
+func void t17(string ai_name)
+{
+ai2_makeignoreplayer C_N55 0
+ai2_spawn C_Sbo56
+}
+
+#tv17 - long box behind the windows and the entrance of the second room
+func void t18(string ai_name)
+{
+ai2_spawn C_S57
+}
+
+### ATRIUM - 4TH FLOOR ###
+
+#18 - around the entrance to the room with console 9
+func void t19(string ai_name)
+{
+ai2_spawn C_S58
+ai2_spawn C_S59
+}
+
+#tv53 - medium volume around console 9 (no funcs); I've disabled it
+
+#tv52 - in front of console 9
+func void t53(string ai_name)
+{
+trigvolume_enable trigger_volume_53 0
+check_consoles
+}
+
+#console 9
+func void powersub3(string ai_name)
+{
+var_counter3 = var_counter3 + 10
+particle spine3 do stop
+particle spinesound3 stop
+if(var_counter3 eq 10 or var_counter3 eq 110) target_set 587 30
+if(var_counter3 eq 11) target_set 595 30
+if(var_counter3 eq 111) power_off
+}
+
+### ATRIUM - 3RD FLOOR ###
+
+#neutral func of C_N60
+func void t20(string ai_name)
+{
+ai2_spawn C_Lbo62
+ai2_spawn C_Sbo61
+}
+
+#tv51 - medium volume around console 8 (no funcs); I've disabled it
+
+#tv50 - in front of console 8
+func void t50(string ai_name)
+{
+trigvolume_enable trigger_volume_50 0
+check_consoles
+}
+
+func void check_consoles(void)
+{
+var_counter2 = var_counter2 + 1
+if(var_counter2 eq 1) sound_dialog_play c14_54_25konoko
+if(var_counter2 eq 2) sound_dialog_play c14_54_26konoko
+if(var_counter2 eq 3) sound_dialog_play c14_54_27konoko
+}
+
+#console 8
+func powersub2(string ai_name)
+{
+var_counter3 = var_counter3 + 100
+particle spine2 do stop
+particle spinesound2 do stop
+if(var_counter3 eq 100 or var_counter3 eq 101) target_set 594 30
+if(var_counter3 eq 110) target_set 587 30
+if(var_counter3 eq 111) power_off
+}
+
+func void power_off(void)
+{
+particle door42_locklight01 do start
+door_unlock 42
+deactivate_sp3
+objective_set 3 silent
+target_set 403 30
+music_stop
+}
+
+### ATRIUM - 2ND FLOOR ###
+
+#tv19 - after the entrance to the first room
+#tv70 - behind the windows of the first room
+func void t21(string ai_name)
+{
+ai2_spawn C_Sbo63
+ai2_spawn C_Sbo64
+}
+
+#tv21 - at the beginning of the stairs down to the ground floor
+#tv22 - in the free middle of the atrium between the first and second floor; if you fall or jump down, you'll trigger it off
+func void t23(string ai_name)
+{
+ai2_spawn C_L71
+ai2_spawn C_S72
+}
+
+#tv20 - long box behind the windows and the entrance of the second room
+func void t22(string ai_name)
+{
+ai2_makeignoreplayer C_C65 0
+}
+
+### ATRIUM - 1ST FLOOR ###
+
+#nothing
+
+### ATRIUM - GROUND FLOOR ###
+
+#nothing
+
+##########
+### SP4 ###
+##########
+
+#tv43 - after door 42
+func void s4(string ai_name)
+{
+if(save_point eq 4) objective_set 3 silent
+else 
+	{
+	fork remove_ai
+	save_game 4 autosave
+	var_counter = 0
+	var_counter2 = 0
+	var_counter3 = 0
+	}
+ai2_spawn C_N74
+target_set 596 30
+sleep 90
+}
+
+#tv36 - at the same place as tv43 (entry func: t41); I've disabled it
+
+### ENTRANCE HALL - 3RD FLOOR ###
+
+#tv23 - after door 41
+func void t25(string ai_name)
+{
+ai2_spawn D_C70
+ai2_spawn D_Sbo71
+ai2_spawn D_Sbo72
+ai2_spawn D_Sbo73
+ai2_spawn D_Sbo75
+ai2_spawn D_N76
+}
+
+#tv33 - after door 46 (entry func: t37); I've disabled it
+
+#console 7
+func void floor4_lock(string ai_name)
+{
+trigvolume_enable trigger_volume_39 1
+particle floor4_lock_locklight01 do start
+particle stair_lock_locklight01 do start
+}
+
+#tv24 - in the passage to the room with the neutral, who gives you a Scramble Cannon (w7_scc)
+func void t26(string ai_name)
+{
+ai2_spawn D_L74
+ai2_spawn new_1
+}
+
+#neutral func of new_1
+func void attack_konoko(string ai_name)
+{
+ai2_attack D_L74 A_player
+}
+
+#tv35 - in front of door 28
+func void t39(string ai_name)
+{
+target_set 598 30
+}
+
+### ENTRANCE HALL - 2ND FLOOR ###
+
+#tv47 - after the end of the stairs to the second floor
+func void t48(string ai_name)
+{
+ai2_spawn D_L91
+ai2_spawn D_S90
+ai2_spawn D_S89
+ai2_spawn D_S101
+ai2_spawn D_C100
+ai2_spawn D_Sbo75
+ai2_spawn D_Sbo92
+}
+
+#tv31 - after door 24 (entry func: t34); I've disabled it
+#tv40 - on the footbridge (entry func: t44); I've disabled it
+
+#console 2
+func void lastdoor3(string ai_name)
+{
+particle lastdoor3_locklight01 do start
+var_counter = var_counter + 1
+if(var_counter eq 1 or var_counter eq 101) target_set 599 30
+if(var_counter eq 11) target_set 597 30
+if(var_counter eq 111) lastdoor_open
+}
+
+### ENTRANCE HALL - 1ST FLOOR ###
+
+#tv29 - after door 20
+func void t31(string ai_name)
+{
+t32
+}
+
+#tv30 - on the footbridge
+func void t32(string ai_name)
+{
+ai2_spawn D_S83
+ai2_spawn D_S87
+ai2_spawn D_L84
+ai2_spawn D_L88
+ai2_spawn D_Lbo85
+ai2_spawn D_Sbo86
+trigvolume_enable trigger_volume_31 0
+trigvolume_enable trigger_volume_32 0
+}
+
+#console 13
+func void lastdoor2(string ai_name)
+{
+particle lastdoor2_locklight01 do start
+var_counter = var_counter + 10
+if(var_counter eq 10 or var_counter eq 110) target_set 598 30
+if(var_counter eq 11) target_set 597 30
+if(var_counter eq 111) lastdoor_open
+}
+
+### ENTRANCE HALL - GROUND FLOOR ###
+
+#tv28 - after door 37
+func void t30(string ai_name)
+{
+ai2_spawn D_L80
+}
+
+#tv26 - after door 32 (inside the room)
+func void t28(string ai_name)
+{
+ai2_spawn D_S78
+ai2_spawn D_S79
+}
+
+#console 11
+func void lastdoor1(string ai_name)
+{
+particle lastdoor1_locklight01 do start
+var_counter = var_counter + 100
+if(var_counter eq 100 or var_counter eq 101) target_set 599 30
+if (var_counter eq 110) target_set 598 30
+if(var_counter eq 111) lastdoor_open
+}
+
+func void lastdoor_open(void)
+{	
+trigvolume_enable trigger_volume_29 1
+particle ZomShin_door_locklight01 do start
+door_unlock 97
+set_objective_4
+target_set 401 30
+}
+
+#tv27 - after door 32 (outside of the room)
+func void t29(string ai_name)
+{
+ai2_spawn D_Lbo81
+ai2_spawn D_S82
+}
+
+#tv 41 - on the platform between the stairs to the torture chamber (entry func: t33); I've disabled it
+
+#tv10 - in front of door 16
+func void t9(string ai_name)
+{
+fork remove_ai
+particle lastdoor1_locklight01 do stop
+particle lastdoor2_locklight01 do stop
+particle lastdoor3_locklight01 do stop
+door_lock 97
+target_set 1 0
+spawn_griffin
+}
+
+func void spawn_griffin(void)
+{
+particle zombiesteam start
+env_show 171 1
+env_show 172 1
+env_show 173 1
+env_show 174 1
+ai2_spawn ZomGrif
+ai2_passive ZomGrif 1
+chr_inv_reset ZomGrif
+ai2_setmovementmode ZomGrif walk
+playback ZomGrif ZomGrifDraw
+fork check_health
+}
+
+##########
+### SP5 ###
+##########
+
+#tv45 - in some distance after door 16
+func void t42(string ai_name)
+{
+if(save_point eq 5)
+	{
+	spawn_griffin
+	set_objective_4
+	target_set 1 0
+	}
+else
+	{
+	save_game 5 autosave
+	door_lock 16
+	}
+particle ZomShin_door_locklight01 do stop
+sleep 1
+sound_ambient_start zomshin_amb_loop 1.0
+sound_music_start mus_sv 0.75
+}
+
+#tv55 - in front of console 402 (entry func: t55); I've disabled it
+#tv64 - in front of the sector with console 402 (entry func: shinzom_voice3); I've disabled it
+#tv56 - in front of console 401 (entry func: t56); I've disabled it
+#tv63 - on the right next to console 401; Iguess, they've forgot to rotate it (entry func: shinzom_voice2); I've disabled it
+#tv56 - in front of console 400 (entry func: t57); I've disabled it
+#tv62 - in front of the sector with console 400 (entry func: shinzom_voice1); I've disabled it
+#tv54 - in front of console 399 (entry func: t52); I've disabled it
+#tv65 - in front of the sector with console 399 (entry func: shinzom_voice4); I've disabled it
+
+func void check_health(void)
+{
+chr_set_health ZomGrif 100
+chr_wait_health ZomGrif 99
+trigvolume_enable trigger_volume_35 1
+ui_suppress_prompt = 0
+objective_set 5
+chr_set_health ZomGrif 100
+chr_wait_health ZomGrif 99
+chr_set_health ZomGrif 250
+ai2_passive ZomGrif 0
+ai2_attack ZomGrif A_player
+}
+
+#tv32 - in front of the room, where Griffin waits
+func void t35(string ai_name)
+{
+killed_griffen 0
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#lose func of ZomGrif
+func void grifdies(string ai_name)
+{
+killed_griffen 1
+fade_out 0 0 0 30
+sleep 30
+win
+}
+
+#####################
+### TEXT CONSOLES ###
+#####################
+
+func void console1(string ai_name)
+{
+text_console level_18c
+console_reset 14
+console_activate 14
+}
+
+func void console2(string ai_name)
+{
+text_console level_18d
+console_reset 15
+}
+
+func void console_android(void)
+{
+text_console level_18b
+console_reset 16
+}
+
+func void console_zombie(void)
+{
+text_console level_18a
+console_reset 17
+}
+
+func void level_18e(string ai_name)
+{
+text_console level_18e
+console_reset 1
+console_activate 1
+}
Index: /nikanabo/current/bsl/onilight/readme.txt
===================================================================
--- /nikanabo/current/bsl/onilight/readme.txt	(revision 185)
+++ /nikanabo/current/bsl/onilight/readme.txt	(revision 185)
@@ -0,0 +1,5 @@
+Original level logic edited by ssg.
+No cutscenes. A few enemies added.
+List of features coming Soon(TM).
+Works with all versions of Oni.
+http://oni.bungie.org/forums/index.php?threadid=43
Index: /nikanabo/current/bsl/onilight/winstall.bat
===================================================================
--- /nikanabo/current/bsl/onilight/winstall.bat	(revision 185)
+++ /nikanabo/current/bsl/onilight/winstall.bat	(revision 185)
@@ -0,0 +1,14 @@
+echo off
+cd ..\mybackup
+IF NOT EXIST backupok.txt (
+    echo Level logic not backed up.
+    cd ..\onilight
+) ELSE (
+    echo Installing Oni Light level logic...
+    cd ..\..\..\GameDataFolder
+    rmdir /s /q IGMD
+    xcopy ..\nikanabo\bsl\onilight\IGMD IGMD /s /k /i
+    cd ..\nikanabo\bsl\onilight
+    echo Oni Light level logic installed.
+)
+PAUSE
Index: /nikanabo/current/bsl/onilight/xinstall.sh
===================================================================
--- /nikanabo/current/bsl/onilight/xinstall.sh	(revision 185)
+++ /nikanabo/current/bsl/onilight/xinstall.sh	(revision 185)
@@ -0,0 +1,13 @@
+#!/bin/sh
+cd ../mybackup
+if [ ! -e backupok.txt ]
+    echo "User level logic not backed up."
+    cd ../onilight
+else
+    echo "Installing Oni Light level logic..."
+    cd ../../../GameDataFolder
+    rm -rf IGMD
+    cp -r ../nikanabo/bsl/onilight/IGMD .
+    cd ../nikanabo/bsl/onilight
+    echo "Oni Light level logic installed."
+fi
Index: /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf2.bsl
===================================================================
--- /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf2.bsl	(revision 185)
+++ /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf2.bsl	(revision 185)
@@ -0,0 +1,2021 @@
+#	tctf2_spawn
+#	scripts for level 18 by wu
+
+var int counter=3;
+var int my_save_point=0;
+var int counterA=0;
+var int counterB=0;
+var int counterC=0;
+var int counterD=0;
+var int counterDestroy=0;
+var int lastdoor_count=0;
+var int sub1 = 0;
+var int sub2 = 0;
+var int sub3 = 0;
+var int ld1;
+var int ld2;
+var int ld3;
+var int audio_counter = 3;
+
+#########
+# music #
+#########
+func void music_intro(void)
+{
+	sound_music_start mus_main03 1.0
+#	this music stopped in t2 script
+}
+
+func void music_chair(void)
+{
+	dprint music_chair
+	sound_music_start mus_wls 1.0
+#	this music stopped in 11 and 11b script
+}
+
+func void music_atrium(void)
+{
+	dprint music_atrium
+	sound_music_start mus_trt .8
+#	this music stopped in check_power script
+}
+
+func void music_zom(void)
+{
+	dprint music_zom
+	sound_music_start mus_sv 0.75
+#	this music stopped in Zom script
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_main03
+	sound_music_stop mus_wls
+	sound_music_stop mus_trt
+	sound_music_stop mus_sv
+}
+
+func void spawnA(void)
+{
+		dprint spawn_zone_A
+
+		ai2_spawn A_L19
+		ai2_spawn l1
+		ai2_spawn l3
+		ai2_spawn A_L12
+		ai2_spawn A_Lbo13
+		ai2_spawn A_L8
+		ai2_spawn l7
+}
+###############################
+#	start and objectives    #
+###############################
+func void start(string ai_name)
+{
+	dprint start
+	trig_deactivate	1	
+	trig_deactivate	2	
+	trig_deactivate	3	
+	trig_deactivate	4	
+	trig_deactivate	5
+	trig_deactivate	6
+	trig_deactivate	7
+	trig_deactivate	8
+	trig_deactivate	9
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+	trig_deactivate	98
+	trig_deactivate	99
+	trig_deactivate	10
+	trig_deactivate	302	
+	trig_deactivate	303	
+	trig_deactivate	315
+	trig_deactivate	320	
+	trig_deactivate	100
+	trig_deactivate	101	
+	trig_deactivate	500	
+	trig_deactivate	501	
+	trig_deactivate	502	
+	trig_deactivate	503	
+	trig_deactivate	400		
+	trig_deactivate	510
+	trig_deactivate 511
+	trig_deactivate	512	
+	trig_deactivate	520
+	trig_deactivate	521
+	trig_deactivate	522
+	door_unlock 65
+	door_unlock 71
+#	door_unlock 59
+	door_unlock 61	
+	door_unlock 67
+	door_lock 7
+	door_lock 4
+	door_lock 5
+	door_lock 8
+	door_lock 6
+	door_lock 9
+	console_deactivate 3
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice1 0
+	trigvolume_enable shinzom_voice2 0
+	trigvolume_enable shinzom_voice3 0
+	trigvolume_enable shinzom_voice4 0
+
+	particle griffin_locklight01 do start
+	particle door42_locklight01 do start
+	particle stair_lock_locklight01 do start
+	particle roof_doors_locklight01 do start
+	trigvolume_enable trigger_volume_29 0
+	trigvolume_enable trigger_volume_35 0
+	trigvolume_enable trigger_volume_39 0
+	trigvolume_enable trigger_volume_36 0
+	trigvolume_enable trigger_volume_41 0
+
+	my_save_point = save_point;
+
+	if (my_save_point eq 0)
+	{
+		objective_set(1)
+		target_set(590,30.0)
+
+		Intro	
+		spawnA
+	}
+
+	if (my_save_point eq 1)
+	{
+		dprint restore1
+		objective_set(1)
+		env_show 403 0 
+		target_set(590,30.0)
+		spawnA
+		music_intro
+		restore_game
+	}
+
+	if (my_save_point eq 2)
+	{
+		dprint restore2
+		objective_set(2)
+		target_set(593,30.0)
+		trigvolume_enable trigger_volume_06 0
+		ai2_spawn B_S22
+
+		particle shin_lock_locklight01 do start
+		door_unlock 48
+		door_unlock 14
+		trig_activate	6
+		trig_activate	7
+		trig_activate	99
+		trig_activate	98
+		restore_game
+	}
+
+	if (my_save_point eq 3)
+	{
+		dprint restore3
+		particle shin_lock_locklight01 do stop
+		door_lock 14
+		objective_set(2)
+		trigvolume_enable trigger_volume_46 0
+		trigvolume_enable trigger_volume_47 0
+		trig_deactivate	60
+		trig_deactivate	61
+		trig_deactivate	62
+		trig_deactivate	63
+		trig_deactivate	64
+		trig_deactivate	65
+		trig_deactivate	70
+		trig_deactivate	71
+		trig_deactivate	72
+		trig_deactivate	73
+		trig_deactivate	74
+		trig_deactivate	75
+		trig_deactivate 91
+		trig_deactivate 92
+		trig_deactivate 93
+		trig_deactivate	98
+		trig_deactivate	99
+		trig_deactivate	6
+		trig_deactivate	7
+		target_set(587,30.0)
+		restore_game
+		spine1
+		sleep 7
+		spine2
+		sleep 7
+		spine3
+	}
+
+	if (my_save_point eq 4)
+	{
+		dprint restore4
+		objective_set(3)
+		target_set(596,30.0)
+		trig_deactivate	60
+		trig_deactivate	61
+		trig_deactivate	62
+		trig_deactivate	63
+		trig_deactivate	64
+		trig_deactivate	65
+		trig_deactivate	70
+		trig_deactivate	71
+		trig_deactivate	72
+		trig_deactivate	73
+		trig_deactivate	74
+		trig_deactivate	75
+		trig_deactivate 91
+		trig_deactivate 92
+		trig_deactivate 93
+		trig_deactivate	98
+		trig_deactivate	99
+		trig_deactivate	6
+		trig_deactivate	7
+		door_lock 42
+		particle door42_locklight01 do stop
+		ai2_spawn D_N74
+		restore_game
+	}
+
+	if (my_save_point eq 5)
+	{
+		dprint restore5
+		objective_set(4)
+		trigvolume_enable trigger_volume_42 0
+		trigvolume_enable trigger_volume_35 0
+		particle ZomShin_door_locklight01 do stop
+		door_lock 16
+
+		#TCTF II cutscene "Base"
+		env_show 171 1
+		env_show 172 1
+		env_show 173 1
+		env_show 174 1
+		particle Forcefield do start
+		particle zombiesteam start
+		sound_ambient_start zomshin_amb_loop 1.0
+		music_zom
+
+		GrifSpawn
+
+		# don't call the GrifSpawn function again
+		trigvolume_enable t9 0
+
+		create_zomshin
+		playback ZomShin BaseShin
+
+		restore_game
+
+		zombie_round_2
+	#	chr_teleport 0 589
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set (1,0)
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective_2
+	objective_set(2)
+	target_set (1,0)
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective_3
+	objective_set(3)
+	target_set (1,0)
+}
+
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective_4
+	objective_set(4)
+	target_set (401,30)
+	particle ZomShin_door_locklight01 do start
+}
+
+
+#################################
+#	cut scene scripts         #
+#################################
+
+func void grifdies(string ai_name)
+{
+	killed_griffen 1
+	OutroKill
+}
+
+func void t35(string ai_name)
+{
+	killed_griffen 0
+	OutroNoKill
+}
+
+func void outta_sight(string ai_name)
+{
+	ai2_dopath n5 patrol_99
+	ai2_setjobstate n5
+}
+
+#########################
+#  trigger volume stuff #
+#########################
+
+func void t68(string ai_name)
+{
+	ai2_spawn mbo_femcop
+}
+
+func void t2(string ai_name)
+{
+	dprint t2_active
+	trigvolume_enable trigger_volume_61 0
+	ai2_spawn n5
+	ai2_spawn A_Sbo14
+	ai2_dopath A_Sbo14 patrol_14
+	ai2_setjobstate A_Sbo14
+	ai2_spawn A_Sbo15
+	sleep 30
+	ai2_dopath A_Sbo15 patrol_14
+	ai2_setjobstate A_Sbo15
+#	ai2_spawn A_Sbo16
+	music_stop
+
+}
+
+func void t61(string ai_name)
+{
+	dprint t61_active
+	trigvolume_enable trigger_volume_02 0
+	ai2_spawn n5
+	ai2_spawn A_Sbo14
+	ai2_spawn A_Sbo15
+	music_stop
+}
+
+func void t3(string ai_name)
+{
+	dprint t3_active
+	ai2_dopath A_n17 patrol_16
+	ai2_setjobstate A_n17
+
+}
+
+func void t4(string ai_name)
+{
+	dprint t4_active
+	ai2_spawn A_L18
+}
+
+func void t6(string ai_name)
+{
+	dprint t6_active
+	ai2_spawn A_L20
+	ai2_spawn A_L21	
+	ai2_spawn B_S22
+	ai2_makeignoreplayer B_S22 1
+	trig_activate	6
+	trig_activate	7
+	trig_activate	99
+	trig_activate	98
+	target_set(593,30.0)
+}
+
+func void t7(string ai_name)
+{
+	dprint t7_active
+	ai2_dopath B_S22 patrol_23
+	ai2_setjobstate B_S22
+	ai2_makeignoreplayer B_S22 0
+	ai2_spawn B_N28	
+}
+
+func void t7b(string ai_name)
+{
+	dprint t7b_active
+	ai2_spawn B_Lbo26
+	playback_block B_Lbo26 run1 interp 20
+	sleep 20
+	ai2_dopath B_Lbo26 patrol_27
+	ai2_setjobstate B_Lbo26
+		
+}
+
+func void t8(string ai_name)
+{
+	dprint t8_active
+	chr_delete A_L19
+	chr_delete l1
+	chr_delete l3
+	chr_delete A_L12
+	chr_delete A_Lbo13
+	chr_delete A_L8
+	chr_delete l7
+	chr_delete n5
+	chr_delete A_T25
+	chr_delete A_n17
+	chr_delete A_N31
+	ai2_spawn B_Sbo38
+	ai2_spawn B_S36	
+	ai2_makeignoreplayer B_S36 1
+	ai2_spawn B_L40
+	ai2_spawn B_L41
+	music_chair
+	sleep 90
+	substation_monologue
+}
+
+func void t9(string ai_name)
+{
+	dprint t9_spawning_griffin
+#	ai2_spawn ZomGrif
+	GrifSpawn
+	target_set (1,0.0)
+}
+
+func void t10(string ai_name)
+{
+	dprint t10_active
+	ai2_spawn B_S29
+}
+
+func void t11(string ai_name)
+{
+	dprint t11_active
+	ai2_dopath B_S36 patrol_38
+	ai2_setjobstate B_S36
+	ai2_makeignoreplayer B_Sbo38 0
+#	ai2_makeignoreplayer B_Sbo35 0
+	ai2_makeignoreplayer B_S36 0
+	ai2_makeignoreplayer B_S37 0
+	ai2_spawn B_Lbo76
+#	ai2_spawn B_Lbo77
+	ai2_spawn B_C34
+	ai2_spawn B_C33
+	ai2_spawn B_C32
+	trigvolume_enable trigger_volume_11_copy 0
+	music_stop
+}
+
+func void t59(string ai_name)
+{
+	ai2_spawn B_L30
+	ai2_spawn B_L95
+	ai2_spawn B_Lbo27
+}
+
+func void t60(string ai_name)
+{
+	ai2_spawn B_C32
+	ai2_spawn B_C34
+	ai2_spawn B_C33
+	ai2_makeignoreplayer B_S36 0
+}
+
+func void t67(string ai_name)
+{
+	ai2_spawn B_S43
+}
+
+func void t11b(string ai_name)
+{
+	dprint t11b_active
+	ai2_dopath B_S36 patrol_38
+	ai2_setjobstate B_S36
+	ai2_makeignoreplayer B_Sbo38 0
+#	ai2_makeignoreplayer B_Sbo35 0
+	ai2_makeignoreplayer B_S36 0
+	ai2_makeignoreplayer B_S37 0
+	ai2_spawn B_Lbo76
+#	ai2_spawn B_Lbo77
+	trigvolume_enable trigger_volume_11 0
+	music_stop
+}
+
+func void t12(string ai_name)
+{
+	dprint t12_active
+	ai2_dopath B_N28 patrol_42
+	ai2_setjobstate B_N28
+}
+
+func void t14(string ai_name)
+{
+	dprint t14_active
+	ai2_spawn C_Sbo44
+#	ai2_spawn C_C46
+	ai2_spawn C_C47
+	ai2_spawn C_N48
+#	ai2_spawn C_L50
+#	ai2_makeignoreplayer C_L50 1
+#	ai2_spawn C_L51
+#	ai2_makeignoreplayer C_L51 1
+
+}
+
+func void t15(string ai_name)
+{
+	dprint t15_active
+	ai2_lookatme C_L51
+	ai2_dopath C_L51 patrol_51
+	ai2_setjobstate C_L51
+	ai2_makeignoreplayer C_L51 0
+	sleep 90
+	ai2_lookatme C_L50
+	ai2_dopath C_L50 patrol_50
+	ai2_setjobstate C_L50 
+	ai2_makeignoreplayer C_L50 0
+
+}
+
+func void t16(string ai_name)
+{
+	dprint t16_active
+	ai2_makeignoreplayer C_L50 0
+	ai2_makeignoreplayer C_L51 0
+
+}
+
+func void t17(string ai_name)
+{
+	dprint t17_active
+	ai2_makeignoreplayer C_N55 0
+	ai2_spawn C_Sbo56
+
+}
+
+func void t18(string ai_name)
+{
+	dprint t18_active
+	ai2_spawn C_S57
+
+}
+
+func void t19(string ai_name)
+{
+	dprint t19_active
+	ai2_spawn C_S58
+	ai2_spawn C_S59
+
+}
+
+func void t20(string ai_name)
+{
+	dprint t20_active
+#	sleep 200
+	ai2_spawn C_Lbo62
+	ai2_spawn C_Sbo61
+
+}
+
+func void t21(string ai_name)
+{
+	dprint t21_active
+	ai2_spawn C_Sbo63
+	ai2_spawn C_Sbo64
+
+}
+
+func void t22(string ai_name)
+{
+	dprint t22_active
+	ai2_makeignoreplayer C_C65 0
+
+}
+
+func void t23(string ai_name)
+{
+	dprint t23_active
+	ai2_spawn C_L71
+	ai2_spawn C_S72
+	ai2_spawn C_N74
+
+}
+
+func void t25(string ai_name)
+{
+	dprint t25_active
+	ai2_spawn D_C70
+	ai2_makeignoreplayer D_C70 1
+	ai2_spawn D_Sbo71
+	ai2_spawn D_Sbo72
+	ai2_spawn D_Sbo73
+	ai2_spawn D_Sbo75
+	ai2_spawn D_N76
+
+}
+
+func void t26(string ai_name)
+{
+	dprint t26_active
+	ai2_spawn D_L74
+	ai2_spawn new_1
+}
+
+func void t28(string ai_name)
+{
+	dprint t28_active
+	ai2_spawn D_S78
+	ai2_spawn D_S79
+	trigvolume_enable trigger_volume_29 1
+
+}
+
+func void t29(string ai_name)
+{
+	dprint t29_active
+	ai2_spawn D_Lbo81
+	ai2_spawn D_S82
+
+}
+
+func void t30(string ai_name)
+{
+	dprint t30_active
+	ai2_spawn D_L80
+
+}
+
+func void t31(string ai_name)
+{
+	dprint t31_active
+	ai2_spawn D_S83
+	ai2_spawn D_L84
+	ai2_spawn D_Lbo85
+	ai2_spawn D_Sbo86
+	trigvolume_enable trigger_volume_32 0
+}
+
+func void t32(string ai_name)
+{
+	dprint t32_active
+	ai2_spawn D_L88
+	ai2_spawn D_S87
+	ai2_spawn D_Sbo86
+	trigvolume_enable trigger_volume_31 0
+	target_set(599,30.0)
+}
+
+
+func void t33(string ai_name)
+{
+	dprint t33_active
+	door_lock 97
+	particle lastdoor1_locklight01 do stop
+	particle lastdoor2_locklight01 do stop
+	particle lastdoor3_locklight01 do stop
+	#play doorsound
+}
+
+func void t34(string ai_name)
+{
+	dprint t34_active
+	ai2_spawn D_Sbo75
+	ai2_spawn D_Sbo92
+	ai2_spawn D_L91
+	ai2_spawn D_S90
+	ai2_spawn D_S89
+}
+
+func void t37(string ai_name)
+{
+	dprint t37_active
+	ai2_makeignoreplayer D_C70 0
+
+}
+
+func void t38(string ai_name)
+{
+	dprint t38
+#	ai2_spawn B_N31
+
+}
+
+func void t41(string ai_name)
+{
+	dprint t41_active
+	target_set(596,30.0)
+}
+
+func void t42(string ai_name)
+{
+	dprint t42_active
+	door_lock 16
+	particle ZomShin_door_locklight01 do stop
+	trigvolume_enable trigger_volume_35 0
+	Base
+	s5
+}
+
+func void t43(string ai_name)
+{
+	dprint t43_active
+	ai2_spawn B_S96
+}
+
+func void t44(string ai_name)
+{
+	dprint t44
+	target_set(598,30.0)
+}
+
+func void t45(string ai_name)
+{
+	dprint t45_active
+	target_set(587,30.0)
+	door_lock 14
+	particle shin_lock_locklight01 do stop
+	console_activate 3
+#	play door lock sound
+	trig_deactivate	60
+	trig_deactivate	61
+	trig_deactivate	62
+	trig_deactivate	63
+	trig_deactivate	64
+	trig_deactivate	65
+	trig_deactivate	70
+	trig_deactivate	71
+	trig_deactivate	72
+	trig_deactivate	73
+	trig_deactivate	74
+	trig_deactivate	75
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+	trig_deactivate	98
+	trig_deactivate	99
+	trig_deactivate	6
+	trig_deactivate	7
+	if (trigvolume_count(20) eq 0)
+	{
+		dprint delete_B_AI
+		chr_delete B_L95
+		chr_delete B_Lbo27
+		chr_delete B_S29
+		chr_delete B_L30
+		chr_delete B_Sbo38
+		chr_delete B_S36	
+		chr_delete B_S37
+		chr_delete B_L40
+		chr_delete B_L41
+		chr_delete B_Lbo39
+		chr_delete B_S43
+		chr_delete B_C32
+		chr_delete B_C33
+		chr_delete B_C34
+		chr_delete B_Lbo26
+		chr_delete B_S96
+		chr_delete B_Lbo76
+		chr_delete B_S22
+		chr_delete B_N31
+		chr_delete B_Lbo77
+	}
+	dprint delete_A_AI
+	chr_delete A_L20
+	chr_delete A_L21
+	chr_delete A_Sbo15
+	chr_delete A_Sbo14
+	chr_delete A_L19
+	chr_delete l1
+	chr_delete l3
+	chr_delete A_L12
+	chr_delete A_Lbo13
+	chr_delete A_L8
+	chr_delete l7
+	chr_delete n5
+	chr_delete A_T25
+	chr_delete B_N28
+	chr_delete A_n17
+	chr_delete A_N31
+}
+
+func void attack_konoko(string ai_name)
+{
+	ai2_attack new_1 A_player
+}
+
+func void substation_monologue(void)
+{
+	dprint playkonokoline
+	sound_dialog_play c14_54_24konoko
+	cinematic_start (KONtalkangryfront, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	sleep f60
+	cinematic_stop (KONtalkangryfront, 19, 20)
+
+	objective_set(2, silent)
+}
+
+func void save3_and_spine(string ai_name)
+{
+	s3
+	spine1
+	sleep 7
+	spine2
+	sleep 7
+	spine3
+}
+func void t45b(string ai_name)
+{
+	dprint t45b_modified_by_okita
+	ai2_spawn C_L51
+	ai2_spawn C_L50
+	ai2_spawn C_C65
+	ai2_spawn C_N66
+	ai2_spawn C_Sbo93
+	ai2_spawn C_N60
+	ai2_spawn C_N55
+	ai2_makeignoreplayer C_L50 1
+	ai2_makeignoreplayer C_L51 1
+	ai2_makeignoreplayer C_N55 1
+	ai2_makeignoreplayer C_C65 1
+	trig_activate	1	
+	trig_activate	2	
+	trig_activate	3	
+	trig_activate	4	
+	trig_activate	5
+	trig_activate	8		
+	trig_activate	303	
+	trig_activate	100
+	trig_activate	101	
+	trig_activate	500	
+	trig_activate	400	
+	trig_activate	503
+	trig_activate	502
+	trig_activate	501
+	trig_activate	510
+	trig_activate 	511
+	trig_activate	512	
+	trig_activate	520
+	trig_activate	521
+	trig_activate	522
+	trig_activate	320
+	trig_activate	315
+	trig_activate	302	
+	music_atrium	
+}
+################ begin #################
+########## okita's modification ########
+########################################
+func void spine1(void)
+{
+	dprint spine1_start
+
+	if (sub1 eq 0)
+	{
+		particle spine1 start
+		particle spinesound1 start
+	}
+}
+
+func void spine2(void)
+{
+	dprint spine2_start
+
+	if (sub2 eq 0)
+	{
+		particle spine2 start
+		particle spinesound2 start
+	}
+}
+
+func void spine3(void)
+{
+	dprint spine3_start
+
+	if (sub3 eq 0)
+	{
+		particle spine3 start
+		particle spinesound3 start
+	}
+}
+################  end  #################
+########## okita's modification ########
+########################################
+func void patrolscript0001(void)
+{
+	playback_block B_S22 taunt1 interp 20
+}
+
+func void B_S22_run (string ai_name)
+{
+	ai2_dopath B_S22 patrol_24
+	ai2_setjobstate B_S22
+}
+
+func void A_T25_run (string ai_name)
+{
+	ai2_dopath A_T25 patrol_25
+	ai2_setjobstate A_T25
+}
+
+func void t39(string ai_name)
+{
+	target_set(598,30.0)
+}
+
+func void t48(string ai_name)
+{
+	ai2_spawn D_S101
+	ai2_spawn D_C100
+}
+#########################################
+#      		console/special	    #
+#########################################
+func void unlock14(string ai_name)
+{
+	dprint unlock14_active
+	door_unlock 14
+	particle shin_lock_locklight01 do start
+}
+
+func void console_android(void)
+{
+	text_console level_18b
+	console_reset 16
+}
+
+func void console_zombie(void)
+{
+	text_console level_18a
+	console_reset 17
+}
+
+func void console1(string ai_name)
+{
+	dprint console1_active
+	text_console level_18c
+	console_reset 14
+	console_activate 14
+}
+
+func void console2(string ai_name)
+{
+	dprint console2_active
+	text_console level_18d
+	console_reset 15
+}
+
+func void level_18e(string ai_name)
+{
+	dprint text_18e
+	text_console level_18e
+	console_reset 1
+	console_activate 1
+}
+
+func void lastdoor_console(string ai_name)
+{	
+	dprint lastdoor_console
+	lastdoor_count = lastdoor_count + 1
+	if (lastdoor_count eq 1)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor3_locklight01 do start
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+	}
+	if (lastdoor_count eq 2)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor2_locklight01 do start
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+	}
+	if (lastdoor_count eq 3)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor1_locklight01 do start
+		set_objective_4
+		target_set(401,30.0)
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+		trigvolume_enable trigger_volume_40 0
+		door_unlock 97
+	}
+
+}
+
+func void refuse_script(string ai_name)
+{	
+	dprint refuse
+	ai2_dopath C_N48 patrol_98
+}
+
+func void patrolscript0098(string ai_name)
+{	
+	dprint patrolscript0098
+	ai2_doalarm C_N48 10
+}
+
+func void shin_lock(string ai_name)
+{
+	particle shin_lock_locklight01 do start
+}
+
+func void stair_lock(string ai_name)
+{
+	particle stair_lock_locklight01 do start
+}
+
+func void roof(string ai_name)
+{
+	particle roof_locklight01 do start
+	particle shin_lock_locklight01 do start
+	ai2_spawn A_T25
+
+}
+
+func void floor4_lock(string ai_name)
+{
+	particle floor4_lock_locklight01 do start
+	trigvolume_enable trigger_volume_39 1
+
+}
+
+func void roof_doors(string ai_name)
+{
+	particle roof_doors_locklight01 do start
+
+}
+
+func void roof_door2(string ai_name)
+{
+	particle roof_door2_locklight01 do start
+	ai2_spawn A_n17
+}
+
+func void enable_t29(string ai_name)
+{
+	trigvolume_enable trigger_volume_29 1
+
+}
+
+func void t40(string ai_name)
+{
+	dprint t40_active
+	if(sub1 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count(49) eq 0)
+			{
+				trigvolume_enable trigger_volume_40 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(49) eq 0)
+			{
+				trigvolume_enable trigger_volume_40 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func void t50(string ai_name)
+{
+	dprint t50_active
+	if(sub2 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count(51) eq 0)
+			{
+
+				trigvolume_enable trigger_volume_50 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(51) eq 0)
+			{
+				trigvolume_enable trigger_volume_50 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func void t53(string ai_name)
+{
+	dprint t53_active
+	if(sub3 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count (54) eq 0)
+			{
+				trigvolume_enable trigger_volume_53 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(54) eq 0)
+			{
+				trigvolume_enable trigger_volume_53 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func powersub1(string ai_name)
+{
+	dprint powersub1_active
+	sub1 = 1;
+	particle spine1 stop
+	particle spinesound1 stop
+
+	if(sub3 eq 0)
+	{
+		target_set(594,30.0)
+	}
+	if(sub3 ne 0)
+	{
+		if(sub2 eq 0)
+		{
+			target_set(595,30.0)
+		}
+	}
+	check_power
+}
+
+func powersub2(string ai_name)
+{
+	dprint powersub2_active
+	particle spine2 do stop
+	particle spinesound2 stop
+	sub2 = 1;
+	if(sub3 eq 0)
+	{
+		target_set(594,30.0)
+	}
+	if(sub3 ne 0)
+	{
+		if(sub1 eq 0)
+		{
+			target_set(587,30.0)
+		}
+	}
+	check_power
+}
+
+func powersub3(string ai_name)
+{
+	dprint powersub3_active
+	sub3 = 1;
+	particle spine3 do stop
+	particle spinesound3 stop
+	if(sub2 eq 0)
+	{
+		target_set(595,30.0)
+	}
+
+	if(sub2 ne 0)
+	{
+		if(sub1 eq 0)
+		{
+			target_set(587,30.0)
+		}
+	}
+	check_power
+}
+
+func check_power(string ai_name)
+{
+	dprint check_power_active
+	counter = counter - 1
+	if (counter eq 1)
+	{
+		sound_dialog_play c14_54_27konoko
+		sound_dialog_play_block pause
+	}
+
+	if (counter eq 0)
+	{
+		dprint power_down
+		trigvolume_enable trigger_volume_36 1
+		trigvolume_enable trigger_volume_41 1
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate substation 0
+		fade_in 30
+	#	sleep 180
+		trig_deactivate	1	
+		trig_deactivate	2	
+		trig_deactivate	3	
+		trig_deactivate	4	
+		trig_deactivate	5
+		trig_deactivate	8		
+		trig_deactivate	303	
+		trig_deactivate	100
+		trig_deactivate	101	
+		trig_deactivate	500	
+		trig_deactivate	400	
+		sleep 15
+		trig_deactivate	503
+		sleep 5
+		trig_deactivate	502
+		sleep 5
+		trig_deactivate	501
+		sleep 15	
+		trig_deactivate	510
+		sleep 5
+		trig_deactivate 	511
+		sleep 5	
+		trig_deactivate	512	
+		sleep 15
+		trig_deactivate	520
+		sleep 5	
+		trig_deactivate	521
+		sleep 5	
+		trig_deactivate	522
+		sleep 15
+		trig_deactivate	320
+		sleep 15
+		trig_deactivate	315
+		sleep 15
+		trig_deactivate	302	
+		door_unlock	16
+		particle ZomShin_door_locklight do start
+		sleep 120
+		fade_out 0 0 0 240
+		cm_reset
+		input 1
+		target_set(403, 30.0)
+		fade_in 30
+		music_stop
+		objective_set(3)
+	}
+}
+
+func void lastdoor1(string ai_name)
+{
+	ld1=1
+	if(ld2 eq 0)
+	{
+		target_set(599,30.0)
+	}
+	if (ld2 ne 0)
+	{
+		if(ld3 eq 0)
+		{
+			target_set(598,30.0)
+		}
+	}
+}
+
+func void lastdoor2(string ai_name)
+{
+	ld2=1
+	if(ld3 eq 0)
+	{
+		target_set(598,30.0)
+	}
+	if(ld3 ne 0)
+	{
+		if(ld1 eq 0)
+		{
+			target_set(597,30.0)
+		}
+	}
+}
+
+func void lastdoor3(string ai_name)
+{
+	ld3=1
+	if(ld2 eq 0)
+	{
+		target_set(599,30.0)
+	}
+	if(ld2 ne 0)
+	{
+		if(ld1 eq 0)
+		{
+			target_set(597,30.0)
+		}
+	}
+}
+
+#########################
+#	save game	      #
+#########################
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME1	
+
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME2	
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME3	
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME4	
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+func void s5(string ai_name)
+{
+	dprint SAVEDGAME5	
+
+	if (my_save_point ne 5)
+	{
+		save_game 5 autosave
+	}
+}
+
+###############################################
+#####   FURIOUS ZOMBIE SHINATAMA FIGHT   ######
+###############################################
+
+var int console_count = 4;
+var int zombie_counter_var = 0;
+
+func void zombie_counter(string player_name)
+{
+	console_count = console_count - 1;
+
+	door_lock 16	
+
+	if (console_count eq 0)
+	{
+		console_count = 4;
+
+		dprint zombie_counter
+		zombie_counter_var = zombie_counter_var + 1;
+
+		if (zombie_counter_var eq 0)
+		{
+			zombie_round_2
+		}
+
+		if (zombie_counter_var eq 1)
+		{
+			zombie_round_3
+		}
+
+		if (zombie_counter_var eq 2)
+		{
+			zombie_round_4
+		}
+
+		if (zombie_counter_var eq 3)
+		{
+			zombie_round_5
+		}
+	}
+}
+
+func void t52(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_102
+}
+
+func void t55(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_103
+}
+
+func void t56(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_104
+}
+
+func void t57(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_105
+}
+
+func void t58(string ai_name)
+{
+	ai2_spawn C_Lbo53
+	ai2_spawn C_Sbo52
+}
+
+func void zombie_dialog_round3(void)
+{
+	sound_dialog_play c14_51_07shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+func void zombie_dialog_round4(void)
+{
+	sound_dialog_play c14_51_08shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+func void zombie_dialog_round5(void)
+{
+	sound_dialog_play c14_51_09shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+# CB: this round is not called any longer! only zombie rounds 2-5 are used now
+# ZOMBIE ROUND 1
+func void zombie_round_1(string ai_name)
+{
+	dprint zombie_round_1
+
+	particle zombie1 create
+	particle zombie1 start
+
+	ai2_allpassive 1
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	sleep 120
+
+	trig_show 91
+	trig_show 92
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	sleep 30
+
+#	trig_speed 202 .2
+#	trig_speed 204 .2
+#	trig_hide 2023
+#	trig_hide 2013
+
+#	particle ????? start
+#	particle ????? start
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_makeignoreplayer ZomGrif 1
+}
+
+# CB: this round has all the old zombie round 2 setup including camera angles
+# OLD ZOMBIE ROUND 2
+func void old_zombie_round_2(string ai_name)
+{
+	dprint zombie_round_2
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	particle zombie1 create
+	particle zombie1 start
+
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_1
+
+	sleep 15
+	trig_hide 91
+	sleep 15
+	trig_hide 92
+	sleep 15
+	trig_hide 93
+
+	sleep 120
+
+	trig_show 210
+	trig_show 310
+	trig_show 410
+	trig_show 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	sleep 90
+	
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_passive ZomShin 1
+	ai2_makeignoreplayer ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}	
+
+# CB: this round is the new zombie round 2 setup which is tabulae rasa
+# and fit to be called from a save point, or from the cutscene
+# ZOMBIE ROUND 2
+func void zombie_round_2(string ai_name)
+{
+	dprint zombie_round_2_active
+
+	particle zombie1 create
+	particle zombie1 start
+
+	ai2_allpassive 1
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	sleep 120
+
+	trig_show 210
+	trig_show 310
+	trig_show 410
+	trig_show 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice1 1
+	trigvolume_enable shinzom_voice2 1
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_makeignoreplayer ZomGrif 1
+	ai2_passive ZomShin 1
+}	
+
+# ZOMBIE ROUND 3
+func void zombie_round_3(string ai_name)
+{
+	dprint zombie_round_3_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice3 1
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	sleep 10
+	particle zombie1 create
+	particle zombie1 start
+
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_2
+
+	sleep 15
+	trig_hide 91
+	sleep 15
+	trig_hide 92
+	sleep 15
+	trig_hide 93
+
+	trig_deactivate 210
+	trig_deactivate 310
+	trig_deactivate 410
+	trig_deactivate 510
+
+	fork zombie_dialog_round3
+	sleep 120
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	trig_reset 210
+	trig_reset 310
+	trig_reset 410
+	trig_reset 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_show 2101
+	trig_show 3101
+	trig_show 4101
+	trig_show 5101
+
+	trig_activate 2101
+	trig_activate 3101
+	trig_activate 4101
+	trig_activate 5101
+
+	trig_speed 210 .3
+	trig_speed 310 .3
+	trig_speed 410 .3
+	trig_speed 510 .3
+
+	trig_speed 2101 .3
+	trig_speed 3101 .3
+	trig_speed 4101 .3
+	trig_speed 5101 .3
+
+	sleep 90
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_passive ZomShin 1
+	# ai2_passive ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}
+
+## ZOMBIE ROUND 4
+func void zombie_round_4(string ai_name)
+{
+	dprint zombie_round_4_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice4 1
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	sleep 30
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	sleep 30
+	particle zombie1 create
+	particle zombie1 start
+
+	fork zombie_dialog_round4
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_3
+
+	trig_hide 91
+	trig_hide 92
+	trig_hide 93
+
+	trig_deactivate 210
+	trig_deactivate 310
+	trig_deactivate 410
+	trig_deactivate 510
+
+	trig_hide 210
+	trig_hide 310
+	trig_hide 410
+	trig_hide 510
+
+	trig_deactivate 2101
+	trig_deactivate 3101
+	trig_deactivate 4101
+	trig_deactivate 5101
+
+	trig_hide 2101
+	trig_hide 3101
+	trig_hide 4101
+	trig_hide 5101
+
+	sleep 120
+		
+	trig_show 214
+	trig_show 314
+	trig_show 414
+	trig_show 514
+
+	sleep 15
+
+	trig_show 94
+
+	sleep 15
+
+	trig_show 910
+
+	trig_activate 214
+	trig_activate 314
+	trig_activate 414
+	trig_activate 514
+
+	trig_activate 910
+	trig_activate 94
+
+	trig_speed 214 .15
+	trig_speed 314 .15
+	trig_speed 414 .15
+	trig_speed 514 .15
+
+	trig_speed 910 .35
+	trig_speed 94 .35
+		
+	sleep 90
+	
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_passive ZomShin 1
+	# # ai2_passive ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}
+
+########## ZOMBIE ROUND 5 - YOU WIN ############
+
+func void zombie_round_5(string ai_name)
+{
+	dprint zombie_round_5_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+
+	trig_hide 214
+	trig_hide 414
+
+	trig_activate 210
+	trig_activate 410	
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	input 0
+
+	begin_cutscene	
+
+	music_stop
+
+	sleep 60
+
+	cm_interpolate zombie_death 0
+	
+	fork zombie_dialog_round5
+	sleep 90
+
+	trig_speed 9 1
+	trig_speed 10 2
+	trig_speed 910 2.5
+	trig_speed 94 .5
+	trig_speed 210 2
+	sleep 90	
+	trig_speed 410 2
+	sleep 90	
+	trig_speed 514 1
+	trig_speed 410 1
+	sleep 90
+	trig_speed 314 2
+	sleep 90
+	trig_speed 210 1
+
+	sleep 60
+	trig_hide 210
+	trig_hide 9
+	trig_speed 10 .2
+	sleep 60	
+	trig_hide 314
+	trig_hide 910
+	sleep 60	
+	trig_speed 514 .2
+	trig_hide 410
+	trig_hide 10
+	trig_hide 94
+	sleep 60
+	trig_hide 514
+	sleep 60
+	trig_hide 93
+	particle zombie1 kill
+	sound_ambient_start shin_zom_shutdown 1.0
+	sleep 10
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	particle zombie1 create
+	particle zombie1 start
+	sleep 30
+	particle zombie1 kill
+	particle zombiesteam stop
+	particle zombient stop
+	
+	sleep 90
+
+#	Hardy, if griffin has to see konoko after or during the zom cutscene, 
+#	make sure this next line makes it into the shorter zombie shin scripts --mike
+
+	ai2_makeignoreplayer ZomGrif 0
+	Zom
+}
+
+
+
+############################################################
+########### INCIDENTAL SHINATAMA ZOMBIE DIALOG #############
+############################################################
+
+func void shinzom_voice1(string ai_name)
+{
+	sound_dialog_play c00_01_102shinatama
+}
+
+func void shinzom_voice2(string ai_name)
+{
+	sound_dialog_play c00_01_101shinatama
+}
+
+func void shinzom_voice3(string ai_name)
+{
+	sound_dialog_play c00_01_100shinatama
+}
+
+func void shinzom_voice4(string ai_name)
+{
+	sound_dialog_play c00_01_103shinatama
+}
Index: /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf_ii_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf_ii_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/orig_mac/IGMD/tctf_ii/tctf_ii_cutscene.bsl	(revision 185)
@@ -0,0 +1,420 @@
+#
+# tctf_cutscene.bsl
+#
+
+func void
+Intro(
+	void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam01 0
+	sleep f14
+	begin_cutscene weapon
+	marketing_line_off=1
+	letterbox 1
+	sleep f60
+	invincible=1
+	obj_create 401 402
+	obj_create 404 407
+	fade_in 90
+	#Outside shot of TCTF
+	cm_interpolate IntroCam01 0
+	playback 0 IntroKonokoSet
+	sleep f300
+	#Griffin and Guy talking
+	chr_create 1201 start
+	chr_create 1202 start
+	playback 1202 IntroTCTF01
+	#make this box animation last as long as conversation
+	chr_envanim 1201 IntroGriffinBox01
+	chr_animate 1201 COMGUYsit_idle1 1800
+	#Conversation between the two
+	cm_interpolate IntroCam02 0
+	sound_dialog_play c14_50_01scigoon1
+	cinematic_start (COPtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	cm_interpolate IntroCamGriffin 0
+	sound_dialog_play c14_50_02griffin
+	cinematic_start (GRIFtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	#TCTF walks out
+	sound_music_start atm_low_perc2 0.8
+	cm_interpolate IntroCam02 0
+	playback 1202 IntroTCTF02
+	sound_dialog_play c14_50_03scigoon1
+	sleep f240
+	cinematic_stop (COPtalking, 15, 20)
+	cinematic_stop (GRIFtalking, 15, 20)
+	sleep f60
+	door_open 70
+	door_jam 70
+	sleep f100
+	#KONOKO on roof
+	playback 0 IntroKonoko01
+	cm_interpolate IntroCamInside01 0
+	cm_interpolate_block IntroCamInside02 400
+	sleep f400
+	cm_anim both IntroCamRoof
+	sleep f210
+	#Konoko falls into view
+	cm_anim both IntroCamFall01
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev18_IntroFall01 140
+	#Griffin gets surprised
+	chr_delete 1202
+	cm_anim_block both IntroCamStand01
+	chr_envanim 1201 IntroGriffinBox02 norotation
+	chr_animate 1201 GRIFINlev18_IntroStand 110
+	env_anim 401 401
+	sleep f88
+	#Konoko enters office
+	playback 0 IntroKonoko02
+	cm_interpolate_block IntroCamKonAim01 0
+	cm_interpolate_block IntroCamKonAim02 350
+	sleep f140
+	cinematic_start(KONangryfront, 180, 180, 18, 6, 30, true)
+	sound_dialog_play c14_50_04konoko
+	sound_dialog_play_block pause
+	cinematic_stop (KONangryfront, 18, 30)
+	#Conversation with Griffin
+	playback 1201 IntroGriffin
+	cm_interpolate IntroCamGriffin02 0
+	cinematic_start(GRIFtalkangry, 180,180,18,6,30, true)
+	sound_dialog_play c14_50_05griffin
+	sound_dialog_play_block pause
+	cinematic_stop (GRIFtalkangry, 18, 30)
+	#Griffin's office goes down
+	sound_music_volume atm_low_perc2 0.0 0.5
+	sound_music_stop atm_low_perc2
+	music_intro
+	env_show 403 0
+	obj_create 403 403
+	cm_anim both IntroCamEscape01
+	chr_envanim 1201 IntroGriffinBox03 norotation
+	env_setanim 401 IntroChair02
+	env_anim 402 407
+	cutscene_sync mark
+	sound_ambient_start c14_46_11grifdesk
+	sleep f16
+	playback 0 IntroKonokoAim fromhere
+	cm_anim_block both IntroCamEscape02
+	cm_wait
+	cm_reset
+	obj_kill 401 407
+	# look out Stefan is editing scripts; yo foolios need to turn back on the laser sight :O)
+	marketing_line_off=0
+	end_cutscene
+	invincible=0
+	chr_delete 1201
+	door_unjam 70
+	door_close 70
+	# who is a foolio? the foo or the foo who follows him?
+	s1
+}
+
+
+func void
+GrifSpawn(
+	void)
+{
+	ai2_spawn ZomGrif
+	chr_invincible ZomGrif 1
+	chr_unstoppable ZomGrif 1
+	ai2_makeignoreplayer ZomGrif 1
+	ai2_setmovementmode ZomGrif walk
+	playback ZomGrif ZomGrifDraw
+}
+
+func void create_zomshin(void)
+{
+	ai2_spawn ZomShin
+	ai2_passive ZomShin 1
+	chr_shadow ZomShin 0
+	chr_invincible ZomShin 1
+	chr_unstoppable ZomShin 1
+	chr_nocollision ZomShin 1
+	chr_neutral ZomShin 1
+	chr_lock_active ZomShin
+}
+
+func void
+Base(
+	void)
+{
+	begin_cutscene
+	#place Griffin here earlier
+	#chr_neutral ZomGrif 1
+	sleep f20
+	#playback ZomGrif BaseGriffin01
+	cm_interpolate BaseCam01 180
+	sleep f210
+	#place Konoko
+	playback 0 BaseKonoko01
+	cm_interpolate BaseCam02 0
+	cm_interpolate_block BaseCam04 500
+	sound_dialog_play c14_51_01konoko
+	cinematic_start(KONangryfront, 180,180,19,7,20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (KONangryfront, 19, 20)
+	cm_interpolate BaseCam01 0
+	cm_interpolate_block BaseCam03 600
+	sound_dialog_play c14_51_02griffin
+	cinematic_start(GRIFtalkangry, 180,180,20,9,20, true)
+	sound_dialog_play_block pause
+	cutscene_sync mark
+	sound_ambient_start c15_04_23_effects
+	sound_dialog_play c14_51_03griffin
+	#Shinzom comes out of ground
+	create_zomshin
+	chr_envanim ZomShin ChairShinBox01
+	obj_create 171 174
+	env_anim 171 174
+	obj_shade 171 174 .5 .5 .5
+	cm_anim both ChairCamZomUp
+	#chr_create ZomShin start
+	#chr_neutral ZomShin 1
+	sleep f270
+	particle zombiespark pulse
+
+	cm_wait
+
+	particle zombient start
+	#hide Chair object, show chair gunk
+	env_show 171 1
+	env_show 172 1
+	env_show 173 1
+	env_show 174 1
+	obj_kill 171 174
+	cm_interpolate BaseCamShin01 0
+	playback ZomShin BaseShin
+	cm_interpolate_block BaseCamShin02 300
+	sound_dialog_play_block
+	cinematic_stop (GRIFtalkangry, 20, 20)
+	sound_dialog_play c14_51_04shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,7,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+	sleep f30
+	particle Forcefield do start
+	sound_ambient_start zomshin_amb_loop 0.1
+	sound_ambient_volume zomshin_amb_loop 1.0 1.0
+	cm_interpolate BaseCam02 0
+	sound_dialog_play c14_51_05konoko
+	cinematic_start(KONscared, 180,180,20,9,20, true)
+	sound_dialog_play_block
+	cinematic_stop (KONscared, 20, 20)
+	playback ZomShin BaseShin
+	cm_interpolate_block BaseCamShin02 0
+	sound_dialog_play c14_51_06shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,7,20, false)
+	particle zombiesteam start
+	sound_dialog_play_block pause
+	cinematic_stop (SHINZOMlistening, 19, 20)
+#	cm_reset
+#	trig_show 9
+#	trig_activate 9
+	end_cutscene
+	music_zom
+	ai2_passive ZomShin 1
+	ai2_makeignoreplayer ZomGrif 1
+	zombie_round_2
+#	ai2_allpassive 1
+#	remove line below after zomshin puzzle is fixed
+#	Zom
+}
+
+func void fade_out_zom_amb(void)
+{
+	sound_ambient_volume zomshin_amb_loop 0.0 1.0
+	sleep 60
+	sound_ambient_stop zomshin_amb_loop
+}
+
+func void
+Zom(
+	void)
+{
+	env_show 1010 0
+	particle Forcefield do stop
+	fork fade_out_zom_amb
+	begin_cutscene
+	marketing_line_off=1
+	#Shinatama will already be created
+	#show the destruction of the turrets and the forcefield around Griffin
+	#cm_interpolate ZomCamGrif01 0
+	ai2_setmovementmode ZomGrif walk
+	playback ZomGrif ZomGrifDrawSet
+	#sleep f120
+	#Shinatama gets up out of chair
+	chr_shadow ZomShin 1
+	chr_invincible ZomShin 0
+	chr_unstoppable ZomShin 0
+	chr_envanim ZomShin ZomShinBox01 norotation
+	chr_animate ZomShin SHINZOMlev18_Free
+	cm_anim both ZomCamFree01
+	sleep f90
+	cutscene_sync mark
+	sound_ambient_start c_shin_escape
+	cm_wait
+	#Griffin says "what are you doing?"
+	cm_interpolate ZomCamGrif01 0
+	sound_dialog_play c14_52_01griffin
+	cinematic_start(GRIFtalkangry, 180,180,19,7,20, false)
+	sound_dialog_play_block
+	cinematic_stop(GRIFtalkangry, 19,20)
+	#Shinatama approaches Griffin
+	cm_interpolate ZomCamShinStart 0
+	playback ZomShin ZomShinSet
+	chr_animate ZomShin SHINZOMwalk1 180
+	chr_nocollision ZomShin 0
+	sleep f175
+	#Griffin says GET BACK OR I'll SHOOT
+	#cm_interpolate ZomCamGrif01 0
+	#playback ZomGrif ZomGrifDrawSet
+	#sleep f120
+	#Shin keeps coming
+	#cm_interpolate ZomCamShinApproach 0
+	playback ZomShin ZomShinWalk
+	chr_animate ZomShin SHINZOMwalk1 600
+	#sleep f120
+	#Griffin draws weapon
+	cm_interpolate ZomCamGrif01 0
+	playback ZomGrif ZomGrifDrawSet
+	sleep f30
+	#sound_dialog_play c14_52_01bgriffin
+	playback ZomGrif ZomGrifDraw
+	sleep f60
+	#konoko drops weapon
+	playback 0 ZomKonokoDrop
+	#Shinatama Approaches Griffin
+	cm_interpolate ZomCamBoth 0
+	sleep f180
+	#Griffin shoots
+	cm_interpolate ZomCamGrifShoot 0
+	playback ZomGrif ZomGrifShoot
+	sleep f50
+	#Shinatama gets hit
+	cm_interpolate ZomCamShinDie 0
+	chr_animate ZomShin SHINZOMshot 126
+	sound_ambient_start c_shin_die 1.0
+	sleep f120
+	#Show Griffin over Shinatama
+	cm_interpolate ZomCamDead 0
+	playback ZomGrif ZomGriffinKilled
+	chr_animate ZomShin SHINZOMfallen_front 1000
+	sleep f10
+	cm_interpolate ZomCamKonokoBehind 270
+	playback 0 ZomKonokoBehind
+	sleep f280
+	#Griffin turns and gets thrown
+	# CB: we force omnipotent off because it breaks this cutscene (you kill
+	# griffin prematurely)
+	omnipotent = 0
+	chr_invincible ZomGrif 0
+	chr_unstoppable ZomGrif 0
+	ai2_kill ZomShin
+	chr_neutral ZomGrif 0
+	cm_interpolate ZomCamThrow 0
+	playback ZomGrif ZomGriffinTurn
+	playback 0 ZomKonokoThrow
+	sleep f140
+	#Knoko holds him down
+	cm_interpolate ZomCamKonokoAim02 0
+	chr_neutral ZomGrif 1
+	chr_envanim ZomGrif ZomGriffinBox01 norotation
+	chr_envanim 0 ZomKonokoBox01 norotation
+	chr_animate 0 KONOKOlev18_ZomAim 300
+	chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	sound_dialog_play c14_52_02konoko
+	cinematic_start(KONangryfront, 180,180,19,7,20, false)
+	sound_dialog_play_block pause
+	#Looking down at griffin
+	#chr_envanim 0 ZomKonokoBox01 norotation
+	#chr_envanim ZomGrif ZomGriffinBox01 norotation
+	#chr_animate 0 KONOKOlev18_ZomAim 300
+	#chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	#cm_interpolate ZomCamKonokoAim01 0
+	#KONoko gets off Griffin
+	#cm_interpolate ZomCamKonokoAim02 0
+	chr_envanim 0 ZomKonokoBox02 norotation
+	chr_envanim ZomGrif ZomGriffinBox01 norotation
+	chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	chr_animate 0 KONOKOlev18_ZomUp 120
+	#sound_dialog_play c14_52_04konoko
+	#Griffin gets up put the gun down
+	sleep f100
+	cm_interpolate ZomCamGriffinUp 0
+	chr_envanim ZomGrif ZomGriffinBox02 norotation
+	chr_animate ZomGrif GRIFINlev18_ZomUp
+	sound_dialog_play c14_52_03griffin
+	cinematic_start(GRIFbeatup, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	#Konoko I'm a rogue agent, very dangerous
+	playback 0 ZomKonokoFace
+	cm_interpolate ZomCamKonokoFace 0
+	sound_dialog_play c14_52_04konoko
+	sound_dialog_play_block pause
+	#Griffin says youre a monster
+	cm_interpolate ZomCamGriffinFace 0
+	playback ZomGrif ZomGriffinFace
+	sound_dialog_play c14_52_05griffin
+	sound_dialog_play_block pause
+	#for you, badly
+	cm_interpolate ZomCamKonokoFace 0
+	sound_dialog_play c14_52_06konoko
+	sound_dialog_play_block pause
+	#Griffin says youre a monster
+	cm_interpolate ZomCamGriffinFace 0
+	sound_dialog_play c14_52_07griffin
+	sound_dialog_play_block pause
+	cinematic_stop(GRIFbeatup, 20, 20)
+	cinematic_stop(KONangryfront, 19, 20)
+	#Give player back control
+	cm_reset
+	end_cutscene
+	ai2_allpassive 1
+	chr_set_health ZomGrif 1
+	marketing_line_off=0
+	trigvolume_enable trigger_volume_35 1
+	objective_set(5)
+}
+
+func void
+OutroKill(
+	void)
+{
+	sound_music_start mus_wls 1.0
+	begin_cutscene jello
+	sleep f40
+	sound_dialog_play c14_53_01konoko
+	cinematic_start(KONintense, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (KONintense, 19, 20)
+	fade_out 0 0 0 120
+	sleep f120
+	end_cutscene
+	win
+}
+
+
+func void
+OutroNoKill(
+	void)
+{
+	begin_cutscene jello
+	cm_detach
+	ai2_takecontrol 1
+	ai2_lookatchar 0 ZomGrif
+	ai2_lookatchar ZomGrif 0
+	sound_music_start mus_sad1
+	sound_dialog_play c14_54_01konoko
+	cinematic_start(KONlistening, 180,180,19,8,20, false)
+	sleep f120
+	cm_interpolate BaseCam01 180
+	sound_dialog_play_block
+	cinematic_stop (KONlistening, 19, 20)
+	fade_out 0 0 0 120
+	sleep f120
+	end_cutscene
+	win
+}
Index: /nikanabo/current/bsl/orig_mac/readme.txt
===================================================================
--- /nikanabo/current/bsl/orig_mac/readme.txt	(revision 185)
+++ /nikanabo/current/bsl/orig_mac/readme.txt	(revision 185)
@@ -0,0 +1,3 @@
+Original level logic for Mac retail.
+Minor differences with PC version.
+Probably completely irrelevant.
Index: /nikanabo/current/bsl/orig_mac/winstall.bat
===================================================================
--- /nikanabo/current/bsl/orig_mac/winstall.bat	(revision 185)
+++ /nikanabo/current/bsl/orig_mac/winstall.bat	(revision 185)
@@ -0,0 +1,17 @@
+echo off
+cd ..\mybackup
+IF NOT EXIST backupok.txt (
+    echo Level logic not backed up.
+    cd ..\orig_mac
+) ELSE (
+    echo Installing original level logic...
+    cd ..\..\..\GameDataFolder
+    rmdir /s /q IGMD
+    xcopy ..\nikanabo\bsl\original\IGMD IGMD /s /k /i
+    xcopy ..\nikanabo\bsl\orig_mac\IGMD\tctf_ii\*.* IGMD\tctf_ii /y /r
+    cd ..\nikanabo\bsl\orig_mac
+    echo Original level logic installed.
+)
+PAUSE
+
+
Index: /nikanabo/current/bsl/orig_mac/xinstall.sh
===================================================================
--- /nikanabo/current/bsl/orig_mac/xinstall.sh	(revision 185)
+++ /nikanabo/current/bsl/orig_mac/xinstall.sh	(revision 185)
@@ -0,0 +1,15 @@
+#!/bin/sh
+cd ../mybackup
+if [ ! -e backupok.txt ]
+    echo "User level logic not backed up."
+    cd ../orig_mac
+else
+    echo "Installing original level logic..."
+    cd ../../../GameDataFolder
+    rm -rf IGMD
+    cp -r ../nikanabo/bsl/original/IGMD .
+    cp -r ../nikanabo/bsl/orig_mac/IGMD/tctf_ii IGMD/tctf_ii
+    cd ../nikanabo/bsl/orig_mac
+    echo "Original level logic installed."
+fi
+
Index: /nikanabo/current/bsl/original/IGMD/Airport/airport1_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport/airport1_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport/airport1_level_logic.bsl	(revision 185)
@@ -0,0 +1,662 @@
+### AIRPORT 1 LEVEL LOGIC ###
+
+### START, SAVE & OBJECTIVES ###
+
+func void func_start(string ai_name)
+{
+	dprint start_active
+
+	trigvolume_enable hidden1 1
+	trigvolume_enable hidden1 1
+
+	if (save_point eq 0)
+		{
+		my_save_point=0;
+		particle auto1 start
+		particle auto1fire start
+		particle auto1spark start
+		particle door1spark start
+		particle tctf1 start
+		}
+
+	if (save_point eq 1)
+		{
+		my_save_point=1;
+		env_show 10 1
+		env_show 11 1
+		env_show 12 1
+		dprint restore1_active
+		particle auto1 start
+		particle auto1fire start
+		particle auto1spark start
+		particle door1spark start
+		particle tctf1 start
+		sound_music_start mus_asian 0.5
+		music_script_start();
+		ai2_spawn IntroStriker01
+		ai2_spawn IntroStriker02
+		restore_game
+		sleep 30
+		set_target_1
+		set_objective_1
+		}
+
+	if (save_point eq 2)
+		{
+		my_save_point=2;
+		dprint restore_2
+		particle fx3 do start
+		particle exhaust create
+		Tarmac1
+		trigvolume_enable tarmac 0
+		trigvolume_enable trigger_volume_03 0
+		trigvolume_enable bomberboom 0
+		trigvolume_enable madbomberbait 0
+		door_lock 3
+		obj_kill 991 992
+		restore_game
+		sleep 30
+		set_target_3
+		set_objective_2
+		}	
+	
+	if (save_point eq 3)
+		{
+		my_save_point=3;	
+		dprint restore3_active
+		door_lock 3
+		door_unlock 6
+		particle lock1_locklight01 do stop
+		particle lock2_locklight01 do start
+		console_deactivate 5
+		particle door7_locklight01 do start
+		particle door2_locklight01 do start
+		console_deactivate 6
+		trigvolume_enable trigger_volume_02 0
+		trigvolume_enable trigger_volume_03 0
+		trigvolume_enable trigger_volume_04 0
+		trigvolume_enable trigger_volume_08 0
+		trigvolume_enable trigger_volume_10 0
+		trigvolume_enable trigger_volume_11 0
+		trigvolume_enable save_game 0
+		trigvolume_enable secondcoming 0
+		TerminalTwo1
+		particle auto1 stop
+		particle auto1fire stop
+		particle auto1spark stop
+		particle door1spark stop
+		particle tctf1 stop
+		ai2_spawn TerminalTwo_Striker_1
+		ai2_spawn TerminalTwo_Striker_2
+		particle fx4 do start	
+		particle fx5 do start
+		particle fx6 do start
+		particle fx1 do stop
+		particle fx2 do stop
+		particle fx3 do stop
+		music_script_start();
+		restore_game
+		sleep 30
+		set_objective_3
+		set_target_5
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	all_music_counters
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	all_music_counters
+	win
+}
+
+func void save_point_1(string player_name)
+{
+	dprint save_point_1_active
+	save_game 1 autosave
+}
+
+func void save_point_2(string player_name)
+{
+	dprint save_point_2_active
+	save_game 2 autosave
+}
+
+func void save_point_3(string player_name)
+{
+	dprint save_point_3_active
+	save_game 3 autosave
+	ai2_spawn TerminalTwo_Striker_1
+	ai2_spawn TerminalTwo_Striker_2
+	particle fx5 do start
+	particle fx6 do start
+	particle fx3 do stop
+	door_unlock 6
+	particle door7_locklight01 do start 
+	particle lock2_locklight01 do start 
+	particle door2_locklight01 do start
+}
+
+
+func void set_objective_1(string chr_index)
+{
+	dprint objective_1
+	objective_set(1)
+	sound_dialog_play c00_01_22shinatama
+}
+func void set_objective_2(string chr_index)
+{
+	dprint objective_2
+	objective_set(2)
+	sound_dialog_play c00_01_19shinatama
+}
+
+func void set_objective_3(string chr_index)
+{
+	dprint objective_3
+	objective_set(3)
+	console_deactivate 2
+	sound_dialog_play c00_01_18shinatama
+}
+
+func void set_objective_4(string chr_index)
+{
+	dprint objective_4
+	objective_set(4)
+	sound_dialog_play c00_01_20shinatama
+}
+
+func void set_target_1(string chr_index)
+{
+	dprint set_target1
+	target_set(1095, 30.0)
+	sound_dialog_play c00_01_28shinatama
+}
+
+func void set_target_2(string chr_index)
+{
+	dprint set_target2
+	target_set(1132, 30.0)
+	sound_dialog_play c00_01_27shinatama
+}
+
+func void set_target_3(string chr_index)
+{
+	dprint set_target3
+	target_set(1109, 30.0)
+	sound_dialog_play c00_01_26shinatama
+}
+
+func void set_target_4(string chr_index)
+{
+	dprint set_target4
+	target_set(1112, 30.0)
+	sound_dialog_play c00_01_25shinatama
+}
+
+func void set_target_5(string chr_index)
+{
+	dprint set_target5
+	target_set(1115, 30.0)
+	sound_dialog_play c00_01_24shinatama
+}
+
+func void set_target_6(string chr_index)
+{
+	dprint set_target6
+	target_set(1139, 30.0)
+	sound_dialog_play c00_01_28shinatama
+}
+
+func void set_target_blank(string chr_index)
+{
+	dprint set_targetblank
+	target_set(0, 0.0)
+}
+
+### MUSIC ###
+
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+	if (0 ne music_counter) 
+		{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+		}
+}
+
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void striker_lullaby_1(string ai_name)
+{
+	dprint striker_lullaby1
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		sleep f120
+		}
+}
+
+func void striker_lullaby_2(string ai_name)
+{
+	dprint striker_lullaby2
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		sleep f120
+		}
+}
+
+func void all_music_counters(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_fitec_hd
+	sound_music_stop mus_fitec
+	sound_music_stop mus_fiteb
+	sound_music_stop mus_asian
+	sound_music_stop atm_gr06
+}
+
+### TEXT CONSOLES ###
+
+func void level_4a(void)
+{
+	dprint set_text_4a
+	text_console level_4a
+	console_reset 7
+}
+
+func void level_4b(void)
+{
+	dprint set_text_4b
+	text_console level_4b
+	console_reset 7
+}
+
+func void level_4c(void)
+{
+	dprint set_text_4c
+	text_console level_4c
+	console_reset 8
+}
+
+### GAMEPLAY PROGRESSION ###
+
+func void FixDoors(string char_index)
+{
+	dprint Fix_Doors
+	particle door2_locklight01 do stop
+	door_lock 10
+}
+
+func void hidden_civilian1(string ai_name)
+{
+	dprint hidden_civilian
+	ai2_spawn hidden_civ_1
+}
+
+func void panic1a(string char_index)
+{
+	dprint panic_1a
+
+	ai2_spawn civ_victim_6
+	playback civ_victim_6 civ_victim6_flee interp 30
+	ai2_spawn civ_victim_4
+	playback civ_victim_4 civ_victim4_flee interp 30
+	sleep 30
+	ai2_spawn Intro_Striker_4
+	playback Intro_Striker_4 striker4_advance interp 30
+	ai2_spawn Intro_Comguy_1
+}
+
+func void panic1b(string char_index)
+{
+	dprint panic_1b
+	ai2_passive Intro_Striker_4 1
+	ai2_spawn civ_victim_2
+	ai2_spawn civ_victim_3
+	playback civ_victim_3 civ_victim3_flee interp 30
+	sleep 120
+	ai2_spawn Intro_Striker_3
+	ai2_attack Intro_Striker_3 civ_victim_2
+	ai2_spawn Friend_Thug_1
+	ai2_spawn Neutral_Thug_1
+	ai2_spawn Neutral_Thug_3
+	particle fx1 do start
+	particle fx2 do start
+	chr_delete civ_victim_4
+	chr_delete civ_victim_6
+}
+
+func void hide_1(string char_index)
+{
+	dprint hide1
+	ai2_spawn civ_victim_5
+	playback_block civ_victim_5 civ_victim5_flee interp 30
+	ai2_dopath civ_victim_5 civ_victim_5
+}
+
+func void horror_1(string char_index)
+{
+	dprint horror1
+	ai2_passive Intro_Striker_4 0
+	ai2_spawn civ_victim_10
+	ai2_spawn civ_victim_11
+	ai2_spawn civ_victim_20
+	ai2_spawn civ_victim_21
+	particle fx1 do start
+	particle fx2 do start
+}
+	
+func void ambush_striker_1(string char_index)
+{
+	dprint ambush_1
+	ai2_spawn Terminal_Striker_1
+	ai2_spawn Terminal_Striker_2
+	ai2_spawn mad_bomber_1
+	obj_create 991 992
+}
+
+func void civ_victim_20s_flee(string char_index)
+{
+	dprint civ_victim_20s
+	ai2_dopath civ_victim_20 civ20s_flee1
+	ai2_dopath civ_victim_21 civ20s_flee2
+}
+
+func void LoadingBay1(string char_index)
+{
+	dprint spawn_guards
+	ai2_spawn LoadingBay_Thug_1
+	ai2_spawn LoadingBay_Thug_2
+	ai2_spawn LoadingBay_Striker_2
+	ai2_spawn LoadingBay_Comguy_1
+	particle fx3 do start
+}
+
+func void bomber_boom(string char_index)
+{
+	dprint bomberboom
+	particle bomb1 do explode
+	obj_kill 991 992
+	sleep 300
+	particle bomb1 stop
+}
+	
+func void mad_bomber_bait(string char_index)
+{
+	dprint bomber_bait
+	ai2_dopath mad_bomber_1 bomber_flee 1
+}
+
+func void patrolscript0200(string char_index)
+{
+	dprint bomber1_death
+	chr_delete mad_bomber_1
+}
+
+func void Tarmac1(string char_index)
+{
+	dprint spawn_guards
+	ai2_spawn Tarmac_Striker_1
+	ai2_spawn Tarmac_Striker_2
+	ai2_spawn Tarmac_Striker_3
+	ai2_spawn Tarmac_Striker_4
+	ai2_spawn Tarmac_Friend_1
+	ai2_spawn LoadingBay_Striker_1
+	sound_music_start atm_gr06 0.75
+	particle tarmacfire do start
+	particle exhaust create
+}
+
+func void back9a(string ai_name)
+{
+	dprint hidden_striker1
+	ai2_spawn hidden_striker1
+}
+
+func void back9b(string ai_name)
+{
+	dprint hidden_striker1
+	ai2_spawn hidden_striker2
+}
+
+func void bay1_particles(void)
+{
+	dprint bay1_fires_on
+	particle fx3 do start
+	particle fx4 do stop
+}
+
+func void fire_damage(string ai_name)
+{	
+	dprint fire_hurt_konoko
+	chr_poison (ai_name, 5, 30, 30);
+}
+
+func void bay2_particles(void)
+{
+	dprint bay2_fires_on
+	particle fx3 do stop
+	particle fx4 do start
+}
+
+# COME TO ME
+func void come_to_me(string ai_name)
+{
+	dprint go_to_konoko
+	ai2_dopath Tarmac_Striker_2 come_to_me 1
+	ai2_dopath Tarmac_Striker_3 come_to_me 1
+	ai2_dopath mad_bomber_2 come_to_me 1
+}
+
+# COME TO ME REDUX
+func void second_coming(string ai_name)
+{
+	dprint go_to_konoko_again
+	ai2_dopath Tarmac_Striker_2 come_to_me 1
+	ai2_dopath Tarmac_Striker_3 come_to_me 1
+	ai2_dopath mad_bomber_2 come_to_me 1
+}
+
+# PROGRESS CHECK
+
+var int progress_counter=2;
+
+func void progress_check_1(string ai_name)
+{
+	dprint progress_check1
+	progress_counter = progress_counter - 1
+	if (progress_counter eq 0)
+		{
+		pass_go_collect_whupass();
+		}
+}
+
+func void progress_check_2(string ai_name)
+{
+	dprint progress_check2
+	progress_counter = progress_counter - 1
+	if (progress_counter eq 0)
+		{
+		pass_go_collect_whupass();
+		}
+}
+
+func void progress_check_3(string ai_name)
+{
+	dprint progress_check3
+	progress_counter = progress_counter - 1
+	if (progress_counter eq 0)
+		{
+		pass_go_collect_whupass();
+		}
+}
+
+func void progress_check_4(string ai_name)
+{
+	dprint progress_check4
+	progress_counter = progress_counter - 1
+	if (progress_counter eq 0)
+		{
+		pass_go_collect_whupass();
+		}
+}
+
+func void exhaust_on(string ai_name)
+{
+	dprint start_exhaust
+	particle exhaust create
+}
+
+func void exhaust_off(string ai_name)
+{
+	dprint stop_exhaust
+	particle exhaust kill
+}
+
+func void pass_go_collect_whupass(string ai_name)
+{
+	dprint let_the_whupping_continue
+	trigvolume_enable save_game_2 1
+	trigvolume_enable secondcoming 0
+}
+
+func void patrolscript000(string ai_name)
+{
+	dprint do_my_bidding
+	particle lock2_locklight01 do start
+	door_unlock 6
+}
+	
+func void BayTwo1(string char_index)
+{
+	dprint spawn_guards
+	ai2_spawn BayTwo_Striker_1
+	ai2_spawn hidden_friend2
+	ai2_spawn mad_bomber_2
+	sound_music_stop atm_gr06
+}
+
+func void Repair1(string char_index)
+{
+	dprint spawn_guards
+	ai2_spawn Repair_Striker_1
+	ai2_spawn Repair_Comguy_1
+	ai2_spawn alamo_thug_1	
+}
+
+func void Repair2(string char_index)
+{
+	dprint spawn_guards
+	ai2_spawn Repair_Striker_2
+	ai2_spawn Repair_Comguy_2	
+}
+
+func void console_2_activate(string char_index)
+{
+	dprint console2_activate
+	console_activate 2
+}
+
+func void final_ambush(string char_index)
+{
+	dprint finalambush
+	input 0
+	begin_cutscene
+	sleep 60
+	cm_interpolate ambush1 0
+	sleep 150
+	console_activate 4
+	sleep 150
+	sound_music_start mus_fitec_hd 0.91
+	music_script_start
+	cm_interpolate ambush2 0
+	cm_interpolate_block ambush3 300
+	sleep 350	
+	cm_interpolate ambush4 300	
+	door_unlock 14
+	particle door3_locklight01 do start
+	ai2_spawn finalam_striker_1
+	ai2_spawn finalam_striker_2
+	ai2_setmovementmode finalam_striker_1 walk
+	ai2_setmovementmode finalam_striker_2 walk
+	playback finalam_striker_1 finalam_striker1 interp 30
+	playback finalam_striker_2 finalam_striker2 interp 30
+	sleep 300
+	particle door3_locklight01 do stop
+	sleep 300
+	door_lock 14	
+	ai2_dopath finalam_striker1 finalam_1 1
+	ai2_dopath finalam_striker2 finalam_2 1
+	trigvolume_enable i_uh_heheheh1 1
+	cm_reset
+	end_cutscene
+	input 1
+}
+
+func void i_uh_heheheh(string char_index)
+{
+	dprint iuh_heheheh
+	ai2_dopath finalam_striker_1 strategic_retreat1
+	ai2_dopath finalam_striker_2 strategic_retreat2
+} 
+	
+### DOOR LOCK LIGHTS ###
+
+func void change_terminaldoor_light(void)
+{
+	dprint door1
+	input 0
+	cm_interpolate door1 0
+	sleep 60
+	particle door1_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void change_door2_light(void)
+{
+	dprint door2
+	input 0 
+	cm_interpolate door2 0
+	sleep 60
+	particle door2_locklight01 do start
+	sleep 150
+	set_objective_3
+	set_target_6
+	cm_reset
+	input 1
+}
+
+func void change_enddoor_light(void)
+{
+	dprint end_door
+	input 0
+	cm_interpolate ambush4 0	
+	sleep 60
+	particle door3_locklight01 do start
+	sleep 150
+	door_unlock 14
+	cm_reset
+	input 1
+}
+
+### Level scripted by Joseph ###
Index: /nikanabo/current/bsl/original/IGMD/Airport/airport_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport/airport_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport/airport_cutscene.bsl	(revision 185)
@@ -0,0 +1,240 @@
+#
+# airport_cutscene.bsl
+#
+
+func
+airport_cs_intro
+{
+	#creates the cars, van
+	obj_create 633 633
+	obj_create 6331 6331
+	obj_create 647 647
+	obj_create 6471 6471 
+	obj_create 960 960
+	obj_create 9601 9602
+	obj_create 2 7
+	fade_out 0 0 0 0
+	cm_interpolate Camout01 0
+	sleep f7
+	
+	begin_cutscene
+
+	cm_jello 0
+	#fade_out 0 0 0 0
+	letterbox 1
+	fade_in 120
+	fork camcontrol
+
+	sound_music_start mus_asian 0.5
+	music_script_start();
+
+	sleep 120
+	fork intro_cars
+	#van start
+	env_anim 2 7
+	
+	fork shinatama_comm
+
+	sleep 855
+	chr_nocollision 0 1
+	#konoko on bike start
+	chr_envanim 0 IntroKonokoBox01
+	chr_animate 0 KONOKOcycle_ride 500
+	obj_create 10 12
+	env_anim 10 12
+	sleep 6
+	chr_create 100 start
+	ai2_spawn IntroStriker01
+	ai2_spawn IntroStriker02	
+
+	chr_forceholster IntroStriker02 1
+	
+	sleep 1
+	playback 100 IntroMuro01
+	playback IntroStriker01 IntroComguy01
+	playback IntroStriker02 IntroStriker01
+	sleep 498
+	#kill van object
+	obj_kill 2 7
+	#konoko off bike
+	chr_envanim 0 IntroKonokoBox02 norotation
+	chr_animate 0 KONOKOlev4_intro
+	
+	sound_music_volume mus_asian .25 0.5
+
+	cinematic_start(KONtalkangryfront, 180, 180, 15, 3, 10, false)
+	sleep 60
+	sound_dialog_play c04_14_02konoko
+	sleep 120
+	cinematic_stop (KONtalkangryfront, 16, 20)
+	playback 100 IntroMuro02
+	playback IntroStriker01 IntroComguy02
+	playback IntroStriker02 IntroStriker02
+	sleep 60
+	cinematic_start(MUROtalking, 180, 180, 15, 1, 15, false)
+	sleep f50
+	sound_dialog_play c04_14_01muro
+	sound_dialog_play_block pause
+	cinematic_stop (MUROtalking, 15, 30)
+
+	sound_music_volume mus_asian 0.8 2.0
+
+	playback 0 IntroKonoko01
+	chr_nocollision 0 0
+	obj_kill 10 12
+	env_show 10 1
+	env_show 11 1
+	env_show 12 1
+	
+	chr_forceholster IntroStriker02 0
+	
+	sleep 60
+	set_objective_1
+	set_target_1	
+
+	save_point_1
+
+	sleep 260
+	chr_delete 100
+}
+
+func
+camcontrol
+{
+	cm_anim both Camout01
+	sleep f80
+	sound_ambient_start c03_44_03truckby
+	cm_anim_block both Camout02
+	sound_ambient_start c03_49_16_truck
+	cm_anim_block both Camout03
+	sound_ambient_start c03_49_16_motorcycle
+	cm_anim_block both Camout04
+	cm_wait
+	sleep 2
+	cm_interpolate Camout05 0
+	sleep 1
+	cm_interpolate Camout06 120
+	sleep 300
+	cm_reset
+	cm_jello 1
+	letterbox 0
+	end_cutscene
+}
+
+func
+intro_cars
+{
+	sleep 633
+	env_anim 633 633
+	env_anim 6331 6331
+	sleep 14
+	env_anim 647 647
+	env_anim 6471 6471
+	sleep 203
+	sleep 110
+	env_anim 960 960
+	env_anim 9601 9602
+	sleep 560
+	obj_kill 633 633
+	obj_kill 6331 6331
+	obj_kill 647 647
+	obj_kill 6471 6471 
+	obj_kill 960 960
+	obj_kill 9601 9602
+}
+
+func shinatama_comm
+	{
+	sleep 90
+	sound_music_volume mus_asian 0.35 1.0
+	sound_dialog_play c00_01_104shinatama
+	cinematic_start (SHINtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	cinematic_stop (SHINtalking, 15, 20)
+	sound_music_volume mus_asian 0.5 1.0
+	}
+
+func
+Booth(string wazzzup)
+{
+	begin_cutscene weapon
+	#make Konoko run to a flag
+	ai2_takecontrol 1
+	ai2_movetoflag 0 1091
+	cm_interpolate BoothCamMuroWalk 240
+	ai2_spawn BoothMuro01
+	playback BoothMuro01 BoothMuroWalk
+	#Muro just stands there and talks for a while
+	sleep f180
+	cinematic_start(MUROtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play c04_17_01muro
+	sound_dialog_play_block pause
+	#Konoko looks to see Strikers
+	ai2_takecontrol 0
+	cm_interpolate BoothCamKonokoLook 0
+	playback 0 BoothKonokoLook
+	ai2_spawn BoothStriker01
+	ai2_spawn BoothStriker02
+	sleep 30
+	playback BoothStriker01 BoothStriker01
+	playback BoothStriker02 BoothStriker02
+	sleep 50
+	#Strikers rush in
+	cm_interpolate BoothCamStrike01 0
+	cm_interpolate_block BoothCamStrike02 180
+	sleep f60
+	sound_dialog_play c04_17_02muro
+	sleep 140
+	#Muro walks out the door
+	playback BoothMuro01 BoothMuroLeave
+	sleep 30
+	cm_interpolate BoothCamLeave01 0
+	cm_interpolate_block BoothCamLeave02 300
+	sleep f30
+	sleep f50
+	sound_dialog_play c04_17_03muro
+	sound_dialog_play_block pause
+	sleep f30
+
+	sound_music_start mus_asian 0.8
+	music_script_start
+	trigvolume_enable stop_booth_music_tv 1
+
+	cinematic_stop (MUROtalking, 15, 20)
+	sleep 120
+	cm_reset
+	fork FixDoors
+	
+	particle door2_locklight01 do stop
+	particle door7_locklight01 do stop
+	door_lock 7
+	set_target_blank
+
+	chr_delete TerminalTwo_Striker_1
+	chr_delete TerminalTwo_Striker_2
+	chr_delete Tarmac_Striker_2
+	chr_delete Tarmac_Striker_4
+
+	chr_delete BoothMuro01
+	end_cutscene
+}
+
+func void stop_booth_music(string who)
+{
+	sound_music_stop mus_asian
+}
+
+func
+outro(string wazzup)
+{
+	begin_cutscene
+	#cm_interpolate OutroCam01 0
+	#playback 0 OutroKonoko
+	#sleep 400
+	fade_out 0 0 0 60
+	sleep f120
+	win
+}
+
+
+
Index: /nikanabo/current/bsl/original/IGMD/Airport/airport_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport/airport_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport/airport_main.bsl	(revision 185)
@@ -0,0 +1,23 @@
+#
+# airport_main.bsl
+#
+
+var int my_save_point;
+
+func void main(void)
+{
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.995
+	gs_farclipplane_set 4000
+	env_show 10 0
+	env_show 11 0
+	env_show 12 0
+#	fork airport_cs_intro();
+	func_start
+	if (my_save_point eq 0)
+	{
+	airport_cs_intro
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_cutscene.bsl	(revision 185)
@@ -0,0 +1,129 @@
+#
+# airportiii_cs_intro.bsl
+#
+
+func
+airportiii_cs_intro
+{
+	begin_cutscene
+	#hides VTOL object
+	fade_out 0 0 0 0
+	playback 0 IntroKonokoSet
+	sleep f60
+	fade_in 60
+	sleep f60
+	end_cutscene
+}
+
+
+func void
+camcontrol(
+	void)
+{
+	#unhides VTOL object
+	obj_create 61 67
+	obj_create 72 79
+	#vtol takes off
+	env_anim 61 67
+	env_anim 72 79
+	#hides Vtol gunk
+	env_show 161 0
+	env_show 162 0
+	env_show 163 0
+	env_show 164 0
+	env_show 165 0
+	env_show 166 0
+	env_show 167 0
+	env_show 172 0
+	env_show 173 0
+	env_show 174 0
+	env_show 175 0
+	env_show 176 0
+	env_show 177 0
+	env_show 178 0
+	env_show 179 0
+	sleep 500
+	#Muro and Cronie in plane talking
+	#chr_create 101 start
+	#chr_create 102 start
+	#chr_envanim 101 OutroComBip
+	#chr_envanim 102 OutroMuroBip
+}
+
+func void rappel_stop_old_music(void)
+{
+	sound_music_stop mus_space01
+}
+
+func void
+rappel(
+	void)
+{
+	rappel_stop_old_music
+
+	begin_cutscene
+	invincible=1
+	obj_create 51 52
+	env_anim 51 52
+	chr_animate 0 KONOKOlev6_rappel
+	chr_envanim 0 RapKonBipBox01 norotation
+	cm_anim both RapCam01
+	sleep f250
+	cutscene_sync mark
+	sound_ambient_start c04_32_23_misc
+	sleep f260
+	dprint CAMERA_RAP_CAM_02
+	cm_interpolate_block RapCam02 0
+	dprint CAMERA_RAP_CAM_03
+	cm_interpolate_block RapCam03 240
+	sleep f45
+	chr_animate 0 KONOKOlev6_tracer
+	sleep f180
+	obj_kill 51 51
+	#camera cut to show Konoko jumping off of plane
+	playback 0 RappelKonRun
+	cm_interpolate RappelCamRun01 0
+	cm_interpolate_block RappelCamRun02 180
+	sleep f180
+
+	#VTOL takes off
+	dprint VTOL_TAKES_OFF
+	sound_ambient_start c04_28_22_helic
+	fork camcontrol
+	cm_anim both OutCam01
+	cm_wait
+	chr_create 101 start
+	chr_create 102 start
+	chr_envanim 101 OutroComBip
+	chr_envanim 102 OutroMuroBip
+
+	cm_anim both OutCam02
+	dprint INSIDE_CAM
+	particle muroplane_prop do stop
+	sound_ambient_start propidle_2 0.4
+	playback 0 OutroKonokoSet
+	sleep f60
+	ai2_allpassive 1
+	sound_dialog_play c06_21_01SynHench2
+	cinematic_start (COMGUYtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block c06_21_02muro
+	cinematic_start (MUROtalking, 180, 180, 20, 9, 20, true)	
+	sleep f200
+	cm_anim both OutCam03
+	dprint CAMERA_OUT_CAM_03
+	sound_ambient_start c04_28_22_helie 0.75
+	sound_ambient_volume propidle_2 0.0 0.0
+	sound_ambient_stop propidle_2
+#	playback 0 OutroKonSet
+	chr_delete 101
+	chr_delete 102
+	cm_wait
+	cinematic_stop (COMGUYtalking, 19, 20)
+	cinematic_stop (MUROtalking, 20, 20)
+	fade_out 0 0 0 60
+	sleep f60
+	end_cutscene
+	sleep f60
+	win
+}
+
Index: /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_level_logic.bsl	(revision 185)
@@ -0,0 +1,1196 @@
+### AIRPORT III LEVEL LOGIC ###
+
+### START, SAVE & OBJECTIVES ###
+
+func void func_start(string ai_name)
+{
+	
+	particle gas2 do stop
+	particle gaslight1 do stop
+	particle hanger5 do stop
+	trig_hide 1
+	trig_hide 2
+	trig_hide 3
+	trig_hide 4
+
+	if (my_save_point eq 0)
+		{
+		fork target_thug
+		}
+	
+	if (my_save_point eq 1)
+		{
+		dprint restore1_active
+		door_lock 11
+		tarmac
+		bomber_off
+		trigvolume_enable tarmac 0
+		restore_game
+		sound_music_start atm_gr09 0.75
+		objective_set(2)
+		target_set(7037,30.00)
+		}
+
+	if (my_save_point eq 2)
+		{
+		dprint restore1_active
+		trigvolume_enable save2 0
+		trigvolume_enable lowroad3 0
+		door_lock 21
+		door_lock 22
+		door_lock 35
+		particle lock5a_locklight01 do stop
+		particle lock5b_locklight01 do stop
+		particle lock35_locklight01 do stop
+		particle rotorwash do stop
+		particle room1 kill
+		Back2	
+		restore_game
+		music_save_point2_start
+		sleep 30
+		objective_set(3)
+		target_set(7085,30.00)
+		}
+
+	if (my_save_point eq 3)
+		{
+		dprint restore3_active
+		door_lock 21
+		door_lock 22
+		door_lock 24
+		particle lock5a_locklight01 do stop
+		particle lock5b_locklight01 do stop
+		trigvolume_enable save2 0
+		trigvolume_enable save3 0
+		Back2	
+		door_open 48
+		door_jam 48
+		trig_show 1
+		trig_show 2
+		trig_show 3
+		trig_show 4
+		restore_game
+		objective_set(3)
+		target_set(7085,30.00)
+		}
+	
+	if (my_save_point eq 4)
+		{
+		dprint restore4_active
+		trigvolume_enable lowroad1 0
+		trigvolume_enable lowroad2 0
+		trigvolume_enable lowroad3 0
+		trigvolume_enable lowroad4 0
+		trigvolume_enable hidden1a 0
+		trigvolume_enable hidden1b 0
+		trigvolume_enable save2 0
+		trigvolume_enable backcompound 0
+		trigvolume_enable remote 0
+		trigvolume_enable trigger_volume_08 1
+		door_lock 21
+		door_lock 22
+		door_lock 35
+		door_unlock 27
+		particle lock6_locklight01 do start
+		particle lock5a_locklight01 do stop
+		particle lock5b_locklight01 do stop
+		particle lock35_locklight01 do stop
+		console_deactivate 10
+		restore_game
+		sleep 30
+		set_objective_4
+		}
+
+	if (my_save_point eq 5)
+		{
+		dprint restore5_active
+		particle muroplane_prop do start
+		trigvolume_enable hangar2_setup 0
+		door_lock 36
+		particle lock7_locklight01 do stop
+		set_objective_5
+		ai2_spawn ambush_striker_2
+		ai2_spawn ambush_commguy_2
+		Hangar2a
+		restore_game
+		sound_music_start mus_space01 0.75
+		music_script_start
+		ai2_doalarm ambush_commguy_2 4
+		sleep 30
+		dprint set_objective5
+		objective_set(5)
+		target_set(1054,30.00)
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	all_music_counters	
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	all_music_counters
+	win
+}
+
+func void save_point_1(string ai_name)
+{
+	dprint savegame_1	
+	sound_music_stop mus_om03
+	if (my_save_point ne 1)
+		{
+		save_game 1 autosave
+		}
+	sound_music_stop
+	sound_music_start atm_gr09 0.75
+}
+
+func void save_point_2(string ai_name)
+{
+	dprint savegame_2
+	if (my_save_point ne 2)
+		{
+		save_game 2 autosave
+		}
+	music_save_point2_start
+	target_set(7085,30.00)
+}
+
+func void save_point_3(string ai_name)
+{
+	dprint savegame_3	
+	if (my_save_point ne 3)
+		{
+		save_game 3 autosave
+		}
+	sound_music_start atm_cl09 0.75
+}
+
+func void save_point_4(string ai_name)
+{
+	dprint savegame_4	
+	if (my_save_point ne 4)
+		{
+		save_game 4 autosave
+		}
+	sound_music_stop atm_cl09 0.75
+}
+
+func void save_point_5(string ai_name)
+{
+	particle muroplane_prop do start
+	dprint savegame_5	
+	if (my_save_point ne 5)
+		{
+		save_game 5 autosave
+		target_set(1054,30.00)
+		}
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective1
+	objective_set(1)
+	sound_music_start mus_om03
+	music_script_start
+	target_set(7124,30.00)
+	#sleep 300
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective2
+	objective_set(2)
+	target_set(7037,30.00)
+	sound_dialog_play c00_01_18shinatama
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective3
+	objective_set(3)
+	target_set(0,0)
+	sound_dialog_play c00_01_20shinatama
+}
+
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective4
+	objective_set(4)
+	target_set(7060,30.00)
+	sound_dialog_play c00_01_19shinatama
+}
+
+func void target_change_1(string ai_name)
+{
+	target_set(7037,30.00)
+}
+
+func void target_change_2(string ai_name)
+{
+	target_set(7037,30.00)
+}
+
+func void low_target_set(string ai_name)
+{
+	target_set(7085,30.00)
+}
+
+func void low_target_clear(string ai_name)
+{
+	target_set(0,0)
+}
+
+func void high_target_set(string ai_name)
+{
+	target_set(7126,30.00)
+}
+
+func void high_target_clear(string ai_name)
+{
+	target_set(0,0)
+}
+
+### MUSIC ###
+
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+	if (0 ne music_counter) 
+		{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+		}
+}
+
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void striker_lullaby_1(string ai_name)
+{
+	dprint striker_lullaby1
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+
+}
+func void striker_lullaby_2(string ai_name)
+{
+	dprint striker_lullaby2
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+}
+
+func void all_music_counters(void)
+{
+	dprint MARTY_HAS_LEFT_THE_BUILDING
+	sound_music_stop mus_asian
+	sound_music_stop mus_space01
+	sound_music_stop mus_om03
+	sound_music_stop mus_ot
+	sound_music_stop atm_cl09
+	sound_music_stop atm_gr09
+}
+
+func void music_save_point2_start(void)
+{
+	sound_music_start atm_cl09 1.0
+}
+
+### TEXT CONSOLES ###
+
+func void level6a(void)
+{
+	dprint text6a
+	text_console level_6a
+	console_reset 16
+}
+
+func void level6b(void)
+{
+	dprint text6b
+	text_console level_6b
+	console_reset 9
+}
+
+func void level6c(void)
+{
+	dprint text6c
+	text_console level_6c
+	console_reset 13
+}
+
+func void level6d(void)
+{
+	dprint text6d
+	text_console level_6d
+	console_reset 17
+}
+
+func void level6e(void)
+{
+	dprint text6e
+	text_console level_6e
+	console_reset 5
+}
+
+func void level6f(void)
+{
+	dprint text6f
+	text_console level_6f
+	console_reset 2
+}
+
+### GAMEPLAY PROGRESSION ###
+
+func void Start1(string char_index)
+{
+	dprint Start1
+	ai2_spawn Start_Striker_1
+	ai2_spawn Start_Striker_2
+	ai2_spawn Start_Comguy_1
+	particle room1 do start
+}
+
+# TARGET THUG
+func void target_thug(void)
+{
+	sleep f120
+	dprint target_thug
+	sound_dialog_play c00_01_28shinatama
+	ai2_spawn Start_Friend_1
+	ai2_spawn Start_Striker_5
+	ai2_makeaware Start_Striker_5 Start_Friend_1
+	sleep 30
+	set_objective_1
+}
+
+# TARGET THUG ROLL
+func void patrolscript0200(string char_index)
+{
+	playback_block Start_Friend_1 roll fromhere
+	ai2_dopath Start_Friend_1 Start_Friend_1b 1
+	ai2_setjobstate Start_Friend_1
+}
+
+# RETURN OF MAD BOMBER
+func void mad_bomber1(string ai_name)
+{
+	dprint boom
+	ai2_spawn mad_bomber1
+	sleep 150
+	particle bomb1 do explode
+	particle squib1a do explode
+	particle squib1b do explode
+	sleep 60
+	particle bomb2 do explode
+	particle squib2 do explode
+	sleep 30
+	particle bomb_damage1 do start
+}
+
+# SAVE THE THUG
+func void victim_thug1(string ai_name)
+{
+	dprint save_the_thug
+	ai2_spawn victim_thug1
+	ai2_spawn cruel_striker1
+}
+
+# HIDDEN FRIENDS
+func void hidden_thugs(string ai_name)
+{
+	ai2_spawn Start_Friend_2
+	ai2_spawn Start_Friend_3
+}
+
+# TARMAC
+func void tarmac(string ai_name)
+{
+	dprint tarmac_setup
+	ai2_spawn tarmac_striker_1
+	ai2_spawn tarmac_striker_2
+	ai2_spawn tarmac_striker_3
+	ai2_spawn tarmac_tanker_1
+	ai2_spawn tarmac_tanker_2
+	ai2_spawn tarmac_commguy_1
+
+	particle compound create
+}
+
+# ROOM 1 CLEAN-UP
+func void room1_cleanup(string ai_name)
+{
+	dprint room_1_clean
+	door_lock 11
+	chr_delete Start_Friend_2
+	chr_delete Start_Friend_3
+}
+
+# STRIKER TEE-OFF
+func void striker_tee_off(string ai_name)
+{
+	dprint I_pity_the_fool
+	ai2_dopath tarmac_striker_4 tarmac_striker_3b 1
+}
+
+# TANKER BACKUP
+func void tanker_backup(string ai_name)
+{
+	dprint tanker_backup
+	ai2_dopath tarmac_tanker_2 tarmac_tanker_2b 1
+}
+
+# UNLOCK COMMGUY
+func void unlock_commguy(string ai_name)
+{
+	dprint you_may_feel_a_zapping_sensation
+	ai2_dopath tarmac_commguy_1 tarmac_commguy_2 1
+	ai2_dopath tarmac_tanker_2 tarmac_tanker_2c 1
+	sound_music_stop atm_gr09
+}
+
+### WIL E. MURO ###
+
+# FIRST MURO
+func void muro_bait(string ai_name)
+{
+	dprint there_goes_muro
+	door_close 12
+	door_lock 12
+	begin_cutscene
+	ai2_spawn muro1
+	ai2_spawn escort_striker1
+	ai2_spawn escort_striker2
+	playback muro1 muro1 interp 30
+	playback escort_striker1 escort_striker1 interp 30
+	playback escort_striker2 escort_striker2 interp 30
+	sleep 30
+	dprint muro2_bait
+	chr_peace 0
+	input 0
+	particle compound kill
+	sound_music_start mus_asian 0.75
+	music_script_start	
+	cm_interpolate_block muro_2 0
+	sleep 90
+	cm_interpolate_block muro_3 400
+	sleep 430
+	particle garage1_locklight02 do start
+	door_open 26
+	door_jam 26
+	ai2_spawn Hangar1_A_Striker_1
+	ai2_spawn Hangar1_A_Striker_2
+	ai2_spawn Hangar1_A_Striker_3
+	playback Hangar1_A_Striker_2 hangar1_striker2 interp 30
+	playback Hangar1_A_Striker_3 hangar1_striker3 interp 30	
+	playback Hangar1_A_Striker_1 hangar1_striker1 interp 30
+	cm_interpolate_block muro_4 0
+	cm_interpolate_block muro_5 300
+	sleep 300
+	chr_delete muro1
+	chr_delete escort_striker1
+	chr_delete escort_striker2
+	cm_reset
+	end_cutscene
+	trigvolume_enable murobait_a 0
+	trigvolume_enable murobait_b 0
+	input 1
+	set_objective_3
+	particle lock3_locklight01 do stop
+	save_game_2
+}
+
+# FINAL MURO
+func void final_muro(string char_index)
+{
+	dprint last_muro_cutscene
+	sound_music_stop mus_ot 0.75
+	input 0
+	letterbox 1
+	cm_interpolate muro2a 0
+	ai2_spawn muro2
+	ai2_spawn escort_striker3
+	ai2_spawn escort_striker4
+	playback escort_striker3 final_escort3
+	playback escort_striker4 final_escort4
+	playback muro2 final_muro
+	cm_interpolate muro2a 0
+	cm_interpolate_block muro2b 300
+	sleep 300
+	cm_interpolate muro2c 0
+	cm_interpolate_block muro2d 300
+	sleep 350
+	cm_interpolate muro2e 0
+	cm_interpolate_block muro2f 300
+	sleep 300
+	chr_delete muro2
+	chr_delete escort_striker3
+	chr_delete escort_striker4
+	cm_reset
+	letterbox 0
+	input 1
+}
+		
+### BACK TO GAMEPLAY ###
+
+func void Hangar1_A(void)
+{
+	dprint open_sesame
+	door_unlock 12
+	particle lock3_locklight01 do start
+	trigvolume_enable murobait_a 1
+	target_set(7085,30.00)
+}
+
+func void hangar1a(string char_index)
+{
+	dprint hangar_1a
+	ai2_spawn Hangar1_B_Striker_1
+	ai2_spawn Hangar1_B_Striker_4
+}
+
+func void hangar1b(string ai_name)
+{
+	dprint hangar_1b
+	ai2_spawn superball_striker
+}
+
+func void hangar1c(string char_index)
+{
+	dprint hangar_1c
+	ai2_spawn Hangar1_B_Striker_5
+	ai2_spawn Hangar1_B_Striker_9
+	ai2_spawn Hangar1_A_Tanker_1
+	ai2_spawn Hangar1_B_Comguy_12
+}
+
+# HANGAR 1 ROOM D OPEN
+func void hangar1d_var(string ai_name)
+{
+	dprint hangar1d
+	hangar1d_counter = hangar1d_counter - 1
+	if (hangar1d_counter eq 0)
+		{
+		access_hangar1d_granted();
+		}
+}
+
+func void access_hangar1d_granted(string ai_name)
+{
+	dprint access_granted_d
+	particle garage2_locklight02 do start
+	door_unlock 19
+	door_open 19
+	door_jam 19
+	ai2_spawn hangar1d_enemy_1
+	ai2_spawn hangar1d_enemy_2
+}
+
+# HANGAR 1 ROOM F OPEN
+func void hangar1f_var(string ai_name)
+{
+	dprint hangar1f
+	hangar1f_counter = hangar1f_counter - 1
+	if (hangar1f_counter eq 0)
+		{
+		access_hangar1f_granted();
+		}
+}
+
+func void access_hangar1f_granted(string ai_name)
+{
+	dprint access_granted_f
+	particle garage3_locklight02 do start
+	door_unlock 20
+	door_open 20
+	door_jam 20
+	ai2_spawn hangar1f_enemy_1
+	ai2_spawn hangar1f_enemy_3
+	ai2_spawn rat_thug_4
+}
+
+func void skip_ratscene(string ai_name)
+{
+	dprint no_ratscene
+	door_unlock 24
+	particle lock9_locklight02 do start
+	console_deactivate
+}
+
+func void hangar1d_backup(string ai_name)
+{
+	dprint backup
+	ai2_spawn hangar1f_enemy_2
+}
+
+func void patrolscript0500(string ai_name)
+{
+	dprint jump_bomber
+	playback_block hangar1f_enemy_2 bomber_jump interp 30
+}
+
+func void secret_striker(string char_index)
+{
+	dprint striker_ambush
+	ai2_spawn secret_striker_1
+}
+
+func void secret_tanker(string char_index)
+{
+	dprint tanker_ambush
+	ai2_spawn secret_tanker_1
+}
+
+func void sos_1(string char_index)
+{
+	dprint sos1
+	ai2_spawn sos_badman_1
+}
+
+func void sos_2(string char_index)
+{
+	dprint sos2
+	ai2_spawn sos_badman_2
+}
+
+
+func void carpool_backup(string char_index)
+{
+	dprint carpool_ambush
+	ai2_spawn carpool_striker_2
+}
+
+func void Back1(string char_index)
+{
+	dprint Back1
+	ai2_spawn Roof1_Striker_1
+	ai2_spawn Roof1_Striker_2
+	ai2_spawn Hangar1_C_Striker_1
+	ai2_spawn Hangar1_C_Striker_2
+	ai2_spawn Hangar1_C_Friend_1
+}
+
+func void low_roadies_1(string ai_name)
+{
+	dprint roadies_1
+	ai2_spawn Back_Striker_1
+	ai2_spawn Back_Striker_2
+	ai2_spawn Back_Striker_3
+	ai2_spawn Back_Thug_1
+}
+
+func void low_roadies_2(string ai_name)
+{
+	dprint roadies_2
+	ai2_spawn Back_Tanker_1
+	ai2_spawn Back_Thug_2
+	ai2_spawn Back_Thug_3
+}
+
+func void Back2(string char_index)
+{
+	dprint Back2
+	ai2_spawn Roof2_Striker_1
+	ai2_spawn Roof2_Striker_2
+	ai2_spawn Roof2_Striker_3
+	ai2_spawn Back2_Comguy_1
+	ai2_spawn Back2_Tanker_1
+	ai2_spawn carpool_striker_1
+	ai2_spawn ahah_badman_1
+	ai2_spawn ahah_badman_2
+	particle roof2 do start
+}
+
+func void Rat_Guards(string char_index)
+{
+	dprint rat_guard
+	ai2_spawn Rat_Comguy_1
+	ai2_spawn Rat_Tanker_1
+	particle lock35_locklight01 do start
+}
+
+func void Back3(string char_index)
+{
+	dprint Back3
+	ai2_spawn Roof3_Striker_1
+	ai2_spawn Roof3_Striker_2
+	ai2_spawn Roof3_Tanker_1
+	particle roof3 do start
+}
+
+func void remote_lot(string ai_name)
+{
+	dprint remote_lot_guards
+	ai2_spawn remote_striker_1
+}
+
+func void roof3_backup1(string char_index)
+{
+	dprint roof_backup1
+	ai2_dopath Roof3_Striker_1 Roof3_Striker_1b 1
+}
+
+func void back_compound(string char_index)
+{
+	dprint compound
+	ai2_spawn compound_tanker_1
+	ai2_spawn compound_bomber_1
+	sound_music_stop atm_cl09
+}
+
+func void remote_parking(string ai_name)
+{
+	dprint remote_action
+	ai2_spawn hostage_thug_1
+	ai2_spawn hostage_thug_2
+	ai2_spawn hostage_thug_3
+	ai2_spawn squad_tanker_1
+	ai2_spawn squad_tanker_2
+}
+
+func void remote_backup_1(string ai_name)
+{
+	dprint remote_backup1
+	ai2_spawn hostage_striker_1
+}
+
+func void remote_backup_2(string ai_name)
+{
+	dprint remote_backup2
+	ai2_spawn hostage_striker_2
+}
+
+func void Office1(string char_index)
+{
+	dprint Office1
+	ai2_spawn Office1_Comguy_1
+	ai2_spawn Office1_Comguy_11
+	ai2_spawn Office2_Striker_1
+	ai2_spawn Office2_Striker_3
+	ai2_spawn Office3_Tanker_12
+	ai2_spawn neutral_1
+	ai2_spawn neutral_2
+	sound_music_start atm_gr09
+	particle muroplane_prop do
+}
+
+# HANGAR 2 AMBUSH
+func void ambush(string ai_name)
+{
+	dprint ambush_active
+	particle lock7_locklight01 do start
+	door_unlock 36
+	ai2_spawn ambush_striker_1
+	ai2_spawn ambush_commguy_1
+	sleep 220
+	ai2_doalarm ambush_commguy_1 4
+	sound_music_stop atm_gr09
+	sound_music_start mus_space01 0.75
+	music_script_start
+}
+
+func void Hangar2a(string char_index)
+{
+	dprint Hangar2a
+	ai2_spawn Hangar2_tanker_1
+	ai2_spawn alarm_striker_1
+}
+
+func void Hangar2b(string char_index)
+{
+	dprint Hangar2b
+	ai2_spawn Hangar2_Striker_3
+	ai2_spawn Hangar2_Striker_4
+	ai2_spawn Hangar2_Striker_5
+}
+
+func void alarm_sound_script(void)
+{
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+func void raise_alarm(string char_index)
+{
+	dprint alarm_raised
+	ai2_dopath alarm_striker_1 alarm_striker_1a 1
+	fork alarm_sound_script
+}
+
+func void alarm_patrol(string char_index)
+{
+	dprint patrol_begun
+	ai2_dopath alarm_striker_1 alarm_striker_1b 1
+}
+
+#STRIKER SHOWDOWN
+var int striker_counter=3;
+
+func void striker_showdown_1(string ai_name)
+{
+	dprint striker_showdown1
+	striker_counter = striker_counter - 1
+	if (striker_counter eq 0)
+		{
+		total_striker_count();
+		}
+
+}
+
+func void striker_showdown_2(string ai_name)
+{
+	dprint striker_showdown2
+	striker_counter = striker_counter - 1
+	if (striker_counter eq 0)
+		{
+		total_striker_count();
+		}
+}
+
+func void striker_showdown_3(string ai_name)
+{
+	dprint striker_showdown3
+	striker_counter = striker_counter - 1
+	if (striker_counter eq 0)
+		{
+		total_striker_count();
+		}
+}
+
+func void total_striker_count(string ai_name)
+{
+	dprint rappel_point_active
+	trigvolume_enable rappel_point 1
+	particle rappel create
+	target_set(1054,30.00)
+	sound_music_stop mus_space01
+}
+
+# OBJECTIVE CHECK
+func void objective_check(string ai_name)
+{
+	dprint check_for_objective
+		if (chr_has_lsi(0))
+		{	
+		dprint set_objective5
+		objective_set(5)
+		target_set(7127,30.00)
+		trigvolume_enable objectivecheck 0
+		}
+}
+
+# LSI CHECK 1
+func void lsi_check_1(string ai_name)
+{
+	dprint check_lsi_1
+	if (chr_has_lsi(0))
+		{	
+		trigvolume_enable tripwire 1
+		}
+}
+
+# LSI CHECK 2
+func void lsi_check_2(string ai_name)
+{
+	dprint check_lsi_2
+	if (chr_has_lsi(0))
+		{	
+		particle rappel kill
+		rappel
+		}
+}
+
+### RATS IN THE SEWER ###
+
+# RAT DOOR
+func void rat_door(string ai_name)
+{
+	dprint open_rat_door
+	particle lock9_locklight02 do start
+	door_unlock 24
+	door_open 24
+	door_jam 24	
+	letterbox 1		
+	input 0
+	ai2_spawn rat_thug_1
+	ai2_spawn rat_thug_2
+	ai2_spawn rat_thug_3
+	cm_interpolate rat_door1 0
+	cm_interpolate_block rat_door2 300
+	sleep 250
+	playback rat_thug_1 rat_thug_1 interp 30
+	playback rat_thug_2 rat_thug_2 interp 30
+	playback rat_thug_3 rat_thug_3 interp 30
+	sleep 90
+	sleep 200
+	cm_reset
+	letterbox 0
+	input 1
+	door_unjam 24
+	door_close 24
+	sleep 250
+	chr_delete rat_thug_1
+	chr_delete rat_thug_2
+	chr_delete rat_thug_3
+}
+
+# GAS START
+func void gas_trig_show(string ai_name)
+{
+	dprint gastrig_show
+	trig_show 1
+	trig_show 2
+	trig_show 3
+	trig_show 4
+}
+
+func void gas(string ai_name)
+{
+	dprint rats_take_cover
+	particle gas1 do start
+	particle gas2 do start
+	particle gaslight1 do start
+	console_activate 14
+	console_activate 15
+	door_unjam 48
+	door_close 48
+	trigvolume_enable gas 1
+	timer_stop
+}
+
+# GAS OFF
+func void gas_off(string ai_name)
+{
+	dprint rats_scurry_on
+	particle gas1 do stop
+	particle gas2 do stop
+	particle gaslight1 do stop
+	console_reset 14
+	console_reset 15
+	door_open 48
+	door_jam 48
+	trigvolume_enable gas 0
+	timer_start 10 gas_on
+}
+
+# GAS ON
+func void gas_on(string ai_name)
+{
+	dprint rats_take_cover_again
+	door_lock 24
+	particle gas1 do start
+	particle gas2 do start
+	particle gaslight1 do start
+	console_activate 14
+	console_activate 15
+	door_unjam 48
+	trigvolume_enable gas 1
+}
+
+# GAS OFF FOR GOOD
+func void gas_kill(string ai_name)
+{
+	particle gas1 do stop
+	particle gas2 do stop
+	particle gaslight1 do stop
+	door_unjam 48
+}
+
+func void gas_trig_hide(string ai_name)
+{
+	dprint gastrig_hide
+	trig_hide 1
+	trig_hide 2
+	trig_hide 3
+	trig_hide 4
+	door_lock 48
+}
+
+func void poison_konoko(string ai_name)
+{	
+	chr_poison (konoko, 10, 60, 90);
+}
+
+func void fire_damage(string ai_name)
+{	
+	chr_poison (ai_name, 5, 30, 30);
+}
+
+### LOCKS & LIGHTS ###
+
+func void lock1(void)
+{
+	input 0
+	cm_interpolate lock1 0
+	sleep 60
+	particle lock1_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	target_set(7125,30.00)
+}
+
+func void lock2(string ai_name)
+{
+	input 0
+	cm_interpolate lock2 0
+	sleep 60
+	particle lock2_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	trigvolume_enable hidden_friends1 1
+}
+
+func void lock4(void)
+{
+	input 0
+	cm_interpolate lock4 0
+	sleep 60
+	particle lock4_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void lock5_counter_decrement(void)
+{
+	dprint ENTERING_LOCK_5_DECREMENT
+	lock5_counter = lock5_counter - 1
+	if (lock5_counter eq 2)
+		{
+		sound_music_start mus_cool13 1.0
+		}
+	if (lock5_counter eq 0)
+		{
+		sound_music_stop mus_cool13
+		lock5_end();
+		}
+}
+
+func void lock5a_var(string ai_name)
+{
+	dprint lock5a
+	lock5_counter_decrement
+	input 0
+	cm_interpolate lock5d 0
+	sleep 60
+	particle lock5a_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void lock5b_var(string ai_name)
+{
+	dprint lock5b
+	lock5_counter_decrement
+	input 0
+	cm_interpolate lock5d 0
+	sleep 60
+	particle lock5b_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void lock5c_var(string ai_name)
+{
+	dprint lock5c
+	lock5_counter_decrement
+}
+
+# LOCK 5 END
+func void lock5_end(string ai_name)
+{
+	dprint room1_end
+	door_unlock 21
+	door_unlock 22
+	trigvolume_enable nodark 1
+}
+
+func void lock5(void)
+{
+	lock5c_var
+	letterbox 1
+	input 0
+	cm_interpolate lock5a 0
+	cm_interpolate_block lock5b 300
+	sleep 350
+	cm_interpolate_block lock5c 0
+	sleep 30
+	cm_interpolate_block lock5d 300
+	sleep 300
+	particle lock5c_locklight01 do start
+	sleep 60
+	cm_reset
+	letterbox 0
+	input 1
+}
+
+func void lock6(void)
+{
+	input 0
+	cm_interpolate lock6 0
+	sleep 60
+	particle lock6_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	set_objective_4
+	trigvolume_enable trigger_volume_08 1
+	door_unlock 27
+}
+
+### PARTICLE CONTROL ###
+
+# MAD BOMBER DAMAGE OFF
+func void bomber_off(string ai_name)
+{
+	dprint mad_bomber_particles_off
+	particle bomb_damage1 do stop
+	particle room1 do stop
+	particle bomber1a kill
+}
+
+# PLANE ROTOR WASH ON
+func void rotor_wash(string ai_name)
+{
+	dprint rotorwash_on
+	particle rotorwash do start
+}
+
+# CARPOOL FIRE ON
+func void carpool_start(string ai_name)
+{
+	dprint carpool_particles_on
+	particle carpool create
+	particle carpool do start
+}
+
+# CARPOOL FIRE OFF
+func void carpool_stop(string ai_name)
+{
+	dprint carpool_particles_off
+	particle carpool kill
+	particle carpool do stop
+}
+
+### Level scripted by Joseph ###
Index: /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/Airport_III/airport2_main.bsl	(revision 185)
@@ -0,0 +1,26 @@
+#
+# airportiii_main.bsl
+#
+
+var int my_save_point;
+var int lock5_counter=3;
+var int hangar1d_counter=2;
+var int hangar1f_counter=2;
+
+func void main(void)
+{
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.99
+	gs_farclipplane_set 5000
+
+	my_save_point = save_point;
+
+	func_start
+
+	if (my_save_point eq 0)
+	{
+		airportiii_cs_intro();
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_anim_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_anim_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_anim_scripts.bsl	(revision 185)
@@ -0,0 +1,34 @@
+#
+# anim_scripts.bsl
+#
+func void patrolscript0002 (string ai_name)
+{
+	playback_block Pod1_TCL_2 alarm2 interp 20
+}
+func void patrolscript0003 (string ai_name)
+{
+	playback_block Pod2_TCL_1 pod2alarm1 interp 20
+}
+func void patrolscript0004 (string ai_name)
+{
+	playback_block Pod2_TCL_2 pod2alarm2 interp 20
+}
+
+
+func void patrolscript0009 (string ai_name)
+{
+	particle lock99_locklight01 do start
+	door_unlock 11
+	sleep 540
+	particle lock99_locklight01 do stop
+	door_lock 11
+}
+func void patrolscript0010 (string ai_name)
+{
+	particle lock99_locklight01 do start
+	door_unlock 11
+# WAIT AND RELOCK DOORS
+	sleep 540
+	particle lock99_locklight01 do stop
+	door_lock 11
+}
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_cutscene.bsl	(revision 185)
@@ -0,0 +1,436 @@
+#
+# warehouse_cutscene.bsl
+#
+
+########################
+func void
+Kon(
+	void)
+{
+	cm_interpolate KonCamFoot01 0
+	cm_interpolate_block KonCamFoot02 300
+	sleep f260
+	#cm_interpolate KonCamChest01 0
+	#cm_interpolate_block KonCamChest02 180
+	#sleep f120
+	cm_interpolate KonCamBack01 0
+	cm_interpolate_block KonCamBack02 180
+	sleep f150
+	cm_interpolate KonCamSide01 0
+	cm_interpolate_block KonCamSide02 210
+	sleep f190
+	cm_interpolate KonCamFinish01
+	cm_interpolate_block KonCamFinish02 200
+	sleep 345
+	fade_out 0 0 0 15
+	sleep 15
+	cm_reset
+	fade_in 15
+	sleep 15
+}
+
+############################
+
+func void
+animate(string me)
+{
+	#chr_animate me KONCOMpunch_fw
+}
+
+func void swing(void)
+{
+	how_far_along = 0;
+	fade_out 0 0 0 30
+	sleep 30
+	splash_screen warehouse_splash_screen
+	swing_cutscene
+}
+
+func void jumping_sounds(void)
+{
+	sleep 97
+	# first hit on ledge
+	sound_impulse_play kon_land_con
+}
+
+func void
+swing_cutscene(
+	void)
+{
+	fade_out 0 0 0 0
+	sleep 15
+	how_far_along = 0;
+	begin_cutscene
+	cutscene_sync off
+	ai2_spawn kerr
+	ai2_spawn griffin
+	playback kerr KerrSet
+	playback griffin GriffinSet
+	cm_interpolate GriffinCam 0
+	sleep 30
+		chr_changeteam char_0 Konoko
+		chr_inv_reset 0
+		chr_giveweapon 0 w1_tap
+		chr_forceholster 0 1
+	cm_interpolate GriffinCam 0
+	fade_in 30
+	sleep 60
+	#griffin talks
+	cinematic_start (GRIFnametag, 180, 180, 15, 1, 20, false)
+	sound_dialog_play c01_01_01griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c01_01_02shinatama
+	cinematic_start (SHINnametagM, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (SHINnametagM, 16, 20)
+	cm_interpolate OfficeCam02 0
+	cm_interpolate_block OfficeCam01 900
+	sleep 15
+	sound_dialog_play c01_01_03kerr
+	cinematic_start (KERRnametagM, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c01_01_04griffin
+	sound_dialog_play_block pause
+	playback 0 KonokoSet
+	sleep 10
+	cinematic_stop (KERRnametagM, 16, 20)
+	#camera of Konoko
+	#cm_reset
+	cm_interpolate KonokoCam01 0
+	cm_interpolate_block KonokoCam02 360
+	cinematic_start (KONnametagM, 180, 180, 16, 3, 20, true)
+	chr_animate 0 KONOKOwatch_idle 3000
+	sleep 10
+	sound_dialog_play c01_01_05griffin
+	sound_dialog_play_block pause
+	#cinematic_start (KONnametagM, 180, 180, 16, 3, 20, true)
+	sleep 30
+	sound_dialog_play c01_01_06konoko	
+	sound_dialog_play_block pause
+	sleep 20
+	cinematic_stop (KONnametagM, 16, 20)
+	sleep 15
+	#griffin cam
+	#sleep 30
+	cm_interpolate GriffinCam 0
+	sleep 30
+	sound_dialog_play c01_01_07griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c01_01_08shinatama
+	cinematic_start (SHINnametagM, 180, 180, 16, 3, 20, true)		
+	sound_dialog_play_block pause
+	cinematic_stop (SHINnametagM, 16, 20)
+	#office cam
+	cm_interpolate OfficeCam01 0
+	cm_interpolate_block OfficeCam02 900
+	sound_dialog_play c01_01_09kerr
+	cinematic_start (KERRnametagM, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c01_01_10griffin
+	sound_dialog_play_block pause
+	#cinematic_stop (KERRnametagM, 16, 20)
+	cinematic_stop (GRIFnametag, 15, 20)
+	sleep 60
+	#KerrCam
+	cm_interpolate KerrCam 0
+	#cinematic_start (KERRnametagM, 180, 180, 16, 3, 20, true)
+	sleep 40
+	sound_dialog_play c01_01_11kerr
+	sound_dialog_play_block pause
+	cutscene_sync on
+	sleep 40
+	cinematic_stop (KERRnametagM, 16, 20)
+	cm_anim both Cam4
+	cutscene_sync mark
+	chr_envanim 0 KonBipedBox02 norotation
+	chr_animate 0 KONOKOlev1_intro
+	fork jumping_sounds
+	env_anim 20 20
+	sleep f180
+	sound_ambient_start c00_20_07window
+	sleep f154
+	playback 0 SwingKonokoSet
+	# hit on the floor
+	sound_impulse_play kon_land_con
+	sleep 30
+	cm_reset
+	sleep f30
+#	end_cutscene
+	letterbox 0
+	chr_full_health 0
+	give_powerup ammo
+	give_powerup ammo
+	give_powerup ammo
+	chr_delete griffin
+	chr_delete kerr
+	s1
+	yhealth
+}
+
+func void chung_music_start(void)
+{
+	sound_music_start atm_low1 0.7
+}
+
+# we stop this music when we spawn the lsi striker (a tad after actually)
+func void chung_music_stop(void)
+{
+	sound_music_stop atm_low1
+}
+
+
+func void
+Chung(
+	void)
+{
+	begin_cutscene
+
+	chung_music_start
+
+	sleep 30
+	cm_jello 1
+	sound_dialog_play_block pause
+	sound_dialog_play c01_02_01konoko
+	sound_dialog_play_block pause
+	sleep 60
+	chr_animate 0 KONOKOwatch_start 60
+	sleep 40
+	cinematic_start (KONnametag, 180, 180, 15, 1, 20, false)
+	cinematic_start (GRIFnametagM, 180, 180, 16, 3, 20, true)
+	sleep 19
+	chr_animate 0 KONOKOwatch_idle 3000
+	sound_dialog_play c01_02_02konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c01_02_03griffin
+	sound_dialog_play_block pause
+	sleep 30
+	sound_dialog_play c01_02_04konoko
+	sound_dialog_play_block pause
+	sleep 60
+	sound_dialog_play c01_02_05griffin
+	sound_dialog_play_block pause
+	chr_animate 0 KONOKOwatch_stop
+	cinematic_stop (KONnametag, 15,20)
+	cinematic_stop (GRIFnametagM, 16,20)
+	sleep 15
+	cm_reset
+	end_cutscene
+	trigvolume_enable gotLSI_tv 1
+	target_set(1,0)
+	input 1
+}
+
+func void
+outro(
+	void)
+{
+	chr_delete WH_Thug_A 
+	chr_delete WH_Striker_B
+	chr_delete WH_Striker_D
+	begin_cutscene
+	#forklift raises into position
+	obj_create 101 109
+	env_show 101 0
+	env_show 102 0
+	env_show 103 0
+	env_show 104 0
+	env_show 105 0
+	env_show 106 0
+	env_show 107 0
+	env_show 108 0
+	env_show 109 0
+	env_anim 101 109
+	cm_anim both OutroCam01
+	cutscene_sync mark
+	sound_ambient_start c00_38_24_forklifta
+	sound_ambient_start c00_38_24_truck
+	playback 0 OutroKonokoWalk
+	cm_wait
+	#Konoko enters booth
+	cm_anim both OutroCam02
+	chr_envanim 0 OutroKonokoBox01 norotation
+	chr_animate 0 KONOKOlev1_Outro1
+	cm_wait
+	#Forklift starts down
+	cm_anim both OutroCam03
+	chr_envanim 0 OutroKonokoBox02
+	chr_animate 0 KONOKOlev1_Outro2 770
+	env_setanim 101 TwoForkLift01
+	env_setanim 102 TwoForkLift02
+	env_setanim 103 TwoForkLift03
+	env_setanim 104 TwoForkLift04
+	env_setanim 105 TwoForkLift05
+	env_setanim 106 TwoForkLift06
+	env_setanim 107 TwoForkLift07
+	env_setanim 108 TwoForkLift08
+	env_setanim 109 TwoForkLift09
+	env_show 201 0
+	env_show 202 0
+	env_show 203 0
+	env_show 204 0
+	env_show 205 0
+	env_show 206 0
+	env_show 207 0
+	obj_create 201 207
+	env_anim 201 207
+	cutscene_sync mark
+	sound_ambient_start c00_38_24_forkliftb
+	cm_anim_block both OutroCam04
+	cm_anim_block both OutroCam05
+	cutscene_sync mark
+	sound_ambient_start c00_52_13_crash_doors
+	cm_anim_block both OutroCam06
+	cm_wait
+	door_unlock 48
+	particle bigdoor_locklight02 do start
+	ai2_spawn OutroTCTF01
+	ai2_spawn OutroTCTF02
+	ai2_spawn OutroTCTF03
+	sleep 21
+	playback 0 OutroKonokoWalk
+	ai2_setmovementmode OutroTCTF01 run
+	ai2_setmovementmode OutroTCTF02 run
+	ai2_setmovementmode OutroTCTF03 run
+	cm_interpolate OutroCam07 0
+	cm_interpolate_block OutroCam08 240
+	playback OutroTCTF01 OutroTCTF01
+	playback OutroTCTF02 OutroTCTF02
+	playback OutroTCTF03 OutroTCTF03
+	sleep 230
+	playback 0 OutroKonokoJump
+	sleep 120
+	cm_interpolate OutroCam09 0
+	sleep 120
+	cm_reset
+	cm_orbit .1
+	chr_animate 0 KONOKOwatch_start 60
+	sleep 40
+	cinematic_start (KONnametag, 180, 180, 15, 1, 20, false)
+	cinematic_start (GRIFnametagM, 180, 180, 16, 3, 20, true)
+	sleep 19
+	chr_animate 0 KONOKOwatch_idle 3000
+	sound_dialog_play c01_03_01konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c01_03_02griffin
+	sound_dialog_play_block pause
+	ai2_spawn griffin
+	playback griffin GriffinSet
+	sound_dialog_play c01_03_03konoko
+	sound_dialog_play_block pause
+	#griffin Cam
+	cm_interpolate GriffinCam 0
+	cm_interpolate_block GriffinCam01 500
+	sound_dialog_play c01_03_04griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c01_03_05konoko
+	sound_dialog_play_block pause
+	cinematic_stop (KONnametag, 15, 20)
+	sleep 20
+	sound_dialog_play c01_03_06shinatama
+	cinematic_start (SHINtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	cinematic_stop (SHINtalking, 15, 20)
+	sleep 20
+	#konoko camera
+	chr_animate 0 KONOKOwatch_idle 3000
+	cm_reset
+	sleep 20
+	sound_dialog_play c01_03_07griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c01_03_08konoko
+	cinematic_start (KONnametag, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	sleep 15
+	chr_animate 0 KONOKOwatch_stop
+	cinematic_stop (KONnametag, 15,20)
+	cinematic_stop (GRIFnametagM, 16,20)
+	fade_out 0 0 0 120
+	sleep 120
+	win
+}
+
+func void
+camcontrol(
+	void)
+{
+	cm_anim both OutroCam03
+	cm_anim both OutroCam04
+	cm_anim both OutroCam05
+	cm_anim both OutroCam06
+	cm_wait
+	end_cutscene
+}
+
+func void
+OutroLose(
+	void)
+{
+	begin_cutscene weapon
+	ai2_spawn LoseTCTF01
+	ai2_spawn LoseTCTF02
+	ai2_spawn LoseTCTF03
+	sleep f30
+	fade_out 0 0 0 15
+	door_unlock 48
+	particle bigdoor_locklight02 do start
+	sleep f15
+	playback 0 OutroLoseKonoko
+	ai2_setmovementmode LoseTCTF01 run
+	ai2_setmovementmode LoseTCTF02 run
+	ai2_setmovementmode LoseTCTF03 run
+	playback LoseTCTF01 OutroLoseTCTF01
+	playback LoseTCTF02 OutroLoseTCTF02
+	playback LoseTCTF03 OutroLoseTCTF03
+	sleep f25
+	fade_in 20
+	##show tctf guys stormin the place
+	cm_interpolate OutroLoseCam01 0
+	cm_interpolate_block OutroLoseCam011 120
+	sleep f150
+	##show and Hide truck stuff
+	env_show 201 0
+	env_show 202 0
+	env_show 203 0
+	env_show 204 0
+	env_show 205 0
+	env_show 206 0
+	env_show 207 0
+	obj_create 201 207
+	##Truck starts up
+	env_setanim 201 Losetruckwheel01
+	env_setanim 202 Losetruckwheel02
+	env_setanim 203 Losetruckwheel03
+	env_setanim 204 Losetruckwheel04
+	env_setanim 205 Losetruckwheel05
+	env_setanim 206 Losetruckback
+	env_setanim 207 Losetruckcab
+	cm_anim both OutroLoseCam02
+	cutscene_sync mark
+	sound_ambient_start truckleave
+	###Truck leaves
+	cm_anim_block both OutroLoseCam03
+	playback LoseTCTF01 OutroLoseRoll
+	playback LoseTCTF02 OutroLoseDie
+	playback LoseTCTF03 OutroLoseDodge
+	sleep f20
+	cutscene_sync mark
+	sound_ambient_start gar_dr_up
+	###
+	sleep f105
+	chr_set_health LoseTCTF02 0
+	#door_jam 48
+	sleep f105
+	cutscene_sync mark
+	sound_ambient_start gar_dr_down
+	cm_wait
+	sleep f30
+	fade_out 0 0 0 90
+	sleep f90
+	lose
+}
+	
+
+
+
+
+
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_level_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_level_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_level_scripts.bsl	(revision 185)
@@ -0,0 +1,949 @@
+# warehouse_level_scripts.bsl
+#
+# LEVEL LOGIC
+#
+########################### START & SAVE ##############################
+var int outro_has_started = 0;
+var int count_alarm;
+var int count_end_striker = 0;
+var int count_end_console = 0;
+var int td;
+var int ns;
+var int in_t64;
+var int d6;
+var int ul5;
+# music #
+
+func void music_train1(void)
+{
+	sound_music_start atm_gr06 0
+	sound_music_volume atm_gr06 0.7 3.0
+#	stopped by moving into combat rooms
+}
+
+func void music_train2(void)
+{
+	sound_music_start atm_ft68 0
+	sound_music_volume atm_ft68 0.75 3.0
+#	stopped by moving into firing range
+}
+
+func void music_train3(void)
+{
+	sound_music_start mus_amasian 0
+	sound_music_volume mus_amasian 0.75 3.0
+#	stopped by using last review console
+}
+
+func void music_firstfight(void)
+{
+	sound_music_start mus_ambgrv1 0
+	sound_music_volume mus_ambgrv1 0.75 3.0
+#	stopped by intro_enemies thug die or hurt scripts
+}
+
+func void music_timer(void)
+{
+	sound_music_start mus_chase 0
+	sound_music_volume mus_chase 0.75 3.0
+#	stopped in end_console or end_striker
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_volume atm_gr06 0.0 2.0
+	sound_music_stop atm_gr06
+	sound_music_volume atm_ft68 0.0 2.0
+	sound_music_stop atm_ft68
+	sound_music_volume mus_amasian 0.0 2.0
+	sound_music_stop mus_amasian
+	sound_music_volume mus_ambgrv1 0.0 2.0
+	sound_music_stop mus_ambgrv1
+	sound_music_volume mus_chase 0.0 3.0
+	sound_music_stop mus_chase
+}
+
+func void level_start(string ai_name)
+{
+# These functions are used when the game is restored.
+	
+	trigvolume_enable(intro_enemies_tv, 0);
+	trigvolume_enable(setup_bay3_tv, 0);
+	trigvolume_enable gotLSI_tv 0
+	trigvolume_enable trigger_volume_06 0
+	particle bigdoor_locklight02 do start
+
+	my_save_point = save_point;
+
+	if (my_save_point eq 0)
+	{
+		can_train_movement=1;
+		dprint SAVE_POINT_0	
+#		USE THIS FUNC TO SET UP TRAINING SEQUENCE AGAIN
+		splash_screen training_splash_screen
+		dprint hello
+	}
+
+	if (my_save_point eq 1)
+	{
+# this is a built in save point for 
+		can_train_movement=0;
+#		objective_set(1)
+		door_lock(15);
+		door_lock(16);
+		particle(lock1_locklight01, do, stop);
+		restore_game
+		playback 0 SwingKonokoSet
+		target_set(1,0.0)
+		dprint RESTORE_SAVE_Point_1
+		splash_screen warehouse_splash_screen
+		swing_cutscene
+	}
+
+	if (my_save_point eq 2)
+	{
+		can_train_movement=0;
+#		objective_set(1)
+		door_lock(15);
+		door_lock(16);
+		particle(lock1_locklight01, do, stop);
+		restore_game
+		ai2_spawn A_t48
+		playback 0 SwingKonokoSet
+		target_set(1,0.0)
+		dprint RESTORE_SAVE_Point_2_begin
+		splash_screen warehouse_splash_screen
+		cm_reset
+		sleep 30
+		chr_forceholster 0 0
+	}
+
+	if (my_save_point eq 3)
+	{
+		dprint RESTORE_SAVE_POINT_3
+		can_train_movement=0;
+		trigvolume_enable trigger_volume_03 0
+		target_set(7053, 15.0)
+		door_lock 16
+		ai2_spawn Mid_Thug_2
+		ai2_spawn Mid_Thug_1
+		restore_game
+		objective_set 2 silent
+		splash_screen warehouse_splash_screen
+	}
+
+	if (my_save_point eq 4)
+	{
+		dprint RESTORE_SAVE_POINT_4
+		can_train_movement=0;
+		door_lock 65
+		trigvolume_enable trigger_volume_68 0
+		target_set(7054, 30.0)
+	#	spawn_top	
+		restore_game
+		objective_set 2 silent
+		splash_screen warehouse_splash_screen
+	}
+
+	if (my_save_point eq 5)
+	{
+		dprint RESTORE_SAVE_POINT_5
+		can_train_movement=0;
+		door_lock 48
+		particle bigdoor_locklight02 do stop
+		ai2_spawn WH_Thug_A 
+		ai2_spawn WH_Striker_B
+		ai2_spawn WH_Striker_C
+		ai2_spawn WH_Striker_D
+		ai2_dopath WH_Thug_A WH_Thug_A
+		ai2_dopath WH_Striker_B WH_Striker_B
+		ai2_dopath WH_Striker_D WH_Striker_D
+		ai2_setjobstate WH_Thug_A 
+		ai2_setjobstate WH_Striker_B
+		ai2_setjobstate WH_Striker_D
+		chr_teleport WH_Striker_D 95
+		trigvolume_enable tv78 0
+		trigvolume_enable mid_warehouse_target 0
+		restore_game
+		splash_screen warehouse_splash_screen
+		sleep 7
+		train_timer
+	}
+}
+
+func void unholstergun(void)
+{
+	sleep 30
+	chr_forceholster 0 0 
+}
+
+# This is an example of a save game console.
+
+func void s1(string player_name)
+{
+	dprint saveit_1
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void s2(string player_name)
+{
+	dprint saveit_2
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+func void s3(string player_name)
+{
+	dprint saveit_3
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+func void s4(string player_name)
+{
+	dprint saveit_4
+
+	if (my_save_point ne 5)
+	{
+		save_game 5 autosave
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void unlock1(string ai_name)
+{
+	dprint unlock1
+	target_set(33, 15.0)
+
+	door_unlock 15
+	door_unlock 16
+
+	input 0
+	cm_interpolate lock1 0
+	sleep 60
+	particle lock1_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	sleep 120
+	ai2_spawn Bay1_Thug_1
+	trigvolume_enable intro_enemies_tv 1
+	trigvolume_enable trigger_volume_77 0
+}
+
+func void unlock2(string ai_name)
+{
+	dprint unlock2
+
+	music_stop
+
+	target_set(84, 15.0)
+
+	door_unlock 24
+	door_unlock 26
+
+	input 0
+	cm_interpolate lock2 0
+	sleep 60
+	particle lock2_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	trigvolume_enable(setup_bay3_tv, 1);
+}
+
+func void setup_bay3(string ai_name)
+{
+	dprint setup_bay_3
+	target_set(84, 15.0)
+#	particle lock3_locklight01 do start
+}
+
+func void checkLSI(string ai_name)
+{
+	var int has_lsi = chr_has_lsi(0);
+
+	dprint checkLSI
+	trigvolume_enable gotLSI_tv 0
+
+	if (has_lsi eq 1)
+	{
+		input 0
+		sleep 25
+		chr_animate 0 KONOKOwatch_start 60 12
+		sleep 59
+		chr_animate 0 KONOKOwatch_idle 15
+		text_console level_1e
+		chr_animate 0 KONOKOwatch_stop
+		sleep 15
+		input 1
+		sleep 15
+		door_unlock 37
+		particle lock3_locklight01 do start
+		ai2_spawn Ambush_Striker_1
+		ai2_spawn Mid_Thug_1
+		ai2_spawn Mid_Thug_2
+		target_set(7053,30.0)
+		chung_music_stop
+		objective_set(2)
+		sound_dialog_play_block c00_01_21shinatama
+		sound_dialog_play_block pause
+	}
+
+	if (has_lsi eq 0)
+	{
+		# sleep and turn the trigger volume back on later
+		sleep 60
+		trigvolume_enable gotLSI_tv 1
+	}
+}
+
+func void t09(string ai_name)
+{
+	target_set(62,30.0)
+}
+
+func void spawn_top(string ai_name)
+{
+ 	dprint spawn_top
+	ai2_spawn Top_Striker_1
+	ai2_spawn Top_Comguy_1
+	ai2_spawn Top_Thug_3
+	ai2_spawn Top_Thug_5
+	ai2_spawn WH_Thug_A 
+	ai2_spawn WH_Striker_B
+	ai2_spawn WH_Striker_C
+	ai2_spawn WH_Striker_D
+}
+
+func void spawn_mid2(string ai_name)
+{
+ 	dprint spawn_mid2
+	ai2_spawn Mid2_Striker_1
+	ai2_spawn Mid2_Striker_2
+	target_set(66, 15.0)
+}
+
+func void unlock4(string ai_name)
+{
+	dprint unlock4
+	target_set(7054, 15.0)
+
+	door_unlock 65
+
+	input 0
+	cm_interpolate lock4 0
+	sleep 60
+	particle lock4_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+}
+
+func void unlock5(string ai_name)
+{
+	dprint unlock5
+	target_set(72, 30.0)
+	console_deactivate 4
+	door_unlock 73
+	door_unlock 74
+	door_unlock 81
+	door_unlock 82
+	ul5 = 1;
+	input 0
+	cm_interpolate lock5 0
+	sleep 60
+	particle lock5_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	console_deactivate 7
+}
+
+func void hurt1(string ai_name)
+{
+	dprint HURT
+	ai2_makeignoreplayer Bay4_Comguy_1 1
+	ai2_doalarm Bay4_Comguy_1 6
+	ai2_dopath Bay4_Comguy_1 Run_To_Alarm
+	ai2_setjobstate Bay4_Comguy_1
+	sleep 60
+	sound_dialog_play_block c00_01_96shinatama
+
+}
+
+func void patrolscript0001(string ai_name)
+{
+	dprint comguy_do_alarm
+	ai2_doalarm Bay4_Comguy_1 6
+}
+
+func void unlock_alarm(void)
+{
+	dprint unlock_alarm
+	door_unlock 73
+	door_unlock 74
+	door_unlock 81
+	door_unlock 82
+	ai2_dopath Alarm_Bay4_Striker_1 Alarm_Bay4_Striker_1
+	sleep 107
+	particle lock5_locklight01 do start
+	console_deactivate 7
+}
+
+func void do_alarm_sound(void)
+{
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+func void alarm_trig(string ai_name)
+{
+	dprint alarm_trig
+	trigvolume_enable alarm_trigvol 0
+	target_set(72,30.0)
+	if(ul5 eq 0)
+	{
+	#watch comguy set alarm, doors initially locked
+	if(count_alarm eq 0)
+	{	
+		ai2_passive Bay4_Comguy_1 1
+		ai2_spawn Alarm_Bay4_Striker_1
+		ai2_makeignoreplayer Alarm_Bay4_Striker_1 1
+		ai2_spawn Alarm_Bay4_Striker_2
+		ai2_makeignoreplayer Alarm_Bay4_Striker_2 1
+	#	ai2_spawn Bay5_Thug_1
+		ai2_spawn Bay5_Thug_2
+		ai2_doalarm Alarm_Bay4_Striker_1 4
+		input 0
+		chr_animate Bay4_Comguy_1 COMGUYconsole 
+		fade_out 0 0 0 30
+		letterbox 1
+		sleep 30
+		cm_interpolate alarm5 0
+		fade_in
+		sleep 90
+		fade_out 0 0 0 15
+		chr_teleport Alarm_Bay4_Striker_1 7033
+		sleep 15
+		cm_interpolate alarm1 0
+		fork do_alarm_sound
+		fade_in
+		sleep 40
+		cm_interpolate alarm2 240
+		sleep 320
+		cm_interpolate alarm3 90
+		sleep 70
+		particle lock5_locklight01 do start
+		sleep 20
+		cm_interpolate alarm4 0
+		sleep 60
+		fade_out 0 0 0 60
+		sleep 60
+		ai2_passive Bay4_Comguy_1 0
+	}
+
+	#no watch comguy set alarm, doors initially locked
+	if(count_alarm eq 1)
+	{	
+		ai2_spawn Alarm_Bay4_Striker_1
+		ai2_makeignoreplayer Alarm_Bay4_Striker_1 1
+		ai2_spawn Alarm_Bay4_Striker_2
+		ai2_makeignoreplayer Alarm_Bay4_Striker_2 1
+	#	ai2_spawn Bay5_Thug_1
+		ai2_spawn Bay5_Thug_2
+		input 0
+		fade_out 0 0 0 30
+		sleep 15
+		chr_teleport Alarm_Bay4_Striker_1 7033
+		ai2_doalarm Alarm_Bay4_Striker_1 4
+		sleep 15
+		letterbox 1
+		cm_interpolate alarm1 0
+		fork do_alarm_sound
+		fade_in
+		sleep 40
+		cm_interpolate alarm2 240
+		sleep 320
+		cm_interpolate alarm3 90
+		sleep 70
+		particle lock5_locklight01 do start
+		sleep 20
+		cm_interpolate alarm4 0
+		sleep 60
+		fade_out 0 0 0 60
+		sleep 60		
+	}
+	}
+
+	#watch comguy set alarm, doors already unlocked
+	if(ul5 eq 1)
+	{
+		if(trigvolume_count (66) eq 0)
+		{
+			if(count_alarm eq 0)
+			{	
+				ai2_passive Bay4_Comguy_1 1
+				ai2_spawn Alarm_Bay4_Striker_1
+				ai2_makeignoreplayer Alarm_Bay4_Striker_1 1
+				input 0
+				chr_animate Bay4_Comguy_1 COMGUYconsole 
+				fade_out 0 0 0 30
+				letterbox 1
+				sleep 30
+				cm_interpolate alarm5 0
+				fade_in
+				sleep 90
+				fade_out 0 0 0 15
+		#		chr_teleport Alarm_Bay4_Striker_1 7033
+				sleep 15
+				cm_interpolate alarm1 0
+				fork do_alarm_sound
+				fade_in
+				sleep 90
+				fade_out 0 0 0 60
+				sleep 60	
+				ai2_passive Bay4_Comguy_1 0
+			}
+
+	#no watch comguy set alarm, doors already unlocked
+			if(count_alarm eq 1)
+			{	
+				ai2_spawn Alarm_Bay4_Striker_1
+				ai2_makeignoreplayer Alarm_Bay4_Striker_1 1
+				input 0
+				fade_out 0 0 0 30
+				sleep 7
+				chr_teleport Alarm_Bay4_Striker_1 7033
+				sleep 23
+				letterbox 1
+				cm_interpolate alarm1 0
+				fork do_alarm_sound
+				fade_in
+				sleep 90
+				fade_out 0 0 0 60
+				sleep 60
+			}
+		}
+	}
+
+	cm_reset
+	fade_in
+	letterbox 0
+	input 1
+	#sleep 15
+	ai2_makeignoreplayer Alarm_Bay4_Striker_1 0
+	ai2_makeignoreplayer Alarm_Bay4_Striker_2 0
+	ai2_makeignoreplayer Bay4_Comguy_1 0
+	ai2_dopath Bay4_Comguy_1 patrol_42
+	ai2_setjobstate Bay4_Comguy_1 
+#	ai2_attack Alarm_Bay4_Striker_1 char_0
+	ai2_attack Alarm_Bay4_Striker_2 char_0
+
+}
+
+func void set_bay6_objective(string ai_name)
+{
+	dprint set_bay6_objective
+	target_set(92, 15.0)
+
+}
+
+func void spawn_bay6_top(string ai_name)
+{
+	ai2_spawn Bay6_Striker_1
+	ai2_spawn Bay6_Neutral_1
+	ai2_spawn Bay6_Neutral_2
+	ai2_spawn guard1
+	trigvolume_enable spawn_bay6_bot_tv 0
+
+	train_neutral();
+}
+
+func void spawn_bay6_bot(string ai_name)
+{
+	ai2_spawn Bay6_Striker_1b
+	ai2_spawn Bay6_Neutral_1b
+	ai2_spawn Bay6_Neutral_2
+	ai2_spawn guard1
+	trigvolume_enable spawn_bay6_top_tv 0
+
+	train_neutral();
+}
+
+func void open_warehouse(string ai_name)
+{
+	trigvolume_enable trigger_volume_06 0
+	objective_set(3)
+	sleep 10
+	target_set(93,15.0)
+	ai2_dopath Bay6_Neutral_2 Open_Warehouse
+	ai2_setjobstate Bay6_Neutral_2
+	ai2_spawn WH_Thug_A 
+	ai2_spawn WH_Striker_B
+	ai2_spawn WH_Striker_C
+	ai2_spawn WH_Striker_D
+	particle lock7_locklight01 do start
+	door_unlock 84
+	door_unlock 85
+	door_unlock 86
+
+	ai2_spawn Final_Thug_1
+	ai2_spawn Final_Thug_2
+	ai2_spawn Final_Thug_3
+	ai2_spawn Final_Thug_5
+
+	ai2_dopath WH_Thug_A WH_Thug_A
+	ai2_dopath WH_Striker_B WH_Striker_B
+	ai2_dopath WH_Striker_D WH_Striker_D
+
+	ai2_setjobstate WH_Thug_A 
+	ai2_setjobstate WH_Striker_B
+	ai2_setjobstate WH_Striker_D
+}
+
+func void t47(string ai_name)
+{
+	ai2_spawn Bay5_Thug_1
+	ai2_spawn Bay5_Thug_2
+}
+
+func void mid_warehouse_target(string ai_name)
+{
+#	Reset Target
+	target_set(96, 15.0)
+}
+func void stair1_target(string ai_name)
+{
+#	Reset Target
+	target_set(31,15.0)
+}
+
+func void stair2_target(string ai_name)
+{
+#	Reset Target
+	target_set(81,15.0)
+}
+
+func void enable_end(string ai_name)
+{
+#	trigvolume_enable end 1
+	timer_stop
+}
+
+func void gotoconsole(string ai_name)
+{
+#	dprint Guard_A_RTAlarm
+	console_activate 9
+	sleep 7
+	ai2_doalarm Bay6_Neutral_2 9
+	sleep 180
+	trigvolume_enable trigger_volume_06 1
+}
+
+func void t06(string ai_name)
+{
+	dprint t06
+	ai2_doalarm Bay6_Neutral_2 9
+}
+
+func void t10(string ai_name)
+{
+	dprint t10
+	ai2_makeignoreplayer Bay6_Neutral_1 1
+	ai2_makeignoreplayer Bay6_Neutral_1b 1
+	ai2_dopath Bay6_Neutral_1 Bay6_Thug_1
+	ai2_dopath Bay6_Neutral_1b Bay6_Thug_1_copy
+	sleep 240
+	ai2_makeignoreplayer Bay6_Neutral_1 0
+	ai2_makeignoreplayer Bay6_Neutral_1b 0	
+}
+
+func void final_striker_attack(void)
+{
+	ai2_attack WH_Striker_C char_0
+}
+
+func void end_console(string ai_name)
+{
+	dprint end_console
+	count_end_console = 1;
+	music_stop
+	timer_stop
+
+	if (count_end_striker eq 0)
+	{
+		final_striker_attack
+	}
+
+	if (count_end_striker eq 1)
+	{
+		outro_start
+	}
+
+}
+
+func void end_striker(string ai_name)
+{
+	dprint end_striker
+	count_end_striker =  1
+	music_stop
+
+	if (count_end_console eq 1)
+	{
+		outro_start
+	}
+}
+
+# we can only start the trigger volume once
+# and only if there are no bad guys in the area
+
+func void outro_start2(void)
+{
+	dprint READY_TO_BATTLE
+	outro_has_started = 1;
+	sleep 20
+	outro
+}
+
+func void outro_start(void)
+{
+	if (outro_has_started eq 0)
+	{
+		if (trigvolume_count (76) eq 0)
+		{
+			if (trigvolume_count (70) eq 1)
+			{
+				outro_start2
+			}
+		}
+	}
+}
+
+# once every 2/3 of a second, check to see if we are in the 
+# trigger and have no badguys near us
+
+func void t70(string ai_name)
+{
+	var int count_end_both = 0;
+
+	dprint t70_END
+
+	count_end_both = count_end_both + count_end_console;
+	count_end_both = count_end_both + count_end_striker;
+
+	trigvolume_enable trigger_volume_70 0
+
+	if (count_end_console eq 1)
+	{
+		outro_start
+	}
+
+	if (outro_has_started eq 0)
+	{
+		if (count_end_console eq 1)
+		{
+			final_striker_attack
+		}
+	}
+
+	if(outro_has_started eq 0)
+	{
+		sleep 40
+		trigvolume_enable trigger_volume_70 1	
+	}
+}
+
+func void t01(string ai_name)
+{
+	dprint t01
+	ai2_spawn A_t50
+}
+
+func void compass(void)
+{
+	target_set(44, 30.0)
+	ui_flash_element compass 1
+	sound_dialog_play_block c00_01_26shinatama
+	message xincoming 130
+	sleep 60
+	input 0
+	sleep 30
+	chr_animate 0 KONOKOwatch_start 60
+	sleep 59
+	chr_animate 0 KONOKOwatch_idle 15
+	text_console level_1d
+	ui_flash_element compass 0
+	chr_animate 0 KONOKOwatch_stop
+	input 1
+	sleep 60
+	objective_set (1)
+}
+
+func void t48_dead(string ai_name)
+{
+	dprint t48dead
+	td = 1;	
+	door_unlock 108
+	if(in_t64 eq 1)
+	{
+		sleep 180
+		compass
+	}
+}
+
+func void t63(string ai_name)
+{
+	dprint t63
+#	ai2_spawn A_t47
+	ai2_spawn A_t48
+}
+
+func void t64(string ai_name)
+{
+	dprint t64
+	if(in_t64 eq 0)
+	{	
+		in_t64 = 1;
+		ai2_dopath A_t48 patrol_49
+		ai2_setjobstate A_t48
+		ai2_attack A_t48 char_0
+	}
+	if(td eq 1)
+	{
+		trigvolume_enable trigger_volume_64 0
+		compass
+	}
+}
+
+func void t65(string ai_name)
+{
+	
+	dprint t65
+	if(d6 eq 0)
+	{
+		message xdoorislocked
+		dprint door_is_locked
+	}
+}
+
+func void t65b(string ai_name)
+{
+	
+	dprint t65b
+	if(d6 eq 0)
+	{
+		message_remove xdoorislocked
+	}
+}
+func void t67(string ai_name)
+{
+	
+	dprint t67
+	chr_changeteam guard1 Syndicate
+}
+
+func void t07(string ai_name)
+{
+	
+	dprint t07
+	ai2_spawn Top_Thug_5
+	ai2_spawn WH_Striker_C
+	ai2_spawn WH_Striker_D
+}
+
+func void t69(string ai_name)
+{
+	
+	dprint t69
+	ai2_spawn Top_Striker_1
+	ai2_spawn Top_Comguy_1
+	ai2_spawn Top_Thug_3
+}
+
+func void unlock6(string ai_name)
+{
+	dprint unlock6
+	d6 = 1
+	door_unlock 6
+	particle d1_locklight01 do start
+	trigvolume_enable trigger_volume_65 1
+}
+
+func void yhealth(string ai_name)
+{
+	dprint yhealth
+	message_remove
+	lock_keys 
+	input 1
+	ui_show_element right 1
+	sound_dialog_play_block c00_01_92shinatama
+	sound_dialog_play_block pause
+	ui_flash_element health 1
+	chr_animate 0 KONOKOwatch_start 60
+	sleep 59
+	chr_animate 0 KONOKOwatch_idle 15
+	text_console level_1m
+	ui_flash_element health 0
+	chr_animate 0 KONOKOwatch_stop
+	chr_forceholster 0 0
+	lock_keys keys_all
+	end_cutscene
+	if (trigvolume_count (63) eq 1)
+	{
+		ai2_spawn A_t48
+	}
+}
+
+func void console_evidence1(string ai_name)
+{
+	text_console level_1a
+	console_reset 19
+}
+
+func void console_evidence2(string ai_name)
+{
+	text_console level_1b
+	console_reset 20
+}
+
+func void t02(string ai_name)
+{
+	dprint t02
+	sleep 60
+	if(trigvolume_count (2) eq 1)
+	{
+		dprint spawned_secret
+		ai2_spawn secret2
+		trigvolume_enable trigger_volume_01 0
+		ai2_spawn A_t50
+		ai2_dopath A_t50 patrol_secret1
+		ai2_setjobstate A_t50
+	}
+}
+
+func void t05(string ai_name)
+{
+	dprint t05
+	ai2_spawn ambush_striker
+}
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_main.bsl	(revision 185)
@@ -0,0 +1,18 @@
+#
+# warehouse_main.bsl
+#
+
+var int my_save_point;
+
+func void main(void)
+{
+	env_show 2010 0
+	gl_fog_blue=.15
+	gl_fog_red=.15
+	gl_fog_green=.15
+	gl_fog_start=.99
+	gs_farclipplane_set 5000
+	obj_create 20 20
+	level_start
+
+}
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_particles.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_particles.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_particles.bsl	(revision 185)
@@ -0,0 +1,71 @@
+#
+# warehouse_particle.bsl
+#
+
+
+
+func void rat1(void)
+{
+	particle rat1 pulse
+}
+func void rat2(void)
+{
+	particle rat2 pulse
+}
+func void rat3(void)
+{
+	particle rat3 pulse
+}
+func void rat4(void)
+{
+	particle rat4 pulse
+}
+func void rat5(void)
+{
+	particle rat5 pulse
+}
+func void rat6(void)
+{
+	particle rat6 pulse
+}
+func void rat7(void)
+{
+	particle rat7 pulse
+}
+func void bug1(void)
+{
+	particle bug1 pulse
+}
+func void bug2(void)
+{
+	particle bug2 pulse
+}
+func void bug3(void)
+{
+	particle bug3 pulse
+}
+func void bug4(void)
+{
+	particle bug4 pulse
+}
+func void bug5(void)
+{
+	particle bug5 pulse
+}
+func void bug6(void)
+{
+	particle bug6 pulse
+}
+func void bug7(void)
+{
+	particle bug7 pulse
+}
+func void bug8(void)
+{
+	particle bug8 pulse
+}
+func void bug0(void)
+{
+	particle bug0 pulse
+}
+
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_train2.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_train2.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_train2.bsl	(revision 185)
@@ -0,0 +1,960 @@
+func void cheater(void)
+{
+	invincible=1
+	omnipotent=1
+	lock_keys keys_all
+	chr_teleport 0 7023
+}
+###################################
+# variables used in train2 scipts #
+###################################
+
+#used to see if PPK combo was successful
+var int combo_did;
+
+#used to determine when to activate or deactivate blocking drone, current script comments out the usefulness of this variable
+var int count_block;
+
+#determines if reload in ballistics or cell
+var int reload=0;
+
+#makes sure reloading cells doesn't play before player has even picked up the rifle
+var int droid_active;
+
+#sees if you already reloaded ballistics ammo before the system had a chance to prompt you to do so
+var int already_reloaded;
+
+#sees if you already reloaded cell ammo before system prompted you to do so.
+var int already_reloaded2;
+
+#counts number of reload prompts necessary, if you reloaded more than one time, you lose rating points
+var int had_to_reload;
+
+#determines when inside the target shooting function
+var int inside_target_function;
+
+#determines when inside ammo reload function
+var int inside_ammo_function = 0;
+
+#determines when not to display block droid message
+var int block_off;
+
+################################
+# fight training scripts below #
+################################
+
+#########################
+# punch and kick script #
+#########################
+func void train_fighting(string ai_name)
+{
+	how_far_along = 4;
+	music_stop
+	particle obj3 kill
+	particle obj4 kill	
+	trig_deactivate 1
+	trig_deactivate 2
+	trig_deactivate 3
+	message_remove c01_50_23
+	message_remove jump_encourage
+	message_remove jump_encourage2
+	sleep 60
+	sound_dialog_play_interrupt c00_01_64shinatama
+	message_remove
+	message begin_fight 240
+	sleep 240
+#	PUNCH-KICK
+	lock_keys keys_attack
+	message xpunch
+	chr_wait_animtype 0 punch
+	sleep 60
+	message_remove xpunch
+	sleep 60
+	message xkick
+	chr_wait_animtype 0 kick
+	sleep 60
+	message_remove xkick
+	sleep 60
+
+	if (how_far_along eq 4)
+	{
+		#throw two punches
+		sound_dialog_play_block c00_01_65shinatama
+		message punch
+		chr_wait_animtype 0 punch2
+		message_remove punch
+		sleep 60
+		message c01_50_27 180
+		sound_dialog_play_interrupt c00_01_66shinatama
+		sound_dialog_play_block pause
+		sleep 40
+	}
+
+	if (how_far_along eq 4)
+	{
+#		more combo
+		sound_dialog_play_block c00_01_67shinatama
+		sound_dialog_play_block pause
+		sleep 60
+	}
+
+	if (how_far_along eq 4)
+	{
+#		FIRST COMBO
+		message c01_50_29
+		fork combo_wait
+		chr_wait_animtype 0 ppk
+		combo_did = 1;
+		sleep 60
+		message_remove c01_50_29
+		message_remove c01_50_29b
+		sleep 60
+		sound_dialog_play_interrupt c00_01_07shinatama
+		message xppk 180
+		sleep 180
+	}
+	if(combo_did eq 1)
+	{
+		if (how_far_along eq 4)
+		{
+#		try linking for more combos
+		sound_dialog_play_block c00_01_69shinatama
+		sound_dialog_play_block pause
+		sleep 240
+		}
+
+		if (how_far_along eq 4)
+		{
+#		you're now ready to train with a sparring partner
+		sound_dialog_play_block c00_01_70shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		}
+		if (how_far_along eq 4)
+		{
+#		proceed to the next room
+		sound_dialog_play_block c00_01_71shinatama
+		message xspar2
+		ai2_spawn dum_hit_flash
+		chr_lock_active dum_hit_flash
+		chr_death_lock dum_hit_flash 1
+		door_unlock 99
+		particle door2_locklight02 do start
+		}
+	}
+}
+
+func void combo_wait(string ai_name)
+{
+	sleep 600
+	if (combo_did eq 0)
+	{
+		dprint rating
+		rating =  rating + 1
+		rating
+		message_remove c01_50_29
+		sound_dialog_play_block c00_01_68shinatama
+		sleep 60
+	}
+	if (combo_did eq 0)
+	{
+		message c01_50_29b 240
+		sleep 240
+	}
+	if (combo_did eq 0)
+	{
+		message c01_50_29
+	}
+
+#	if(combo_did eq 0)
+#	{
+#		if (how_far_along eq 4)
+#		{
+#			try linking for more combos
+#			sound_dialog_play_block c00_01_69shinatama
+#			sound_dialog_play_block pause
+#			sleep 240
+#		}
+#
+#		if (how_far_along eq 4)
+#		{
+#			you're now ready to train with a sparring partner
+#			sound_dialog_play_block c00_01_70shinatama
+#			sound_dialog_play_block pause
+#			sleep 30
+#		}
+#		if (how_far_along eq 4)
+#		{
+#			proceed to the next room
+#			sound_dialog_play_block c00_01_71shinatama
+#			message xspar2
+#			ai2_spawn dum_hit_flash
+#			chr_lock_active dum_hit_flash
+#			chr_death_lock dum_hit_flash 1
+#			door_unlock 99
+#			particle door2_locklight02 do start
+#		}
+#	}
+}
+
+##################################
+# train player about hit flashes #
+##################################
+func void train_hit_flash(string ai_name)
+{
+	particle steam stop
+	music_train2
+	how_far_along = 6;
+	message_remove xspar2
+	sleep 60
+#	try hitting this dummy
+	sound_dialog_play_block c00_01_77shinatama
+	message start_hit
+	ai2_makeignoreplayer dum_hit_flash 1
+}
+
+func void hurt_dummy1(string ai_name)
+{
+	message_remove start_hit
+	sleep 60
+	door_lock 99
+	particle door2_locklight02 do stop
+#	dynamic hit flashes
+	message c01_50_35 300
+	sleep 240
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+	ai2_setjobstate dum_hit_flash
+	sleep 60
+#	more dynamic hit flashes blue
+	message blueflash 300
+	sleep 240
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+	ai2_setjobstate dum_hit_flash
+	sleep 60
+	message c01_50_37 300
+	sleep 240
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+	ai2_setjobstate dum_hit_flash
+	sleep 60
+#	more dynamic hit flashes
+	message c01_50_38 300
+	sleep 240
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+	ai2_setjobstate dum_hit_flash
+#	move on to the next room to learn how to perform the most dangerous attacks.
+	sleep 60
+	sound_dialog_play_block c00_01_78shinatama
+	message goto_throw
+	sleep 60
+	door_unlock 100
+	particle door3_locklight02 do start
+	ai2_spawn dum_train_throw
+	chr_lock_active dum_train_throw
+	chr_death_lock dum_train_throw 1
+	ai2_makeignoreplayer dum_train_throw 1
+}
+
+###################################
+# train player to throw opponents #
+###################################
+func void lockthrow(void)
+{
+	door_lock 100
+	particle door3_locklight02 do stop
+}
+
+func void train_throw(string ai_name)
+{
+	how_far_along = 7;
+	message_remove goto_throw
+	sleep 60
+	if (how_far_along eq 7)
+	{
+#		FIRST THROW
+		sound_dialog_play_block c00_01_79shinatama
+		message c01_50_41
+		chr_wait_animtype 0 throw_forward_punch throw_forward_kick run_throw_forward_punch run_throw_forward_kick 
+		message_remove c01_50_41
+		sleep 60
+	}
+
+	if (how_far_along eq 7)
+	{
+#		more throws
+		sound_dialog_play_block c00_01_80shinatama
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		message xthrow1 360
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		message xthrow2 360
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+		sleep 180
+		ai2_dopath dum_train_throw patrol_train_throw2
+		ai2_setjobstate dum_train_throw
+	}
+
+	if (how_far_along eq 7)
+	{
+#		Proceed to the next room and try blocking the training dummy'sleep 240 attacks.
+		message goto_block
+		sleep 60
+		door_unlock 101
+		particle door4_locklight02 do start
+		particle door4b_locklight02 do start
+		ai2_spawn dum_train_block
+		ai2_makeignoreplayer dum_train_block 1
+		chr_invincible char_0 1
+	}
+
+}
+
+###############################
+# train player to block blows #
+###############################
+func void train_block(string ai_name)
+{
+#introduce blocking
+	how_far_along = 5;
+	message_remove goto_block
+#	dummy attack
+	sound_dialog_play_block c00_01_72shinatama
+	sound_dialog_play_block pause
+	sound_dialog_play_block c00_01_73shinatama
+	if(count_block eq 0)
+	{
+		message c01_50_33
+	}
+}
+
+func void train_block2(string ai_name)
+{	
+	ai2_makeignoreplayer dum_train_block 0
+	ai2_dopath dum_train_block patrol_56b
+	ai2_setjobstate dum_train_block
+	message_remove c01_50_33
+	if(count_block eq 0)
+	{
+		count_block = 1
+		door_lock 101
+		door_close 101
+		particle door4_locklight02 do stop
+		chr_delete dum_train_throw
+		chr_delete dum_hit_flash
+		chr_delete demo1
+		chr_delete demo2
+		chr_delete demo3
+		if (how_far_along eq 5)
+		{
+#			more blocking
+			sleep 60
+			message c01_50_32 300
+			sound_dialog_play_block c00_01_74shinatama
+			sound_dialog_play_pause 
+			sleep 30
+			sound_dialog_play_block c00_01_75shinatama
+			message xblocking2 300
+			sound_dialog_play_pause 
+			sleep 30
+			sound_dialog_play_block c00_01_76shinatama
+		}
+		sleep 120
+	#	message_remove xdronedeactive
+		ai2_makeignoreplayer dum_train_block 1
+		ai2_dopath dum_train_block patrol_56b
+		ai2_setjobstate dum_train_block 
+		sound_dialog_play_block c00_01_83shinatama
+		sound_dialog_play_block pause
+		door_unlock 102
+		particle door5_locklight02 do start
+		message goto_shoot
+		chr_inv_reset 0
+		music_stop
+		sleep 60
+		dprint spawn_shoot
+		ai2_spawn dum_train_shoot
+		ai2_spawn dum_train_shoot2
+		ai2_passive dum_train_shoot 1
+		ai2_passive dum_train_shoot2 1
+		chr_invincible dum_train_shoot 1
+		chr_invincible dum_train_shoot2 1
+		chr_invincible char_0 0
+		console_deactivate 12
+		trigvolume_enable tv75 0
+		trigvolume_enable tv74 0
+	}
+}
+
+func void disable_tv46(void)
+{
+	message_remove c01_50_33
+	trigvolume_enable trigger_volume_46 0
+}
+
+##################################
+# put drones back on their spots #
+##################################
+func void flash_path(string ai_name)
+{
+	sleep 90
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+}
+
+func void throw_path(string ai_name)
+{
+	sleep 90
+	ai2_dopath dum_train_throw patrol_train_throw2
+}
+
+func void block_path(string ai_name)
+{
+	if(block_off eq 0)
+	{
+		block_off = 1;
+		message xdronedeactive 180
+	}
+	ai2_makeignoreplayer dum_train_block 1
+	ai2_dopath dum_train_block patrol_56
+	sleep 180
+	block_off = 0;
+}
+
+func void block_path2(string ai_name)
+{
+
+	ai2_makeignoreplayer dum_train_block 1
+	ai2_dopath dum_train_block patrol_56
+}
+######################################################
+# regenerate first two training dummies as necessary #
+######################################################
+
+func void regen1(string ai_name)
+{
+	dprint regen1
+	message_remove blueflash
+	message_remove c01_50_37
+	message_remove c01_50_38
+	sleep 60
+	message xregen1 180
+	sleep 180
+	chr_set_health dum_hit_flash 50
+	ai2_dopath dum_hit_flash patrol_dum_hit_flash
+	ai2_setjobstate dum_hit_flash
+}
+
+func void regen2(string ai_name)
+{
+	dprint regen2
+	sleep 60
+	message xregen1 180
+	sleep 180
+	chr_set_health dum_train_throw 50
+	ai2_dopath dum_hit_flash patrol_train_throw2
+	ai2_setjobstate dum_train_throw
+}
+
+#########################
+# train player to shoot #
+#########################
+func void train_shoot(string ai_name)
+{
+#	message_remove xdroneactive
+	message_remove xdronedeactive
+	particle g_tap1 create
+	sleep 7
+	weapon_spawn w1_tap 7042
+	wp_disable_fade=1
+	how_far_along = 8;
+	message_remove goto_shoot
+	sleep 60
+	ai2_dopath dum_train_throw patrol_train_throw
+	ai2_setjobstate dum_train_throw
+
+	if (how_far_along eq 8)
+	{
+	lock_keys keys_inventory
+	lock_keys keys_reload
+#	approach weapons
+	sound_dialog_play_block c00_01_84shinatama
+	sound_dialog_play_pause 
+	chr_wait_animtype char_0 Pickup_Pistol Pickup_Pistol_Mid 
+	door_lock 102
+	particle door5_locklight02 do stop
+	trigvolume_enable tv75 1
+	trigvolume_enable tv74 1
+	ui_show_element left 1
+	sleep 60
+	message c01_50_54
+#	hit targets
+	sound_dialog_play_block c00_01_85shinatama
+	chr_wait_animtype char_0 Autopistol_Recoil
+	sleep 120
+	message_remove c01_50_54
+	sleep 60
+	message c01_50_53 300
+	sleep 300
+	}
+}
+
+func void enter_ammo_function(void)
+{
+   dprint enter_ammo_function
+   inside_ammo_function = 1;
+}
+
+func void exit_ammo_function(void)
+{
+   dprint exit_ammo_function
+   inside_ammo_function = 0;
+}
+
+func void need_ammo(string ai_name)
+{
+   trigvolume_enable tv74 0
+
+   sleep 67
+   var int empty_weapon = chr_has_empty_weapon(char_0);
+
+   dprint trying_ammo_function
+
+   if (inside_ammo_function eq 0)
+   {
+      dprint doing_ammo_function
+      enter_ammo_function();
+
+	   if(empty_weapon eq 1)
+	   {
+		sleep 15
+		if(reload eq 0)
+		{
+			message_remove xkeepshoot
+			already_reloaded = 0;
+			sound_dialog_play_block c00_01_87shinatama
+			message c01_50_61
+		#	generate powerup
+			particle g_tap1 create
+			sleep 7
+			powerup_spawn ammo 7042
+			particle g_tap2 create
+			sleep 7
+			powerup_spawn ammo 7043
+			chr_wait_animtype char_0 Pickup_Object_Mid Pickup_Object
+			fork remove_reload_message
+		#	sleep 60
+			message_remove c01_50_61
+			sleep 90
+			if(already_reloaded eq 0)
+			{
+				message xreload
+				chr_wait_animtype char_0 reload_pistol
+				increase_rating()
+				message_remove xreload
+				sleep 90
+			}
+			message xkeepshoot
+		}
+		if(reload eq 1)
+		{
+			if(droid_active eq 1)
+			{
+				message c01_50_62
+			#	generate powerup
+				particle g_phr1 create
+				sleep 7
+				powerup_spawn cell 7044
+				particle g_phr2 create
+				sleep 7
+				powerup_spawn cell 7045
+				chr_wait_animtype char_0 Pickup_Object_Mid Pickup_Object
+			#	sleep 60
+				message_remove c01_50_62
+				fork remove_reload_message2
+				if(already_reloaded2 eq 0)
+				{
+					sleep 90
+					message xreload
+					chr_wait_animtype char_0 reload_rifle
+					dprint rating
+					increase_rating()
+					message_remove xreload
+				}
+			}
+		}
+	   }
+
+	   exit_ammo_function();
+	}
+
+   sleep 60
+   trigvolume_enable tv74 1
+}
+
+func void increase_rating(void)
+{
+	dprint rating
+	if(had_to_reload ne 0)
+	{
+
+		rating = rating + 1;
+	}
+	had_to_reload = had_to_reload + 1;
+}
+
+func void remove_reload_message(void)
+{
+	chr_wait_animtype char_0 reload_pistol
+	already_reloaded = 1;
+}
+
+func void remove_reload_message2(void)
+{
+	chr_wait_animtype char_0 reload_rifle
+	already_reloaded2 = 1;
+}
+
+func void enter_target_function(void)
+{
+   dprint enter_target_function
+   inside_target_function = 1;
+}
+
+func void exit_target_function(void)
+{
+   dprint exit_target_function
+   inside_target_function = 0;
+}
+
+func void targets_are_gone(void)
+{
+	reload=1;
+	message_remove xkeepshoot
+	trigvolume_enable tv75 0
+	sleep 7
+	particle g_phr1 create
+	sleep7
+	weapon_spawn w3_phr 7045
+	sound_dialog_play_block c00_01_86shinatama
+	sound_dialog_play_block pause
+	message_remove
+	#plasma, switch weapons
+	sound_dialog_play_block c00_01_88shinatama
+	chr_wait_animtype char_0 Pickup_Rifle Pickup_Rifle_Mid 
+	droid_active = 1;
+	sleep 30
+	#activate drone, hit it
+	chr_invincible dum_train_shoot 0		
+	ai2_passive dum_train_shoot 0
+	sound_dialog_play_block c00_01_89shinatama
+	ai2_dopath dum_train_shoot patrol_train_shoot
+	ai2_setjobstate dum_train_shoot
+}
+
+func void targets_are_not_gone(void)
+{
+	# CB: turn off the trigger volume and sleep for a second
+	# so as not to cause hideous performance loss
+	trigvolume_enable tv75 0
+	sleep 60
+	trigvolume_enable tv75 1
+}
+
+func void targets_gone(string ai_name)
+{
+	if(inside_target_function eq 0)
+	{	
+		enter_target_function()
+
+		var int num_broken = env_broken(3001, 3018);
+
+		if (num_broken eq 18)
+		{
+			targets_are_gone();
+		}
+	
+		if (num_broken < 18)
+		{
+			targets_are_not_gone();
+		}
+
+		exit_target_function
+	}
+}
+
+func void droid1_gone(string ai_name)
+{
+	if (how_far_along eq 8)
+	{
+		chr_invincible dum_train_shoot2 0
+#		now side to side
+		sound_dialog_play_block c00_01_90shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		ai2_passive dum_train_shoot2 0
+		ai2_dopath dum_train_shoot2 patrol_train_shoot2
+		ai2_setjobstate dum_train_shoot2
+	}
+}
+
+func void droid2_gone(string ai_name)
+{
+	if (how_far_along eq 8)
+	{
+		reload = 2;
+		droid_active = 0;
+		message_remove
+		cinematic_start (SHINnametag, 180, 180, 15, 1, 20, false)
+#		great, done training
+		chr_changeteam char_0 Syndicate
+		music_train3
+		if(rating eq 0)
+		{
+			message poopy 
+
+		}
+		if(rating eq 1)
+		{
+			message poopy2 
+
+		}
+		if(rating eq 2)
+		{
+			message poopy3 
+
+		}
+		if(rating eq 3)
+		{
+			message poopy4 
+
+		}
+		if(rating eq 4)
+		{
+			message poopy5 
+
+		}
+		if(rating eq 5)
+		{
+			message poopy6 
+
+		}
+		if(rating > 5)
+		{
+			message poopy7 
+
+		}
+		sound_dialog_play_block c00_01_91shinatama
+		sound_dialog_play_block pause
+		sleep 40
+		sound_dialog_play_block c00_01_81shinatama
+		sound_dialog_play_block pause
+		message_remove
+		sleep 40
+		sound_dialog_play_block c00_01_82shinatama
+		sound_dialog_play_block pause
+		cinematic_stop (SHINnametag, 15, 20)
+ 		message xf1 400
+		sleep 400
+		message xlastreview
+		particle obj_lastreview create
+		console_activate 12
+		wp_disable_fade=0
+	}
+}
+
+func void lastreview(string ai_name)
+{
+	music_stop
+	particle obj_lastreview kill
+	message_remove
+	message_remove xlastreview
+	text_console level_1f
+	lock_keys keys_all
+	sleep 60
+	dprint swing
+	swing
+	ui_suppress_prompt=0
+} 
+
+######################################
+# training scripts used in warehouse #
+######################################
+# note: health function 'yhealth' is in the level_script file #
+
+func void train_fathealth(string ai_name)
+{
+	chr_wait_animtype char_0 Pickup_Object 
+	if(trigvolume_count (80) eq 1)
+	{
+		sleep 90
+		message xtabhypo 300
+		sound_dialog_play_block c00_01_93shinatama
+		sound_dialog_play_block pause
+		sleep 40
+		sound_dialog_play_block c00_01_94shinatama
+	}
+}
+
+func void intro_enemies(string ai_name)
+{
+	dprint intro_enemies
+	how_far_along = 11;
+
+	music_firstfight
+
+	if (how_far_along eq 11)
+	{
+		ai2_spawn Bay2_Thug_1
+		ai2_spawn Bay2_Thug_2
+	}
+
+	if (how_far_along eq 11)
+	{
+#		enemies
+		message c01_50_84 240
+		sleep 360
+	}
+}
+
+func void train_alarm(string ai_name)
+{
+	how_far_along = 13;
+
+	if (how_far_along eq 13)
+	{
+	ai2_spawn Bay4_Comguy_1
+#	alarm
+	sleep 180
+	message c01_50_88 240
+	sleep 240
+	}
+
+	if (how_far_along eq 13)
+	{
+#	alarm
+	message c01_50_89 240
+	sleep 240
+	}
+
+#	if (how_far_along eq 13)
+#	{
+#	alarm
+#	message c01_50_90 240
+#	sleep 240
+#	}
+}
+
+func void train_neutral(string ai_name)
+{
+	how_far_along = 14;
+	target_set(92,15.0)
+	if (how_far_along eq 14)
+	{
+#		neutrals
+		message c01_50_91 240
+		sleep 240
+		sound_dialog_play_block c00_01_97shinatama
+	}
+}
+
+func void train_timer(string ai_name)
+{
+	how_far_along = 15;
+
+	if(how_far_along eq 15)
+	{
+		target_set(96,15.0)
+		timer_start 180 OutroLose
+		sound_dialog_play_block c00_01_95shinatama
+		sleep 180
+		objective_set(4)
+		sound_dialog_play_block pause
+		music_timer
+	}
+
+	if (how_far_along eq 15)
+	{
+		sleep 60
+		message timer_text 300
+		sleep 360
+		message timer_text2 240
+	}
+}
+
+############################
+# warn about alarm console #
+############################
+func void alarm_warning(string ai_name)
+{ 
+	if(count_alarm eq 0)
+	{
+		message alarm_warn 300
+	}
+	count_alarm = 1;
+}
+
+func void alarm_warningb(string ai_name)
+{ 
+	count_alarm = 0;
+}
+
+#############################
+# consoles and compass hint #
+#############################
+func void console_jump(string ai_name)
+{
+	text_console level_1g
+	console_reset 18
+}
+
+func void console_escape(string ai_name)
+{
+	text_console level_1h
+	console_reset 17
+}
+
+func void console_attack(string ai_name)
+{
+	text_console level_1i
+	console_reset 16
+}
+
+func void console_flash(string ai_name)
+{
+	text_console level_1j
+	console_reset 15
+}
+
+func void console_throw(string ai_name)
+{
+	text_console level_1k
+	console_reset 14
+}
+
+func void console_block(string ai_name)
+{
+	text_console level_1l
+	console_reset 13
+}
+
+func void t77(string ai_name)
+{
+	message xarrow 400
+}
Index: /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_training_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_training_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/EnvWarehouse/warehouse_training_scripts.bsl	(revision 185)
@@ -0,0 +1,1143 @@
+######################
+# training variables #
+######################
+
+#checks to see if player is in correct room for executing current script
+var int how_far_along=0;
+
+#number of dash track lights
+var int tcount=17;
+
+#sees if player sprinted
+var int didsprint;
+
+#sees if player jumped up to big crate with power cell
+var int powerupon;
+
+#checks to see if OK to run training (for restored game funkiness)
+var int can_train_movement = 1;
+
+#continues crouch training
+var int onto_crouch2;
+
+#used to determine if dashing on track for the first time
+var int A;
+
+#used to determine if finished run was slow
+var int B;
+
+#set if running was failed
+var int bad;
+
+#used to measure performance of player
+var int rating = 1;
+
+#karen dies!
+var int demo3dead;
+
+#determines which jump script continues after getting on biggest crate	
+var int got_ammo;
+
+#prevents forcefield and particle/gunk from starting multiple times and not after jumping to the next room
+var int forcefieldstopped;
+var int particlestarted;
+
+##################
+# basic movement #
+##################
+func void train_movement(string ai_name)
+{
+	if (can_train_movement eq 1)
+	{
+		train_movement_internal
+	}
+}
+
+func void train_movement_internal(void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate KonCamFoot01 0
+	particle forcefield1 do start
+	particle forcefield2 do start
+	particle steam start
+	ui_suppress_prompt=1
+	ui_show_element left 0
+	ui_show_element right 0
+	target_set (1,0.0)
+	env_show 2010 0
+	how_far_along = 1;
+	trigvolume_enable trigger_volume_54 0
+	lock_keys 
+	lock_keys keys_pause
+	trigvolume_enable tv_train_door 0
+	trigvolume_enable tv1 0
+	trigvolume_enable tv2 0	
+	trigvolume_enable tv3 0
+	trigvolume_enable tv4 0
+	trigvolume_enable tv5 0
+	trigvolume_enable tv6 0
+	trigvolume_enable tv7 0
+	trigvolume_enable tv8 0
+	trigvolume_enable tv9 0
+	trigvolume_enable tv10 0
+	trigvolume_enable tv11 0
+	trigvolume_enable tv12 0
+	trigvolume_enable tv13 0
+	trigvolume_enable tv14 0
+	trigvolume_enable tv15 0
+	trigvolume_enable tv16 0
+	trigvolume_enable tv17 0
+	trigvolume_enable tv_move4 0
+	trigvolume_enable tv_end 0
+	trigvolume_enable tv_review 0
+	console_deactivate 11
+
+	dprint train_movement
+
+	if(how_far_along eq 1)
+	{	
+		input 0
+		fade_in 120
+		sleep 90
+		fork Kon
+		####Shinatama telling Konoko that their neurolink is working perfectly, and telling her they're about to start training.
+		cinematic_start (SHINnametag, 180, 180, 15, 1, 20, false)
+		sleep f10
+		music_train1
+		sound_dialog_play c00_01_29shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		sound_dialog_play c00_01_30shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		sound_dialog_play c00_01_31shinatama
+		sound_dialog_play_block pause		
+		sleep 30
+		sound_dialog_play c00_01_32shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		message xwelcome 240
+		sound_dialog_play c00_01_35shinatama
+		sound_dialog_play_block pause
+		cinematic_stop (SHINnametag, 15, 20)
+		input 1
+	}
+
+	if(how_far_along eq 1)
+	{
+		#use mouse
+		message xmouse 
+		chr_wait_animtype 0 standing_turn_left standing_turn_right
+		message_remove xmouse
+		sleep 60
+		#move with wads
+		lock_keys keys_movement 
+		message xmove 
+		chr_wait_animtype 0 run
+		sleep 60
+		message_remove xmove
+		sleep 60
+	}
+	if(how_far_along eq 1)
+	{
+		#combine to move diag
+		message xcombo 300
+		sleep 300
+	}
+	if(how_far_along eq 1)
+	{
+		#control console
+		message xconsole1
+		sleep 30
+		particle obj_control create
+		trigvolume_enable trigger_volume_54 1
+		console_activate 10
+		lock_keys keys_action
+
+	}
+}
+
+func void move2(string ai_name)
+{
+	#trigger volume near control console
+	message_remove xmouse
+	message_remove xmove
+	message_remove xcombo
+	message_remove xconsole1
+	particle obj_control kill
+}
+
+func void lights(string ai_name)
+{
+		particle t17 create
+		sleep 60
+		particle t16 create
+		sleep 60
+		particle t15 create
+		sleep 60
+		particle t14 create
+		sleep 60
+		particle t13 create
+		sleep 60
+		particle t12 create
+		sleep 60
+		particle t11 create
+		sleep 60
+		particle t10 create
+		sleep 60
+		particle t9 create
+		sleep 60
+		particle t8 create
+		sleep 60
+		particle t7 create
+		sleep 60
+		particle t6 create
+		sleep 60
+		particle t5 create
+		sleep 60
+		particle t4 create
+		sleep 60
+		particle t3 create
+		sleep 60
+		particle t2 create
+		sleep 60
+		particle t1 create
+}
+
+func void move3(string ai_name)
+{
+	#used control console
+	message_remove xactivate1
+	particle obj_control kill
+	sleep 60
+
+	if(A eq 0)
+	#first run, so warm up
+	{
+		if(how_far_along eq 1)
+		{
+			#we'll use lights for dash
+			sound_dialog_play c00_01_36shinatama			
+			message xactivate2 300
+			fork lights
+			sleep 30
+			#better warmup
+			sound_dialog_play_block c00_01_33shinatama
+			sound_dialog_play_block pause	
+		}
+		
+		if(how_far_along eq 1)
+		{
+			#turn and dash
+			message xdash1
+			fork encourage_dash
+			chr_wait_animation 0 KONSPRrun_lt KONSPRrun_rt
+			didsprint = 1
+			message_remove xdash1
+			message_remove xencouragedash
+			sleep 60
+			sound_dialog_play c00_01_37shinatama
+		#	sound_dialog_play_block pause
+		}
+
+		if(how_far_along eq 1)
+		{
+			#beautiful sprint
+			message xdash2 240
+			sleep  240
+		}
+
+		if(how_far_along eq 1)
+		{
+			#dash is fast but loud
+			message xdash3
+			sound_dialog_play c00_01_38shinatama
+			sound_dialog_play_block pause
+		}
+	}
+
+	if(A eq 1)
+	{
+		tcount= 17;
+		B = 0;
+		bad = 0;
+		if(how_far_along eq 1)
+		{
+		#	sound_dialog_play_block c00_01_41shinatama
+			dprint kill_parts
+			particle t17 kill
+			particle t16 kill
+			particle t15 kill
+			particle t14 kill
+			particle t13 kill
+			particle t12 kill
+			particle t11 kill
+			particle t10 kill
+			particle t9 kill
+			particle t8 kill
+			particle t7 kill
+			particle t6 kill
+			particle t5 kill
+			particle t4 kill
+			particle t3 kill
+			particle t2 kill
+			particle t1 kill
+			dprint recreate_parts
+			particle t17 create
+			particle t16 create
+			particle t15 create
+			particle t14 create
+			particle t13 create
+			particle t12 create
+			particle t11 create
+			particle t10 create
+			particle t9 create
+			particle t8 create
+			particle t7 create
+			particle t6 create
+			particle t5 create
+			particle t4 create
+			particle t3 create
+			particle t2 create
+			particle t1 create
+			trigvolume_reset tv_move4 
+		}
+	}
+
+	if(how_far_along eq 1)
+	{
+		message_remove xdash3
+		sleep 60
+		#goto track and trigger script in volume
+		particle obj_start create
+		message xgotrack
+		trigvolume_enable tv_move4 1
+	}
+}
+
+func void encourage_dash(string ai_name)
+{
+	sleep 600
+	if(didsprint eq 0)
+	{
+		message_remove xdash1
+		sleep 60
+		#that'sleep 300 not a dash
+		sound_dialog_play c00_01_39shinatama
+		message xencouragedash
+		dprint rating
+		rating = rating + 1;
+	}
+}
+
+func void move4(string ai_name)
+{
+  if(A eq 0)
+  {
+	if(how_far_along eq 1)
+	{
+		message_remove xgotrack
+		trigvolume_enable tv1 1
+		trigvolume_enable tv2 1	
+		trigvolume_enable tv3 1
+		trigvolume_enable tv4 1
+		trigvolume_enable tv5 1
+		trigvolume_enable tv6 1
+		trigvolume_enable tv7 1
+		trigvolume_enable tv8 1
+		trigvolume_enable tv9 1
+		trigvolume_enable tv10 1
+		trigvolume_enable tv11 1
+		trigvolume_enable tv12 1
+		trigvolume_enable tv13 1
+		trigvolume_enable tv14 1
+		trigvolume_enable tv15 1
+		trigvolume_enable tv16 1
+		trigvolume_enable tv17 1
+		particle obj_start kill
+		sound_dialog_play c00_01_41shinatama
+		sleep 60
+		message xrun
+	}
+  }
+ 	if(A eq 1)
+  	{
+		if(how_far_along eq 1)
+		{
+			message_remove xgotrack
+			trigvolume_reset tv1 
+			trigvolume_reset tv2 
+			trigvolume_reset tv3 
+			trigvolume_reset tv4 
+			trigvolume_reset tv5 
+			trigvolume_reset tv6 
+			trigvolume_reset tv7 
+			trigvolume_reset tv8 
+			trigvolume_reset tv9 
+			trigvolume_reset tv10 
+			trigvolume_reset tv11 
+			trigvolume_reset tv12 
+			trigvolume_reset tv13 
+			trigvolume_reset tv14 
+			trigvolume_reset tv15 
+			trigvolume_reset tv16 
+			trigvolume_reset tv17 
+			particle obj_start kill
+			sound_dialog_play c00_01_41shinatama
+			sleep 60
+			message xrun
+		}
+	}
+
+	particle obj_end create
+	trigvolume_reset tv_end
+	trigvolume_enable tv_end 1
+	sleep 660
+	dprint timeup
+	B = 1;
+}
+
+func void track_end(string ai_name)
+{
+	if(B eq 1)
+	{
+		bad = 1;
+	}
+	if(how_far_along eq 1)
+	{
+		particle obj_end kill
+		particle obj_start kill
+		message_remove
+		message_remove xrun
+		sleep 60
+		###all targets hit
+		if(tcount eq 0)
+		{
+			#### all hit, RUN WAS fast	
+			if(bad eq 0)
+			{
+				sound_dialog_play_block c00_01_42shinatama
+				message xgreat 240
+				A = 0;
+				sleep 240
+			}
+			####all hit, RUN WAS slow
+			if(bad eq 1)
+			{
+				dprint rating
+				rating = rating + 1;
+				sound_dialog_play_block c00_01_11shinatama
+				message xgoodbutslow 240
+				A = 0;
+				sleep 240
+			}
+		}
+
+		####targets were MISSED
+		if(tcount ne 0)
+		{
+			dprint rating
+			rating = rating + 1;
+			###missed, fast
+			if(bad eq 0)
+			{
+				sound_dialog_play_block c00_01_43shinatama
+				message xpractice 360
+				A = 1;
+				sleep 360
+			}
+			####missed, slow
+			if(bad eq 1)
+			{
+				sound_dialog_play_block c00_01_43shinatama
+				message xslowtoo 360
+				A = 1;
+				sleep 360
+			}
+		}
+	}
+   #####THIS ENDS BASIC MOVEMENTS FOR SUCCESSFUL RUNNERS
+  if(A eq 0)
+  {
+	if(how_far_along eq 1)
+	{
+		sound_dialog_play_block c00_01_44shinatama
+		message xendbasic 300
+		sleep 300
+	}
+
+	if(how_far_along eq 1)
+	{
+		sound_dialog_play c00_01_45shinatama
+		message xreview 
+		console_activate 11
+		trigvolume_enable tv_review 1
+		particle obj_data create
+	}
+  }
+      ####IF THE RUN WASN'T GOOD, THEN RESET CONSOLE
+	if(A eq 1)
+	{
+		message xconsole1
+		sleep 30
+		particle obj_control create
+		console_reset 10
+		console_activate 10
+		trigvolume_reset trigger_volume_54 		
+		trigvolume_enable trigger_volume_54 1
+	}
+}
+
+func void review(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		message_remove xreview
+		particle obj_data kill
+	#	sleep 60
+	#	message xactivate3
+	}
+}
+
+func void review2(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+	#	message_remove xactivate3
+		text_console level_1c
+		console_reset 11
+		sleep 120
+		message xgodoor
+		trigvolume_enable tv_train_door 1
+		sound_dialog_play c00_01_48shinatama
+	#	sound_dialog_play_block pause
+		particle obj1 create
+	}
+}
+
+func void track17(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t17 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track16(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t16 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track15(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t15 kill
+		tcount = tcount - 1
+}
+}
+
+func void track14(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t14 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track13(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t13 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track12(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t12 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track11(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		tcount = tcount - 1
+		particle t11 kill
+	}
+}
+
+func void track10(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t10 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track9(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t9 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track8(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t8 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track7(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t7 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track6(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t6 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track5(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t5 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track4(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t4 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track3(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t3 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track2(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t2 kill
+		tcount = tcount - 1
+	}
+}
+
+func void track1(string ai_name)
+{
+	if(how_far_along eq 1)
+	{
+		particle t1 kill
+		tcount = tcount - 1
+	}
+}
+
+###################
+# use manual door #
+###################
+func void train_door(string ai_name)
+{
+	dprint train_door
+	message_remove xgodoor
+	sleep 60
+#	Good.  Now the door will unlock as the indicator light turns green.
+	particle obj1 kill
+	#light goes green
+	message unlock_door1 240
+	sleep 40
+	door_unlock 98 
+	particle door1_locklight02 do start
+	sleep 200
+
+	if (how_far_along eq 1)
+	{
+		message open_door1b 300
+		sleep 300
+	}
+
+	if (how_far_along eq 1)
+	{
+#		Please proceed to the next room
+		message proceed_door1 300	
+		sleep 300
+	}
+	if (how_far_along eq 1)
+	{
+#		message open_door1	
+	}
+}
+
+########
+# jump #
+########
+func void train_jump(string ai_name)
+{	
+	how_far_along = 2;
+	lock_keys keys_inventory
+	message_remove open_door1
+	message_remove open_door1b
+	message_remove proceed_door1
+	sleep 120
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+			sound_dialog_play c00_01_49shinatama
+			message jump_basic 240
+			sleep 240
+		}
+	}
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+			lock_keys keys_jump
+#			SPACE to jump
+			message c01_50_06 
+			chr_wait_animtype 0 jump
+			sleep 60
+			message_remove c01_50_06
+			sleep 60
+		}
+	}
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+			sound_dialog_play c00_01_08shinatama
+		}
+	}
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+#			directional jumping
+#			(press W and then SPACE when you want to jump)
+			message c01_50_07 		
+			chr_wait_animation 0 KONOKOjump_fw_start KONOKOjump_lt_start KONOKOjump_rt_start KONOKOjump_bk_start
+			sleep 60
+			message_remove c01_50_07
+			sleep 60
+		}
+
+	}
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+#			longer hit space, longer jump
+			message jump_basic2 300		
+			sleep 120
+		}
+	}
+########################encourage players to jump to next room unless they are on the large crate
+	if (how_far_along eq 2)
+	{
+		if(powerupon eq 0)
+		{
+			if(forcefieldstopped eq 0)
+			{
+				forcefieldstopped = 1;
+				particle forcefield1 do stop
+				sleep 180
+			}
+		}
+		if(powerupon eq 0)
+		{
+			if(particlestarted eq 0)
+			{
+				particlestarted = 1;
+		 		sound_dialog_play c00_01_50shinatama
+		  	  	message jump1
+				particle obj2 create
+				env_show 2011 0
+			}
+
+		}
+	}
+}
+
+func void powerup(string ai_name)
+{
+	powerupon = 1
+	fork pickup_powerup
+	dprint rating
+	rating =  rating - 1;
+	message_remove jump_basic
+	message_remove jump_basic2
+	message_remove good
+	message_remove jump1
+#	particle obj2 kill
+	sleep 80
+	if(how_far_along eq 2)
+	{
+		sound_dialog_play c00_01_46shinatama
+		sound_dialog_play_block pause
+		sleep 30
+		sound_dialog_play c00_01_47shinatama
+		sound_dialog_play_block pause
+	}
+#############################encourage players to jump to next room unless they are getting the ammo
+	if(got_ammo eq 0)
+	{
+		if(how_far_along eq 2)
+		{	
+		#	particle obj2 kill
+			message_remove jump1
+		 	if(forcefieldstopped eq 0)
+			{
+				forcefieldstopped =1;
+				particle forcefield1 do stop
+				sleep 180
+        	}
+		}
+	}
+	if(got_ammo eq 0)
+	{
+		if(how_far_along eq 2)
+		{
+			sound_dialog_play c00_01_50shinatama
+			if(particlestarted eq 0)
+ 			{
+				particlestarted = 1;
+				particle obj2 create
+				env_show 2011 0
+            }
+		}
+	}
+}
+
+func void pickup_powerup(void)
+{
+#	particle obj2 kill
+	message_remove jump1
+	chr_wait_animtype 0 Pickup_Object
+	got_ammo = 1;
+	sleep 80
+	message xpower1 300
+	sleep 120
+#########################encourage players to jump to next room unless the messages have already gone by
+	
+	forcefieldstopped = 1;
+	particle forcefield1 do stop
+	sleep 180
+	if(how_far_along eq 2)
+	{
+		sound_dialog_play c00_01_50shinatama
+		if(particlestarted eq 0)
+		{
+			particlestarted = 1;
+			particle obj2 create
+			env_show 2011 0
+		}
+	}
+	if(how_far_along eq 2)
+	{
+		message jump1
+	}	
+}
+
+################
+# escape moves #
+################
+func void train_crouch(string ai_name)
+{
+	how_far_along = 3;
+	trigvolume_enable trigger_volume_62 0
+	message_remove
+	door_lock 98
+	particle door1_locklight02 do stop
+	particle obj2 kill
+	particle obj1 kill
+	particle obj_start kill
+	particle obj_end kill
+	particle obj_control kill
+	dprint train_crouch
+	trigvolume_enable trigger_volume_71 0
+	sleep 60
+	message_remove
+	particle obj2 kill
+	sound_dialog_play_interrupt c00_01_01shinatama
+	ai2_spawn demo1
+	ai2_spawn demo2
+	ai2_spawn demo3
+	chr_nocollision demo1 1
+	chr_nocollision demo2 1 
+	chr_nocollision demo3 1
+		ai2_dopath demo1 pdemo1
+		ai2_dopath demo2 pdemo2
+   		ai2_dopath demo3 pdemo3
+		ai2_setjobstate demo1
+		ai2_setjobstate demo2
+		ai2_setjobstate demo3
+	#shift important
+	if(how_far_along eq 3)
+	{
+		lock_keys keys_crouch
+		message shift 240
+		sleep 240
+	}
+
+	if(how_far_along eq 3)
+	{
+#		SHIFT to crouch
+		message c01_50_08 
+		chr_wait_animtype 0 crouch
+		sleep 60
+		message_remove c01_50_08
+		sleep 120
+	}
+
+	if(how_far_along eq 3)
+	{
+		sleep 30
+#		sorry to interrupt you
+		sound_dialog_play c00_01_51shinatama
+		sleep 60
+		message xinterrupt 180
+		sleep 180
+		message xfite
+		sleep 30
+		particle fight create
+		trigvolume_enable trigger_volume_71 1
+	}
+}
+
+func void crouch2(string ai_name)
+{
+	if (how_far_along eq 3)
+	{
+		message xresume 180
+		sleep 180
+#		MOVEWHile crouching
+		message c01_50_09
+		chr_wait_animtype 0 crouch_run crouch_run_backwards crouch_run_sidestep_left crouch_run_sidestep_right
+		sleep 60
+		message_remove c01_50_09
+		sleep 60
+		message c01_50_10 240
+		sound_dialog_play_block c00_01_54shinatama
+		sleep 240
+
+	}
+
+	if (how_far_along eq 3)
+	{
+#		ESCAPE MOVES somersault
+		message c01_50_11
+		chr_wait_animation 0 KONCOMcrouch_fw KONCOMcrouch_rt KONCOMcrouch_lt KONOKOcrouch_fw KONOKOss_lt_slide KONOKOss_rt_slide KONOKOrun_bk_slide
+		sleep 60
+		message_remove c01_50_11
+		sleep 60
+	}
+
+	if (how_far_along eq 3)
+	{
+#		cartwheel
+		message back 
+		chr_wait_animtype 0 crouch_back
+		sleep 60
+		sound_dialog_play_block c00_01_07shinatama
+		message_remove back
+		sleep 60
+	}
+
+	if (how_far_along eq 3)
+	{
+#		SLIDE
+		sleep 30
+		sound_dialog_play_block c00_01_55shinatama
+		sound_dialog_play_block pause
+		message c01_50_16 
+		chr_wait_animstate 0 run_slide
+		sleep 60
+		message_remove c01_50_16
+		sleep 60
+	}
+
+	if (how_far_along eq 3)
+	{
+#		slide under traps
+#		try sliding beneath these moving laser sensors
+		sleep 60
+		sound_dialog_play_block c00_01_57shinatama
+	}
+	if (how_far_along eq 3)
+	{
+		message slide 360
+		sleep 30
+		trig_activate 3
+		sleep 40
+		trig_activate 2
+		sleep 40
+		trig_activate 1
+		sleep 300
+		sound_dialog_play_block c00_01_56shinatama
+		sleep 300
+	}
+
+	if (how_far_along eq 3)
+	{
+#		especially important when fighting multiple opponents
+#		message c01_50_13 240
+		sound_dialog_play_block c00_01_59shinatama
+		sound_dialog_play_block pause
+		sleep 60
+	}
+
+	if (how_far_along eq 3)
+	{
+#		JUMP-FLIP
+		message jump_flip 300
+		sleep 300
+	}
+	if (how_far_along eq 3)
+	{
+		message c01_50_19	
+		chr_wait_animtype 0 flip
+		message_remove c01_50_19
+		sleep 60
+		sound_dialog_play_block c00_01_03shinatama
+		sound_dialog_play_block pause
+	}
+
+	if (how_far_along eq 3)
+	{
+#		hit opponent on ground
+		sound_dialog_play_block c00_01_60shinatama
+		sound_dialog_play_block pause
+	}
+
+	if (how_far_along eq 3)
+	{
+#		more jump-flip
+#		starting at the target cursor on the floor, dash and jump-flip up to the next level.
+		particle forcefield2 do stop
+		sleep 180	
+		sound_dialog_play_block c00_01_61shinatama
+		message c01_50_23 	
+		particle obj3 create
+		env_show 2012 0
+		sleep 600
+	}
+
+	if (how_far_along eq 3)
+	{
+		sound_dialog_play_block c00_01_62shinatama
+		sound_dialog_play_block pause
+		message_remove c01_50_23
+		sleep 60
+		message jump_encourage 300
+		sleep 300
+	}
+	if (how_far_along eq 1)
+	{
+		message c01_50_23
+		sleep 900	
+	}
+
+	if (how_far_along eq 3)
+	{
+		message_remove c01_50_23 
+		sleep 60
+	}
+	if (how_far_along eq 3)
+	{
+		sound_dialog_play_block c00_01_63shinatama
+		particle obj3 kill
+		sleep 30
+	}
+	if (how_far_along eq 3)
+	{
+		particle obj4 create
+		message jump_encourage2 
+		dprint rating
+		rating = rating + 1;
+	}
+}
+
+################
+# karen fights #
+################
+
+func void t71(string ai_name)
+{
+	message_remove xfite
+	chr_nocollision demo1 0
+	chr_nocollision demo2 0 
+	chr_nocollision demo3 0
+	env_show 2010 1
+	chr_changeteam demo1 Syndicate
+	chr_changeteam demo2 Syndicate
+	particle fight kill
+}
+
+func void demo3dies(string ai_name)
+{
+	dprint oh_no
+	demo3dead = 1;
+	chr_changeteam demo1 Konoko
+	chr_changeteam demo2 Konoko
+	if(trigvolume_count (71) eq 1)
+	{
+		sleep 60
+		sound_dialog_play c00_01_52shinatama
+		sound_dialog_play_block pause
+	}
+	sleep 60
+	crouch2
+
+}
+
+func void demo_over(string ai_name)
+{
+	onto_crouch2 = onto_crouch2 + 1
+	if(onto_crouch2 eq 2)
+	{
+		ai2_dopath demo3 pdemo4
+		ai2_setjobstate demo3
+		sleep 90
+		sound_dialog_play c00_01_53shinatama
+		sound_dialog_play_block pause
+		if(demo3dead eq 0)
+		{
+			crouch2
+		}
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/compound/compound.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/compound/compound.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/compound/compound.bsl	(revision 185)
@@ -0,0 +1,1654 @@
+#	mountain compound
+#	scripts for level 19 by wu
+#	
+#	LEGEND
+#
+#	character naming convention: X_Yx
+#	where X = area letter (A=first area, B=second area, etc.)
+#	      Y = character type (N=ninja, T=tanker, S=striker, R=red, etc.)
+#		x = character number, usually same as character's initial patrol id
+#
+#	trigger volume scripts: t##, where ## refers to trigger volume id
+#	
+#	CONTENTS
+#	
+#	0.temporary debugging scripts
+#	1.variables defined
+#	1b.music scripts
+#	2.start and objectives scripts
+#	3.save game scripts
+#	4.cut scene scripts
+#	5.console scripts
+#	6.trigger volume scripts
+
+#	temporary debugging scripts 	#
+
+func void xxx(void)
+{
+	ParkLeft
+	t11
+	sleep 300
+	Truck
+}
+
+func void truck(string ai_name)
+{
+#	ai2_ignore_player=1
+	omnipotent=1
+	invincible=1
+	chr_teleport 0 4
+}
+
+func void computer(string ai_name)
+{
+#	ai2_ignore_player=1
+	dprint WALK_BACKWARDS_DOWN_THE_STAIRS_TO_OPEN_DOOR
+	omnipotent=1
+	invincible=1
+	chr_teleport 0 6
+}
+
+func void e(string ai_name)
+{
+	ai2_ignore_player=1
+	chr_teleport 0 100
+}
+
+func void butcher_test(void)
+{
+	invincible = 1
+	omnipotent = 1
+	extra_guys = 1
+	fork dish
+}
+
+func void test_setup(void)
+{
+	ai2_allpassive 1	
+
+	playback GrifElite01 GrifElite01Set
+	playback GrifElite02 GrifElite02Set
+	playback GrifElite03 GrifElite03Set
+	sleep f10
+	playback GrifElite02 GrifElite02Set
+	sleep f5
+	playback GrifElite03 GrifElite03Set
+	sleep f300
+
+
+	chr_envanim Griffin GrifGrifBox01
+	if (extra_guys eq 1) {
+		chr_envanim GrifOps01 GrifOps01Box01
+		chr_envanim GrifOps02 GrifOps02Box01
+	}
+	if (extra_guys eq 0) {
+		chr_envanim GrifOps02 GrifOps01Box01
+	}
+	chr_envanim GrifOps03 GrifOps03Box01
+	chr_animate Griffin COMGUYlev7_helistand 500
+	chr_animate GrifOps01 STRIKEcrouch_idle 400
+	chr_animate GrifOps02 STRIKEcrouch_idle 400
+	chr_animate GrifOps03 STRIKEcrouch_idle 400
+	sleep f90
+	sleep f200
+	chr_envanim Griffin GrifGrifBox02 norotation
+	if (extra_guys eq 1) {
+		chr_envanim GrifOps01 GrifOps01Box02 norotation
+		chr_envanim GrifOps02 GrifOps02Box02 norotation
+	}
+	if (extra_guys eq 0) {
+		chr_envanim GrifOps02 GrifOps01Box02 norotation
+	}
+	chr_envanim GrifOps03 GrifOps03Box02 norotation
+	chr_animate Griffin COMGUYlev7_Grif
+	if (extra_guys eq 1) {
+		chr_animate GrifOps01 STRIKElev7_Ops01
+		chr_animate GrifOps02 STRIKElev7_Ops02
+	}
+	if (extra_guys eq 0) {
+		chr_animate GrifOps02 STRIKElev7_Ops01
+	}
+	chr_animate GrifOps03 STRIKElev7_Ops03
+	sleep f240
+	playback Griffin GrifGrifRunAlt
+	if (extra_guys eq 1) {
+		playback GrifOps01 GrifOps01Run
+		playback GrifOps02 GrifOps02Run
+	}
+	if (extra_guys eq 0) {
+		playback GrifOps02 GrifOps01Run
+	}
+	sleep f10
+	playback_block GrifOps03 GrifOps03Run
+
+	sleep f300
+
+	playback GrifElite04 GrifWave2_Run1
+	playback GrifElite06 GrifWave2_Run3
+	playback_block GrifElite05 GrifWave2_Run1
+	sleep f300
+	
+
+	ai2_allpassive 0
+}
+
+func void test_boyz(void)
+{
+	playback Griffin GrifGrifRunAlt
+	if (extra_guys eq 1) {
+		playback GrifOps01 GrifOps01Run
+		playback GrifOps02 GrifOps02Run
+	}
+	if (extra_guys eq 0) {
+		playback GrifOps02 GrifOps01Run
+	}
+	sleep f10
+	playback_block GrifOps03 GrifOps03Run
+}
+
+###############################
+#	variables defined 	#
+###############################
+
+var int counter=2;
+var int my_save_point=0;
+var int console_count=0;
+var int stairs_open=0;
+var int comdies_ok=0;
+var int conused_ok=0;
+var int platform_ok=0;
+var int thru_door;
+var int count_swat_dies=3;
+var int console100used;
+var int console200used;
+var int console300used;
+var int console101used;
+var int count_attack3;
+var int muro_in_danger=0;
+var int round2_spawned=0;
+var int extra_guys=0;
+
+###############################
+#		music		      #
+###############################
+
+func void music_intro(void)
+{
+	sound_music_start mus_om01 .9
+#	stopped at set_objective_2
+}
+
+func void music_guns_timer(void)
+{
+	dprint OBSOLETE_music_guns_timer
+}
+
+func void music_truck(void)
+{
+	sound_music_start mus_asianb
+#	this music stopped at the end of the truck cutscene
+}
+
+func void stop_music_truck(void)
+{
+	sound_music_stop mus_asianb
+#	this music stopped at the end of the truck cutscene
+}
+
+func void music_guns(void)
+{
+	sound_music_start mus_main03_hd
+#	this music stopped in console301 or console300
+}
+
+func void music_guns_stop(void)
+{
+	sound_music_stop mus_main03_hd
+}
+
+func void music_battle(void)
+{
+	dprint MUSIC_BATTLE
+	sound_music_start mus_ot
+#	this music stopped in Outro
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_om01
+	sound_music_stop mus_asianb
+	sound_music_stop mus_main03
+	sound_music_stop mus_main03_hd
+}
+
+###############################
+#	start and objectives	#
+###############################
+func void paths(string ai_name)
+{
+	ai2_dopath GrifOps01 patrol_521
+	ai2_dopath GrifOps02 patrol_515
+	ai2_dopath GrifOps03 patrol_517
+	ai2_dopath GrifElite01 patrol_513
+	ai2_dopath GrifElite02 patrol_514
+	ai2_dopath GrifElite03 patrol_518
+}
+
+func void spawnA(void)
+{
+	ai2_spawn A_S1
+	ai2_spawn A_S2
+	ai2_spawn A_E3
+	ai2_spawn A_E5
+	ai2_spawn A_E5b
+}
+
+func void start(string ai_name)
+{
+	dprint start	
+
+	trigvolume_enable trigger_volume_21 0
+	trigvolume_enable trigger_volume_21_copy 0
+	trigvolume_enable trigger_volume_44 0
+	trigvolume_enable trigger_volume_45 0
+	trigvolume_enable attack_1tv 0
+	trigvolume_enable attack_2tv 0
+	trigvolume_enable attack_3tv 0
+	trigvolume_enable attack_3tv_copy 0
+	trigvolume_enable attack_4tv 0
+
+	particle door12_locklight01 do start
+
+	door_lock 35
+	door_lock 36
+	door_lock 37
+	door_lock 39
+	door_lock 40
+	door_lock 41
+
+	if (my_save_point eq 0)
+	{
+		objective_set(1)
+		spawnA()
+	}
+
+	if (my_save_point eq 1)
+	{
+		save_point=1;	
+		objective_set(1)
+		music_intro
+		ai2_dopath A_S1 patrol_01b
+		ai2_setjobstate A_S1
+		spawnA()
+		restore_game
+		chr_set_health 0 400
+	}
+
+	if (my_save_point eq 2)
+	{
+		save_point=2;	
+		dprint restore2_beforetruck
+		objective_set(2)
+		door_lock 12
+		particle door12_locklight01 do stop
+		ai2_spawn C_Sr18
+		ai2_dopath C_Sr18 patrol_18
+		ai2_spawn C_Sr17
+		ai2_spawn C_Sr19
+		ai2_spawn C_Sb75
+		ai2_spawn C_Sb76
+		trigvolume_enable trigger_volume_39 0
+		restore_game
+	}
+
+	if (my_save_point eq 3)
+	{
+		save_point=3;	
+		dprint restore3_aftertruck
+		objective_set(4)
+		target_set (501,30.0)
+		env_show 151 0
+		env_show 152 0
+		env_show 153 0
+		env_show 154 0
+		env_show 155 0
+		env_show 156 0
+		env_show 157 0
+		env_show 158 0
+		env_show 159 0
+		#Hides door, unhides broken door 
+		env_show 911 1
+		env_show 912 0
+		env_show 913 0
+		#Shows Gunk truck
+		env_show 251 1
+		env_show 252 1
+		env_show 253 1
+		env_show 254 1
+		env_show 255 1
+		env_show 256 1
+		env_show 257 1
+		env_show 258 1
+		env_show 259 1
+		env_show 911 1
+		env_show 912 0
+		env_show 913 0
+		env_show 914 1
+		env_show 915 1
+		env_show 916 1 
+
+		ai2_spawn D_R33
+		restore_game
+	}
+
+	if (my_save_point eq 4)
+	{
+		dprint restore4_finalbattle
+		#hides original dish 
+		env_show 301 0
+		env_show 302 0
+		env_show 303 0
+		env_show 304 0
+		env_show 305 0
+		env_show 306 0
+		env_show 307 0
+		env_show 308 0
+		env_show 309 0
+		#Shows in place dish 
+		env_show 401 1
+		env_show 402 1
+		env_show 403 1
+		env_show 404 1
+		env_show 405 1
+		env_show 406 1
+		env_show 407 1
+		env_show 408 1
+		env_show 409 1
+		music_battle
+		gs_farclipplane_set 3000
+		particle dishpulse do start
+		particle sturm_ambient start
+
+		# start the dish loop
+		sp_start_dish_loop
+	
+
+		if (did_kill_griffen() eq 1)
+		{
+			dprint restoreMutant
+			ai2_spawn MutantMuro
+			chr_boss_shield MutantMuro
+			restore_game
+			objective_set(7,silent)
+		}
+
+		if (did_kill_griffen() eq 0)
+		{
+			dprint restoreGriffin
+			ai2_boss_battle = 1
+			ai2_spawn Griffin
+			if (extra_guys eq 1) 
+			{
+				ai2_spawn GrifOps01
+			}
+			ai2_spawn GrifOps02
+			ai2_spawn GrifOps03			
+			ai2_spawn Muro
+			chr_boss_shield Muro
+			if (extra_guys eq 1) 
+			{
+				ai2_spawn GrifElite01
+			}
+			ai2_spawn GrifElite02
+			ai2_spawn GrifElite03
+			chr_set_health Muro 500
+			fork wait_to_help
+			restore_game
+			objective_set(6,silent)
+			paths			
+		}
+	}
+}
+
+func void deathfall(void)
+{
+	cm_detach
+	sleep f90
+	chr_set_health 0 0
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set (1,0.0)
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective_2
+	ai2_spawn B_Eb11
+	ai2_spawn B_Eb16
+	ai2_spawn B_Esb15
+	ai2_spawn B_N1
+	ai2_spawn B_Sr9
+	ai2_spawn C_Sr17
+	ai2_spawn C_Sr18
+	ai2_spawn C_Sb75
+	ai2_spawn C_Sb76
+#	ai2_spawn C_Sb77
+	ai2_spawn C_Sb78
+	objective_set(2)
+	target_set (558,30.0)
+	music_stop
+}
+
+func void set_objective_5(string ai_name)
+{
+	dprint set_objective_5
+	objective_set(5)
+#	target_set (258,30.0)
+}
+
+###################
+#	save game	#
+###################
+
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME1	
+
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME2	
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+
+	ai2_dopath C_Sr17 patrol_17
+	ai2_setjobstate C_Sr17
+	ai2_dopath C_Sr18 patrol_18
+	ai2_setjobstate C_Sr18
+
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME3	
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME4	
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+##########################
+#	cut scene scripts  #
+##########################
+
+var int run_truck_once = 0;
+
+func void runTruck(string ai_name)
+{
+	dprint runTruck_check
+	if (run_truck_once eq 0)
+	{
+		ai2_tripalarm 1 char_0
+	}
+	run_truck_once = 1;
+
+	if (chr_has_lsi(0))
+	{
+		dprint LSI_OK
+		if (trigvolume_count(29) eq 0)
+		{
+			trigvolume_enable trigger_volume_23 0
+			dprint truck_ok
+			chr_delete C_b74
+			chr_delete C_Eb73
+			Truck
+			sleep 30
+			ai2_spawn D_R33	
+			chr_delete C_Eb21
+			chr_delete C_Eb22
+			chr_delete C_Eb27			
+			chr_delete C_Eb29
+			chr_delete C_Eb30
+			chr_delete C_N23
+			chr_delete C_N24
+			chr_delete C_Sb25
+			chr_delete C_Sb26
+			chr_delete C_Sr17
+			chr_delete C_Sr18
+			chr_delete C_Tb20
+			chr_delete C_Tr28	
+			#chr_delete C_Sb77
+			chr_delete C_Sb78		
+			objective_set(4)
+			target_set (501,30.0)
+			particle obj1 kill
+			s3
+		}	
+	}
+}
+
+
+func void t10(string ai_name)
+{
+
+	dprint t10
+	if (trigvolume_count(25) eq 0)
+	{
+		if (stairs_open eq 1)
+		{
+			trigvolume_enable trigger_volume_10 0
+			trigvolume_enable trigger_volume_12 0
+			trigvolume_enable trigger_volume_26 0
+			dprint ParkLeft
+			ParkLeft	
+			particle obj1 create
+			objective_set(3)
+			target_set(511,30.0)
+#			ai2_makeignoreplayer ParkStriker 1
+		}
+	}
+}
+
+func void t12(string ai_name)
+{
+
+	dprint t12
+	if (trigvolume_count(26) eq 0)
+	{	
+		if (stairs_open eq 1)
+		{
+			trigvolume_enable trigger_volume_12 0
+			trigvolume_enable trigger_volume_10 0
+			trigvolume_enable trigger_volume_25 0
+			dprint ParkRight
+			ParkRight
+			particle obj1 create
+			objective_set(3)
+			target_set(511,30.0)
+#			ai2_makeignoreplayer ParkStriker 1
+		}
+	}
+}
+
+func void patrolscript0027(string ai_name)
+{
+	dprint patrolscript0027
+	ai2_dopath C_Sb25 patrol_52
+	ai2_setjobstate C_Sb25
+	ai2_dopath C_Sb26 patrol_53
+	ai2_setjobstate C_Sb26
+	ai2_dopath C_Eb27 patrol_27b
+	ai2_setjobstate C_Eb27
+}
+
+func void com_ok(string ai_name)
+{
+	dprint final_ok
+	comdies_ok = 1
+}
+
+func void fconsole_ok(string ai_name)
+{
+	dprint fconsole_ok
+	conused_ok = 1
+	objective_set(6)
+	text_console level_19d
+	target_set(502,30.0)
+	particle green create
+	sleep 400
+	particle green2 create
+	particle green3 create
+}
+
+func void t31(string ai_name)
+{
+	dprint t31
+	if (conused_ok eq 1)
+	{
+#		if (comdies_ok eq 1)
+#		{
+			dprint TO_FINAL_BATTLE
+			target_set(1,0.0)
+			music_stop
+			dish
+#		}
+	}
+}
+
+func void check_death1a(string ai_name)
+{
+	dprint death1a
+	Round2a
+}
+
+func void check_death1b(string ai_name)
+{
+	dprint death1a
+	Round2b
+}
+
+func void final_round(string ai_name)
+{
+	dprint check_ROUND_3
+	counter = counter - 1
+	if(counter eq 0)
+	{
+		Round3
+	}
+}
+
+func void check_death2(string ai_name)
+{
+	Outro
+}
+
+func void Round2a(string ai_name)
+{
+	dprint ROUND_2a
+	round2_spawned = round2_spawned + 1;
+
+	ai2_spawn GrifElite04
+
+	ai2_passive GrifElite04 1
+
+	playback_block GrifElite04 GrifWave2_Run1
+
+	ai2_passive GrifElite04 0
+
+	if (muro_in_danger eq 1) {
+		# force the backup to go after konoko only
+		ai2_attack GrifElite04 char_0
+	}
+	if (muro_in_danger eq 0) {
+		ai2_makeaware GrifElite04 char_0
+	}
+}
+
+func void Round2b(string ai_name)
+{
+	dprint ROUND_2b
+	round2_spawned = round2_spawned + 1;
+
+	ai2_spawn GrifElite05
+
+	ai2_passive GrifElite05 1
+
+	playback_block GrifElite05 GrifWave2_Run1
+
+	ai2_passive GrifElite05 0
+
+	if (muro_in_danger eq 1) {
+		# force the backup to go after konoko only
+		ai2_attack GrifElite05 char_0
+	}
+	if (muro_in_danger eq 0) {
+		ai2_makeaware GrifElite05 char_0
+	}
+}
+
+func void Round3(string ai_name)
+{
+	dprint ROUND_3
+	round2_spawned = round2_spawned + 1;
+
+	ai2_spawn GrifElite06
+
+	ai2_passive GrifElite06 1
+
+	playback_block GrifElite06 GrifWave2_Run3
+
+	ai2_passive GrifElite06 0
+
+
+	if (muro_in_danger eq 1) {
+		# force the backup to go after konoko only
+		ai2_attack GrifElite06 char_0
+	}
+	if (muro_in_danger eq 0) {
+		# go after other dudes
+		ai2_makeaware GrifElite06 char_0
+	}
+}
+
+func void wait_to_help(void)
+{
+	chr_wait_health Muro 200
+	
+	dprint MURO_IN_DANGER
+	ai2_boss_battle = 0;
+	muro_in_danger = 1;
+	ai2_attack GrifElite01 char_0
+	ai2_attack GrifElite02 char_0
+	ai2_attack GrifElite03 char_0
+	ai2_attack GrifElite04 char_0
+	ai2_attack GrifElite05 char_0
+	ai2_attack GrifElite06 char_0
+}
+
+###################
+#	console	#
+###################
+
+func void console_truckinfo(void)
+{
+	text_console level_19e
+	console_reset 6
+}
+
+func void unlock44(string ai_name)
+{
+#	begin_cutscene
+#	ai2_makeignoreplayer C_Sb77 1
+#	ai2_makeignoreplayer C_Sb78 1
+#	ai2_makeignoreplayer C_Eb22 1
+#	ai2_makeignoreplayer C_Eb21 1
+#	ai2_makeignoreplayer C_Tb20 1
+#	ai2_makeignoreplayer C_Sr19 1
+#	ai2_makeignoreplayer C_Sr18 1
+#	ai2_makeignoreplayer C_Sr17 1
+#	ai2_makeignoreplayer C_Sb76 1
+#	ai2_makeignoreplayer C_Sb75 1
+	input 0
+	chr_invincible char_0 1
+	letterbox 1
+	fade_out 0 0 0 30
+	ai2_spawn C_Er79
+	music_guns
+	cm_interpolate door44 0
+	fade_in 30
+	target_set(559,30.0)
+}
+
+func void patrolscript0079(string ai_name)
+{
+	particle d1_locklight01 do start
+#	sleep 60
+	door_unlock 44
+	sleep 60
+	sound_dialog_play c18_70_13elite
+	sound_dialog_play_block
+}
+
+func void patrolscript0080(string ai_name)
+{
+	sleep 90
+	cm_interpolate door44b 300
+	sleep 160
+	sound_dialog_play c18_74_05elite
+#	sound_dialog_play_block
+	sleep 80
+	fade_out 0 0 0 60
+	sleep 60
+	cm_reset
+	fade_in 30
+	input 1
+#	end_cutscene
+	letterbox 0
+	chr_invincible char_0 0
+#	ai2_makeignoreplayer C_Sb77 0
+#	ai2_makeignoreplayer C_Sb78 0
+#	ai2_makeignoreplayer C_Eb22 0
+#	ai2_makeignoreplayer C_Eb21 0
+#	ai2_makeignoreplayer C_Tb20 0
+#	ai2_makeignoreplayer C_Sr19 0
+#	ai2_makeignoreplayer C_Sr18 0
+#	ai2_makeignoreplayer C_Sr17 0
+#	ai2_makeignoreplayer C_Sb76 0
+#	ai2_makeignoreplayer C_Sb75 0
+#	ai2_dopath C_Sr17 patrol_81
+#	ai2_dopath C_Sb75 patrol_81
+#	ai2_dopath C_Sb76 patrol_81
+	ai2_tripalarm 1 char_0
+}
+
+func void run1(string ai_name)
+{
+	dprint run1
+	ai2_doalarm A_Sb7 1
+	ai2_dopath A_Sb7 patrol_00
+#	ai2_setjobstate A_Sb7
+}
+
+func void patrolscript0054(string ai_name)
+{
+	dprint doalarm
+	ai2_doalarm A_Sb7 1
+}
+
+func void do_alarm_sound(void)
+{
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+func void run1_alarm(string ai_name)
+{
+	dprint run1_alarm
+	fork do_alarm_sound
+	ai2_dopath A_E3 patrol_49	
+	ai2_dopath A_E4 patrol_49
+	ai2_dopath A_E5 patrol_49
+	ai2_dopath A_E6 patrol_49
+	ai2_spawn B_Sr9
+	sleep 7
+	ai2_dopath B_Sr9 patrol_10
+	ai2_spawn B_Eb11
+	sleep 60
+	ai2_dopath B_Eb11 patrol_10
+}
+
+func void driverhurt(string ai_name)
+{
+	dprint driverhurt
+	ai2_tripalarm 1 char_0
+}
+
+func void AreaF(string ai_name)
+{
+	console_count = console_count + 1
+	if(console_count eq 1)
+	{
+		text_console level_19a
+		sound_dialog_play_block c15_57_01konoko
+		sound_dialog_play_block pause
+		end_cutscene
+	}
+	if(console_count eq 2)
+	{
+		text_console level_19b
+		sound_dialog_play_block c15_57_02konoko
+	}
+	if (console_count eq 3)
+	{
+		dprint Area_F_now_open
+		trigvolume_enable attack_1tv 1
+		trigvolume_enable attack_2tv 1
+		trigvolume_enable attack_3tv 1
+		trigvolume_enable attack_3tv_copy 1
+		trigvolume_enable attack_4tv 1
+		text_console level_19c
+		set_objective_5
+		sound_dialog_play_block c15_57_03konoko
+		sound_dialog_play_block pause
+		sleep 60
+		music_guns
+	}
+}
+
+func void target100(void)
+{
+	console100used = 1;
+	if(console200used eq 0)
+	{
+		target_set(556,30.0)
+	}
+	if(console200used eq 1)
+	{
+		if(console300used eq 0)
+		{
+			target_set(557,30.0)
+		}
+	}
+	if(console200used eq 1)
+	{
+		if(console300used eq 1)
+		{
+			target_set(547,30.0)
+		}
+	}
+}
+	
+func void target200(void)
+{
+	console200used = 1;
+	if(console300used eq 0)
+	{
+		target_set(557,30.0)
+	}
+	if(console300used eq 1)
+	{
+		if(console100used eq 0)
+		{
+			target_set(555,30.0)
+		}
+	}
+	if(console300used eq 1)
+	{
+		if(console100used eq 1)
+		{
+			target_set(547,30.0)
+		}
+	}
+}
+
+func void target300(void)
+{
+	console300used = 1;
+	if(console200used eq 0)
+	{
+		target_set(556,30.0)
+	}
+	if(console200used eq 1)
+	{
+		if(console100used eq 0)
+		{
+			target_set(555,30.0)
+		}
+	}
+	if(console200used eq 1)
+	{
+		if(console100used eq 1)
+		{
+			target_set(547,30.0)
+		}
+	}
+}
+
+#func void console100(string ai_name)
+#{
+#	dprint console100
+#	console_deactivate 101
+#	AreaF
+#	target100
+#}
+
+func void console101(string ai_name)
+{
+	dprint console101
+	console101used = 1;
+	target100
+#	console_deactivate 100
+	AreaF
+}
+
+func void console200(string ai_name)
+{
+	dprint console200
+	target200
+	AreaF
+}
+
+func void console300(string ai_name)
+{
+	music_guns_stop
+	dprint console300
+	console_deactivate 301
+	target300
+	AreaF
+}
+
+func void console301(string ai_name)
+{
+	music_guns_stop
+	dprint console301
+	console_deactivate 300
+	target300
+	AreaF
+}
+
+func void purp2(void)
+{
+	input 0
+	fade_out 0 0 0 30
+	cm_interpolate unlock_door 0
+	fade_in 30
+	sleep 60
+	particle purple2_locklight01 do start
+	door_unlock 20
+	door_unlock 21
+	door_unlock 22
+	door_unlock 23
+	door_unlock 24
+	door_unlock 25
+	door_unlock 26
+	door_unlock 27
+	door_unlock 28
+	sleep 90
+	fade_out 0 0 0 30
+	cm_reset
+	fade_in 30
+	input 1
+}
+
+func void purple2_unlock(string ai_name)
+{
+	dprint purple2_unlock
+	purp2()
+	trigvolume_enable trigger_volume_21 1
+	trigvolume_enable trigger_volume_21_copy 1
+	trigvolume_enable trigger_volume_44 1
+	trigvolume_enable trigger_volume_45 1
+	console_deactivate 100
+}
+
+func void purple2_unlock_b(string ai_name)
+{
+	dprint purple2_unlockb
+	purp2()
+	if(console101used eq 0)
+	{
+		target_set(555,30.0)
+	}
+	console_deactivate 200
+}
+
+func void unlock_stairs(string ai_name)
+{
+	dprint unlock_stairs
+	music_stop
+	door_unlock 10
+	door_unlock 15
+	door_unlock 16
+	door_unlock 17
+	particle stair_locklight01 do start
+	ai2_spawn S_Tr41
+	console_deactivate 4
+#	console_deactivate 5
+	console_deactivate 3
+	stairs_open = 1
+	target_set(1,0.0)
+}
+
+
+func void unlock_stairs2(string ai_name)
+{
+	dprint unlock_stairs
+	music_stop
+	door_unlock 10
+	door_unlock 15
+	door_unlock 16
+	door_unlock 17
+	particle stair_locklight01 do start
+	console_deactivate 3
+#	console_deactivate 5
+	ai2_spawn S_Tr41
+	ai2_spawn C_b74
+	ai2_spawn C_Eb73
+	chr_teleport C_b74 224
+	ai2_dopath C_b74 patrol_80
+	chr_teleport C_Eb73 237
+	ai2_dopath C_Eb73 patrol_80
+	stairs_open = 1
+}
+
+
+#########################
+#  trigger volume stuff #
+#########################
+func void t8(string ai_name)
+{
+	dprint t8
+#	ai2_spawn C_Sb77
+	ai2_spawn C_Sb78
+	ai2_spawn C_Sr19
+	ai2_spawn C_Tb20
+	ai2_spawn C_Eb21
+	ai2_spawn C_Eb22
+	ai2_spawn C_N23
+	ai2_spawn C_N24
+	ai2_spawn C_Eb29
+	ai2_spawn C_Eb30
+}
+
+
+func void t9(string ai_name)
+{
+	dprint t9
+	ai2_spawn B_Eb16
+}
+
+func void t11(string ai_name)
+{
+	dprint t11
+	ai2_dopath C_Sb25 patrol_48
+	sleep 60
+	ai2_dopath C_Sb26 patrol_48
+	sleep 60
+	ai2_dopath C_Eb27 patrol_48
+
+}
+
+
+func void t13(string ai_name)
+{
+	dprint t13
+	ai2_spawn E_Er34
+	sleep 60
+	door_unlock 24
+#	door_unlock 23
+#	door_unlock 22
+	particle purple_locklight01 do start
+	ai2_dopath E_Er34 patrol_34
+	ai2_setjobstate E_Er34
+	ai2_spawn E_Eb35
+	target_set(501,30.0)	
+}
+
+func void t14(string ai_name)
+{
+	dprint t14
+	ai2_spawn E_N36
+	ai2_spawn E_Tr40
+	trigvolume_enable trigger_volume_15 0	
+}
+
+func void t15(string ai_name)
+{
+	dprint t15
+	ai2_spawn E_N35
+	ai2_spawn E_Nr46
+	trigvolume_enable trigger_volume_14 0	
+}
+
+func void t16(string ai_name)
+{
+	dprint t16
+	ai2_spawn E_Nr36
+	ai2_spawn E_Nb37
+	ai2_spawn E_Nr39
+	target_set (556,30.0)
+	door_unlock 22
+	particle purple3_locklight01 do start
+}
+
+func void t20(string ai_name)
+{
+	dprint t20
+	ai2_spawn E_N42
+	trigvolume_enable trigger_volume_18 0
+#	console_deactivate 100	
+	
+}
+
+func void t18(string ai_name)
+{
+	dprint t18
+	ai2_spawn E_N44
+	ai2_spawn E_R46
+	trigvolume_enable trigger_volume_20 0	
+#	console_deactivate 101	
+
+}
+
+func void t19(string ai_name)
+{
+	dprint t19
+	ai2_spawn E_Er45
+	ai2_spawn E_N41
+	trigvolume_enable trigger_volume_17 0
+#	console_deactivate 300	
+}
+
+func void t17(string ai_name)
+{
+	dprint t17
+	ai2_spawn E_N43
+	trigvolume_enable trigger_volume_19 0
+#	console_deactivate 301	
+	
+}
+
+func void t45(string ai_name)
+{
+	ai2_makeignoreplayer E_Eb35 1
+	ai2_makeignoreplayer E_Er34 1
+	ai2_makeignoreplayer E_Er45 1
+	ai2_makeignoreplayer E_Nb37 1
+	ai2_makeignoreplayer E_Nb38 1
+	ai2_makeignoreplayer E_Nr36 1
+	ai2_makeignoreplayer E_Nr39 1
+	ai2_makeignoreplayer E_Nr46 1
+	ai2_makeignoreplayer E_R46 1
+	ai2_makeignoreplayer E_Tr40 1
+	sleep 600
+	if(thru_door eq 0)
+	{
+		dprint DIDNOTGOTHRUDOOR
+	ai2_makeignoreplayer E_Eb35 0
+	ai2_makeignoreplayer E_Er34 0
+	ai2_makeignoreplayer E_Er45 0
+	ai2_makeignoreplayer E_Nb37 0
+	ai2_makeignoreplayer E_Nb38 0
+	ai2_makeignoreplayer E_Nr36 0
+	ai2_makeignoreplayer E_Nr39 0
+	ai2_makeignoreplayer E_Nr46 0
+	ai2_makeignoreplayer E_R46 0
+	ai2_makeignoreplayer E_Tr40 0
+	}
+}
+
+func void t21(string ai_name)
+{
+	dprint t21
+	input 0
+	letterbox 1
+	cm_interpolate red1 260
+	music_guns
+	sleep 90
+	particle mainchamber_locklight01 do start
+	door_unlock 18
+	door_unlock 19
+	ai2_spawn D_R31
+	ai2_spawn D_R32
+	ai2_spawn D_E83
+	door_open 18
+	door_open 19
+	sleep 180
+	door_lock 18
+	door_lock 19
+	particle mainchamber_locklight01 do stop
+	sleep 15
+	cm_interpolate red2 400
+	sleep 90
+	fade_out 0 0 0 30
+	sleep 30
+	cm_reset
+	fade_in 30
+	letterbox 0
+	input 1
+	trigvolume_enable trigger_volume_21_copy 0
+	trigvolume_enable trigger_volume_45 0
+	sleep 60
+	ai2_makeignoreplayer E_Eb35 0
+	ai2_makeignoreplayer E_Er34 0
+	ai2_makeignoreplayer E_Er45 0
+	ai2_makeignoreplayer E_Nb37 0
+	ai2_makeignoreplayer E_Nb38 0
+	ai2_makeignoreplayer E_Nr36 0
+	ai2_makeignoreplayer E_Nr39 0
+	ai2_makeignoreplayer E_Nr46 0
+	ai2_makeignoreplayer E_R46 0
+	ai2_makeignoreplayer E_Tr40 0
+	thru_door = 1;
+	sleep 300
+}
+
+func void t22(string ai_name)
+{
+	dprint t22
+	ai2_makeignoreplayer E_Eb35 1
+	ai2_makeignoreplayer E_Er34 1
+	ai2_makeignoreplayer E_Er45 1
+	ai2_makeignoreplayer E_Nb37 1
+	ai2_makeignoreplayer E_Nb38 1
+	ai2_makeignoreplayer E_Nr36 1
+	ai2_makeignoreplayer E_Nr39 1
+	ai2_makeignoreplayer E_Nr46 1
+	ai2_makeignoreplayer E_R46 1
+	ai2_makeignoreplayer E_Tr40 1
+	input 0
+	letterbox 1
+	cm_interpolate red3 260
+	music_guns
+	sleep 90
+	particle mainchamber_locklight01 do start
+	door_unlock 18
+	door_unlock 19
+	ai2_spawn D_R31
+	ai2_spawn D_R32
+	ai2_spawn D_E83
+	door_open 18
+	door_open 19
+	sleep 180
+	door_lock 18
+	door_lock 19
+	particle mainchamber_locklight01 do stop
+	sleep 15
+	cm_interpolate red4 400
+	sleep 90
+	fade_out 0 0 0 30
+	sleep 30
+	cm_reset
+	fade_in 30
+	letterbox 0
+	input 1
+	trigvolume_enable trigger_volume_21 0
+	trigvolume_enable trigger_volume_44 0
+	sleep 60
+	ai2_makeignoreplayer E_Eb35 0
+	ai2_makeignoreplayer E_Er34 0
+	ai2_makeignoreplayer E_Er45 0
+	ai2_makeignoreplayer E_Nb37 0
+	ai2_makeignoreplayer E_Nb38 0
+	ai2_makeignoreplayer E_Nr36 0
+	ai2_makeignoreplayer E_Nr39 0
+	ai2_makeignoreplayer E_Nr46 0
+	ai2_makeignoreplayer E_R46 0
+	ai2_makeignoreplayer E_Tr40 0
+	thru_door = 1;
+	sleep 300
+	music_stop
+}
+
+func void wake_E(string ai_name)
+{
+	sleep 60
+	ai2_makeignoreplayer E_Eb35 0
+	ai2_makeignoreplayer E_Er34 0
+	ai2_makeignoreplayer E_Er45 0
+	ai2_makeignoreplayer E_Nb37 0
+	ai2_makeignoreplayer E_Nb38 0
+	ai2_makeignoreplayer E_Nr36 0
+	ai2_makeignoreplayer E_Nr39 0
+	ai2_makeignoreplayer E_Nr46 0
+	ai2_makeignoreplayer E_R46 0
+	ai2_makeignoreplayer E_Tr40 0
+}
+
+func void sleep_E(string ai_name)
+{
+	ai2_makeignoreplayer E_Eb35 1
+	ai2_makeignoreplayer E_Er34 1
+	ai2_makeignoreplayer E_Er45 1
+	ai2_makeignoreplayer E_Nb37 1
+	ai2_makeignoreplayer E_Nb38 1
+	ai2_makeignoreplayer E_Nr36 1
+	ai2_makeignoreplayer E_Nr39 1
+	ai2_makeignoreplayer E_Nr46 1
+	ai2_makeignoreplayer E_R46 1
+	ai2_makeignoreplayer E_Tr40 1
+}
+
+func void fpath(string ai_name)
+{
+	ai2_dopath F_Eb43 patrol_43
+	ai2_setjobstate F_Eb43
+	sleep 30
+	ai2_dopath F_Eb44 patrol_44
+	ai2_setjobstate F_Eb44
+	sleep 30
+	ai2_dopath F_Eb47 patrol_47
+	ai2_setjobstate F_Eb47
+	music_stop
+}
+
+func void attack_1(string ai_name)
+{
+	dprint attack_1
+	sleep_E
+	chr_invincible char_0 1
+	letterbox 1
+	sleep 15
+	input 0
+	cm_interpolate attack1 90
+	ai2_spawn F_Eb43
+	ai2_spawn F_Eb44
+	ai2_spawn F_Eb47
+	door_unlock 43	
+#	sleep 60
+	sleep 90
+	particle F_locklight01 do start
+	fpath
+
+	cm_interpolate attack2 240
+	sleep 300
+	cm_interpolate attack1 600
+	chr_teleport 0 506
+	sleep 90
+	letterbox 0
+	cm_reset
+	chr_invincible char_0 0
+	trigvolume_enable attack_2tv 0
+	trigvolume_enable attack_3tv 0
+	trigvolume_enable attack_3tv_copy 0
+	trigvolume_enable attack_4tv 0
+	input 1
+	ai2_dopath F_Eb43 patrol_43b
+	ai2_setjobstate F_Eb43
+	ai2_dopath F_Eb44 patrol_44b
+	ai2_setjobstate F_Eb44
+	ai2_dopath F_Eb47 patrol_47b
+	ai2_setjobstate F_Eb47
+	wake_E
+}
+
+func void attack_2(string ai_name)
+{
+	dprint attack_2
+	sleep_E
+	chr_invincible char_0 1
+	letterbox 1
+	sleep 15
+	input 0
+	cm_interpolate attack2b 120
+	sleep 120
+	cm_interpolate attack2 400
+	sleep 100
+	particle F_locklight01 do start
+	sleep 80
+	ai2_spawn F_Eb43
+	ai2_spawn F_Eb44
+	ai2_spawn F_Eb47
+	door_unlock 43
+	fpath
+	sleep 290
+	cm_interpolate attack2b 500
+	chr_teleport 0 507
+	sleep 90
+	letterbox 0
+	cm_reset
+	chr_invincible char_0 0
+	trigvolume_enable attack_1tv 0
+	trigvolume_enable attack_3tv 0
+	trigvolume_enable attack_3tv_copy 0
+	trigvolume_enable attack_4tv 0
+	input 1
+	ai2_dopath F_Eb43 patrol_43b
+	ai2_setjobstate F_Eb43
+	ai2_dopath F_Eb44 patrol_44b
+	ai2_setjobstate F_Eb44
+	ai2_dopath F_Eb47 patrol_47b
+	ai2_setjobstate F_Eb47
+	wake_E
+}
+
+
+func void attack_3(string ai_name)
+{
+  if(count_attack3 eq 0)
+  {
+	count_attack3 = count_attack3 + 1;
+	dprint attack_3
+	chr_invincible char_0 1
+	sleep_E
+	letterbox 1
+	sleep 15
+	input 0
+	cm_interpolate attack3 90
+	ai2_spawn F_Eb43
+	ai2_spawn F_Eb44
+	ai2_spawn F_Eb47
+	door_unlock 43	
+	sleep 90
+	cm_interpolate attack4 210
+	particle F_locklight01 do start
+	fpath
+	sleep 150
+	cm_interpolate attack3 400
+	chr_teleport 0 508
+	sleep 90
+	letterbox 0
+	cm_reset
+	chr_invincible char_0 0
+	trigvolume_enable attack_2tv 0
+	trigvolume_enable attack_3tv_copy 0
+	trigvolume_enable attack_3tv 0
+	trigvolume_enable attack_1tv 0
+	trigvolume_enable attack_4tv 0
+	input 1
+	ai2_dopath F_Eb43 patrol_43b
+	ai2_setjobstate F_Eb43
+	ai2_dopath F_Eb44 patrol_44b
+	ai2_setjobstate F_Eb44
+	ai2_dopath F_Eb47 patrol_47b
+	ai2_setjobstate F_Eb47
+	wake_E
+  }
+}
+
+func void attack_4(string ai_name)
+{
+	dprint attack_4
+	chr_invincible char_0 1
+	sleep_E
+	letterbox 1
+	sleep 15
+	input 0
+	cm_interpolate attack3b 120
+	sleep 120
+	cm_interpolate attack4 300
+	sleep 240
+	particle F_locklight01 do start
+	ai2_spawn F_Eb43
+	ai2_spawn F_Eb44
+	ai2_spawn F_Eb47
+	door_unlock 43
+	fpath
+	sleep 160
+	cm_interpolate attack3b 500
+	chr_teleport 0 509
+	sleep 90
+	letterbox 0
+	cm_reset
+	chr_invincible char_0 0
+	trigvolume_enable attack_2tv 0
+	trigvolume_enable attack_3tv 0
+	trigvolume_enable attack_3tv_copy 0
+	trigvolume_enable attack_1tv 0
+	input 1
+	ai2_dopath F_Eb43 patrol_43b
+	ai2_setjobstate F_Eb43
+	ai2_dopath F_Eb44 patrol_44b
+	ai2_setjobstate F_Eb44
+	ai2_dopath F_Eb47 patrol_47b
+	ai2_setjobstate F_Eb47
+	wake_E
+}
+
+
+func void t27(string ai_name)
+{
+	dprint t27
+	ai2_dopath C_Sb25 patrol_54
+	ai2_dopath C_Sb26 patrol_54
+	ai2_dopath C_Eb27 patrol_54
+}
+
+func void t30(string ai_name)
+{
+	dprint t30
+	ai2_makeignoreplayer F_C62 0
+	ai2_spawn F_Er89
+}
+
+func void t33(string ai_name)
+{
+	dprint t33
+	ai2_spawn F_Er86
+	ai2_spawn F_Nr87
+	target_set(258,30.0)
+	sound_dialog_play c15_57_04konoko
+}
+func void t41(string ai_name)
+{
+	dprint t41
+	ai2_spawn F_Er59
+}
+
+func void t42(string ai_name)
+{
+	dprint t42
+	ai2_spawn F_Nr60
+}
+
+func void t43(string ai_name)
+{
+	dprint t43
+	ai2_spawn F_R61
+	ai2_spawn F_Er88
+	ai2_spawn F_C62
+	ai2_makeignoreplayer F_C62 1
+}
+
+func void comalarm(string ai_name)
+{
+	dprint comalarm
+	ai2_tripalarm 2 char_0
+}
+
+func void t38(string ai_name)
+{
+	dprint t38
+	ai2_spawn A_E4
+	ai2_spawn A_Sb63
+	ai2_spawn A_E6
+	ai2_spawn A_Sb7
+	ai2_spawn new_2
+}
+
+func void t40(string ai_name)
+{
+	dprint t40
+	input 0
+	letterbox 1
+	cm_interpolate red1 240
+	sleep 60
+	particle purple2_locklight01 do start
+	sleep 90
+	fade_out 0 0 0 30
+	cm_reset
+	fade_in 30
+	input 1
+}
+
+func void swat_dies(void)
+{
+	count_swat_dies = count_swat_dies - 1;
+	if(count_swat_dies eq 0)
+	{
+		ai2_attack GrifElite01 char_0
+		ai2_attack GrifElite02 char_0
+		ai2_attack GrifElite03 char_0
+		ai2_attack GrifElite04 char_0
+		ai2_attack GrifElite05 char_0
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/compound/compound_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/compound/compound_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/compound/compound_cutscene.bsl	(revision 185)
@@ -0,0 +1,677 @@
+#
+# Compound_cutscene.bsl
+
+func void intro(void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam00 0
+	sleep f14
+	begin_cutscene	
+	ai2_allpassive 0
+	gs_farclipplane_set 10000
+	letterbox 1
+	cm_interpolate IntroCam00 0
+	sleep f60
+	chr_super 0 1
+	fade_in 120
+	music_intro
+	sleep f240
+	#Konoko drops from sky
+	cm_interpolate IntroCam01 300
+	sleep f300
+	cm_anim both IntroCam01
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev7_Intro
+	sleep f90
+	cutscene_sync mark
+	sound_ambient_start c05_05_15kon_land
+	sleep f60
+	particle IntroImpact do explode
+	#close up of Konoko
+	cm_anim_block both IntroCam02
+	ai2_allpassive 1
+	#Vista shot
+	cm_wait
+	playback 0 IntroKonokoSet
+	cm_reset
+	end_cutscene
+	chr_set_health 0 400
+	chr_super 0 0
+	s1
+}
+
+
+func void ParkLeft(void)
+{
+	begin_cutscene
+	chr_teleport C_b74 541
+	ai2_dopath C_b74 patrol_74
+	chr_teleport C_Eb73 528
+	ai2_dopath C_Eb73 patrol_73
+	trigvolume_corpse 29
+	sleep f30
+	obj_create 51 59
+	env_anim 51 59
+	sleep f2
+	cm_interpolate ParkLeftCam01 0
+	#Show Truck objects
+	#see van entering from tunnel
+	sleep f8
+	cutscene_sync mark
+	sound_ambient_start c05_26_17_trucka
+	sleep f270
+	#Striker exits van
+	ai2_spawn ParkStriker
+	chr_lock_active ParkStriker
+	chr_neutral ParkStriker 1
+	cm_anim both ParkCam01
+	env_setanim 51 truckbackstop
+	env_setanim 52 truckcabstop
+	env_setanim 53 truckdoorstop
+	env_setanim 54 truckdoor2stop
+	env_setanim 55 truckwheel03stop
+	env_setanim 56 truckwheel04stop
+	env_setanim 57 truckwheel05stop
+	env_setanim 58 truckwheel06stop
+	env_setanim 59 truckwheel07stop
+	chr_envanim ParkStriker ParkStrikeBox01 norotation
+	sleep f40
+	cutscene_sync mark
+	sound_ambient_start c05_31_21_brake_doorsa
+	sleep f60
+	chr_animate ParkStriker STRIKElev7_Park
+	playback 0 ParkLeftKonoko
+	ai2_spawn C_Sb25
+	ai2_spawn C_Sb26
+	ai2_spawn C_Eb27
+	playback C_Sb25 truckers
+	sleep 40
+	playback C_Sb26 truckers
+	sleep 30
+	playback C_Eb27 truckers
+	sleep 60
+	#hide object van and unhide gunk van
+	obj_kill 51 59
+	env_show 151 1
+	env_show 152 1
+	env_show 153 1
+	env_show 154 1
+	env_show 155 1
+	env_show 156 1
+	env_show 157 1
+	env_show 158 1
+	env_show 159 1
+	#cm_wait
+	playback 0 ParkLeftKonoko01
+	#sleep f240
+	cm_reset
+	#chr_delete ParkStriker
+	#konoko talks
+	sleep f120
+	sound_dialog_play c15_57_05konoko
+	cinematic_start (KONlistening, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	cinematic_stop (KONlistening, 19, 20)
+	end_cutscene
+	music_truck
+}
+
+func void ParkRight(void)
+{
+	begin_cutscene
+	chr_teleport C_b74 541
+	ai2_dopath C_b74 patrol_74
+	chr_teleport C_Eb73 528
+	ai2_dopath C_Eb73 patrol_73
+ 	trigvolume_corpse 29
+	sleep f30
+	obj_create 51 59
+	env_anim 51 59
+	sleep f2
+	cm_interpolate ParkRightCam01 0
+	#Show Truck objects
+	#see van entering from tunnel
+	sleep f8
+	cutscene_sync mark
+	sound_ambient_start c05_26_17_trucka
+	sleep f270
+	#Striker exits van
+	ai2_spawn ParkStriker
+	chr_lock_active ParkStriker
+	chr_neutral ParkStriker 1
+	cm_anim both ParkCam01
+	env_setanim 51 truckbackstop
+	env_setanim 52 truckcabstop
+	env_setanim 53 truckdoorstop
+	env_setanim 54 truckdoor2stop
+	env_setanim 55 truckwheel03stop
+	env_setanim 56 truckwheel04stop
+	env_setanim 57 truckwheel05stop
+	env_setanim 58 truckwheel06stop
+	env_setanim 59 truckwheel07stop
+	chr_envanim ParkStriker ParkStrikeBox01 norotation
+	sleep f40
+	cutscene_sync mark
+	sound_ambient_start c05_31_21_brake_doorsa
+	sleep f60
+	chr_animate ParkStriker STRIKElev7_Park
+	playback 0 ParkRightKonoko
+	ai2_spawn C_Sb25
+	ai2_spawn C_Sb26
+	ai2_spawn C_Eb27
+	playback C_Sb25 truckers
+	sleep 40
+	playback C_Sb26 truckers
+	sleep f30
+	playback C_Eb27 truckers
+	sleep 60
+	#hide object van and unhide gunk van
+	obj_kill 51 59
+	env_show 151 1
+	env_show 152 1
+	env_show 153 1
+	env_show 154 1
+	env_show 155 1
+	env_show 156 1
+	env_show 157 1
+	env_show 158 1
+	env_show 159 1
+	#cm_wait
+	playback 0 ParkRightKonoko01
+	#sleep f240
+	cm_reset
+	#chr_delete ParkStriker
+	#kononko talks
+	sleep f120
+	sound_dialog_play c15_57_05konoko
+	cinematic_start (KONlistening, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	cinematic_stop (KONlistening, 19, 20)
+	end_cutscene
+	music_truck
+}
+
+
+func void Truck(void)
+{
+	trigvolume_corpse 29
+	begin_cutscene
+
+	#hide gunk and show object
+	obj_create 51 59
+	env_show 151 0
+	env_show 152 0
+	env_show 153 0
+	env_show 154 0
+	env_show 155 0
+	env_show 156 0
+	env_show 157 0
+	env_show 158 0
+	env_show 159 0
+	#Konoko enters Truck
+	cm_anim both TruckCam01
+	cutscene_sync mark
+	sound_ambient_start c05_26_17_truckb
+	chr_envanim 0 TruckKonBox01 norotation
+	chr_animate 0 KONOKOlev7_TruckEnter
+	env_setanim 54 truckdoor2enter
+	sound_dialog_play c15_57_06konoko
+	cinematic_start (KONintense, 180, 180, 19, 7, 20, false)
+
+	#Truck exhaust starts and truck peels out
+	#sleep f10
+	sound_ambient_start c05_31_21_brake_doorsb
+	cm_anim_block both TruckCam02
+	playback 0 TruckKonokoHide
+	ai2_allpassive 0
+	cinematic_stop (KONintense, 19, 20)
+	sleep f80
+	chr_teleport C_Sb25 238
+	ai2_dopath C_Sb25 patrol_70
+	chr_teleport C_Sb26 195
+	ai2_dopath C_Sb26 patrol_84
+	chr_teleport C_Eb27 227
+	ai2_dopath C_Eb26 patrol_85
+	env_setanim 51 truckbackdrive01
+	env_setanim 52 truckcabdrive01
+	env_setanim 53 truckdoordrive01
+	env_setanim 54 truckdoor2drive01
+	env_setanim 55 truckwheel03drive01
+	env_setanim 56 truckwheel04drive01
+	env_setanim 57 truckwheel05drive01
+	env_setanim 58 truckwheel06drive01
+	env_setanim 59 truckwheel07drive01
+
+	#Truck heads towrads camera
+	cm_interpolate_block TruckCam04 0
+	env_setanim 51 truckbackdrive02
+	env_setanim 52 truckcabdrive02
+	env_setanim 53 truckdoordrive02
+	env_setanim 54 truckdoor2drive02
+	env_setanim 55 truckwheel03drive02
+	env_setanim 56 truckwheel04drive02
+	env_setanim 57 truckwheel05drive02
+	env_setanim 58 truckwheel06drive02
+	env_setanim 59 truckwheel07drive02
+	sleep f160
+	fade_out 0 0 0 15
+	fade_in 15
+
+	#Truck heads towrads door
+	cm_anim both TruckCam03	
+	env_setanim 51 truckbackdrive02
+	env_setanim 52 truckcabdrive02
+	env_setanim 53 truckdoordrive02
+	env_setanim 54 truckdoor2drive02
+	env_setanim 55 truckwheel03drive02
+	env_setanim 56 truckwheel04drive02
+	env_setanim 57 truckwheel05drive02
+	env_setanim 58 truckwheel06drive02
+	env_setanim 59 truckwheel07drive02
+
+	#Truck crashes through door
+	cm_anim_block both TruckCam05
+	env_setanim 51 truckbackcrash
+	env_setanim 52 truckcabcrash
+	env_setanim 53 truckdoorcrash
+	env_setanim 54 truckdoor2crash
+	env_setanim 55 truckwheel03crash
+	env_setanim 56 truckwheel04crash
+	env_setanim 57 truckwheel05crash
+	env_setanim 58 truckwheel06crash
+	env_setanim 59 truckwheel07crash
+
+	#break door here
+	sleep f35
+	cutscene_sync mark
+	sound_ambient_start c05_53_27_crash
+	sleep f10
+	particle TruckDoor do explode
+	env_show 911 1
+	env_show 912 0
+	env_show 913 0
+	env_show 914 1
+
+	#Konoko exits truck
+	sleep f125
+	cutscene_sync mark
+	sound_ambient_start c05_31_21_brake_doorsc
+	cm_anim_block both TruckCam06
+	chr_envanim 0 TruckKonBox02 norotation
+	chr_animate 0 KONOKOlev7_TruckExit
+	env_setanim 54 truckdoor2exit
+
+	#gameplay resumes
+	cm_wait
+	env_show 915 1
+	env_show 916 1
+	env_show 251 1
+	env_show 252 1
+	env_show 253 1
+	env_show 254 1
+	env_show 255 1
+	env_show 256 1
+	env_show 257 1
+	env_show 258 1
+	env_show 259 1
+	obj_kill 51 59
+	cm_reset
+	playback 0 TruckExitKonoko
+	end_cutscene
+
+	stop_music_truck
+}
+
+func void sp_start_dish_loop(void)
+{
+	sound_ambient_start mc_dish_loop 0.6
+}
+
+func void sp_start_dish_and_wait(void)
+{
+	sleep 320
+	sound_ambient_start mc_dish_loop 0.1
+	sound_ambient_volume mc_dish_loop 0.6 4.0
+}
+
+func void dish(void)
+{
+	begin_cutscene
+	gs_farclipplane_set 5000
+	sleep f60
+	#hide and unhide dish stuff
+	obj_create 201 209
+	obj_shade 201 209 .5 .5 .5
+	env_show 301 0
+	env_show 302 0
+	env_show 303 0
+	env_show 304 0
+	env_show 305 0
+	env_show 306 0
+	env_show 307 0
+	env_show 308 0
+	env_show 309 0
+	cm_anim both DishCam01
+	chr_peace 0
+	chr_envanim 0 DishKonokoBox01
+	sleep f60
+	obj_force_draw 201 209
+	cutscene_sync mark
+	sound_ambient_start c06_08_03_basic
+	sleep f440
+	#dish thing starts to raise
+	env_anim 201 209
+	cm_anim_block both DishCam02
+	cm_anim_block both DishCam03
+	cm_anim_block both DishCam04
+	sleep f120
+	cutscene_sync mark
+	sound_ambient_start c06_35_00_servo
+	cm_anim_block both DishCam05
+	sleep f300
+	#close up of Konoko
+	env_show 401 1
+	env_show 402 1
+	env_show 403 1
+	env_show 404 1
+	env_show 405 1
+	env_show 406 1
+	env_show 407 1
+	env_show 408 1
+	env_show 409 1
+	obj_kill 201 209
+	#Vista shot
+	particle dish do explode
+	cutscene_sync mark
+	sound_ambient_start c16_49_01_amb2
+	gs_farclipplane_set 3000
+	cm_interpolate DishCam06 0
+	cm_interpolate_block DishCam07 940
+	sleep f600
+	cutscene_sync mark
+	sound_ambient_start c16_49_01_effectsa
+	sleep f330
+	cutscene_sync mark
+	sound_ambient_start c16_49_01_effectsb
+	fork sp_start_dish_and_wait
+	cm_wait
+	cm_interpolate DishCam08 0
+	particle dishpulse do start
+	particle sturm_ambient start
+	sleep f300
+	playback 0 GrifKonokoSet
+	cm_interpolate GrifCam01 180
+	sleep f120
+
+	#cm_reset
+	if (did_kill_griffen() eq 1)
+	{
+		mutant
+	}
+	if (did_kill_griffen() eq 0)
+	{
+		grif
+	}
+}
+
+
+func void grif(void)
+{
+	begin_cutscene
+	cutscene_sync mark
+	sound_ambient_start c07_17_19heli
+	#camera pans to see Konoko looking at dish
+	#playback 0 GrifKonokoSet
+	#cm_interpolate GrifCam01 180
+	#sleep f240
+
+	# CB: this sets up the AI target selection parameters for the group battle
+	ai2_boss_battle = 1
+
+	#camera pans to see Muro
+	ai2_spawn Muro
+	ai2_passive Muro 1
+	if (extra_guys eq 1) {
+		ai2_spawn GrifElite01
+		counter = counter + 1;
+	}
+	ai2_spawn GrifElite02
+	ai2_spawn GrifElite03
+	playback Muro GrifMuroSet
+	playback GrifElite01 GrifElite01Set
+	playback GrifElite02 GrifElite02Set
+	playback GrifElite03 GrifElite03Set
+	cm_interpolate GrifCam02 150
+	sleep f10
+	playback GrifElite02 GrifElite02Set
+	sleep f5
+	playback GrifElite03 GrifElite03Set
+	sleep f150
+	#Muro says  you shouldn't have come here alone
+	cm_interpolate GrifCamMuro01 0
+	sound_dialog_play c15_60_01muro
+	cinematic_start (MUROtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block pause
+	cinematic_stop (MUROtalking, 19, 20)
+	#Konoko looks pissed
+	playback 0 GrifKonokoSet02
+	cm_interpolate GrifCamKon01 0
+	sleep f15
+	#griffin appears in a helicopter behind her
+	cm_interpolate GrifCamHeli 240
+	sleep f20
+	obj_create 901 906
+	env_anim 901 906
+	ai2_spawn Griffin
+	if (extra_guys eq 1) {
+		ai2_spawn GrifOps01
+		count_swat_dies = count_swat_dies + 1;
+	}
+	ai2_spawn GrifOps02
+	ai2_spawn GrifOps03
+	chr_envanim Griffin GrifGrifBox01
+	if (extra_guys eq 1) {
+		chr_envanim GrifOps01 GrifOps01Box01
+		chr_envanim GrifOps02 GrifOps02Box01
+	}
+	if (extra_guys eq 0) {
+		chr_envanim GrifOps02 GrifOps01Box01
+	}
+	chr_envanim GrifOps03 GrifOps03Box01
+	chr_animate Griffin COMGUYlev7_helistand 500
+	chr_animate GrifOps01 STRIKEcrouch_idle 400
+	chr_animate GrifOps02 STRIKEcrouch_idle 400
+	chr_animate GrifOps03 STRIKEcrouch_idle 400
+	sleep f90
+	sound_dialog_play c15_60_02griffin
+	cinematic_start (GRIFshouting, 180, 180, 15, 1, 20, false)
+	sleep f200
+	cinematic_stop (GRIFshouting, 15, 20)
+	#Guys jump out of helicopter
+	env_setanim 901 heli_doors_rt08
+	env_setanim 902 heli_doors_lt08
+	env_setanim 903 heli_rotorblades08
+	env_setanim 904 heli_body08
+	env_setanim 905 heli_canopy08
+	env_setanim 906 heli_interior08
+	chr_envanim Griffin GrifGrifBox02 norotation
+	if (extra_guys eq 1) {
+		chr_envanim GrifOps01 GrifOps01Box02 norotation
+		chr_envanim GrifOps02 GrifOps02Box02 norotation
+	}
+	if (extra_guys eq 0) {
+		chr_envanim GrifOps02 GrifOps01Box02 norotation
+	}
+	chr_envanim GrifOps03 GrifOps03Box02 norotation
+	chr_animate Griffin COMGUYlev7_Grif
+	if (extra_guys eq 1) {
+		chr_animate GrifOps01 STRIKElev7_Ops01
+		chr_animate GrifOps02 STRIKElev7_Ops02
+	}
+	if (extra_guys eq 0) {
+		chr_animate GrifOps02 STRIKElev7_Ops01
+	}
+	chr_animate GrifOps03 STRIKElev7_Ops03
+	cm_anim both GrifCamOut
+	ai2_allpassive 1
+	sleep f240
+	#Guys run to help Konoko
+	playback Griffin GrifGrifRunAlt
+	if (extra_guys eq 1) {
+		playback GrifOps01 GrifOps01Run
+		playback GrifOps02 GrifOps02Run
+	}
+	if (extra_guys eq 0) {
+		playback GrifOps02 GrifOps01Run
+	}
+	sleep f10
+	playback GrifOps03 GrifOps03Run
+	cm_wait
+	#sleep f20
+	cm_interpolate GrifCamHelp01 0
+	sleep f20
+	cm_interpolate_block GrifCamHelp02 180
+	sleep f180
+	cm_interpolate GrifCamWatch01 0
+	cm_interpolate_block GrifCamWatch02 210
+	playback 0 GrifKonokoWatch
+	sleep f210
+
+	#Muro says you gonna trust him?
+	obj_kill 901 906
+	cm_interpolate GrifCamFace01 0
+	cm_interpolate_block GrifCamFace02 700
+	sound_dialog_play c15_60_03muro
+	cinematic_start (MUROtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block pause 
+
+	#Konoko says he dreamed of life
+	cm_interpolate GrifCamKonFace01 0
+	cm_interpolate_block GrifCamKonFace02 800
+	sound_dialog_play c15_60_04konoko
+	cinematic_start (KONintense, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c15_60_05konoko
+	sound_dialog_play_block pause
+
+	sound_music_start mus_ot
+
+	cm_interpolate GrifCamMuroFace01 0
+	sound_dialog_play c15_60_06muro
+	sound_dialog_play_block pause
+	cinematic_stop (MUROtalking, 19, 20)
+
+	chr_set_health Muro 500
+
+	cinematic_stop (KONintense, 20, 20)
+	end_cutscene
+	ai2_passive Muro 0
+	chr_boss_shield Muro
+	cm_reset
+	s4
+	fork wait_to_help
+	paths
+	objective_set(6)
+}
+
+
+func void mutant(void)
+{
+	begin_cutscene
+	#camera pans to see Konoko looking at dish
+	#playback 0 GrifKonokoSet
+	#cm_interpolate GrifCam01 180
+	#sleep f240
+	#camera pans to see Muro
+	ai2_spawn Muro
+	ai2_passive Muro 1
+	playback Muro GrifMuroSet
+	cm_interpolate GrifCam02 150
+	sleep f150
+	#Muro says  you shouldn't have come here alone
+	cm_interpolate GrifCamMuro01 0
+	cm_interpolate_block MutantCam01 900
+	sound_dialog_play c15_59_01muro
+	cinematic_start (MUROtalking, 180, 180, 19, 7, 20, false)
+	sleep f500
+	#Konoko looks pissed
+	playback 0 GrifKonokoSet02
+	cm_interpolate GrifCamKon01 0
+	sleep f150
+	cinematic_stop (MUROtalking, 19, 20)
+	#muro transforms
+	cm_interpolate GrifCam02 0
+	particle MutantTransform do explode
+	cutscene_sync mark
+	sound_ambient_start c08_06_25muro
+	sleep f150
+	chr_animate Muro MUROtransform
+	cm_interpolate_block MutantCam01 200
+	sleep f170
+	#show Konoko protecting herself from the blast
+	cm_interpolate MutantCamKon 0
+	chr_animate 0 KONOKOlev7_blown
+	sleep f100
+	#kill muro and spawn mutant muro
+	chr_delete Muro 
+	ai2_spawn MutantMuro
+	playback MutantMuro MutantMuroEnd01
+	sleep 1
+	ai2_allpassive=1
+	chr_neutral MutantMuro 1
+	sleep f10
+	chr_animate MutantMuro MUTCOMtransform
+	cm_interpolate MutantCam01 0
+	cm_interpolate_block  MutantCam03 240
+	sleep f60
+	sound_dialog_play c15_59_02muro
+	cinematic_start (MUTANTMUROface, 180, 180, 19, 7, 20, false)
+	cm_interpolate MutantCam04 700
+	sound_dialog_play_block pause
+	#Konoko says surrender
+	cm_interpolate MutantCamKonTalk 0
+	sound_dialog_play c15_59_03konoko
+	cinematic_start (KONangryfront, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+
+	sound_music_start mus_ot
+
+	#Muro says never
+	#playback MutantMuro MutantMuroEnd01
+	#cm_interpolate MutantCamMuroEnd 0
+	#sleep f60
+	#playback MutantMuro MutantMuroEnd02
+	#sleep f120
+	#gameplay resumes
+	cinematic_stop (KONangryfront, 20, 20)
+	cinematic_stop (MUTANTMUROface, 19, 20)
+	cm_reset	
+	end_cutscene
+	chr_boss_shield MutantMuro
+	ai2_passive MutantMuro 0
+	s4
+	objective_set(7)
+}
+
+
+
+func void
+Outro(
+	void)
+{
+	sound_music_stop mus_ot
+
+	begin_cutscene jello
+
+	#slowmo
+	#weird particle effect
+	sleep f120
+	chr_animate 0 KONOKOendpowerup
+	sleep f120
+	cm_interpolate EndCam 600
+	sound_ambient_volume mc_dish_loop 1.0 4.0
+	sleep f500
+	fade_out 0 0 0 120
+	sleep f120
+	win
+}
Index: /nikanabo/current/bsl/original/IGMD/compound/compound_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/compound/compound_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/compound/compound_main.bsl	(revision 185)
@@ -0,0 +1,64 @@
+#
+# compound_main.bsl
+#
+
+func void
+main(
+	void)
+{
+	env_shade 912 913 .4 .4 .4
+	env_show 911 0
+	env_show 914 0
+	env_show 915 0
+	env_show 916 0
+	input	1	
+	#hide animation Truck Gunk
+	env_show 151 0
+	env_show 152 0
+	env_show 153 0
+	env_show 154 0
+	env_show 155 0
+	env_show 156 0
+	env_show 157 0
+	env_show 158 0
+	env_show 159 0
+	env_show 251 0
+	env_show 252 0
+	env_show 253 0
+	env_show 254 0
+	env_show 255 0
+	env_show 256 0
+	env_show 257 0
+	env_show 258 0
+	env_show 259 0
+	#Hide dish2 gunk
+	env_show 401 0
+	env_show 402 0
+	env_show 403 0
+	env_show 404 0
+	env_show 405 0
+	env_show 406 0
+	env_show 407 0
+	env_show 408 0
+	env_show 409 0
+
+	my_save_point = save_point;
+
+	start
+
+	if (my_save_point eq 0)
+	{
+		gl_fog_blue=0.0
+		gl_fog_red=0.0
+		gl_fog_green=0.0
+		gl_fog_start=.985
+		intro
+		gs_farclipplane_set 1000
+	}
+
+	gl_fog_blue=0.0
+	gl_fog_red=0.0
+	gl_fog_green=0.0
+	gl_fog_start=.985
+	gs_farclipplane_set 1000
+}
Index: /nikanabo/current/bsl/original/IGMD/compound/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/compound/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/compound/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,43 @@
+#snow for the airfield
+func void snow1_start(string ai_name)
+{
+	dprint snow1_start
+	particle snow1 start
+}
+func void snow1_stop(string ai_name)
+{
+	dprint snow1_stop
+	particle snow1 stop
+}
+func void snow2_start(string ai_name)
+{
+	dprint snow2_start
+	particle snow2 start
+}
+func void snow2_stop(string ai_name)
+{
+	dprint snow2_stop
+	particle snow2 stop
+}
+func void snow3_start(string ai_name)
+{
+	dprint snow3_start
+	particle snow3 start
+}
+func void snow3_stop(string ai_name)
+{
+	dprint snow3_stop
+	particle snow3 stop
+}
+
+#peak particles form the mountain top
+func void peak_start(string ai_name)
+{
+	dprint peak_start
+	particle peak start
+}
+func void peak_stop(string ai_name)
+{
+	dprint peak_stop
+	particle peak stop
+}
Index: /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_cutscene.bsl	(revision 185)
@@ -0,0 +1,441 @@
+#
+# dreamlab_cutscene.bsl
+#
+
+func void stop_xtr2_in_15(void)
+{
+	sleep 720
+	sound_music_stop mus_xtr2
+}
+
+
+func void
+intro(
+	void)
+{
+	fade_out 0 0 0 0
+	obj_create 131 132
+	cm_interpolate IntroCamOpen 0
+	sleep f14
+	begin_cutscene
+	env_show 231 0
+	env_show 232 0
+	sleep f90
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Sit 8000
+	cm_interpolate IntroCamOpen 0
+	fade_in 120
+	sleep f180
+	#Konoko opens up laptop
+	cm_anim both IntroCamOpen
+	sound_dialog_play c12_42_01konoko
+	
+	sound_music_start atm_cl16 0.75
+
+	sleep f285
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Open
+	env_anim 131 132
+	#Konoko puts in disk
+	cm_wait
+	obj_create 481 481
+	cm_anim both IntroCamDisk
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Disk
+	env_anim 481 481
+	sleep f83
+	obj_kill 481 481
+	cm_wait
+	#Konoko reads
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Sit 8000
+	cm_anim both ImageCam01
+	sound_dialog_play c12_43_01hasegawa
+	sleep f120
+	obj_create 101 107
+	env_anim 101 101
+	sleep f60
+	fadefog
+	sound_dialog_play_block pause
+	sound_dialog_play c12_43_02hasegawa
+	sound_dialog_play_block pause
+	sleep f15
+	sound_dialog_play c12_43_03hasegawa
+	env_anim 102 102
+	sound_dialog_play_block pause
+	sleep f15
+	sound_dialog_play c12_43_04hasegawa
+	env_anim 103 103
+	obj_kill 101 101
+	sound_dialog_play_block pause
+	sleep f15
+	sound_dialog_play c12_43_05hasegawa
+	sound_dialog_play_block pause
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Sit 8000
+	env_anim 104 104
+	sleep f90
+	sound_dialog_play c12_43_06hasegawa
+	sound_dialog_play_block pause
+	sleep f60
+	sound_dialog_play c12_43_07hasegawa
+
+	sound_music_volume atm_cl16 0.0 6.0
+	sound_music_start atm_cl05 0.1
+	sound_music_volume atm_cl05 0.5 6.0
+
+	obj_kill 102 102
+	sound_dialog_play_block pause
+	sleep f15
+	env_anim 105 105
+	sleep f50
+	sound_dialog_play c12_43_08hasegawa
+	obj_kill 103 103
+	sound_dialog_play_block pause
+	sleep f45
+	sound_dialog_play c12_43_09hasegawa
+	env_anim 106 106
+	obj_kill 104 104
+	sound_dialog_play_block pause
+	sleep f60
+	sound_dialog_play c12_43_10hasegawa
+	env_anim 107 107
+	obj_kill 105 105
+	sound_dialog_play_block pause
+	sleep f120
+	#put gunshot and sobbing in here
+
+	sound_ambient_start gunshot
+	sound_music_stop atm_cl16
+	sound_music_volume atm_cl05 0.0 0.25
+
+	sleep 120
+	
+	sound_music_stop atm_cl05
+	sound_music_start mus_xtr2 0.6
+
+	sleep 120
+	#sound_dialog_play hasegawa_cry
+	#sound_dialog_play_block pause
+	#sleep f90
+	#Konoko reads more
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Sit 8000
+	cm_interpolate IntroCamHighLeft 0
+	cm_interpolate_block IntroCamHighRight 1000
+	fork stop_xtr2_in_15
+	sound_dialog_play c12_43_11hasegawa
+	sound_dialog_play_block pause
+	#camera pans to see wall missing and Konoko looks up
+	env_show 200 0
+	env_show 227 0
+	env_show 201 0
+	env_show 999 0
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev13_Sit 8000
+	cm_interpolate IntroCamLowLeft 0
+	obj_kill 106 106
+	obj_kill 107 107
+	gl_fog_end=1
+	gl_fog_start=.975
+	cm_interpolate_block IntroCamLook 800
+	sound_dialog_play c12_44_01konoko
+
+	particle fog_floor1 do start
+	
+	sleep f360
+
+	ai2_spawn IntroMuro
+	chr_lock_active IntroMuro
+	ai2_passive IntroMuro 1
+	playback IntroMuro IntroMuroEnter
+	chr_nocollision IntroMuro 1
+	sound_dialog_play_block pause
+	cinematic_start (MUROevilgrin, 180, 180, 15, 1, 20, false)
+		
+	sound_music_start mus_om01 .75
+	
+	sound_dialog_play c12_44_02muro
+	chr_animate 0 KONOKOlev13_Look
+	sleep f75
+	#Konoko gets up
+	chr_envanim 0 IntroKonBox02 norotation
+	chr_animate 0 KONOKOlev13_Getup
+	cm_anim both IntroCamGetup
+	sound_dialog_play_block pause
+	sleep f60
+	sound_dialog_play c12_44_03konoko
+	cinematic_start (KONlistening, 180, 180, 20, 9, 20, true)
+	cm_wait
+	#Camera pans to show Konoko from behind
+	env_show 231 1
+	env_show 232 1
+	obj_kill 131 132
+	playback 0 IntroKonokoSet
+	cm_interpolate IntroCamDoor01 0
+	cm_interpolate_block IntroCamDoor02 180
+	sound_dialog_play_block pause
+	sound_dialog_play c12_44_04muro
+	sleep f240
+	cinematic_stop (KONlistening, 20, 20)
+	cinematic_stop (MUROevilgrin, 15, 20)
+	#gameplay resumes
+	cm_reset
+	end_cutscene
+	ai2_passive IntroMuro 1
+	chr_nocollision IntroMuro 0
+
+	save_point_1
+}
+
+
+
+func void
+murodeath(
+	void)
+{
+	dprint WE_KILLED_MURO
+
+	env_show 999 0
+	env_show 1010 0
+	gs_farclipplane_set 2000
+
+	# ensure that muro doesn't get knocked out of his "death" anim
+	chr_unstoppable IntroMuro 1
+
+	chr_animate IntroMuro COMCOMlev13_death 120
+	gl_fog_start_changeto .995 30
+	sleep f24
+	chr_delete IntroMuro
+
+	sound_music_volume mus_om01 0.0 1.0
+	sound_music_start atm_gr09 0.75
+
+	objective_set(1)
+
+	sleep 60
+	sound_music_stop mus_om01
+}
+
+
+func void
+griffindeath(
+	void)
+{
+	# ensure that griffin doesn't get knocked out of his "death" anim
+	chr_unstoppable griffin 1
+
+	chr_animate griffin COMCOMlev13_death 120
+	sleep f20
+	chr_delete griffin
+	door_unlock 3
+}
+
+func void
+fadefog(
+	void)
+{
+	gl_fog_start_changeto .8 45
+}
+
+
+func void
+murofog(
+	void)
+{
+	ai2_passive IntroMuro 0
+	env_show 201 1
+	env_show 999 1
+	env_show 250 0
+	env_show 252 0
+	gl_fog_start_changeto .95 12
+	sleep f12
+	gs_farclipplane_set 75
+}	
+
+
+
+
+
+func void
+Griffin01(
+	void)
+{
+	begin_cutscene
+	door_lock 2
+	chr_lock_active griffin
+	playback griffin GrifGriffinSet
+	cm_interpolate GrifCamGriffin 200
+	#griffin talks
+	sleep f120
+	sound_dialog_play c12_45_01griffin
+	cinematic_start (GRIFtalkangry, 180, 180, 16, 3, 20, true)
+	playback 0 GrifKonokoSet
+	sound_dialog_play_block pause
+	cm_interpolate GrifCamKonoko01 0
+	cm_interpolate_block GrifCamKonoko02 800
+	sound_dialog_play c12_45_02konoko
+	cinematic_start (KONintense, 180, 180, 19, 7, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c12_45_03griffin
+	sound_dialog_play_block pause
+	cm_interpolate GrifCamBoth01 0
+	cm_interpolate_block GrifCamBoth02 800
+	sound_dialog_play c12_45_04konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_45_05griffin
+	sound_dialog_play_block pause
+	cinematic_stop (KONintense, 20, 20)
+	cinematic_stop (GRIFtalkangry, 15, 20)
+	cm_reset
+	end_cutscene
+	save_point_2
+}
+
+func void
+Konoko01(
+	void)
+{
+	begin_cutscene weapon
+	chr_lock_active evilkonoko
+	playback evilkonoko KonKonoko01Set
+	cm_interpolate KonCamKon01 200
+	#griffin talks
+	sleep f120
+	sound_dialog_play c12_46_01badasskon
+	cinematic_start (KONevil, 180, 180, 15, 1, 20, true)
+	playback 0 KonKonokoSet
+	sound_dialog_play_block pause
+	cm_interpolate KonCamBoth01 0
+	cm_interpolate_block KonCamBoth02 1000
+	sound_dialog_play c12_46_02konoko
+	cinematic_start (KONintense, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_03badasskon
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_04konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_05badasskon
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_06konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_07badasskon
+	cinematic_stop (KONintense, 20, 20)
+	sound_dialog_play_block pause
+	cinematic_stop (KONevil, 15, 20)
+	cm_reset
+	chr_animate evilkonoko KONOKOpowerup 0
+	chr_set_health evilkonoko 400
+	sleep f245
+	end_cutscene
+	env_show 250 1
+	env_show 252 1
+}
+
+func void
+Konoko02(
+	void)
+{
+	begin_cutscene
+	chr_lock_active evilkonoko
+	playback evilkonoko Kon2Konoko02Set
+	cm_interpolate Kon2CamKon201 140
+	sleep f120
+	cm_interpolate Kon2CamKon202 180	
+	#griffin talks
+	sleep f120
+	sound_dialog_play c12_46_01badasskon
+	cinematic_start (KONevil, 180, 180, 15, 1, 20, true)
+	playback 0 Kon2KonokoSet
+	sound_dialog_play_block pause
+	cm_interpolate Kon2Both01 0
+	cm_interpolate_block Kon2Both02 1000
+	sound_dialog_play c12_46_02konoko
+	cinematic_start (KONintense, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_03badasskon
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_04konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_05badasskon
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_06konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_46_07badasskon
+	cinematic_stop (KONintense, 20, 20)
+	sound_dialog_play_block pause
+	cinematic_stop (KONevil, 15, 20)
+	cm_reset
+	chr_animate evilkonoko KONOKOpowerup 0
+	chr_set_health evilkonoko 400
+	sleep f245
+	end_cutscene
+}
+
+
+func void
+Griffin02(
+	void)
+{
+	begin_cutscene
+	chr_lock_active griffin_2
+	playback griffin_2 Grif2GrifSet
+	cm_interpolate Kon2CamKon201 140
+	sleep f120
+	cm_interpolate Kon2CamKon202 180
+	#griffin talks
+	sleep f120
+	sound_dialog_play c12_45_01griffin
+	cinematic_start (GRIFtalkangry, 180, 180, 15, 1, 20, true)
+	playback 0 Kon2KonokoSet
+	sound_dialog_play_block pause
+	cm_interpolate Kon2Both01 0
+	cm_interpolate_block Kon2Both02 1000
+	sound_dialog_play c12_45_02konoko
+	cinematic_start (KONintense, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	sound_dialog_play c12_45_03griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c12_45_04konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c12_45_05griffin
+	sound_dialog_play_block pause
+	cinematic_stop (KONintense, 20, 20)
+	cinematic_stop (GRIFtalkangry, 15, 20)
+	cm_reset
+	end_cutscene
+}
+
+
+func void delay_then_play_wakeup(void)
+{
+	sleep 5
+	sound_impulse_play konoko_wakeup
+
+}
+
+func void
+outro(
+	void)
+{
+	begin_cutscene
+	env_show 252 1
+	env_show 250 1
+	env_show 200 1
+	env_show 227 1
+	env_show 231 0
+	env_show 232 0
+	fade_out 0 0 0 10
+	sleep f10
+	delay_then_play_wakeup
+	ai2_spawn outro_konoko
+	chr_envanim outro_konoko OutroKonBox01 norotation
+	chr_animate outro_konoko KONOKOlev13_outro
+	cm_anim both OutroCam01
+	fade_in 5
+	sleep f240
+	fade_out 0 0 0 60
+	sleep 90
+	end_cutscene
+	win
+}
Index: /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_logic.bsl	(revision 185)
@@ -0,0 +1,771 @@
+### DREAMLAB LEVEL LOGIC ###
+
+### START, SAVE & OBJECTIVES ###
+
+# START
+func void start(string ai_name)
+{
+	door_lock 3
+	door_lock 1
+	env_show 1976 0
+	trigvolume_enable splash_trigger 0
+
+	if (save_point eq 0)
+		{
+		my_save_point=0;
+		trigvolume_enable shinatama1a 1
+		trigvolume_enable shinatama1b 1
+		#env_show 999 0
+		ai2_spawn ghost_1
+		ai2_spawn ghost_2
+		set_objective_1
+		}
+
+	if (save_point eq 1)
+		{
+		my_save_point=1;
+		dprint restore1
+		ai2_spawn IntroMuro
+		playback IntroMuro IntroMuroSet
+		ai2_passive IntroMuro 1
+		playback 0 IntroKonokoSet
+		env_show 200 0
+		env_show 201 0
+		env_show 227 0
+		env_show 231 1
+		env_show 232 1
+		env_show 999 0
+		particle fog_floor1 do start
+		sound_music_start mus_om01 .75
+		trigvolume_enable shinatama1a 1
+		trigvolume_enable shinatama1b 1
+		set_objective_1
+		restore_game
+		ai2_spawn ghost_1
+		ai2_spawn ghost_2
+		}
+
+	if (save_point eq 2)
+		{
+		my_save_point=2;	
+		dprint restore2
+		particle fog_room1 do start
+		ai2_spawn griffin
+		playback griffin GrifGriffinSet
+		door_lock 3
+		trigvolume_enable room1a 0
+		trigvolume_enable room1b 0
+		set_objective_2
+		restore_game
+		sound_music_start mus_wls .75
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	all_music_counters
+	lose
+}
+
+func void you_win(string char_index)
+{
+	sound_music_volume mus_wls 0.0 2.0
+	sleep 180
+	fade_out 0 0 0 180 
+	outro
+}
+
+func void save_point_1(string player_name)
+{
+	dprint save_1
+	save_game 1 autosave
+}
+
+func void save_point_2(string player_name)
+{
+	dprint save_2
+	save_game 2 autosave
+	chr_delete liliput_striker_1
+	chr_delete liliput_striker_2
+	chr_delete liliput_striker_3
+	set_objective_2
+}
+
+func void set_objective_1(string chr_index)
+{
+	dprint objective_1
+	objective_set(1)
+}
+
+func void set_objective_2(string chr_index)
+{
+	dprint objective_2
+	objective_set(2)
+}
+
+### MUSIC ###
+
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+	if (0 ne music_counter) 
+		{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+		}
+}
+
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void striker_lullaby_1(string ai_name)
+{
+	dprint striker_lullaby1
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+}
+
+func void striker_lullaby_2(string ai_name)
+{
+	dprint striker_lullaby2
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+}
+
+func void all_music_counters(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop atm_cl16
+	sound_music_stop mus_om01
+	sound_music_stop atm_gr09
+	sound_music_stop mus_wls
+	sound_music_stop atm_ft81
+}
+
+### FOLLOW THE WHITE SHINATAMA ###
+
+# SHINATAMA 1a
+func void shinatama_1a(string ai_name)
+{
+	sound_dialog_play c12_63_01shinatama
+	ai2_spawn shinatama_1a
+	ai2_lookatme shinatama_1a
+}
+
+# SHINATAMA 1b
+func void shinatama_1b(string ai_name)
+{
+	ai2_dopath shinatama_1a shinatama_flee_1
+	door_lock 8
+}
+
+# SHINATAMA 1a DEATH
+func void patrolscript0100(string ai_name)
+{
+	chr_delete shinatama_1a
+	door_lock 7	
+}
+
+# SHINATAMA 2
+func void shinatama_2(string ai_name)
+{
+	sound_dialog_play c12_63_03shinatama
+	dprint shinatama_2
+	ai2_spawn shinatama_2
+	ai2_spawn liliput_striker_1
+	ai2_spawn liliput_striker_2
+	ai2_spawn liliput_striker_3
+	chr_lock_active shinatama_2
+	door_lock 8
+	door_open 11
+	door_open 12
+}
+
+# SHINATAMA 2 DEATH
+func void patrolscript0101(string ai_name)
+{
+	chr_delete shinatama_2
+}
+
+# SHINATAMA 3
+func void shinatama_3(string ai_name)
+{
+	chr_delete ghost_1
+	chr_delete ghost_2
+	sound_dialog_play c12_63_04shinatama
+	ai2_spawn shinatama_3
+	ai2_spawn shin_striker_1
+	ai2_spawn shin_striker_2
+	ai2_spawn shin_striker_3
+	ai2_spawn shin_striker_4
+}
+
+# SHINATAMA 3 DEATH
+func void patrolscript0102(string ai_name)
+{
+	chr_delete shinatama_3
+	sleep 400
+	chr_delete shin_striker_1
+	chr_delete shin_striker_2
+	chr_delete shin_striker_3
+	chr_delete shin_striker_4
+	chr_delete shin_striker_5
+	chr_delete shin_striker_6
+	chr_delete shin_striker_7
+}
+
+func void delay_and_play_shin(void)
+{
+	sleep 240
+	sound_dialog_play c12_63_05shinatama
+}
+
+# SHINATAMA NO-GRAV
+func void shinatama_nograv(string ai_name)
+{
+	dprint shinatama_nograv
+	sound_music_volume atm_gr09 0.0 2.0
+	sound_music_stop atm_gr09
+	sound_music_start atm_ft81 .75	
+	particle fog_room1 do stop
+	particle fog_room2 do start
+	door_lock 5
+	door_lock 6
+	ai2_spawn shinatama_nograv
+	chr_invincible shinatama_nograv 1
+	chr_nocollision shinatama_nograv 1
+	sound_music_start atm_cl22 0.1
+	sound_music_volume atm_cl22 1.0 4
+	fork delay_and_play_shin
+	playback_block shinatama_nograv shinatama_nograv interp 30
+	chr_delete shinatama_nograv
+	door_unlock 6
+	door_close 5
+	door_jam 5
+	invincible = 0
+	sound_music_volume atm_cl22 0.0 6
+	sleep 250
+	sound_music_stop atm_cl22
+}
+
+### AMBUSHES, BACKUPS ###
+
+func void ghost_1(string ai_name)
+{
+	dprint vanish_ghost1
+	chr_delete ghost_1
+}
+
+func void ghost_2(string ai_name)
+{
+	dprint vanish_ghost2
+	chr_delete ghost_2
+}
+
+# AMBUSH 1a
+func void ambush_1a(string ai_name)
+{
+	dprint ambush_1a
+	ai2_spawn ambush_tanker_1a
+	sound_music_stop atm_gr09
+	sound_music_start mus_wls .75
+}
+
+# AMBUSH 1b
+func void ambush_1b(string ai_name)
+{
+	dprint ambush_1b
+	ai2_spawn ambush_tanker_1b
+	door_open 8
+	door_jam 8
+}
+
+# AMBUSH 2
+func void ambush_2(string ai_name)
+{
+	dprint ambush_2
+	ai2_spawn ambush_red_1
+	sound_music_stop atm_ft81 
+	sound_music_start mus_wls .75
+}
+
+# TANKER VARIABLE
+func void tanker_1_var(string ai_name)
+{
+	dprint tanker_var1
+	tanker_counter = tanker_counter - 1
+	chr_inv_reset ambush_tanker_1a
+	if (tanker_counter eq 0)
+		{
+		new_music();
+		}
+}
+
+func void tanker_2_var(string ai_name)
+{
+	dprint tanker_var2
+	tanker_counter = tanker_counter - 1
+	chr_inv_reset ambush_tanker_1b
+	if (tanker_counter eq 0)
+		{
+		new_music();
+		}
+}
+
+func void new_music(string ai_name)
+{
+	dprint change_the_track
+	door_unlock 9
+	sound_music_stop mus_wls
+	sound_music_start atm_ft81 .75
+}
+
+# RED VARIABLE
+func void red_1_var(string ai_name)
+{
+	dprint red_var
+	red_counter = red_counter - 1
+	if (red_counter eq 0)
+		{
+		redbackup();
+		}
+}
+
+# RED BACKUP
+func void redbackup(string ai_name)
+{
+	dprint red_backup
+	ai2_spawn ambush_red_2
+	door_unlock 1
+	door_lock 2
+	door_unjam 8
+	chr_delete liliput_striker_1
+	chr_delete liliput_striker_2
+	chr_delete liliput_striker_3
+}
+
+# RED RETREAT
+func void red_retreat(string ai_name)
+{
+	dprint retreat_reds
+	ai2_makeignoreplayer ambush_red_1 1
+	ai2_makeignoreplayer ambush_red_2 1
+	ai2_dopath ambush_red_1 red_retreat_1 1
+	ai2_dopath ambush_red_2	red_retreat_2 1
+}
+
+func void patrolscript0007(string ai_name)
+{
+	dprint red_react
+	ai2_makeignoreplayer ambush_red_1 0
+	ai2_makeignoreplayer ambush_red_2 0
+}
+
+# RED (MUSIC) SHIFT
+func void redmusic_1_var(string ai_name)
+{
+	dprint redmusic_1
+	rmusic_counter = rmusic_counter - 1
+	if (rmusic_counter eq 0)
+		{		
+		red_shift();
+		}
+}
+
+func void redmusic_2_var(string ai_name)
+{
+	dprint redmusic_2
+	rmusic_counter = rmusic_counter - 1
+	if (rmusic_counter eq 0)
+		{		
+		red_shift();
+		}
+}
+
+func void red_shift(string player_name)
+{
+	dprint redshift
+	sound_music_stop mus_wls
+	sound_music_start atm_gr09 0.75
+	door_unlock 2
+}
+
+
+# SWAT VARIABLE
+func void swat_1_var(string ai_name)
+{
+	dprint swat_var
+	swat_counter = swat_counter - 1
+	if (swat_counter eq 0)
+		{
+		swatbackup();
+		}
+}
+
+# SWAT BACKUP
+func void swatbackup(string ai_name)
+{
+	dprint swat_backup
+	door_unlock 2
+	ai2_spawn griffin_b1
+	ai2_spawn griffin_b2
+}
+
+# ROOM 1 END VAR
+func void end_1a_var(string ai_name)
+{
+	dprint swat_var
+	end1_counter = end1_counter - 1
+	if (end1_counter eq 0)
+		{
+		room1_end();
+		}
+}
+
+func void end_1b_var(string ai_name)
+{
+	dprint swat_var
+	end1_counter = end1_counter - 1
+	if (end1_counter eq 0)
+		{
+		room1_end();
+		}
+}
+
+func void end_1c_var(string ai_name)
+{
+	dprint swat_var
+	end1_counter = end1_counter - 1
+	if (end1_counter eq 0)
+		{
+		room1_end();
+		}
+}
+
+# ROOM 1 END
+func void room1_end(string ai_name)
+{
+	dprint room1_end
+	door_unlock 3
+	trigvolume_enable nodark 1
+}
+
+### GOTTA CATCH 'EM ALL! (WITH NO APOLOGIES TO YOU KNOW WHAT) ###
+
+# MINISTRIKE
+func void mini_strike(string ai_name)
+{
+	dprint mini_strike
+	ai2_spawn mini_strike_1
+	ai2_spawn mini_strike_2
+	ai2_spawn mini_strike_3
+	ai2_spawn mini_strike_4
+	chr_delete ghost_1
+	chr_delete ghost_2
+}
+
+# MINISTRIKE 1 FLEE
+func void mini_strike_flee_1(string ai_name)
+{
+	ai2_dopath mini_strike_1 mini_strike_flee_1
+}
+
+# MINISTRIKE 2 FLEE
+func void mini_strike_flee_2(string ai_name)
+{
+	ai2_dopath mini_strike_2 mini_strike_flee_2
+}
+
+# MINISTRIKE 3 FLEE
+func void mini_strike_flee_3(string ai_name)
+{
+	ai2_dopath mini_strike_3 mini_strike_flee_3
+}
+
+# MINISTRIKE 4 FLEE
+func void mini_strike_flee_4(string ai_name)
+{
+	ai2_dopath mini_strike_4 mini_strike_flee_4
+}
+
+# SWISS CHEESE
+
+func void patrolscript0001(string ai_name)
+{
+	dprint swisscheese_1
+	chr_nocollision mini_strike_1 1
+	playback_block mini_strike_1 cheese1 interp 30
+	chr_delete mini_strike_1
+}
+func void patrolscript0002(string ai_name)
+{
+	dprint swisscheese_2
+	chr_nocollision mini_strike_2 1
+	playback_block mini_strike_2 cheese2 interp 30
+	chr_delete mini_strike_2
+}
+
+func void patrolscript0003(string ai_name)
+{
+	dprint swisscheese_3
+	chr_nocollision mini_strike_3 1
+	playback_block mini_strike_3 cheese3 interp 30
+	chr_delete mini_strike_3
+}
+
+func void patrolscript0004(string ai_name)
+{
+	dprint swisscheese_4
+	chr_nocollision mini_strike_4 1
+	playback_block mini_strike_4 cheese4 interp 30
+	chr_delete mini_strike_4
+}
+
+# MINISTRIKE 1 HOLE
+func void patrolscript0110(string ai_name)
+{
+	chr_delete mini_strike_1
+}
+
+# MINISTRIKE 2 HOLE
+func void patrolscript0111(string ai_name)
+{
+	chr_delete mini_strike_2
+}
+
+# MINISTRIKE 3 HOLE
+func void patrolscript0112(string ai_name)
+{
+	chr_delete mini_strike_3
+}
+
+# MINISTRIKE 4 HOLE
+func void patrolscript0113(string ai_name)
+{
+	chr_delete mini_strike_4
+}
+
+### EVERYBODY WAS DREAM LAB FIGHTIN' ###
+
+# ROOM 1
+func void room_1(string ai_name)
+{
+	dprint room_1
+	sound_music_stop atm_gr09
+	sound_music_start mus_wls .75
+	particle fog_room1 do start
+	ai2_spawn griffin
+	Griffin01
+	trigvolume_enable room1a 0
+	trigvolume_enable room1b 0
+	trigvolume_enable room1c 0
+}
+
+# ROOM 2
+func void room_2(string ai_name)
+{
+	dprint room_2
+	ai2_spawn evilkonoko
+	Konoko02
+	door_lock 6
+	trigvolume_enable room2 0
+}
+
+# ROOM 2 MUSIC
+func void room2_music(string ai_name)
+{
+	dprint room2music
+	sound_music_volume atm_ft81 0.0 2.0
+	sound_music_stop atm_ft81 .75
+	sound_music_start mus_wls .75
+}
+
+### GENERAL CHICANERY ###
+
+# MURO'S WALL
+func void bring_the_wall(string char)
+{
+	dprint oops
+	env_show 1010 1
+}
+
+# FOG ON 1
+func void fog_floor1on(void)
+{
+	dprint fog_on
+	particle fog_floor1 do start
+	particle fog_floor2a do stop
+}
+
+# FOG OFF 1
+func void fog_floor1off(void)
+{
+	dprint fog_off
+	particle fog_floor1 do stop
+	particle fog_floor2a do start
+}
+
+# FOG ON 2
+func void fog_floor2boff(void)
+{
+	dprint fog_on
+	particle fog_floor2a do start
+	particle fog_floor2b do stop
+}
+
+# FOG OFF 2
+func void fog_floor2bon(void)
+{
+	dprint fog_off
+	particle fog_floor2a do stop
+	particle fog_floor2b do start
+}
+
+func void show_the_acid(string char)
+{
+	dprint show_acid
+	sound_music_volume mus_wls 0.0 2.0	
+	sound_music_stop mus_wls
+	sound_music_start atm_gr09 0.75
+	env_show 1976 1
+	trigvolume_enable splash_trigger 1
+	particle fog_floor1 do stop
+}
+
+# ACID DOOOOOM
+func void splash(string char)
+{
+  	var bool eggman;
+	eggman = chr_is_player(char);
+  	if (eggman eq 0)
+  		{
+    		chr_animate(char, KONOKOacid);
+    		sleep f10
+    		chr_set_health(char, 0);
+  		}
+
+  	if (eggman eq 1)
+  		{
+		input 0
+		chr_animate(char, KONOKOacid);
+		cm_detach
+
+		sound_impulse_play konoko_gruesome_death
+
+		sleep f5
+		chr_set_health(char, 0);
+  		}
+}
+
+func void laser_cutscene_fog(void)
+{
+	gs_farclipplane_set 2000
+	gl_fog_start_changeto .995 45
+}
+
+# LASER CUTSCENE
+func void laser_cutscene(string ai_name)
+{
+	dprint laser_cutscene
+	fork laser_cutscene_fog
+	begin_cutscene
+	sleep 90
+	trig_activate 1 
+	cm_interpolate laser_4 0
+	door_close 4
+	door_jam 4
+	cm_interpolate_block laser_3 250
+	sleep 250
+	cm_interpolate laser_2 0
+	cm_interpolate_block laser_8 200
+	ai2_spawn laser_ops_1
+	playback_block laser_ops_1 lstriker_1 interp 30
+	sleep 60
+	ai2_allpassive 0
+	cm_reset
+	door_lock 4
+	door_lock 5
+	trigvolume_enable lasercutscene 0
+	trigvolume_enable death_by_bungie 1
+	trigvolume_enable splash 1
+	sleep 15
+	end_cutscene
+}
+
+func void laser_cleanup(string ai_name)
+{
+	dprint laser_unlock
+	door_unlock 5
+}
+
+# BIG HEAD VAR
+func void bighead_1a_var(string ai_name)
+{
+	dprint bighead_var
+	bighead_counter = bighead_counter - 1
+	if (bighead_counter eq 0)
+		{
+		big_head();
+		}
+}
+
+func void bighead_1b_var(string ai_name)
+{
+	dprint bighead_var
+	bighead_counter = bighead_counter - 1
+	if (bighead_counter eq 0)
+		{
+		big_head();
+		}
+}
+
+func void bighead_1c_var(string ai_name)
+{
+	dprint bighead_var
+	bighead_counter = bighead_counter - 1
+	if (bighead_counter eq 0)
+		{
+		big_head();
+		}
+}
+
+func void bighead_1d_var(string ai_name)
+{
+	dprint bighead_var
+	bighead_counter = bighead_counter - 1
+	if (bighead_counter eq 0)
+		{
+		big_head();
+		}
+}
+
+# BIG HEAD
+func void big_head(string ai_name)
+{
+	dprint bighead
+	sleep 200
+	chr_big_head = 1
+	timer_start 120 small_head
+}
+
+func void small_head(string ai_name)
+{
+	dprint smallhead
+	chr_big_head = 0
+}
+
+### Level scripted by Joseph ###
Index: /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/dream_lab/dream_lab_main.bsl	(revision 185)
@@ -0,0 +1,29 @@
+#
+# dream_lab_main.bsl
+#
+
+var int my_save_point=0;
+var int rmusic_counter=2;
+var int tanker_counter=2;
+var int red_counter=1;
+var int swat_counter=1;
+var int end1_counter=3;
+var int bighead_counter=4;
+
+func void main(void)
+{
+	sound_ambient_start roomtone_softhum03 0.8
+
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.995
+	gs_farclipplane_set 2000
+	start
+
+	if (my_save_point eq 0)
+	{
+		intro
+	}
+}
+
Index: /nikanabo/current/bsl/original/IGMD/dream_lab/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/dream_lab/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/dream_lab/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,99 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+
+#room1
+func void room1_start(string ai_name)
+{
+	dprint room1_start
+	particle room1 do start
+}
+func void room1_stop(string ai_name)
+{
+	dprint room1_stop
+	particle room1 do stop
+}
+#room2
+func void room2_start(string ai_name)
+{
+	dprint room2_start
+	particle room2 do start
+}
+func void room2_stop(string ai_name)
+{
+	dprint room2_stop
+	particle room2 do stop
+}
+
+#room3
+func void room3_start(string ai_name)
+{
+	dprint room3_start
+	particle room3 do start
+}
+func void room3_stop(string ai_name)
+{
+	dprint room3_stop
+	particle room3 do stop
+}
+
+#room4
+func void room4_start(string ai_name)
+{
+	dprint room4_start
+	particle room4 do start
+}
+func void room4_stop(string ai_name)
+{
+	dprint room4_stop
+	particle room4 do stop
+}
+
+#room5
+func void room5_start(string ai_name)
+{
+	dprint room5_start
+	particle room5 do start
+}
+func void room5_stop(string ai_name)
+{
+	dprint room5_stop
+	particle room5 do stop
+}
+
+#room4
+func void room6_start(string ai_name)
+{
+	dprint room6_start
+	particle room6 do start
+}
+func void room6_stop(string ai_name)
+{
+	dprint room6_stop
+	particle room6 do stop
+}
+
+#room7
+func void room7_start(string ai_name)
+{
+	dprint room7_start
+	particle room7 do start
+}
+func void room7_stop(string ai_name)
+{
+	dprint room7_stop
+	particle room7 do stop
+}
+
+#room8
+func void room8_start(string ai_name)
+{
+	dprint room8_start
+	particle room8 do start
+}
+func void room8_stop(string ai_name)
+{
+	dprint room8_stop
+	particle room8 do stop
+}
+
Index: /nikanabo/current/bsl/original/IGMD/lab/lab_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/lab/lab_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/lab/lab_cutscene.bsl	(revision 185)
@@ -0,0 +1,368 @@
+#
+# lab_cutscene.bsl
+#
+
+func void shin_intro_dialogue(void)
+{
+	sound_dialog_play c00_01_99shinatama
+	cinematic_start (SHINtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	cinematic_stop (SHINtalking, 15, 20)
+}
+
+func void intro(void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate Camout01 0
+	sleep 13
+	begin_cutscene		
+	#hide motorcycle gunk
+	env_show 8 0
+	env_show 9 0
+	env_show 10 0
+	chr_nocollision 0 1
+	chr_forceholster 0 1
+	sleep 60
+	fade_in 120
+	#fork camcontrol
+	cm_anim both Camout01
+	obj_create 8 10
+	env_anim 8 10
+	chr_envanim 0 KonBipedBox01
+	chr_animate 0 KONOKOcycle_ride 880
+	sleep 15
+	cutscene_sync mark
+	sound_ambient_start c02_02_01_motorcyclea
+	cm_wait
+	cm_anim both Camout02
+	cutscene_sync mark
+
+	fork shin_intro_dialogue
+
+	sound_ambient_start c02_02_01_motorcycleb 0.7
+
+	cm_wait
+	cm_anim both Camout03
+	cutscene_sync mark
+
+	sound_ambient_start c02_02_01_motorcyclec 0.7
+
+	ai2_spawn Barabus
+	ai2_setmovementmode Barabus walk
+	playback Barabus IntroSubboss01
+	cm_wait
+	cm_anim both Camout04
+	sleep 20
+	cutscene_sync mark
+
+	sound_ambient_start c02_14_27_jump_land_skid
+
+	sleep 40
+	chr_animate Barabus STRIKElev3_startle
+	cm_wait
+	cm_anim both Camout05
+	chr_animate 0 KONOKOlev3_intro_stop
+	env_setanim 8 hubs_stop
+	env_setanim 9 hubs_rear_stop
+	env_setanim 10 motorcycle02_stop
+	chr_envanim 0 KonBipedBox02 norotation
+	cm_wait
+	cm_interpolate Camout06 0
+	#chr_create 1000 start
+	#chr_neutral 1000 1
+	cinematic_start (BOSS1talking, 180, 180, 20, 8, 20, false)
+	sleep 20
+	sound_dialog_play c03_10_01barabas
+	sound_dialog_play_block pause
+	sleep 20
+	cinematic_stop (BOSS1talking, 19, 20)
+	#hide motorcycle object
+	obj_kill 8 10
+	#unhide motorcycle gunk
+	env_show 10 1
+	env_show 9 1
+	env_show 8 1
+	#setup Konoko for scene
+	playback 0 IntroKonoko01
+	sleep 10
+	cm_reset
+	chr_nocollision 0 0
+	end_cutscene
+	set_objective_1
+	trigvolume_enable save_1_trig 1
+	ai2_attack Barabus konoko
+
+	sound_music_start mus_main01_hd	0.8
+}
+
+func void camcontrol(void)
+{
+	cm_anim both Camout01
+	cm_anim both Camout02
+	cm_anim both Camout03
+	cm_anim both Camout04
+	cm_anim both Camout05
+	cm_wait
+	letterbox 0
+	cm_jello 1
+	cm_reset
+	chr_nocollision 0 0
+	input 1
+}
+
+func void rocket(void)
+{
+	sound_music_stop mus_main01_hd	
+
+	begin_cutscene jello
+	chr_animate Barabus STRIKEknockdown1
+	sleep 60
+	ai2_takecontrol 1
+	ai2_lookatchar 0 Barabus
+	chr_animate Barabus BARABstunned 1000
+	sound_dialog_play c03_10_02barabas
+	cinematic_start (BOSS1talking, 180, 180, 16, 1, 20, false)	
+	sleep 280
+	chr_nocollision Barabus 1
+	chr_animate Barabus BARABrocket 250
+	sleep 130
+	cutscene_sync mark
+	sound_ambient_start c01_00_02barjet
+	#Barabas flies into the sky
+	chr_animate_block Barabus BARABlev3_rocket
+	chr_envanim Barabus RocketBox01
+	cm_anim both RocketCam01
+	sleep 90
+	sound_dialog_play c03_11_01barabas
+	sound_dialog_play_block pause
+	sound_dialog_play c03_11_02muro
+	cinematic_start (MUROtalking, 180, 180, 16, 3, 20, true)	
+	sound_dialog_play_block pause
+	sound_dialog_play c03_11_03barabas
+	sound_dialog_play_block pause
+	sound_dialog_play c03_11_04muro
+	sound_dialog_play_block pause
+	sound_dialog_play c03_11_05barabas
+	sound_dialog_play_block pause
+	sleep 30
+	cinematic_stop (BOSS1talking, 15, 20)
+	cinematic_stop (MUROtalking, 16, 20)
+	sleep 10
+	cm_reset
+	end_cutscene
+	ai2_takecontrol 0
+	chr_delete Barabus
+	set_objective_2
+	trigvolume_enable floor1 1
+	trigvolume_enable outside_left 1
+	trigvolume_enable outside_right 1
+	trigvolume_enable outside_back 1
+
+	target_set(143, 30.0)
+
+	sleep 180
+
+	sound_ambient_start c00_01_98shinatama
+
+#	dprint savegame_1	
+#	save_game 1
+}
+
+
+func void bomber(void)
+{
+	chr_animate Tower_MB_1 STRIKEknockdown1
+	chr_invincible Tower_MB_1 1
+	chr_unstoppable Tower_MB_1 1
+	dprint(ainame);
+	begin_cutscene
+	#input 0
+	#cm_jello 0		
+	#letterbox 1
+	#add dialogue "Help Konoko!  We're pinned down!!"
+	sleep f60
+	sound_dialog_play c03_12_02tctfag1
+	door_unlock 60
+	door_unlock 61
+	sleep 60
+	cm_interpolate BomberCam01 0
+	cm_interpolate_block BomberCam02 300
+	ai2_spawn BombComguy
+	ai2_setmovementmode BombComguy run
+	playback BombComguy COMGUYfiring
+	sleep 180
+	#sound_dialog_play
+	ai2_spawn BombTCTF1
+	ai2_spawn BombTCTF2
+	chr_create 1004 start
+	ai2_setmovementmode BombTCTF1 run
+	ai2_setmovementmode BombTCTF2 run
+	playback BombTCTF1 TCTFfiring01
+	playback BombTCTF2 TCTFfiring02
+	playback 1004 TCTFradio
+	playback BombComguy COMGUYfiring
+	chr_animate 1004 COMGUYtalk_radio 380
+	sound_dialog_play_block pause
+	# CB: this sound file no longer exists (it was a duplicate)
+	sound_dialog_play c03_12_12TCTFAG1
+
+	cinematic_start (TCTFshouting, 180, 180, 16, 3, 20, true)	
+	sound_dialog_play_block pause
+	#env_show 777 1
+	#env_show 778 0
+	cinematic_stop (TCTFshouting, 16, 20)
+	#back in the tower Bomber man staggers to his feet
+	playback 0 KonBomb
+	chr_envanim Tower_MB_1 BomberBox01 norotation
+	chr_animate Tower_MB_1 BOMBlev3_stagger
+	cm_interpolate BomberCam03 0
+	cm_interpolate_block BomberCam04 330
+	cinematic_start (KONtalkangryfront, 180, 180, 18, 6, 20, true)
+	sleep 40
+	sound_dialog_play c03_12_03konoko
+	sound_dialog_play_block pause
+	sleep 60
+	cinematic_stop (KONtalkangryfront, 17, 20)
+	chr_envanim_block Tower_MB_1 BomberBox02 norotation
+	chr_animate Tower_MB_1 BOMBlev3_stand 1200
+	cm_interpolate_block BomberCam05 0
+	cinematic_start (BOMBbeatup, 180, 180, 18, 4, 30, false)
+	sound_dialog_play c03_12_04bombgreen
+	sound_dialog_play_block pause
+	cinematic_stop (BOMBbeatup, 17, 30)
+	playback BombComguy COMGUYfiring
+	chr_envanim 0 KonBomBox01
+	chr_animate 0 KONOKOlev3_bomber
+	cm_interpolate BomberCam06 0
+	sleep 195
+	cm_anim both BomberCam07
+	chr_envanim Tower_MB_1 BomberBox03 norotation
+	sleep 110
+	chr_animate Tower_MB_1 BOMBlev3_fall1 100
+	sleep 13
+	#break tower glass here
+	#env_show 776 1
+
+	sound_impulse_play glass_big 1.0
+
+	env_show 777 1
+	env_show 778 0
+	particle BomberCharge01 do explode
+	cm_wait
+	cm_anim both BomberCam08
+	chr_envanim Tower_MB_1 BomberBox04 norotation
+	chr_animate Tower_MB_1 BOMBlev3_fall2
+	sleep 50
+	#break atrium glass here
+	particle BomberCharge02 do explode
+	sleep 105
+	#explode bomber here
+	particle BomberExplosion create
+	chr_delete BombComguy
+	cm_wait
+	sleep 60
+	playback 0 KonBomb02
+	cm_interpolate BomberCam09 0
+	cinematic_start (TCTFtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play c03_12_05tctfag1
+	sound_dialog_play_block pause
+	cinematic_stop (TCTFtalking, 20, 20)
+	# sounds of TCTF saying "uhhhh, we're not pinned down.
+	#cm_reset
+	#end_cutscene
+	set_objective_5
+	door_unlock 38
+	door_unlock 41
+	door_unlock 42
+	door_lock 60
+	door_lock 61
+	particle locktower_locklight01 do start
+	chr_delete BombTCTF1
+	chr_delete BombTCTF2
+	chr_delete BombComguy
+	chr_delete 1004
+	chr_delete Tower_MB_1
+	playback 0 BomberKonRun01
+	sleep 120
+	cm_interpolate BomberCamRun01 0
+	playback 0 BomberKonRun02
+	cm_interpolate_block BomberCamRun02 200
+	sleep 210
+	#begin_cutscene
+	sleep 30
+	chr_nocollision 0 1
+	cm_anim both ElevCam01
+	chr_envanim 0 ElevBox01
+	chr_animate 0 KONOKOidle1
+
+	sound_ambient_start rl_elevator 1.0
+
+	env_show 540 0 
+	cm_wait
+	end_cutscene
+	cm_reset
+	chr_nocollision 0 0
+	obj_create 2 7
+	sapper_damage_off
+#	save_game_3
+}
+
+
+func void fallinthevat(string char)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(char);
+
+  if (eggman eq 0)
+  {
+    chr_animate(char, KONOKOacid);
+    sleep 10
+    chr_set_health(char, 0);
+  }
+
+  if (eggman eq 1)
+  {
+    cm_detach
+
+    sound_impulse_play konoko_gruesome_death
+
+    chr_animate(char, KONOKOacid);
+    sleep 10
+    chr_set_health(char, 0);
+  }
+}
+
+func void outro(void)
+{
+	target_set(256, 0.0)
+	ai2_allpassive=1
+	#begin_cutscene
+	#ai2_takecontrol 1
+	#ai2_movetoflag 0 257
+	env_anim 2 7
+	sound_ambient_start truck_driveaway
+	#cm_interpolate OutroCam01 360
+	sound_dialog_play c03_13_01konoko
+	cinematic_start (KONintense, 180, 180, 19, 7, 15, true)
+	sound_dialog_play_block pause
+	cm_interpolate OutroCam01 200
+	sleep 30
+	cinematic_stop (KONintense, 19, 30)
+	begin_cutscene
+	ai2_takecontrol 1
+	ai2_movetoflag 0 257
+	#camera cut to van
+	sound_dialog_play c03_13_02synhench1
+	cinematic_start (COMGUYtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	sound_dialog_play c03_13_03muro
+	sleep 120
+	fade_out 0 0 0 60
+	cinematic_start (MUROtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (MUROtalking, 16, 15)
+	cinematic_stop (COMGUYtalking, 15, 15)
+	sleep 30
+	win
+}
Index: /nikanabo/current/bsl/original/IGMD/lab/lab_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/lab/lab_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/lab/lab_level_logic.bsl	(revision 185)
@@ -0,0 +1,898 @@
+################## RESEARCH LAB LEVEL LOGIC ##########################
+
+################ SCRIPTS BY Hardy AND Joseph #########################
+
+################# START, SAVE & OBJECTIVES ###########################
+
+
+# creates counterS for stuff
+
+var int door_counter=3;
+var int passage_counter=3;
+var int count_dead_end=2;
+
+func void turnoffcompass(string ai_name)
+{
+	target_set(143, 0.0)
+}
+
+func void level_start(string ai_name)
+{
+	dprint func_void_start
+
+	if (my_save_point eq 1)
+		{
+		dprint restore_game_1
+
+		set_objective_1
+
+		ai2_spawn Barabus
+
+		dprint SPAWN_BARABUS
+
+		ai2_attack Barabus konoko
+
+		env_show 10 1
+		env_show 9 1
+		env_show 8 1
+
+		#obj_kill 8 10
+
+		trigvolume_enable save_1_trig 0
+		trigvolume_enable floor1 0
+		trigvolume_enable outside_left 0
+		trigvolume_enable outside_right 0
+		trigvolume_enable outside_back 0
+
+		#chr_animate Barabus STRIKElev3_startle
+		#ai2_setmovementmode Barabus walk
+		#playback Barabus IntroSubboss01
+		playback 0 IntroKonoko01
+
+		sound_music_start mus_main01_hd	0.8
+
+		restore_game
+		}
+
+	if (my_save_point eq 2)
+		{
+		dprint restore_game_2
+
+		set_objective_2_from_save
+
+		dprint restore_game_2_a
+
+		door_lock 43
+
+		dprint restore_game_2_b
+
+		particle lock99_locklight01 do stop
+
+		dprint restore_game_2_c
+
+		spawn_floor1_guards
+
+		dprint restore_game_2_d
+
+		restore_game
+		cm_reset
+		}
+	
+	if (my_save_point eq 3)
+		{
+		dprint restore_game_3
+
+		spawn_lobby_tctf
+
+		trigvolume_enable save_3_trig 0
+
+		door_lock 35
+		dprint objective5
+		objective_set(5, silent)
+		target_set(142, 30.0)
+		
+		restore_game
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void save_game_1(string ai_name)
+{
+	dprint savegame_1	
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void save_game_2(string ai_name)
+{
+	dprint savegame_2
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void save_game_3(string ai_name)
+{
+	dprint savegame_3	
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+########### GAME OBJECTIVES ############################3
+
+func void set_objective_1(void)
+{
+	dprint objective_1
+	objective_set(1)
+}
+
+func void set_objective_2_from_save(void)
+{
+	objective_set(2)	
+}
+
+func void set_objective_2(string chr_index)
+{
+	sleep 180
+	dprint objective_2
+	objective_set(2)
+	particle lock99_locklight01 do start
+	door_unlock 43
+}
+
+func void set_objective_3(string chr_index)
+{
+	dprint objective_3
+	#sound_dialog_play_block c00_01_20shinatama
+	#sound_dialog_play_block pause
+	objective_set(3)
+	target_set(205, 30.0)
+}
+
+func void set_objective_4(string chr_index)
+{
+	dprint objective_4
+	sound_dialog_play_block c00_01_19shinatama
+	sound_dialog_play_block pause
+	objective_set(4)
+	target_set(110, 30.0)
+}
+
+func void set_objective_5(string chr_index)
+{
+	dprint objective_5
+	#sound_dialog_play_block c00_01_18shinatama
+	#sound_dialog_play_block pause
+	objective_set(5)
+	target_set(142, 30.0)
+}
+
+func void set_objective_6(string chr_index)
+{
+	dprint objective_6
+	sound_dialog_play_block c00_01_22shinatama
+	sound_dialog_play_block pause
+	objective_set(6)
+	target_set(256, 30.0)
+}
+
+func void set_target_4(string chr_index)
+{
+	sound_dialog_play_block c00_01_26shinatama
+	sound_dialog_play_block pause
+	target_set(253, 30.0)
+}
+
+func void set_target_5(string chr_index)
+{
+	sound_dialog_play_block c00_01_28shinatama
+	sound_dialog_play_block pause
+	target_set(254, 30.0)
+}
+
+func void set_target_6(string chr_index)
+{
+	target_set(256, 30.0)
+}
+
+
+### MARTY'S HUGE SACK ###
+
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+
+	if (0 ne music_counter) 
+	{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+	}
+}
+
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void striker_siesta_1(string ai_name)
+{
+	dprint striker_siesta1
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+
+}
+func void striker_siesta_2(string ai_name)
+{
+	dprint striker_siesta2
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+}
+
+func void all_music_counters(void)
+{
+	dprint WHEN_THE_LIGHTS_GO_DOWN_IN_THE_CITY
+	
+	sound_music_stop mus_trt
+#	sound_music_stop mus_fiteb
+#	sound_music_stop mus_asian
+}
+
+
+### TEXT CONSOLES ###
+
+func void level3a(string chr_index)
+{
+	dprint text3a
+	text_console level_3a
+	console_reset 7
+}
+
+func void level3b(string chr_index)
+{
+	dprint text3b
+	text_console level_3b
+	console_reset 6
+}
+
+func void level3c(string chr_index)
+{
+	dprint text3c
+	text_console level_3c
+	console_reset 1
+}
+
+func void level3d(string chr_index)
+{
+	dprint text3d
+	text_console level_3d
+	day_264
+}
+
+
+
+
+### GAMEPLAY PROGRESSION ###
+
+func void tower_lock_1(string chr_index)
+{
+	sound_music_stop mus_main03
+
+	ai2_spawn Tower_MB_1
+	trigvolume_enable towertrig_2 0
+	door_lock 41
+}
+
+func void sapper_damage_on(string chr_index)
+{
+	dprint sapper_dmg_start
+	particle sapper start
+}
+
+func void sapper_damage_off(string chr_index)
+{
+	dprint sapper_dmg_stop
+	particle sapper stop
+}
+
+func void spawn_floor1_guards(string ai_name)
+{
+	dprint spawn_floor1
+	particle lock1_locklight01 do stop
+	particle lockA_locklight01 do start
+	ai2_spawn Floor1_Striker_1
+	ai2_spawn Floor1_Striker_2
+	ai2_spawn Floor1_Sci_1
+	ai2_spawn Floor1_Sci_2
+	ai2_spawn Floor1_Sci_3
+	ai2_spawn Floor1_Sci_4
+
+	set_objective_3
+}
+
+func void spawn_right_patrol(string ai_name)
+{
+	dprint spawn_right_patrol
+	ai2_spawn right_patrol_striker_1
+}
+
+func void spawn_left_patrol(string ai_name)
+{
+	dprint spawn_right_patrol
+	ai2_spawn left_patrol_striker_1
+}
+
+func void spawn_back_patrol(string ai_name)
+{
+	dprint spawn_right_patrol
+	ai2_spawn back_patrol_striker_1
+	ai2_spawn back_patrol_striker_2
+}
+
+func void spawn_floor1_striker_10(string ai_name)
+{
+	dprint spawn_ambush_striker_10
+#	trig_activate 1
+	ai2_spawn Floor1_Striker_10
+	ai2_spawn Floor1_Striker_12
+}
+
+func void spawn_floor1_striker_11(string ai_name)
+{
+	dprint spawn_ambush_striker_11
+#	trig_activate 1
+	ai2_spawn Floor1_Striker_11
+	ai2_spawn Floor1_Striker_12
+}
+
+func void fake_console(string ai_name)
+{
+	sleep 180
+	dprint fake_console
+
+	door_unlock 2
+	door_unlock 9
+	door_unlock 12
+	door_unlock 15
+	door_unlock 18
+	door_unlock 21
+	door_unlock 24
+	door_unlock 27
+
+	particle lock2_locklight01 do start
+}
+
+func void spawn_floor2_guards(string ai_name)
+{
+	dprint spawn_floor2
+
+	particle lock2_locklight01 do stop
+
+	ai2_spawn Floor2_Striker_2
+	ai2_spawn Floor2_Striker_3
+	ai2_spawn Floor2_Striker_4
+
+	sleep 15
+
+	ai2_spawn Floor2_Striker_1
+	ai2_doalarm Floor2_Striker_1 3
+
+	sleep 15
+
+	ai2_spawn Floor2_Sci_1
+	ai2_spawn Floor2_Sci_2
+	ai2_spawn Floor2_Sci_3
+	ai2_spawn Floor2_Sci_4
+	ai2_spawn Floor2_Sci_5
+
+	trigvolume_enable attack_trigger 0
+}
+
+func void commence_attack(string ai_name)
+{
+	dprint commence_attack
+
+	ai2_setalert Floor2_Striker_2 high
+	ai2_setalert Floor2_Striker_3 high
+	ai2_setalert Floor2_Striker_4 high
+
+	ai2_dopath Floor2_Striker_1 Floor2_Stk_1
+	ai2_dopath Floor2_Striker_2 scram_path
+	ai2_dopath Floor2_Striker_3 attack_path_1
+	ai2_dopath Floor2_Striker_4 attack_path_2
+
+	ai2_setjobstate Floor2_Striker_1
+	ai2_setjobstate Floor2_Striker_2
+	ai2_setjobstate Floor2_Striker_3
+	ai2_setjobstate Floor2_Striker_4
+
+	ai2_attack Floor2_Striker_4 Floor2_Sci_4
+	ai2_attack Floor2_Striker_3 Floor2_Sci_1
+}
+
+func void death_sentence_1(string ai_name)
+{
+	dprint death_sentence_1
+	ai2_attack Floor2_Striker_4 Floor2_Sci_5
+}
+
+func void death_sentence_2(string ai_name)
+{
+	dprint death_sentence_2
+	ai2_attack Floor2_Striker_3 Floor2_Sci_2
+}
+
+func void death_sentence_3(string ai_name)
+{
+	dprint death_sentence_2
+	ai2_attack Floor2_Striker_3 Floor2_Sci_3
+}
+
+func void spawn_floor3_guards(string ai_name)
+{
+	dprint spawn_floor3
+
+	ai2_spawn Floor3_Striker_1
+	ai2_spawn Floor3_Striker_2
+	ai2_spawn Floor3_Striker_3
+	ai2_spawn Floor3_Striker_4
+
+	ai2_spawn Floor3_Comguy_1
+	
+	particle lock3_locklight01 do stop
+}
+
+func void spawn_roof_guards(string ai_name)
+{
+	dprint spawn_roof_guards
+
+	ai2_spawn Roof_Striker_1
+	ai2_spawn Roof_Striker_2
+	ai2_spawn Roof_Striker_3
+
+#	particle lock3_locklight01 do start
+}
+
+func void roof_surprise(string ai_name)
+{
+	dprint roof_surprise
+	ai2_dopath Roof_Striker_3 Roof_Striker_3b
+	ai2_setjobstate	Roof_Striker_3
+}
+
+func void spawn_tower_guards(string ai_name)
+{
+	dprint spawn_tower_guards
+
+	ai2_spawn Tower_Striker_1
+	ai2_spawn Tower_Striker_2
+#	particle lock3_locklight01 do start
+}
+
+func void spawn_lobby_tctf(string ai_name)
+{
+	dprint spawn_lobby_guards
+	ai2_spawn Lobby_TCL_1
+	ai2_spawn Lobby_TCL_2
+	ai2_spawn Lobby_TCS_1
+
+#	particle lock3_locklight01 do start
+}
+
+func void spawn_lobby_synd(string ai_name)
+{
+	dprint spawn_lobby_attackers
+
+	sleep 600
+
+	ai2_spawn Lobby_Striker_1
+	ai2_spawn Lobby_Striker_2
+	ai2_spawn Lobby_Striker_3
+	ai2_spawn Lobby_Striker_4
+
+	door_lock 35
+
+#	particle lock3_locklight01 do start
+}
+
+func void spawn_lively_1(string ai_name)
+{
+	dprint spawn_lively_1
+
+	ai2_spawn lively_striker_1
+}
+
+func void spawn_lively_2(string ai_name)
+{
+	dprint spawn_lively_2
+
+	ai2_spawn lively_striker_2
+}
+
+func void spawn_lively_3(string ai_name)
+{
+	dprint spawn_lively_3
+
+	ai2_spawn lively_striker_3
+	ai2_spawn lively_striker_4
+}
+
+func void spawn_opposite_striker_1(string ai_name)
+{
+	dprint spawn_opposite_1
+
+	ai2_spawn opposite_striker_1
+	trigvolume_enable spawn_opposite_2 0
+}
+
+func void spawn_opposite_striker_2(string ai_name)
+{
+	dprint spawn_opposite_2
+
+	ai2_spawn opposite_striker_2
+	trigvolume_enable spawn_opposite_1 0
+}
+
+func void backdoor(string ai_name)
+{
+	dprint spawn_backdoor_squad
+
+	ai2_spawn backdoor_striker_1
+	ai2_spawn backdoor_striker_3
+}
+
+func void spawn_vats(string ai_name)
+{
+	dprint spawn_vats
+
+	ai2_spawn Vat_Striker_1
+	ai2_spawn Vat_Striker_2
+	ai2_spawn Vat_Striker_3
+	ai2_spawn Vat_Striker_4
+	ai2_spawn Vat_Striker_5
+
+	particle lock4_locklight01 do stop
+	trigvolume_enable final_ambush 0
+	trigvolume_enable outro_volume_1 0
+	door_lock 49
+	door_lock 50
+}
+
+func void gethelp(string ai_name)
+{
+	trigvolume_enable outro_volume_1 1
+	sleep 120
+	door_unlock 49
+	door_unlock 50
+	ai2_attack Ambush_Striker_2 Konoko
+	particle lock177_locklight01 do start
+	sound_music_stop mus_main03
+}
+
+func void final_ambush(string ai_name)
+{
+	dprint spawn_final_ambush
+	ai2_spawn Ambush_Striker_1
+	ai2_spawn Ambush_Striker_2
+}
+
+func void unlock_floor1_doors(string ai_name)
+{
+	dprint unlock_floor1_doors
+
+	trigvolume_enable trigger_volume_10 0
+
+	door_unlock 3
+	door_unlock 8
+	door_unlock 11
+	door_unlock 14
+	door_unlock 17
+	door_unlock 20
+	door_unlock 23
+	door_unlock 26
+
+	if(trigvolume_count(36) eq 0)
+		{
+		input 0
+#		begin_cutscene
+		cm_interpolate lock1 0
+		sleep 60
+		particle lock1_locklight01 do start
+		sleep 150
+		cm_interpolate tophint 0
+		sleep 60
+		particle lock4a_locklight01 do start
+		sleep 150
+		cm_reset
+		end_cutscene
+		input 1
+		cm_reset
+#		end_cutscene
+		input 1
+		}
+
+	particle lock1_locklight01 do start
+	particle lock4a_locklight01 do start
+
+	door_counter = door_counter - 1
+	if (door_counter eq 0)
+		{
+		unlock_roof();
+		}
+}
+
+func void unlock_floor2_doors(string ai_name)
+{
+	dprint unlock_floor2_doors
+
+	trigvolume_enable attack_trigger 1
+
+	door_unlock 2
+	door_unlock 9
+	door_unlock 12
+	door_unlock 15
+	door_unlock 18
+	door_unlock 21
+	door_unlock 24
+	door_unlock 27
+
+	if(trigvolume_count(37) eq 0)
+		{
+		input 0
+#		begin_cutscene
+		cm_interpolate lock2 0
+		sleep 60
+		particle lock2_locklight01 do start
+		sleep 150
+		cm_interpolate tophint 0
+		sleep 60
+		particle lock4b_locklight01 do start
+		sleep 150
+		cm_reset
+		end_cutscene
+		input 1
+		cm_reset
+#		end_cutscene
+		input 1
+		}
+
+	particle lock2_locklight01 do start
+	particle lock4b_locklight01 do start
+
+	door_counter = door_counter - 1
+	if (door_counter eq 0)
+		{
+		unlock_roof();
+		}
+
+	sleep 60
+
+	ai2_dopath Floor2_Striker_1 Floor2_Stk_1
+	ai2_setjobstate	Floor2_Striker_1
+}
+
+func void unlock_floor3_doors(string ai_name)
+{
+	dprint unlock_floor3_doors
+
+	door_unlock 28
+	door_unlock 22
+	door_unlock 16
+	door_unlock 1
+	door_unlock 10
+	door_unlock 13
+	door_unlock 19
+	door_unlock 25
+
+	if(trigvolume_count(37) eq 0)
+		{
+		input 0
+#		begin_cutscene
+		cm_interpolate lock3 0
+		sleep 60
+		particle lock3_locklight01 do start
+		sleep 150
+		cm_interpolate tophint 0
+		sleep 60
+		particle lock4c_locklight01 do start
+		sleep 150
+		cm_reset
+#		end_cutscene
+		input 1
+		}
+
+	particle lock3_locklight01 do start
+	particle lock4c_locklight01 do start
+
+	door_counter = door_counter - 1
+	if (door_counter eq 0)
+		{
+		unlock_roof();
+		}
+}
+
+func void unlock_roof(string ai_name)
+{
+	dprint unlock_roof
+	door_unlock 4
+	spawn_roof_guards
+	door_unlock 56
+
+	sound_music_start mus_main03	
+}
+
+func void passage_1(string ai_name)
+{
+	dprint unlock_floor1_doors
+
+	input 0
+	cm_interpolate passage 0
+	sleep 60
+	particle lock69a_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	passage_counter = passage_counter - 1
+	if (passage_counter eq 0)
+		{
+		unlock_passage();
+		}
+}
+
+func void passage_2(string ai_name)
+{
+	dprint unlock_floor1_doors
+
+	input 0
+	cm_interpolate passage 0
+	sleep 60
+	particle lock69b_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	passage_counter = passage_counter - 1
+	if (passage_counter eq 0)
+		{
+		unlock_passage();
+		}
+}
+
+func void passage_3(string ai_name)
+{
+	dprint unlock_floor1_doors
+
+	input 0
+	cm_interpolate passage 0
+	sleep 60
+	particle lock69c_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	passage_counter = passage_counter - 1
+	if (passage_counter eq 0)
+		{
+		unlock_passage();
+		}
+}
+
+func void unlock_passage(string ai_name)
+{
+	dprint unlock_passage
+
+	sound_music_start mus_main03 1.0
+
+	door_unlock 48
+	#target_set(256, 0.0)
+}
+
+func void unlock_end_door(string ai_name)
+{
+	dprint unlock_end_door
+
+	door_unlock 56
+
+	trigvolume_enable final_ambush 1
+
+	input 0
+	cm_interpolate lock5 0
+	sleep 60
+	particle lockend_locklight02 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	target_set(52, 30.0)
+	sleep 30
+	ai2_spawn Vat_MB_1
+}
+
+
+func void Lobby_Hurt_TCL_1(string ai_name)
+{
+	dprint Hurt_TCL_1
+	ai2_dopath Lobby_TCL_1 Lobby_Hurt_TCL_1
+}
+
+
+func void Lobby_Hurt_TCL_2(string ai_name)
+{
+	dprint Hurt_TCL_2
+
+	sleep 120
+
+	ai2_dopath Lobby_TCL_2 Lobby_Hurt_TCL_2
+}
+
+
+### MISE EN SCENE ###
+
+
+func void miseenscene_start(string ai_name)
+{
+	dprint scene_start
+	particle scene create
+
+	ai2_spawn scene_thug_1
+	ai2_spawn scene_thug_2
+}
+
+func void miseenscene_stop(string ai_name)
+{
+	dprint scene_stop
+	particle scene kill
+}
+
+func void day_264(string ai_name)
+{
+	dprint day264
+	
+	sleep 150
+	particle day264 create
+	particle dayafter create
+	particle dayafter start
+
+	ai2_dopath scene_thug_1 scene_flee_1 1
+	ai2_dopath scene_thug_2 scene_flee_2 1
+
+	sleep 300
+	ai2_spawn arcy
+	
+	sleep 1000
+	chr_delete scene_thug_1
+	chr_delete scene_thug_2
+
+	sleep 500
+	chr_delete arcy
+}
Index: /nikanabo/current/bsl/original/IGMD/lab/lab_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/lab/lab_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/lab/lab_main.bsl	(revision 185)
@@ -0,0 +1,39 @@
+#
+# lab_main.bsl
+#
+
+
+var int my_save_point;
+
+func void main(void)
+{
+	trigvolume_enable save_1_trig 0
+	env_show 776 0
+	env_show 777 0
+	gl_fog_blue=.15
+	gl_fog_red=.30
+	gl_fog_green=.17
+	gl_fog_start=.99
+	gs_farclipplane_set 5000
+
+	obj_create 2 7
+
+	my_save_point = save_point;
+
+	level_start
+
+	if (my_save_point eq 0)
+	{
+		trigvolume_enable outside_left 0
+		trigvolume_enable outside_right 0
+		trigvolume_enable outside_back 0
+
+		intro
+	}
+}
+
+func void chase1(void)
+{
+}
+
+
Index: /nikanabo/current/bsl/original/IGMD/lab/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/lab/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/lab/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,10 @@
+func void splash(string ai_name)
+{
+	dprint we_entered_splash
+	chr_animate ai_0 KONOKOacid
+}
+func void entry(string character)
+{
+	dprint EWW_GROSS
+	particle bug pulse
+}
Index: /nikanabo/current/bsl/original/IGMD/manplant/manplant_anim_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/manplant/manplant_anim_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/manplant/manplant_anim_scripts.bsl	(revision 185)
@@ -0,0 +1,39 @@
+#
+# anim_scripts.bsl
+#
+
+func void patrolscript0001 (string ai_name)
+{
+	playback_block Pod1_TCL_1 alarm1 interp 20
+}
+func void patrolscript0002 (string ai_name)
+{
+	playback_block Pod1_TCL_2 alarm2 interp 20
+}
+func void patrolscript0003 (string ai_name)
+{
+	playback_block Pod2_TCL_1 pod2alarm1 interp 20
+}
+func void patrolscript0004 (string ai_name)
+{
+	playback_block Pod2_TCL_2 pod2alarm2 interp 20
+}
+
+
+func void patrolscript0009 (string ai_name)
+{
+	particle lock99_locklight01 do start
+	door_unlock 11
+	sleep 540
+	particle lock99_locklight01 do stop
+	door_lock 11
+}
+func void patrolscript0010 (string ai_name)
+{
+	particle lock99_locklight01 do start
+	door_unlock 11
+# WAIT AND RELOCK DOORS
+	sleep 540
+	particle lock99_locklight01 do stop
+	door_lock 11
+}
Index: /nikanabo/current/bsl/original/IGMD/manplant/manplant_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/manplant/manplant_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/manplant/manplant_cutscene.bsl	(revision 185)
@@ -0,0 +1,411 @@
+#
+# manplant_cutscene.bsl
+#
+
+func void
+manplant_cs_intro(void)
+{
+
+}
+
+
+func void intro(void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate Camout01 0
+	env_show 561 0
+	sleep f14
+	begin_cutscene
+	sleep f30
+	#Outside shot of cops walking in
+	ai2_spawn Recep
+	ai2_spawn partner_cop_1
+	ai2_spawn partner_cop_2
+	playback 0 IntroKonoko01
+	playback partner_cop_1 IntroCop01
+	playback partner_cop_2 IntroCop02
+	#cm_interpolate Camout01 0
+	
+	sound_music_start mus_ambgrv1b 0.90
+	#music_script_start();
+
+	fade_in 120
+
+	sleep f240
+	#cops enter building, shot behind the receptionist
+	cm_anim both Camin02
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_prehello 540
+	chr_lock_active Recep
+	chr_lock_active partner_cop_1
+	chr_lock_active partner_cop_2
+	#receptionist looks up and Cop introduces himself
+	cm_interpolate_block Camin03 0
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_prehello 120
+	chr_animate_block Recep SECRETsit_hello 90
+
+	sound_music_volume mus_ambgrv1b 0.6 1
+
+	chr_animate_block Recep SECRETsit_talk 600
+	chr_envanim Recep IntroSecBox01 norotation
+
+	sound_dialog_play c01_04_01receptionist
+	cinematic_start (RECEPtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (RECEPtalking, 20, 20)
+	cinematic_start (TCTFtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play c01_04_02tctfag1
+	chr_envanim Recep IntroSecBox01 norotation
+	#Konoko interrupts Cop guy
+	playback 0 IntroKonokoInt
+	sleep f100
+	#sound_dialog_play_block pause
+	chr_envanim Recep IntroSecBox01 norotation
+	cm_interpolate IntroCamInterrupt 0
+	cinematic_start (KONpsychedup, 180, 180, 20, 7, 20, false)
+	playback partner_cop_1 IntroCopInt
+	sound_dialog_play_interrupt c01_04_03konoko
+	cinematic_stop (TCTFtalking, 19, 20)
+	sound_dialog_play_block pause
+	cinematic_stop (KONpsychedup, 19, 20)
+	#Receptionis says ok officer
+	cm_interpolate Camin03 0
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_talk 400
+	sleep f30
+	cinematic_start (RECEPtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play c01_04_04receptionist
+	sleep f90
+	#Receptionis hits alarm
+	cm_anim both IntroCamAlarm
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_alarm 400
+	sleep f110
+	particle IntroLight01 create
+	particle IntroLight01 do start
+	cinematic_stop (RECEPtalking, 20, 20)
+	#Bad guys see alarm is hit
+	cm_wait
+	chr_create 1050 start
+	ai2_spawn Barabus
+	chr_neutral 1050 1
+	#chr_neutral 1051 1
+	playback 1050 IntroMuroSet
+	playback Barabus IntroBossSet
+	cm_interpolate IntroCamBadGuys00 0
+
+	sound_ambient_start alarm_loop
+
+	cm_interpolate_block IntroCamBadGuys01 240
+	sleep f120
+	cinematic_start (BOSS1nametag, 180, 180, 16, 3, 20, false)
+	sound_dialog_play c02_05_01barabas
+
+	sound_ambient_volume alarm_loop .35 1.0
+	
+	sound_dialog_play_block pause
+	#Muro turns to Bossman
+	playback 1050 IntroMuro01
+	cm_interpolate IntroCamMuro01 0
+	cinematic_start (MUROnametag, 180, 180, 15, 1, 20, false)	
+	sound_dialog_play c02_05_02muro
+	sound_dialog_play_block pause
+	#Bossman and Muro talk
+	cm_interpolate IntroCamBothLt 0
+	cm_interpolate_block IntroCamBothRt 500
+	sound_dialog_play c02_05_03barabas
+	sound_dialog_play_block pause
+	sound_dialog_play c02_05_04muro
+	sound_dialog_play_block pause
+	sound_dialog_play c02_05_05barabas
+	sound_dialog_play_block pause
+	#Muro talks
+	cm_interpolate IntroCamMuro02 0
+
+	sound_ambient_volume alarm_loop 0.0 1.0
+	sound_ambient_stop alarm_loop
+
+	sound_dialog_play c02_05_06muro
+	sound_dialog_play_block pause
+	#Bossman and Muro talk
+	cm_interpolate IntroCamBothRtHigh 0
+	cm_interpolate_block IntroCamBothLtHigh 500
+	sound_dialog_play c02_05_07muro
+	sound_dialog_play_block pause
+	sound_dialog_play c02_05_08barabas
+	sound_dialog_play_block pause
+	sound_dialog_play c02_05_09muro
+	sound_dialog_play_block pause
+	sound_dialog_play c02_05_10barabas
+	sound_dialog_play_block pause
+	#Muro talks
+	cm_interpolate IntroCamMuro01 0
+	sound_dialog_play c02_05_11muro
+	sound_dialog_play_block pause
+	cinematic_stop (MUROnametag, 15,20)
+	cinematic_stop (BOSS1nametag, 16,20)
+	#Receptionist says hold on
+	cm_interpolate Camin03 0
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_unalarm 180
+	chr_animate_block Recep SECRETsit_talk 500
+	sound_dialog_play c02_05_12receptionist
+	cinematic_start (RECEPtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (RECEPtalking, 20,20)
+	#Strikers Rush in
+
+	sound_ambient_volume mus_ambgrv1b 0 .5
+
+	music_script_start();
+
+	ai2_spawn ambush_striker_3
+	ai2_spawn ambush_striker_2
+	#chr_neutral ambush_striker_3 1
+	#chr_neutral ambush_striker_2 1
+	
+	door_open 21
+	door_jam 21
+
+	playback ambush_striker_3 IntroStrikerRight01
+	playback ambush_striker_2 IntroStrikerRight02
+	cm_interpolate IntroCamDoorRight01 0
+	sleep f180
+	#Cop says what the?
+	playback partner_cop_2 IntroCop02Surprise
+	chr_envanim 1003 IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_talk 400
+	cm_interpolate IntroCamSurprise 0
+	cm_interpolate_block IntroCamSurprise02 90
+	sound_dialog_play c02_05_13tctfag1
+	ai2_spawn ambush_striker_1
+	#chr_neutral ambush_striker_1 1
+
+	door_unlock 4
+	door_open 4
+	door_jam 4
+	
+	playback ambush_striker_1 IntroStrikerLeft01
+	sleep f60
+	#Konoko looks around
+	chr_envanim Recep IntroSecBox01 norotation
+	chr_animate Recep SECRETsit_talk 180
+	cm_reset
+	playback 0 IntroKonokoLook
+	sleep f30
+	cinematic_start (KONangryfront, 180, 180, 20, 7, 10, false)
+	sleep f170
+	#Konoko says we got company
+	playback Recep IntroRecepRun
+	cm_interpolate IntroCamCompany 0
+	sound_dialog_play c02_05_14konoko
+	sleep f30
+	playback Recep IntroRecepRun
+	sound_dialog_play_block pause
+	cinematic_stop (KONangryfront, 19 ,20)
+	#gameplay resumes
+	cm_reset
+	env_show 561 1
+	env_show 560 0
+	end_cutscene
+
+	ai2_attack partner_cop_1 ambush_striker_1
+	ai2_attack partner_cop_2 ambush_striker_3
+
+	chr_delete 1050
+	chr_delete Barabus
+	particle IntroLight01 kill
+	sleep f90
+	#chr_delete Recep
+	
+	door_lock 1
+	door_unjam 4
+	door_lock 4
+	door_unjam 21
+	set_objective_1
+	
+	save_point_1
+}
+
+func void
+Chase(
+	void)
+{
+	sleep 60
+	begin_cutscene jello
+#	sleep f10
+#	cm_orbit .1
+	sleep f30
+	chr_animate 0 KONOKOwatch_start 60
+	sleep f40
+	cinematic_start (KONtalking, 180, 180, 15, 1, 20, false)
+	cinematic_start (GRIFtalking, 180, 180, 16, 3, 20, true)
+	sleep f19
+	chr_animate 0 KONOKOwatch_idle 3000
+
+	sound_music_volume atm_low_perc1 0.35 1.0
+
+	sound_dialog_play c02_06_01konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_02griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_03konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_04griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_05konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_06griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_06_07konoko
+	sound_dialog_play_block pause
+	cinematic_stop (KONtalking, 15,20)
+	cinematic_stop (GRIFtalking, 16,20)
+	chr_animate 0 KONOKOwatch_stop
+	sleep f15
+	cm_reset
+	end_cutscene
+
+	sound_music_volume atm_low_perc1 .90 1.0
+	
+	striker_counter = striker_counter + 2
+	particle save1b_locklight01 do start
+	door_unlock 11
+	console_deactivate 15
+	
+	if (alarm_counter eq 1)		
+		{
+		ai2_spawn hall_striker_2
+		ai2_tripalarm konoko 1
+		}
+}
+
+
+func void
+Griffin_1(
+	void)
+{
+	begin_cutscene jello
+	sound_ambient_stop alarm_loop
+	sleep f30
+	chr_animate 0 KONOKOwatch_start 60
+	sleep 40
+	cinematic_start (KONtalking, 180, 180, 15, 1, 20, false)
+	cinematic_start (GRIFtalking, 180, 180, 16, 3, 20, true)
+	sleep f19
+	chr_animate 0 KONOKOwatch_idle 3000
+	sound_dialog_play c02_07_01griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_07_02konoko
+	sound_dialog_play_block pause
+	chr_animate 0 KONOKOwatch_stop
+	cinematic_stop (KONtalking, 15,20)
+	cinematic_stop (GRIFtalking, 16,20)
+	sleep f15
+	cm_reset
+	end_cutscene
+}
+
+
+func void
+outro(
+	void)
+{
+	begin_cutscene
+	env_show 555 1
+	env_show 556 0
+	#Konok talks on watch radio to Griffin
+	#playback 0 OutroKonokoSet
+	##cm_interpolate OutroCam00 0
+	##cm_interpolate_block OutroCam01 180
+	fork soundplay
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_end=.999
+	gl_fog_start_changeto 0.92 60
+	sleep f60
+	sleep f30
+	playback 0 OutroKonokoRun
+	cm_interpolate OutroCam00 0
+	cm_interpolate_block OutroCam01 180
+	sleep f120
+	#Konoko jumps out of room
+	playback 0 OutroKonoko01
+	cm_interpolate OutroCam02 0
+	sleep f60
+	#cm_interpolate_block OutroCam03 180
+	sleep f40
+	particle OutroCharge do explode
+	sleep f200
+	#Konoko runs out of room
+	playback 0 OutroKonoko02
+	door_open 4
+	door_jam 4
+	cm_interpolate OutroCam04 0
+	sleep f90
+	cm_interpolate_block OutroCam05 180
+	sleep f180
+	#Konoko runs out of front door
+	cm_interpolate OutroCam06 0
+	cm_interpolate_block OutroCam07 180
+	sleep f100
+	door_open 1
+	door_jam 1
+	sleep f140
+	fade_out 0 0 0 120
+	#win
+}
+
+func void
+soundplay(
+	void)
+{
+	cinematic_start (GRIFtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play c02_09_01griffin
+	sleep f60
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_02kerr
+	cinematic_start (KERRtalking, 180, 180, 16, 3, 20, true)	
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_03griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_04kerr
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_05griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_06kerr
+	sound_dialog_play_block pause
+	sound_dialog_play c02_09_07griffin
+	sound_dialog_play_block pause
+	cinematic_stop (KERRtalking, 16,20)
+	cinematic_stop (GRIFtalking, 15,20)
+	sleep f100
+	gl_fog_end=1
+	gl_fog_start=.975
+	win
+}
+
+
+
+func void
+animate(
+	void)
+{
+	env_anim 1101 1
+	env_anim 1102 1
+	env_anim 1103 1
+	env_anim 1104 1
+	env_anim 1105 1
+	env_anim 1106 1
+	env_anim 1107 1
+	env_anim 1108 1
+	env_anim 1109 1
+	env_anim 1110 1
+	env_anim 1111 1
+	env_anim 1201 1
+	env_anim 1202 1
+	env_anim 1203 1
+	env_anim 1204 1
+}
Index: /nikanabo/current/bsl/original/IGMD/manplant/manplant_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/manplant/manplant_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/manplant/manplant_level_logic.bsl	(revision 185)
@@ -0,0 +1,1091 @@
+### MANPLANT LEVEL LOGIC###
+
+# START, SAVE & OBJECTIVES
+
+func void func_start(string ai_name)
+{
+	dprint start_active	
+	particle lock_1_locklight01 do start
+	particle guardroom_2_locklight01 do start
+	particle foyer_right_locklight01 do start
+	particle brainlock_2_locklight01 do start
+	chr_forceholster 0 1
+	trig_hide 205	
+	trig_hide 204
+	trig_hide 2042	
+	trig_hide 203
+	trig_hide 2032		
+	trig_hide 202
+	trig_hide 2022
+	trig_hide 2023
+	trig_hide 201	
+	trig_hide 2012
+	trig_hide 2013
+	particle febtober1_locklight01 do start
+	particle save1a_locklight01 do start
+
+	if (save_point eq 0)
+		{
+		my_save_point=0;	
+		particle vent03 start
+		}
+	
+	if (save_point eq 1)
+		{
+		my_save_point=1;	
+		particle vent03 start
+		ai2_spawn partner_cop_1
+		ai2_spawn partner_cop_2
+		ai2_spawn ambush_striker_1
+		ai2_spawn ambush_striker_2
+		ai2_spawn ambush_striker_3
+		chr_delete Recep
+		door_lock 1
+		door_lock 4
+		restore_game
+		ai2_attack partner_cop_1 ambush_striker_1
+		ai2_attack partner_cop_2 ambush_striker_3
+		music_script_start();
+		sleep 30
+		set_objective_1
+		}
+
+	if (save_point eq 2)
+		{
+		my_save_point=2;	
+		dprint restore2_active
+		door_lock 1
+		door_lock 4
+		door_lock 11
+		door_lock 12
+		door_lock 13
+		door_unlock 3
+		door_unlock 19
+		trigvolume_enable nook_1 0
+		trigvolume_enable nookright 0
+		trigvolume_enable tech_1 0
+		trigvolume_enable bait_1 0
+		trigvolume_enable tech_ambush_1 0
+		chr_delete Recep
+		chr_delete extra_thug_1
+		ai2_spawn hall_striker_1
+		console_deactivate 1
+		console_deactivate 9
+		particle lock_1b_locklight01 do start
+		particle lock_1a_locklight01 do start
+		particle save1b_locklight01 do stop
+		particle febtober1_locklight01 do start
+		particle vent01 start
+		particle vent03 start
+		restore_game
+		sound_music_start atm_low_perc1 0.90
+		sleep 30
+		set_objective_1
+		target_set (123,30)
+		}
+
+	if (save_point eq 3)
+		{
+		my_save_point=3;	
+		dprint restore3_active
+		door_lock 1
+		door_lock 12
+		door_lock 13
+		door_lock 25
+		door_unlock 19
+		door_unlock 3
+		trigvolume_enable nook_1 0
+		trigvolume_enable nookright 0
+		trigvolume_enable tech_1 0
+		trigvolume_enable bait_1 0
+		trigvolume_enable Griffin 0
+		trigvolume_enable lowthug_1 0
+		trigvolume_reset febtober
+		trigvolume_reset febtober2
+		chr_delete Recep
+		console_deactivate 10
+		particle lock_1b_locklight01 do start
+		particle lock_1a_locklight01 do start
+		particle vent01 start
+		particle vent03 start
+		ai2_spawn low_thug_1
+		ai2_spawn low_thug_2
+		restore_game
+		sleep 30
+		set_objective_3
+		}
+
+	if (save_point eq 4)
+		{
+		dprint save_point_4
+		my_save_point=4;	
+		dprint restore4_active
+		particle brainlock_2_locklight01 do stop
+		particle brainlock_3_locklight01 do start
+		door_lock 26
+		door_unlock 27
+		trigvolume_reset lockit 
+		trigvolume_enable save_point4 0
+		brain_counter
+		trig_show 202
+		trig_show 204
+		trig_speed 202 .2
+		trig_speed 204 .2
+		trig_hide 2023
+		trig_hide 2013
+		particle brain start
+		particle brain1 start
+		restore_game
+		sound_ambient_start deadlybrain_sound 0.75
+		sleep 30
+		set_objective_4	
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	win
+}
+
+func void save_point_1(string player_name)
+{
+	dprint save_point_1_active
+	save_game 1 autosave
+}
+
+func void save_point_2(string player_name)
+{
+	dprint save_point_2_active
+	save_game 2 autosave
+}
+
+func void save_point_3(string player_name)
+{
+	dprint save_point_3_active
+	save_game 3
+	door_lock 25 autosave
+}
+
+func void save_point_4(string player_name)
+{
+	dprint save_point_4_active
+	save_game(4, autosave); 
+	particle(brainlock_2_locklight01, do, stop);
+	particle(brainlock_3_locklight01, do, start);
+	door_lock(26);
+	door_unlock(27);
+	particle vent01 kill
+	particle vent02 kill
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective1
+	objective_set(1)
+	target_set (38,30)
+	sound_dialog_play c00_01_22shinatama
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective2
+	objective_set(2)
+	target_set (128,30)
+	sound_dialog_play c00_01_26shinatama
+}
+
+func void set_target(string ai_name)
+{
+	dprint new_target
+	target_set (124,30)
+	sound_dialog_play c00_01_27shinatama
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective3
+	objective_set(3)
+	target_set (125,30)
+	trigvolume_enable Griffin 0
+	sound_dialog_play c00_01_18shinatama
+}
+
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective4
+	objective_set(4)
+	sound_dialog_play c00_01_20shinatama
+}
+
+### MUSIC ###
+
+var int music_counter=3;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+
+	if (0 ne music_counter) 
+	{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+	}
+}
+
+func void music_script_start(void)
+{
+	sound_music_start mus_fiteb_hd 0.75
+	music_counter=3;
+}
+
+func void striker_lullaby_1(string ai_name)
+{
+	dprint striker_lullaby1
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+
+}
+
+func void striker_lullaby_2(string ai_name)
+{
+	dprint striker_lullaby2
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+}
+
+func void striker_lullaby_3(string ai_name)
+{
+	dprint striker_lullaby3
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+}
+
+
+func void all_music_counters(void)
+{
+	dprint ELVIS_HAS_LEFT_THE_BUILDING
+	sound_music_stop mus_ambgrv1b
+	sound_music_stop mus_fiteb_hd
+	sound_music_stop atm_low_perc1
+	sound_music_stop atm_cl12
+	sound_music_stop atm_cl11
+	sound_music_stop mus_sv
+}
+
+# SCRAMBLE SOUND ON
+func void scramble_sound_on(void)
+{
+	dprint scramble_sound_start
+	sound_music_start atm_cl12 0.75
+}
+
+# SCRAMBLE SOUND OFF
+func void scramble_sound_off(void)
+{
+	dprint scramble_sound_end
+	sound_music_stop atm_cl12
+}
+
+### TEXT CONSOLES ###
+
+func void level2a(string chr_index)
+{
+	dprint text2a
+	text_console level_2a
+	console_reset 2
+}
+
+func void level2b(string chr_index)
+{
+	dprint text2b
+	text_console level_2b
+	console_reset 12
+}
+
+func void level2c(string chr_index)
+{
+	dprint text2c
+	text_console level_2c
+	console_reset 13
+}
+
+func void level2d(string chr_index)
+{
+	dprint text2d
+	text_console level_2d
+	console_reset 14
+}
+
+func void level2e(string chr_index)
+{
+	dprint text2e
+	text_console level_2e
+	console_reset 11
+}
+
+### GAMEPLAY PROGRESSION ###
+
+# FIRST ROOM GUARDS
+func void tech_1(string ai_name)
+{
+
+	dprint trigger_tech_1_active
+	ai2_spawn tech_thug_1
+	ai2_spawn tech_thug_1a
+	ai2_dopath partner_cop_1 cop_backup_1a 1
+	ai2_dopath partner_cop_2 cop_backup_1b 1
+}
+
+# FIRST CONSOLE
+func void door_1(string ai_name)
+{
+
+	dprint trigger_door_1_active
+	input 0
+	begin_cutscene
+	door_unlock 19
+	door_unlock 3
+	cm_interpolate lock_1a 0
+	sleep 60
+	particle lock_1a_locklight01 do start
+	sleep 150
+	cm_interpolate lock_1b 0
+	sleep 60
+	particle lock_1b_locklight01 do start
+	sleep 150
+	cm_reset
+	end_cutscene
+	input 1
+	target_set (123,30)
+}
+
+# NOOK 1
+func void nook_1(string ai_name)
+{
+	dprint nook_1_active
+	ai2_spawn nookleft_thug_1
+}
+
+# FOYER RETURN REWARD
+func void nookright(string ai_name)
+{
+	dprint nookright_active
+	ai2_spawn nookright_thug_1
+}
+
+# FLYWAY AMBUSH
+func void flyway_1(string ai_name)
+{
+	dprint flyway_1_active
+	ai2_spawn flyway_striker_1
+}
+
+# COMMGUY BAIT
+func void bait_1(string ai_name)
+{
+	dprint bait_1_active
+	trigvolume_enable alarm_1 1
+	ai2_spawn bait_commguy_1
+	ai2_spawn tech_thug_2
+	sleep 120
+	ai2_doalarm bait_commguy_1 15
+	sound_music_start atm_low_perc1 0.90
+}
+
+# ALARM 
+func void patrolscript0300(string ai_name)
+{
+	dprint alarm
+	ai2_doalarm bait_commguy_1 1
+}
+
+# PLASMA STRIKER 1
+func void plasma_striker_1(string ai_name)
+{
+	dprint plasma_striker_1_active
+	ai2_spawn plasma_striker_1
+}
+
+# ALARM 1 AMBUSH
+func void alarm_1(string ai_name)
+{
+	dprint alarm_1_active
+	alarm_counter = alarm_counter + 1
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+
+
+### CUTSCENE COUNTDOWN
+
+func void hall_striker_var(string ai_name)
+{
+	dprint striker_var
+	striker_counter = striker_counter - 1
+
+	if (striker_counter eq 0)
+	{		
+		sayonara_strikey();
+	}
+}
+
+func void hall_commguy_var(string ai_name)
+{
+	dprint commguy_var
+	striker_counter = striker_counter - 1
+
+	if (striker_counter eq 0)
+	{		
+		sayonara_strikey();
+	}
+}
+
+func void hall_thug1_var(string ai_name)
+{
+	dprint thug1_var
+	striker_counter = striker_counter - 1
+
+	if (striker_counter eq 0)
+	{		
+		sayonara_strikey();
+	}
+}
+
+func void sayonara_strikey
+{
+	dprint sayonara
+	Chase
+}
+
+### BACK TO THE LOGIC
+
+# TECH AMBUSH
+func void tech_ambush_1(string ai_name)
+{
+	dprint tech_ambush_1_active
+	ai2_spawn hall_striker_1
+}
+
+# SECOND CONSOLE
+func void door_2(string ai_name)
+{
+	dprint trigger_door_2_active
+	letterbox 1
+	door_lock 4
+	input 0
+	cm_interpolate lock_2 0
+	sleep 60
+	particle lock88_locklight02 do start
+	door_unlock 23
+	door_open 23
+	ai2_spawn patrol_striker_2
+	sleep 350
+	cm_reset
+	letterbox 0
+	input 1
+	door_lock 12
+	particle save1a_locklight01 do stop
+	target_set (124,30)
+	console_activate 4 1	
+}
+
+# THIRD CONSOLE
+func void door_3(string ai_name)
+{
+	dprint trigger_door_3_active
+	door_unlock 4
+	input 0
+	cm_interpolate lock_3 0
+	sleep 60
+	particle lock_3_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	set_objective_2
+	sound_music_stop atm_low_perc1
+}
+
+# CRUEL COMMGUY
+func void cruel_1(string ai_name)
+{
+
+	dprint cruel_1_active_active
+	ai2_spawn cruel_commguy_1
+	ai2_spawn victim_femsci_1
+}
+
+# TECH 3 PATROL
+func void tech_3(string ai_name)
+{
+	dprint tech_3_active_active
+	ai2_spawn tech_thug_3
+}
+
+# NEW TARGET 1
+func void new_target_1(string ai_name)
+{
+	dprint new_target_1_active
+	target_set (54,30)
+}
+
+# BEATER ROOM 1
+func void beaters_1(string ai_name)
+{
+	dprint beaters_1_active
+	ai2_spawn scram_striker_1
+	ai2_spawn beater_thug_1
+	particle vent01 start
+	chr_delete plasma_striker_1
+}
+
+# BEATER THUG 2
+func void beater_thug_2(string ai_name)
+{
+	dprint beater_thug_2_active
+	ai2_spawn beater_thug_2
+}
+
+
+# BEATER BACKUP 1
+func void backup_1(string ai_name)
+{
+	dprint backup_1_active
+	ai2_spawn backup_thug_1
+	ai2_tripalarm 1 0
+}
+
+# BEATER BACKUP 2
+func void backup_2(string ai_name)
+{
+	dprint backup_2_active
+	ai2_spawn backup_thug_2
+	ai2_tripalarm 2 0
+}
+
+# NEW TARGET 2
+func void new_target_2(string ai_name)
+{
+	dprint new_target_2_active
+	target_set (54,30)
+}
+
+# NEW TARGET 3
+func void new_target_3(string ai_name)
+{
+	dprint new_target_3_active
+	target_set (126,30)
+}
+
+# LOW THUGS 1
+func void lowthug_1(string ai_name)
+{
+	dprint lowthug_1_active
+	ai2_spawn low_thug_1
+	ai2_spawn low_thug_2
+}
+
+# DISABLE OBJECTIVE TRIGGER 1
+func void disable_obj_trig_1(string ai_name)
+{
+	dprint_disable_obj_trig_1_active
+	trigvolume_enable low_thug_1 1
+}
+
+# HIDDEN LOCK 1
+func void hidden_1(string ai_name)
+{
+	dprint trigger_door_3_active
+	door_unlock 22
+	ai2_spawn hidden_sci_1
+	particle vent02 start
+	input 0
+	begin_cutscene
+	cm_interpolate hlock_1 0
+	sleep 60
+	particle hlock_1_locklight01 do start
+	sleep 150
+	cm_interpolate ShinatamaCam01 0
+	cm_interpolate_block ShinatamaCam02 900
+	chr_animate 0 KONOKOwatch_start 60
+	sleep f40
+	cinematic_start (SHINtalking, 180, 180, 16, 3, 20, true)
+	sleep f19
+	chr_animate 0 KONOKOwatch_idle 3000
+	sound_dialog_play c02_08_01shinatama
+	sound_dialog_play_block pause
+	sound_dialog_play c02_08_02konoko
+	cinematic_start(KONtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	sound_dialog_play c02_08_03shinatama
+	sound_dialog_play_block pause
+	cm_interpolate brain_off_1b 0
+	cm_interpolate_block brain_off_1a 1000
+	particle brain start
+	particle brain1 start	
+	sound_ambient_start deadlybrain_sound 0.75		
+	sound_dialog_play c02_08_04konoko
+	sound_dialog_play_block pause
+	sound_dialog_play c02_08_05shinatama
+	sound_dialog_play_block pause
+	sound_dialog_play c02_08_06konoko
+	sound_dialog_play_block pause
+	chr_animate 0 KONOKOwatch_stop 15
+	cinematic_stop(KONtalking, 15, 20)
+	cinematic_stop(SHINtalking, 16, 20)
+	sleep f15
+	sound_ambient_volume deadlybrain_sound 0
+	cm_reset
+	end_cutscene
+	particle brain stop
+	particle brain1 stop
+	target_set (127,30)
+	sleep 10
+	sound_ambient_stop deadlybrain_sound
+}
+
+# HIDDEN TRIGGER 1A
+func void hidden_1a(string ai_name)
+{
+	dprint hidden_1a_active
+	trigvolume_enable hidden_1b 1
+	particle vent02 start
+}
+
+# HIDDEN TRIGGER 1B
+func void hidden_1b(string ai_name)
+{
+	dprint hidden_1b_active
+	ai2_spawn patrol_striker_3
+}
+
+# TRIGGER DEACTIVATE 4
+func void trigger_deactivate_4(string ai_name)
+{
+	dprint trigger_deactivate_4_active
+	input 0
+	cm_interpolate trigger_4 0
+	sleep 90
+	trig_deactivate 4
+	sleep 150
+	cm_reset
+	input 1
+	target_set (125,30)
+}
+
+# LOW STRIKER 1
+func void low_striker_1(string ai_name)
+{
+	dprint low_striker_1_active
+	ai2_spawn low_striker_1
+	ai2_spawn low_striker_2
+}
+
+# HALL TRIGGER ACTIVATE
+func void trigger_active_1(string ai_name)
+{
+	dprint trigger_active_1_active
+	trig_activate 2
+}
+
+# GUARD ROOM 1
+func void guardroom_1(string ai_name)
+{
+	dprint guardroom_1_active
+	door_unlock 14
+	input 0
+	cm_interpolate guardroom_1 0
+	sleep 60
+	particle guardroom_1_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+	target_set (65,30)
+}
+
+# BRAIN COMMGUY 1
+func void brain_commguy_1(string ai_name)
+{
+	dprint brain_commguy_1_active
+	ai2_spawn brain_commguy_1
+	ai2_spawn brain_commguy_2
+}
+
+# BRAIN LOCK 1
+func void brainlock_1(string ai_name)
+{
+	dprint brainlock_1_active
+	door_unlock 6
+	input 0
+	cm_interpolate brainlock_1 0
+	sleep 60
+	particle brainlock_1_locklight02 do start
+	sleep 150
+	cm_reset
+	input 1
+	target_set (129,30)
+	trigvolume_enable cruel_striker_1 1
+}
+
+# BRAIN DEFEAT
+func void braindefeat(string ai_name)
+{
+	target_set (130,30)
+}
+
+# CRUEL STRIKER
+func void cruel_striker_1(string ai_name)
+{
+	dprint cruel_striker_1_active
+	ai2_spawn cruel_striker_1
+	ai2_spawn victim_mansci_1
+	particle vent01 stop
+	particle vent02 stop
+	particle brain start
+	particle brain1 start
+}
+
+# AAIIEE!
+func void flee(string ai_name)
+{
+	dprint we_are_in_flee
+	chr_talk victim_mansci_1 c02_62_11sci 0 0
+	ai2_dopath victim_mansci_1 victim_2
+	sleep 300
+	set_objective_4
+}
+
+# LOCKIT
+func void lockit(string ai_name)
+{
+	dprint lockit_active
+	particle brainlock_3_locklight01 do stop
+	door_close 27
+	door_jam 27
+	particle vent01 kill
+	if (mus_cool4_playing eq 0)
+		{
+		sound_music_start mus_cool4_hd 1
+		mus_cool4_playing = 1;
+		}
+}
+
+### GLORIOUS DEADLY BRAIN FIGHT ###
+
+var int console_count = 4;
+
+func void brain_counter(string player_name)
+{
+	console_count = console_count - 1;
+
+	if (console_count eq 0)
+	{
+		console_count = 4;
+
+		dprint brain_counter_active
+		brain_counter_var = brain_counter_var + 1;
+
+		if (brain_counter_var eq 0)
+		{
+			brain_round_1
+		}
+
+		if (brain_counter_var eq 1)
+		{
+			brain_round_2
+		}
+
+		if (brain_counter_var eq 2)
+		{
+			brain_round_3
+		}
+
+		if (brain_counter_var eq 3)
+		{
+			brain_round_4
+		}
+	}
+}
+
+# BRAIN ROUND 1
+func void brain_round_1(string ai_name)
+{
+	ai2_allpassive 1
+	turret_deactivate 20
+	input 0
+	begin_cutscene jello
+	#sound_music_start atm_cl11 0.75
+	sound_ambient_start deadlybrain_sound 1.0
+	sleep 60
+	cm_interpolate brain_off_1b 0
+	sleep 30
+	cm_interpolate brain_off_1a 800
+	sleep 5
+	trig_show 202
+	trig_show 204
+	trig_speed 202 .2
+	trig_speed 204 .2
+	trig_hide 2023
+	trig_hide 2013
+	cinematic_start (SHINtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play c00_01_106Shinatama
+	sound_dialog_play_block pause
+	sound_dialog_play c00_01_107Shinatama
+	sound_dialog_play_block pause
+	sleep 30
+	sound_dialog_play c00_01_108Shinatama
+	sound_dialog_play_block pause
+	cinematic_stop(SHINtalking, 16, 20)
+	cm_interpolate_block brain_closeup 0
+	sleep 30
+	sound_dialog_play brain07final
+	sleep 200 
+	sound_music_stop atm_cl11
+	cm_reset
+	end_cutscene
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	save_point_4
+	console_reset 21
+	console_reset 22
+	console_reset 23
+	console_reset 24
+}
+
+# BRAIN ROUND 2
+func void brain_round_2(string ai_name)
+{
+	ai2_allpassive 1
+	turret_deactivate 20
+	input 0
+	begin_cutscene jello	
+	#sound_music_start atm_cl11 0.75
+	sound_music_volume mus_cool4_hd 0.7 1
+	sleep 60
+	cm_interpolate brain_off_1a 0
+	sleep 30
+	cm_interpolate brain_off_1b 850
+	cinematic_start (SHINtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play c00_01_113Shinatama
+	sleep 120
+	trig_hide 204
+	trig_hide 202
+	sleep 120
+	trig_speed 2012 0
+	trig_speed 2022 0
+	trig_show 2012
+	trig_show 2022
+	sleep 90
+	trig_speed 2012 .2
+	trig_speed 2022 .2
+	sound_dialog_play_block pause
+	cinematic_stop(SHINtalking, 16, 20)
+	sleep 60
+	cinematic_start (SHINscared, 180, 180, 16, 3, 20, true)
+	sound_dialog_play c00_01_114Shinatama
+	sound_dialog_play_block pause
+	cinematic_stop(SHINscared, 16, 20)
+	cm_interpolate_block brain_closeup 0
+	sleep 30
+	sound_dialog_play brain03final
+	sleep 200
+	end_cutscene
+	#sound_music_stop atm_cl11
+	sound_music_volume mus_cool4_hd 1 1
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	console_reset 21
+	console_reset 22
+	console_reset 23
+	console_reset 24
+}
+
+# BRAIN ROUND 3
+func void brain_round_3(string ai_name)
+{
+	ai2_allpassive 1
+	turret_deactivate 20
+	input 0
+	begin_cutscene jello	
+	#sound_music_start atm_cl11 0.75
+	sound_music_volume mus_cool4_hd 0.7 1
+	sleep 60
+	cm_interpolate brain_off_1b 0
+	sleep 30
+	cm_interpolate brain_off_1a 1200
+	cinematic_start (SHINtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play c00_01_115Shinatama
+	sleep 120
+	trig_hide 2012	
+	trig_hide 2022
+	sleep 120
+	trig_speed 205 0	
+	trig_speed 2042 0	
+	trig_speed 2032 0	
+	trig_speed 2023 0	
+	trig_speed 2013 0		
+	trig_show 205
+	sleep 60	
+	trig_show 2042
+	sleep 60	
+	trig_show 2032
+	sleep 60	
+	trig_show 2023
+	sleep 60	
+	trig_show 2013
+	sound_dialog_play_block pause
+	sleep 60
+	sound_dialog_play c00_01_117Shinatama
+	sound_dialog_play_block pause	
+	trig_speed 205 .4
+	trig_speed 2042 .4
+	trig_speed 2032 .4
+	trig_speed 2023 .4
+	trig_speed 2013 .4
+	cinematic_stop(SHINtalking, 16, 20)
+	cm_interpolate_block brain_closeup 0
+	sleep 30
+	sound_dialog_play brain08final
+	sleep 200
+	end_cutscene
+	#sound_music_stop atm_cl11
+	sound_music_volume mus_cool4_hd 1.0 1
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	console_reset 21
+	console_reset 22
+	console_reset 23
+	console_reset 24
+}
+
+# BRAIN ROUND 4
+func void brain_round_4(string ai_name)
+{
+	ai2_allpassive 1
+	turret_deactivate 20
+	input 0
+	sound_music_stop mus_cool4_hd
+	sound_music_start mus_sv 0.75
+	begin_cutscene jello	
+	sleep 60
+	cm_interpolate brain_off_1a 0
+	sleep 30
+	cm_interpolate brain_off_1b 1000 
+	sleep 90
+	trig_speed 205 1
+	sleep 90	
+	trig_speed 2042 2
+	sleep 90	
+	trig_speed 2032 1
+	sleep 90
+	trig_speed 2023 2
+	sleep 90
+	trig_speed 2013 2
+	sleep 60
+	trig_hide 205
+	trig_hide 2013
+	sleep 60	
+	trig_hide 2042
+	sleep 60	
+	trig_hide 2032
+	trig_hide 2023
+	sleep 60
+	trig_hide 402
+	sound_ambient_stop deadlybrain_sound
+	particle brain1 kill
+	sleep 10
+	particle brain1 create
+	particle brain1 start
+	sleep 20
+	particle brain1 kill
+	particle brain1 create
+	particle brain1 start
+	sleep 30
+	particle brain1 kill
+	sleep 30
+	particle brain kill
+	sleep 250
+	trigvolume_enable febtober 0
+	door_unlock 1
+	door_unlock 4
+	particle lock_3_locklight01 do start
+	outro
+}
+
+### FEBTOBER ###
+
+# FEBTOBER TRIGGER 1
+func void feb_tober(string ai_name)
+{
+	dprint febtober_active
+
+	all_music_counters();
+
+	door_lock 10
+	door_lock 13
+	door_unlock 25
+	door_unlock 23
+	ai2_spawn febtober_striker_1
+	trigvolume_reset feb_tober2
+	trigvolume_enable cruel_1 0
+	trigvolume_enable flyway_1 0
+	trigvolume_enable beaters_1 0
+	console_deactivate 1
+	console_deactivate 4
+	particle lock_3_locklight01 do start
+	particle lock88_locklight02 do start
+	particle febtober1_locklight01 do stop
+}
+
+# FEBTOBER TRIGGER 2
+func void feb_tober2(string ai_name)
+{
+	dprint febtober_2_active
+	trigvolume_reset febtober
+}
+
+### I NEED SOME BACKUP ###
+
+func void calling_all_cars(string ai_name)
+{
+	dprint callingallcars
+	ai2_dopath partner_cop_1 cop_backup_2a 1
+	ai2_dopath partner_cop_2 cop_backup_2b 1
+}
+
+func void calling_all_cars2(string ai_name)
+{
+	dprint callingallcars
+	
+	ai2_dopath partner_cop_1 cop_backup_2a 1
+	ai2_dopath partner_cop_2 cop_backup_2b 1
+}
+
+### Level scripted by Joseph ###
Index: /nikanabo/current/bsl/original/IGMD/manplant/manplant_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/manplant/manplant_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/manplant/manplant_main.bsl	(revision 185)
@@ -0,0 +1,30 @@
+#
+# CZ_main.bsl
+#
+
+var int my_save_point;
+var int brain_counter_var=0;
+var int striker_counter=2;
+var int backup1a_counter=1;
+var int backup1b_counter=1;
+var int mus_cool4_playing=0;
+var int alarm_counter;
+
+func void main(void)
+{
+	env_show 555 0
+	#obj_create 1101 1111
+	obj_create 1201 1208
+	#env_anim 1101 1111
+	env_anim 1201 1208
+	gl_fog_blue=.15
+	gl_fog_red=.15
+	gl_fog_green=.15
+	gl_fog_start=.98
+	gs_farclipplane_set 5000
+	func_start
+	if (my_save_point eq 0)
+	{
+	intro
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/manplant/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/manplant/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/manplant/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,16 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+####################################
+##             brain1		    ##
+####################################
+func void brain1_on(string ai_name)
+{
+	dprint begin_evil_particles
+	particle brain1 do start
+}
+func void brain1_off(string ai_name)
+{
+	dprint stop_the_evil
+	particle brain1 do stop
+}
Index: /nikanabo/current/bsl/original/IGMD/neuro/neuro_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/neuro/neuro_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/neuro/neuro_cutscene.bsl	(revision 185)
@@ -0,0 +1,915 @@
+#
+# neuro_cutscene.bsl
+#
+
+func void
+neuro_cs_intro(
+	void)
+{
+	fade_out 0 0 0 0		
+	env_show 271 0
+	env_show 272 0
+	obj_create 271 272
+	cm_interpolate IntroCamOut01 0
+	sleep f14
+	obj_shade 271 272 .4 .4 .2
+	begin_cutscene							
+	sleep f1
+	sound_music_start mus_low1 1.0
+	#fork music_force_stop
+	#Camera shot outside
+	cm_interpolate IntroCamOut01 0
+	ai2_spawn IntroTCTF01
+	playback IntroTCTF01 IntroSecSet
+	fade_in 60
+	sleep f100
+	playback IntroTCTF01 IntroSecStart
+	sleep f200
+	#Lobby shot
+	cm_interpolate IntroCamIn01 0
+	sleep f180
+	sound_dialog_play c13_47_03blackops
+	cinematic_start (TCTFtalking, 180, 180, 20, 9, 20, true)
+	sleep f60
+	#Security lets guy in
+	cm_interpolate IntroCamSecSet 0
+	playback IntroTCTF01 IntroSecSet
+	sleep f150
+	sound_dialog_play c13_47_04opsguard2
+	cinematic_start (BOPSface, 180, 180, 15, 1, 20, false)	
+	sleep f150
+	cinematic_stop (BOPSface, 15, 20)
+	cinematic_stop (TCTFtalking, 20, 20)
+	#Door opens
+	ai2_spawn IntroTCTF02
+	cm_interpolate IntroCamDoorOpen 0
+	playback IntroTCTF01 IntroSecSet
+	playback IntroTCTF02 IntroSecWalk
+	env_anim 271 272
+	sound_ambient_start c12_42_00door
+	sleep f240
+	#camera inside looking down
+	cm_interpolate IntroCamTopDown 0
+	playback 0 IntroKonCrouch
+	chr_animate 0 KONOKOcrouch_idle 1000
+	sleep f300
+	#camera showing security talking
+	playback IntroTCTF01 IntroSecMonitor01
+	#cm_interpolate IntroCamBothTalk 0
+	#sleep f180
+	#Security goes over to monitors
+	cm_interpolate IntroCamMonitorMid 0
+	playback IntroTCTF02 IntroSecMonitor02
+	#next line was 180
+	sleep f120
+	sound_dialog_play c13_47_01opsguard1
+	cinematic_start (TCTFtalking, 180, 180, 20, 9, 20, true)
+	sleep f60
+	#konoko jumps down behind Security
+	cm_interpolate IntroCamKonDrop 0
+	sleep f120
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev14_IntroJump
+	#Konoko hides from guys
+	chr_envanim_block 0 IntroKonBox02 norotation
+	cm_anim both IntroCamHide
+	sound_dialog_play c13_47_02opsguard2
+	cinematic_start (BOPSface, 180, 180, 15, 1, 20, false)	
+	sleep f100
+	chr_animate 0 KONOKOlev14_IntroHide
+	sound_dialog_play_block pause
+	cinematic_stop (BOPSface, 15, 20)
+	cinematic_stop (TCTFtalking, 20, 20)
+	#Show doors closing
+	cm_wait
+	cm_interpolate IntroCamDoors 0
+	env_setanim 271 IntroDoorRt01
+	env_setanim 272 IntroDoorLt01
+	sound_ambient_start c13_04_03doorclose
+	sleep f120
+	#Konoko makes a run for it
+	env_setanim 271 IntroDoorRt01
+	env_setanim 272 IntroDoorLt01
+	cm_anim both IntroCamKonRun
+	chr_envanim 0 IntroKonBox03 norotation
+	chr_animate 0 KONOKOlev14_IntroRun
+	sound_music_stop mus_low1
+	#Konoko dives through closing door and sec turns around
+	cm_anim_block both IntroCamKonDive
+	chr_envanim 0 IntroKonBox04 norotation
+	chr_animate 0 KONOKOlev14_IntroDive
+	playback IntroTCTF01 IntroSecEnd
+	chr_envanim IntroTCTF02 IntroSecBox01 norotation
+	chr_animate IntroTCTF02 SECURIlev14_IntroTurn
+	#reset cam outside
+	cm_wait
+	playback 0 IntroKonstart
+	sleep f10
+	cm_reset
+	chr_delete IntroTCTF01
+	chr_delete IntroTCTF02
+	obj_kill 271 272
+	env_show 271 1
+	env_show 272 1
+	env_shade 271 272 .4 .4 .2
+	fork Setup_Intro
+	fork set_objective_1
+	end_cutscene
+}
+
+
+func void
+spawn_kerr(
+	void)
+{
+	ai2_spawn ScanKerr01
+	ai2_passive ScanKerr01 1
+	chr_unstoppable KerrKerr 1
+	chr_delete KerrKerr
+}
+
+
+func void
+scanner_start(
+	void)
+{
+	var int number_near = 0;
+
+	number_near = number_near + trigvolume_count(68);
+	number_near = number_near + trigvolume_count(69);
+	number_near = number_near + trigvolume_count(70);
+	number_near = number_near + trigvolume_count(71);
+
+	if (number_near eq 0) 
+	{
+		trigvolume_enable trigger_volume_13 0
+		doscanscene
+	}
+}
+
+##############################
+
+func void wait_and_play_xtr5(void)
+{
+	sleep 60
+	sound_music_start mus_xtr5 1.0
+}
+
+
+func void
+doscanscene(
+	void)
+{
+		sound_ambient_start lab_amb1 0.1
+		sound_ambient_volume lab_amb1 1 2
+		fork Scan_Guards	
+		has_probed = 1
+		begin_cutscene
+		#hide scanner gunk
+		env_show 51 0
+		env_show 52 0
+		env_show 53 0
+		env_show 54 0
+		env_show 55 0
+		env_show 56 0
+		env_show 57 0
+		env_show 58 0
+		env_show 59 0
+		obj_create 51 59
+		#create this character before konoko gets into the scanner room
+		cm_interpolate ScanCamDocTalk 200
+		#patrol Konoko to flag 1009
+		ai2_takecontrol 1
+		ai2_movetoflag 0 1009
+		sleep f200
+		#Konoko talks
+		ai2_takecontrol 0
+		playback 0 ScanKonokoSet
+		sound_dialog_play c13_64_01konoko
+		cinematic_start (KONlistening, 180, 180, 19, 7, 20, false)	
+		sound_dialog_play_block pause
+		sleep f15
+		#Doctor says Go Sit in That Chair
+		cm_interpolate ScanCamDocTalk 0
+		sound_dialog_play c13_65_01kerr
+		cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+		sound_dialog_play_block pause
+		sleep f25
+		#Is this necessary?
+		cm_interpolate ScanCamBoth 0
+		sound_dialog_play c13_65_02konoko
+		sound_dialog_play_block pause
+		sleep f10
+		sound_dialog_play c13_65_03kerr
+		sound_dialog_play_block pause
+		cinematic_stop (KERRtalking, 20, 20)
+		#Konoko walk to chair & doctor walks to booth
+		playback 0 ScanKonokoWalk
+		cm_interpolate ScanCamKonWalk 0
+		playback ScanKerr01 ScanDoctorWalk
+		sleep f120
+		sound_dialog_play c13_65_04konoko
+		sleep f140
+		cinematic_stop (KONlistening, 19, 20)
+		#chair drops
+		cm_interpolate ScanCamChairDown 0
+		sleep f30
+		cutscene_sync mark
+		sound_ambient_start c18_01_29_effectsa
+		sleep f30
+		env_setanim 53 Scan_chair01
+		env_setanim 54 Scan_chair02
+		env_setanim 55 Scan_chair03
+		sleep f30
+		sleep f150
+		#Doctor enters booth
+		cm_interpolate ScanCamBoothIn 0
+		sleep f200
+		#show doctor in booth
+		playback ScanKerr01 ScanDocBooth
+		cm_interpolate ScanCamBooth 0
+		chr_envanim 0 ScanKonBox04
+		chr_animate 0 KONOKOlev14_scan 500
+		sound_dialog_play c13_65_05kerr
+		cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+		sound_dialog_play_block pause
+		cinematic_stop (KERRtalking, 20, 20)
+		sleep f30
+		#scanner starts
+		env_setanim 51 Scan_arm01
+		env_setanim 52 Scan_arm02
+		env_setanim 53 Scan_chair0101
+		env_setanim 54 Scan_chair0201
+		env_setanim 55 Scan_chair0301
+		env_setanim 56 Scan_tube01
+		env_setanim 57 Scan_tube02
+		env_setanim 58 Scan_tube03
+		env_setanim 59 Scan_tube04
+		chr_envanim 0 ScanKonBox01
+		chr_animate 0 KONOKOlev14_scan 2000
+		cm_interpolate ScanCamScan01 0
+		sleep f60
+		cutscene_sync mark
+		sound_ambient_start c18_01_29_effectsb
+		sleep f120
+		cm_interpolate_block ScanCamScan02 300
+		#Konoko gets scanned
+		chr_envanim_block 0 ScanKonBox02
+		chr_animate 0 KONOKOlev14_scan 2000
+		cm_interpolate ScanCamScan03 0
+		cm_interpolate_block ScanCamScan04 360
+		particle brainscan do start
+		sound_ambient_start scanner
+		sleep f120
+		sound_ambient_volume scanner .5 2
+		sleep f60
+		#Doctor in booth
+		sound_dialog_play c13_65_07kerr
+		cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+		cm_interpolate_block ScanCamBoothOut 0
+		sleep f10
+		sound_dialog_play c13_65_08konoko
+		cinematic_start (KONdeepthought, 180, 180, 19, 7, 20, false)	
+		sound_dialog_play_block pause
+		#Doctrof rom inside booth
+		cm_interpolate ScanCamBooth 0
+		sound_dialog_play c13_65_09kerr
+		sound_dialog_play_block pause
+		#konoko scanned
+		chr_envanim 0 ScanKonBox02
+		chr_animate 0 KONOKOlev14_scan 2000
+		cm_interpolate ScanCamScan02 0
+		cm_interpolate_block ScanCamScan01 1000
+		sound_dialog_play c13_65_10konoko
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_11kerr
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_12konoko
+		sound_dialog_play_block pause
+		cm_interpolate ScanCamBoothOut02 0
+		cm_interpolate_block ScanCamBoothOut 900
+		sound_dialog_play c13_65_13kerr
+		sound_dialog_play_block pause
+		cm_interpolate ScanCamScan04 0
+		cm_interpolate_block ScanCamScan03 800
+		sound_dialog_play c13_65_14konoko
+		sound_dialog_play_block pause
+		sleep f75
+		cm_interpolate ScanCamBoothOut 0
+		cm_interpolate_block ScanCamBoothOut02 900
+		sound_dialog_play c13_65_15kerr
+		sound_dialog_play_block pause
+		sleep f25
+		sound_dialog_play c13_65_16konoko
+		sound_dialog_play_block pause
+		sleep f20
+		#Doc in Booth
+		sound_dialog_play c13_65_17kerr
+		sleep f100
+		#Scanner stops
+		particle brainscan do stop
+		cutscene_sync_mark
+		sound_ambient_stop scanner
+		env_setanim 51 Scan_arm0102
+		env_setanim 52 Scan_arm0202
+		env_setanim 53 Scan_chair0102
+		env_setanim 54 Scan_chair0202
+		env_setanim 55 Scan_chair0302
+		env_setanim 56 Scan_tube0102
+		env_setanim 57 Scan_tube0202
+		env_setanim 58 Scan_tube0302
+		env_setanim 59 Scan_tube0402
+		chr_envanim 0 ScanKonBox03
+		chr_animate 0 KONOKOlev14_scan 730
+		cm_interpolate ScanCamScan01 0
+		cutscene_sync mark
+		sound_ambient_start c18_01_29_effectsc
+		cm_interpolate_block ScanCamScanStop 300
+		sleep f700
+		cinematic_stop (KONdeepthought, 19, 20)
+		cinematic_stop (KERRtalking, 20, 20)
+		#Doctor comes out of booth
+		playback ScanKerr01 ScanDocWalkOut
+		cm_interpolate ScanCamBoothOut 0
+		sleep f60
+		playback 0 ScanKonDone
+		sleep f150
+		sleep f80
+		#Konoko and Doc meet to talk
+		cm_interpolate ScanCamBoth02 0
+		cm_interpolate_block ScanCamBoth03 300
+		sleep f120
+		sound_dialog_play c13_65_18konoko
+		cinematic_start (KONlistening, 180, 180, 19, 7, 20, false)	
+		sleep f240
+		#Doc talks
+		playback ScanKerr01 ScanDoctorSet
+		cm_interpolate ScanCamDocTalk 0
+		cm_interpolate_block ScanCamDocTalk02 1100
+		sound_dialog_play c13_65_19kerr
+		cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_20konoko
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_21kerr
+		sound_music_start mus_sad1 0.8
+		sound_dialog_play_block pause
+		#KOnoko talks
+		playback 0 ScanKonokoSet
+		cm_interpolate ScanCamKonTalk 0
+		cm_interpolate_block ScanCamKonTalk03 600
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_22konoko
+		sound_dialog_play_block pause
+		sleep f25
+		sound_dialog_play c13_65_23kerr
+		sound_dialog_play_block pause
+		#Both talk
+		cm_interpolate ScanCamTalkBoth 0
+		cm_interpolate_block ScanCamTalkBoth02 800
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_24konoko
+		sound_dialog_play_block pause
+		sleep f55
+		sound_dialog_play c13_65_25kerr
+		sound_dialog_play_block pause
+		sleep f40
+		#Konoko cam
+		cm_interpolate ScanCamKonTalk04 0
+		cm_interpolate_block ScanCamKonTalk 1000
+		sound_dialog_play c13_65_26konoko
+		sound_dialog_play_block pause
+		#KerrCam
+		cm_interpolate ScanCamDocTalk02 0
+		cm_interpolate_block ScanCamDocTalk03 800
+		sound_dialog_play c13_65_27kerr
+		sound_dialog_play_block pause
+		#BothCam
+		cm_interpolate ScanCamTalkBoth02 0
+		cm_interpolate_block ScanCamTalkBoth 1000
+		sound_dialog_play c13_65_28konoko
+		sound_dialog_play_block pause
+		sleep f25
+		sound_dialog_play c13_65_29kerr
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_30konoko
+		sound_dialog_play_block pause
+		sleep f20
+		sound_dialog_play c13_65_31kerr
+		sound_dialog_play_block pause
+		sleep f20
+		sound_dialog_play c13_65_32konoko
+		sound_dialog_play_block pause
+		sleep f20
+		#KerrCam
+		cm_interpolate ScanCamDocTalk 0
+		cm_interpolate_block ScanCamDocTalk03 1000
+		sound_dialog_play c13_65_33kerr
+		sound_dialog_play_block pause
+		sleep f20
+		#Konoko cam
+		cm_interpolate ScanCamKonTalk02 0
+		cm_interpolate_block ScanCamKonTalk 800
+		sound_dialog_play c13_65_34konoko
+		sound_dialog_play_block pause
+		#BothCam
+		cm_interpolate ScanCamTalkBoth02 0
+		cm_interpolate_block ScanCamTalkBoth 800
+		sound_dialog_play c13_65_35kerr
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_36konoko
+		sound_dialog_play_block pause
+		sleep f20
+		#show scanner gunk and hide scanner objects
+		env_show 51 1
+		env_show 52 1
+		env_show 53 1
+		env_show 54 1
+		env_show 55 1
+		env_show 56 1
+		env_show 57 1
+		env_show 58 1
+		env_show 59 1
+		obj_kill 51 59
+		sound_dialog_play_block pause
+		sound_dialog_play c13_65_37kerr
+		sound_dialog_play_block pause
+#		#Ambush sequence starts
+		#dOORS start to open
+		sound_music_stop mus_sad1
+		door_open 7
+		ai2_spawn ScanOps01
+		ai2_setmovementmode ScanOps01 run
+		playback ScanOps01 AmbushTCTFenter
+		sleep f60
+		#Konoko and Doctor hear doors opening
+		cm_interpolate AmbushCamTurn 0
+		playback ScanKerr01 AmbushDoctorTurn
+		sleep f10
+		chr_animate 0 KONCOMstartle_lt1
+		sleep f60
+		#TCTF is shown entering
+		playback ScanOps01 AmbushTCTFenter011
+		cinematic_stop (KONlistening, 19, 20)
+		cinematic_stop (KERRtalking, 20, 20)
+		cm_interpolate AmbushCamTCTFenter02 160
+		sleep f120
+		sound_dialog_play c13_65_38opsguard1
+		cinematic_start (BOPSface, 180, 180, 15, 1, 20, false)
+		particle_temp_start
+		sound_dialog_play_block
+		cinematic_stop (BOPSface, 15, 20)
+		#TCTF shoots gun
+		playback ScanOps01 AmbushTCTFshoot fromhere
+		sleep f40
+		particle_temp_kill
+		#Doctor takes bullets for konoko
+		#chr_envanim 0 AmbushKonBox02 norotation
+		#chr_animate 0 KONOKOlev14_Ambush01
+		#chr_envanim ScanKerr01 AmbushKerrBox02 norotation
+		#chr_animate ScanKerr01 DOClev14_Ambush01
+		#cm_anim both AmbushCamDie01
+		#sleep f30
+		#other angle of above
+		slowmo 120
+		cm_anim both AmbushCamDie02
+		chr_envanim 0 AmbushKonBox02 norotation
+		chr_animate 0 KONOKOlev14_Ambush01
+		chr_envanim ScanKerr01 AmbushKerrBox02 norotation
+		chr_animate ScanKerr01 DOClev14_Ambush01
+		cm_anim both AmbushCamDie02
+		sleep f22
+		particle_temp_stop
+		particle ScanMerc pulse
+		sleep f1
+		particle scanexplode create
+		sound_dialog_play kerr_dth1
+
+		fork wait_and_play_xtr5
+
+		#TCTF says you're next
+		cm_wait
+		ai2_kill ScanKerr01
+		#chr_set_health ScanKerr01 0
+		cm_interpolate ScanCamSynDie 0
+		playback 0 ScanKonDie
+		sleep f120
+		#konoko says let's get it on gameplay resumes
+		cm_interpolate ScanCamKonDie 0
+		sound_dialog_play c13_65_39konoko
+		cinematic_start (KONangryfront, 180, 180, 19, 7, 20, true)	
+ 		sound_dialog_play_block pause
+		cinematic_stop (KONangryfront, 20, 20)
+		cm_reset
+		fork set_objective_3
+		trigvolume_enable trigger_volume_13 0
+
+		# CB: set up the monologue for konoko telling herself about her next objective
+		prepare_vat_monologue();
+
+		end_cutscene
+		env_show 823 0
+		save_point_3
+
+		sound_ambient_volume lab_amb1 0 4
+
+		sleep 120
+		post_scan_music_start
+}
+
+func void
+KerrSpawn(void)
+{
+		ai2_spawn KerrKerr
+		#playback KerrKerr KerrKerrSet
+		ai2_passive KerrKerr 1
+}
+
+func void
+Kerr(void)
+{
+	if(trigvolume_count(36) eq 0)
+	{
+		sound_music_start mus_sad1 0.8
+		begin_cutscene
+		#ai2_spawn KerrKerr
+		ai2_takecontrol 1
+		ai2_movetoflag 0 1261 setfacing
+		playback KerrKerr KerrKerrSet
+		cm_interpolate KerrCamKerr 180
+		sleep f100
+		#Konoko says Hi Uncle
+		sound_dialog_play c13_64_01konoko
+		cinematic_start (KONlistening, 180, 180, 19, 9, 20, true)
+		sound_dialog_play_block pause
+		#Kerr says what are you doing here?
+		cm_interpolate KerrCamKerr 180
+		sound_dialog_play c13_64_02kerr
+		cinematic_start (KERRtalking, 180, 180, 16, 1, 20, false)
+		sound_dialog_play_block pause
+		#Konoko says I need your help
+		playback 0 KerrKonSet
+		cm_interpolate KerrCamLt02 0
+		cm_interpolate_block KerrCamLt01 800
+		sound_dialog_play c13_64_03konoko
+		sound_dialog_play_block pause
+		#Kerr says yep, you do
+		sound_dialog_play c13_64_04kerr
+		sound_dialog_play_block pause
+		sleep f20
+		#Konoko says I'm on it
+		sound_dialog_play c13_64_05konoko
+		sound_dialog_play_block pause
+		sleep f30
+		#Kerr says meet me in lab
+		sound_dialog_play c13_64_06kerr
+		sound_dialog_play_block pause
+		cinematic_stop (KONlistening, 20, 20)
+		cinematic_stop (KERRtalking, 15, 20)
+		cm_reset
+		letterbox 0
+		playback KerrKerr KerrKerrGive fromhere
+		sleep f90
+		chr_animate KerrKerr COMGUYact_give
+		chr_animate 0 KONOKOact_give
+		sleep f90
+		give_powerup hypo
+		sleep f2
+		give_powerup hypo
+		ai2_takecontrol 0
+		fork set_objective_2
+		end_cutscene
+		trigvolume_enable Kerr_trig 0
+		trigvolume_enable Kerr_trig_copy 0
+		console_activate 13
+		save_point_2
+		sound_music_volume mus_sad1 0 2
+		kerr_console_music
+	}	
+}
+
+
+func void Acid01(string char)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(char);
+
+  if (eggman eq 0)
+  {
+    chr_animate(char, KONOKOacid);
+    sleep 10
+    chr_set_health(char, 0);
+  }
+
+  if (eggman eq 1)
+  {
+	chr_animate(char, KONOKOacid);
+	trigvolume_enable LastVat 0
+	cm_interpolate AcidCam01 500
+	sleep 5
+	input 0
+	invincible=1
+	sleep 525
+	chr_animate(char, KONOKOlev14_grinder);
+	chr_envanim(char, GrinderKonBox01, norotation);
+	sleep f60
+	sound_ambient_start c13_47_11_bonecrunch
+	sleep f10
+	sound_impulse_play konoko_gruesome_death
+	sleep f75
+	chr_set_health(char, 0);
+  }
+}
+
+
+func void Acid02(string char)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(char);
+
+  if (eggman eq 0)
+  {
+    chr_animate(char, KONOKOacid);
+    sleep f10
+    chr_set_health(char, 0);
+  }
+
+  if (eggman eq 1)
+  {
+	chr_animate(char, KONOKOacid);
+	input 0
+	trigvolume_enable LastVat 0
+	cm_interpolate AcidCam01 400
+	sleep f5
+	invincible=1
+	sleep f430
+	chr_animate(char, KONOKOlev14_grinder);
+	chr_envanim(char, GrinderKonBox01, norotation);
+	sleep f60
+	sound_ambient_start c13_47_11_bonecrunch
+	sleep f10
+	sound_impulse_play konoko_gruesome_death
+	sleep f75
+	chr_set_health(char, 0);
+  }
+}
+
+
+
+func void Acid03(string char)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(char);
+
+  if (eggman eq 0)
+  {
+    chr_animate(char, KONOKOacid);
+    sleep f10
+    chr_set_health(char, 0);
+  }
+
+  if (eggman eq 1)
+  {
+	input 0
+	trigvolume_enable LastVat 0
+	chr_animate(char, KONOKOacid);
+	cm_interpolate AcidCam01 200
+	sleep f5
+	invincible=1
+	sleep 230
+	chr_animate(char, KONOKOlev14_grinder);
+	chr_envanim(char, GrinderKonBox01, norotation);
+	sleep f60
+	sound_ambient_start c13_47_11_bonecrunch
+	sleep f10
+	sound_impulse_play konoko_gruesome_death
+	sleep f75
+	chr_set_health(char, 0);
+  }
+}
+
+
+
+func void acid04(string char)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(char);
+
+  if (eggman eq 0)
+  {
+    chr_animate(char, KONOKOacid);
+    sleep f10
+    chr_set_health(char, 0);
+  }
+
+  if (eggman eq 1)
+  {
+	cm_detach
+	input 0
+	trigvolume_enable LastVat 0
+	chr_animate(char, KONOKOacid);
+	sleep f5
+	invincible=1
+	sleep 40
+	cm_interpolate GrinderCamEnd 0
+	sleep f10
+	chr_animate(char, KONOKOlev14_grinderend);
+	chr_envanim(char, EndGrinderKonBox01, norotation);
+	sleep f60
+	sound_ambient_start c13_47_11_bonecrunch
+	sleep f10
+	sound_impulse_play konoko_gruesome_death
+	sleep f75
+	chr_set_health(char, 0);
+  }
+}
+
+
+
+
+
+func void
+EndScan(
+	void)
+{
+	sound_dialog_play c13_66_01konoko
+	cinematic_start (KONtalkangryfront, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	sleep f60
+	cinematic_stop (KONtalkangryfront, 19, 20)
+}
+
+
+func void
+CraneTalk(
+	void)
+{
+	sound_dialog_play c13_66_03konoko
+	cinematic_start (KONtalkangryfront, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	sleep f60
+	cinematic_stop (KONtalkangryfront, 19, 20)	
+}
+
+func void
+BeginVat(
+	void)
+{
+	sound_dialog_play c13_66_02konoko	
+	cinematic_start (KONtalkangryfront, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	sleep f60
+	cinematic_stop (KONtalkangryfront, 19, 20)
+}
+
+
+func void
+Outro(
+	void)
+{
+	if(final_check eq 0)
+	{
+		dprint OUTRO_1
+		begin_cutscene
+		trigvolume_enable LastVat 0
+		ai2_takecontrol 1
+		ai2_movetoflag 0 222
+		sleep f200
+		Outro2
+	}
+
+	if(final_check ne 0)
+	{
+		Outro2
+	}
+}
+
+func void
+Outro2(
+	void)
+{
+	dprint OUTRO_2
+	begin_cutscene
+	trigvolume_enable LastVat 0
+	ai2_takecontrol 1	
+	#dialog talking about how to get to the crane
+	#Konoko runs to Crane
+	cm_interpolate OutroCam01 0
+	sound_dialog_play c13_66_04konoko
+	cinematic_start (KONintense, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	chr_envanim 0 OutroKonBox01 norotation
+	env_anim 71 74
+	cm_anim both OutroCam01
+	cutscene_sync mark
+	sound_ambient_start c13_59_22_crane
+	sleep f150
+	chr_animate 0 KONOKOlev14_Run
+	#Konoko jumps to Crane
+	cm_anim_block both OutroCamJump
+	chr_envanim 0 OutroKonBox02 norotation
+	chr_animate 0 KONOKOlev14_Jump
+	env_setanim 71 cranehook_jump
+	env_setanim 72 cranerope_jump
+	#Konoko tucks over shredders
+	cm_anim_block both OutroCamTuck
+	chr_envanim 0 OutroKonBox03 norotation
+	chr_animate 0 KONOKOlev14_Tuck
+	env_setanim 71 cranehook_tuck
+	env_setanim 72 cranerope_tuck
+	sleep f160
+	sound_dialog_play c13_66_05konoko
+	#Konoko dives into acid
+	chr_nocollision 0 1
+	cm_anim_block both OutroCamDive
+	chr_envanim 0 OutroKonBox04 norotation
+	chr_animate 0 KONOKOlev14_Dive
+	env_setanim 71 cranehook_dive
+	env_setanim 72 cranerope_dive
+	sleep f90
+	cinematic_stop (KONintense, 20, 20)
+	sleep f60
+	particle OutroSplash create
+	sound_ambient_start c14_15_12_splash
+	sleep f120
+	sound_ambient_start c14_16_18_bubbles	
+	sleep f80
+
+
+
+	### CB: this is the two-guys-at-the-acid-pool script
+#	playback OutroTCTF1 OutroTCTFSwat01
+#	playback OutroTCTF2 OutroTCTFLite01
+#	sleep f100
+#	cm_interpolate OutroCamWater01 0
+#	sleep f120
+#	sound_dialog_play c13_67_01opsguard1
+#	cinematic_start (TCTFtalking, 180, 180, 19, 7, 20, false)
+#	sound_dialog_play_block
+#	sound_dialog_play c13_67_02opsguard2
+#	cinematic_start (BOPSface, 180, 180, 20, 9, 20, true)
+#	sound_dialog_play_block
+#	#TCTFguys from birds eye
+#	cm_interpolate OutroCamWater02 0
+#	#sound_dialog_play c13_67_03opsguard3
+#	#sound_dialog_play_block
+#	#sound_dialog_play c13_67_04opsguard1
+#	#sound_dialog_play_block
+#	sleep f30
+#	sound_dialog_play c13_67_05opsguard2
+#	sound_dialog_play_block
+#	cinematic_stop (BOPSface, 20, 20)
+#	cinematic_stop (TCTFtalking, 19, 20)
+
+
+
+
+
+
+	### CB: this is the same script with a third character added
+	ai2_spawn OutroTCTF1
+	ai2_spawn OutroTCTF2
+	ai2_spawn OutroTCTF3
+	playback OutroTCTF1 OutroTCTFSwat01
+	playback OutroTCTF2 OutroTCTFLite01
+	sleep f40
+	playback OutroTCTF3 OutroTCTFLite02
+	sleep f60
+	cm_interpolate OutroCamWater01 0
+	sleep f120
+	sound_dialog_play c13_67_01opsguard1
+	cinematic_start (TCTFtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	sound_dialog_play c13_67_02opsguard2
+	cinematic_start (BOPSface, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block
+	sound_dialog_play c13_67_03opsguard3
+	sound_dialog_play_block
+	cinematic_stop (BOPSface, 20, 20)
+	cinematic_stop (TCTFtalking, 19, 20)
+
+	#TCTFguys from birds eye
+	cm_interpolate OutroCamWater02 0
+	sleep f40
+	cinematic_start (TCTFtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play c13_67_04opsguard1
+	sound_dialog_play_block
+	sleep f30
+	cinematic_start (BOPSface, 180, 180, 19, 7, 20, false)
+	sound_dialog_play c13_67_05opsguard2
+	sound_dialog_play_block
+	sleep f140
+	cinematic_stop (BOPSface, 19, 20)
+	cinematic_stop (TCTFtalking, 20, 20)
+
+
+
+
+	sleep f140
+	win
+}
+
Index: /nikanabo/current/bsl/original/IGMD/neuro/neuro_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/neuro/neuro_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/neuro/neuro_level_logic.bsl	(revision 185)
@@ -0,0 +1,1166 @@
+# neuro_spawn_guards.bsl
+#
+# SCRIPTS TO SPAWN SECURITY GUARDS
+#
+
+################# START GAME LOGIC #############################
+
+# creates counterS for stuff
+var int neuro_counter;
+var int kerr_counter;
+var int has_probed = 0;
+var int ambush_counter = 2;
+var int final_check = 0;
+var int FTS_variable = 2;
+
+func void level_start(void)
+{
+# set counter values
+
+	neuro_counter = 3
+	end_counter = 2
+	kerr_counter = 3
+
+	############# SAVE GAME SCRIPTS #############
+
+# These functions are used when the game is restored.
+
+	if (save_point eq 0)
+	{
+		dprint SAVE_POINT_0
+#		VOODOO COMPUTING
+	}
+
+	if (save_point eq 1)
+	{
+		fork Setup_Intro
+		fork set_objective_1
+		dprint Restore_Autosave_Point_1
+		restore_game
+	}
+
+	if (save_point eq 2)
+	{
+		dprint Restore_Autosave_Point_2
+
+		objective_set 1 silent
+		target_set(1261, 30.0)
+
+		dprint Restore_Pod_1
+		ai2_spawn Pod1_TCL_1
+		ai2_spawn Pod1_TCL_2
+		ai2_spawn Pod1_TCL_3
+		ai2_spawn Pod1_Scientist_1
+		ai2_spawn Pod1_Scientist_2
+		#particle lock1_locklight01 do start
+		door_lock(11);
+		trigvolume_enable(autosave_trigger_1, 0);
+
+		restore_game
+
+#		console_deactivate 10
+#		trigvolume_enable(trig_train_saves, 0);
+#		trigvolume_enable(trig_train_objectives, 1);
+	}
+
+	if (save_point eq 3)
+	{
+		dprint RESTORE_SAVE_POINT_3
+
+		objective_set 2 silent
+		target_set(366, 30.0)
+
+		particle lock3_locklight02 do start
+		particle lock4_locklight02 do start
+
+		door_unlock(58);
+
+		door_lock(32);
+		door_lock(33);
+		door_lock(34);
+		door_lock(35);
+
+		trig_deactivate 2
+
+		trigvolume_enable(trigger_volume_76, 0);
+		trigvolume_enable(trigger_volume_06, 1);
+		trigvolume_enable(Kerr_trig, 0);
+		console_deactivate 12
+		console_deactivate 13
+
+		restore_game
+
+		kerr_console_music
+	}
+
+	if (save_point eq 4)
+	{
+		dprint RESTORE_SAVE_POINT_4
+
+		env_show 823 0
+
+		objective_set 3 silent
+		target_set(346, 30.0)
+
+		door_lock 58
+
+		door_unlock(1);
+		door_unlock(6);
+		door_unlock(7);
+
+		particle lock5a_locklight01 do start
+		particle lock5b_locklight01 do start
+		particle lock5c_locklight01 do start
+
+		particle labalarm1_emlight01 do stop
+		particle labalarm2_emlight01 do stop
+		particle labalarm3_emlight01 do stop
+
+		particle labalarm1 do stop
+		particle labalarm2 do stop
+		particle labalarm3 do stop
+
+		particle lock6_locklight02 do start
+
+		trigvolume_enable(trigger_volume_13, 0);
+		trigvolume_enable(spawn_kerr_trig, 0);
+		#trigvolume_enable(Setup_Security_Trig, 1);
+		#trigvolume_enable(chase_trigger, 1);
+
+		# CB: set up the monologue for konoko telling herself about her next objective
+		prepare_vat_monologue();
+
+		console_deactivate 3
+		console_deactivate 4
+		console_deactivate 5
+		console_deactivate 14
+		console_deactivate 88
+
+		ai2_spawn Scan_BOS_1
+		ai2_spawn Scan_BOS_2
+		ai2_spawn Scan_BOS_3
+		ai2_spawn Scan_BOS_4
+
+		ai2_spawn CS_ScanOps01
+
+		restore_game
+
+		post_scan_music_start
+	}
+}
+
+# This is an example of a save game console.
+
+func void autosave_1(string player_name)
+{
+	dprint autosave_1
+#	PLAY AUTOSAVE SOUND - ADD LATER!!!
+	save_game 2 autosave
+}
+
+func void save_point_2(string player_name)
+{
+	dprint saveit_2
+	save_game 3 autosave
+}
+
+func void save_point_3(string player_name)
+{
+	dprint saveit_3
+	save_game 4 autosave
+}
+
+########################################################
+
+func void start_trap_music(string ai_name)
+{
+	dprint martys_baby
+	sound_music_start mus_space01 0.8
+}
+
+func void Die_For_Kerr_1(string ai_name)
+{
+	dprint DFK_1
+	kerr_counter = kerr_counter - 1
+
+	if (kerr_counter eq 0)
+	{
+		Kerr_Console_All_Counters();
+	}
+}
+
+func void Die_For_Kerr_2(string ai_name)
+{
+	dprint DFK_2
+	kerr_counter = kerr_counter - 1
+
+	if (kerr_counter eq 0)
+	{
+		Kerr_Console_All_Counters();
+	}
+}
+
+func void Die_For_Kerr_3(string ai_name)
+{
+	dprint DFK_3
+	kerr_counter = kerr_counter - 1
+
+	if (kerr_counter eq 0)
+	{
+		Kerr_Console_All_Counters();
+	}
+}
+
+func void Kerr_Console_All_Counters(void)
+{
+	dprint START_KERR
+	trigvolume_enable(Kerr_trig, 1);
+	fork Pod3_Unlock_Doors
+}
+
+func void Setup_Intro(string ai_name)
+{
+# SETUP POD 1 AREA
+	dprint Setup_Intro
+	trig_activate 1
+	particle lock99_locklight02 do start
+	particle lock100_locklight01 do stop
+
+	door_unlock 11
+}
+
+func void Setup_Pod1(string ai_name)
+{
+# SETUP POD 1 AREA
+	dprint SetupPod1
+
+	door_lock 20
+	door_lock 21
+	door_lock 22
+	door_lock 23
+
+	ai2_spawn Pod1_TCL_1
+	ai2_spawn Pod1_TCL_2
+	ai2_spawn Pod1_TCL_3
+	ai2_spawn Pod1_Scientist_1
+	ai2_spawn Pod1_Scientist_2
+
+	particle lock1_locklight01 do stop
+	#particle lock1_locklight01 do start
+	sound_music_stop mus_space01
+}
+#########################################
+func void Pod1_RTAlarm_A(string ai_name)
+{
+	dprint Guard_A_RTAlarm
+	ai2_doalarm Pod1_TCL_1 10
+}
+
+func void Pod1_RTAlarm_B(string ai_name)
+{
+	dprint Guard_B_RTAlarm
+	ai2_doalarm Pod1_TCL_2 10
+}
+#########################################
+
+func void Pod1_Alarm_Sound(void)
+{
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+func void Pod1_Alarm(string ai_name)
+{
+	dprint Pod1Alarm
+	door_unlock(11);
+	particle lock99_locklight02 do start
+	sleep 180
+# SPAWN ALARM CHARACTERS
+	ai2_spawn Pod1_BOL_Alarm_1
+	ai2_spawn Pod1_BOL_Alarm_2
+	ai2_spawn pod1_a_1
+	ai2_spawn pod1_a_2
+# SET ALERT LEVELS
+	ai2_setalert Pod1_TCL_1 high 
+	ai2_setalert Pod1_TCL_2 high 
+	ai2_setalert Pod1_TCL_3 high 
+	ai2_setalert Pod1_BOL_Alarm_1 high 
+	ai2_setalert Pod1_BOL_Alarm_2 high 
+# EXECUTE ALARM PATHS
+	ai2_dopath Pod1_TCL_1 Pod1_Final_Guard_A
+	ai2_dopath Pod1_TCL_2 Pod1_Final_Guard_B
+	ai2_dopath Pod1_TCL_3 Pod1_Final_Guard_C
+	ai2_dopath Pod1_Scientist_1 Pod1_Final_Sci_A
+	ai2_dopath Pod1_Scientist_2 Pod1_Final_Sci_B
+# MAKE ALARM PATHS THEIR JOBS
+	ai2_setjobstate Pod1_TCL_1
+	ai2_setjobstate Pod1_TCL_2
+	ai2_setjobstate Pod1_TCL_3
+
+	ai2_setjobstate Pod1_Scientist_1
+	ai2_setjobstate Pod1_Scientist_2
+
+# TRIP ALARM FOR BADDIES TO PURSUE KONOKO
+
+	ai2_tripalarm 11 Konoko
+
+	particle lock1_locklight01 do stop
+
+	particle alarm1_emlight01 do start
+
+# DOOR LOCK COMMAND
+	door_lock 20
+	door_lock 21
+	door_lock 22
+	door_lock 23
+
+# annoy the player with alarm sound
+	fork Pod1_Alarm_Sound
+
+	console_reset 1
+}
+
+# UNLOCK DOORS FROM CONSOLE
+func void Pod1_UnlockDoors(string ai_name)
+{
+	dprint Pod1UnlockDoors
+
+	door_unlock 20
+	door_unlock 21
+	door_unlock 22
+	door_unlock 23
+	door_lock(11);
+	particle lock99_locklight02 do stop
+
+	input 0
+	cm_interpolate lock1 0
+	sleep 30
+	particle alarm1_emlight01 do stop
+	sleep 30
+	particle lock1_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	console_reset 10
+}
+###################### POD 2 #################################
+func void Pod2_Setup(string ai_name)
+{
+	dprint SetupPod2
+	ai2_spawn Pod2_TCL_1
+	ai2_spawn Pod2_TCL_2
+	ai2_spawn Pod2_Sci_1
+
+	particle lock2_locklight01 do stop
+}
+##############################################################
+func void Pod2_RTAlarm_A(string ai_name)
+{
+	dprint Guard_A_RTAlarm
+	ai2_doalarm Pod2_TCL_1 11
+}
+
+func void Pod2_RTAlarm_B(string ai_name)
+{
+	dprint Guard_B_RTAlarm
+	ai2_doalarm Pod2_TCL_2 11
+}
+##############################################################
+
+func void Pod2_Alarm_Sound(void)
+{
+	sound_ambient_start alarm_loop
+	sleep 900
+	sound_ambient_stop alarm_loop
+}
+
+func void Pod2_Alarm(string ai_name)
+{
+	dprint Pod2Alarm
+	door_unlock(11);
+	particle lock99_locklight02 do start
+	sleep 180
+
+# SPAWN ALARM CHARACTERS
+	#ai2_spawn Pod2_BOS_1
+	ai2_spawn Pod2_BOL_Alarm_1
+	ai2_spawn pod2_a_1
+	ai2_spawn pod2_a_2
+
+# SET ALERT LEVELS
+	ai2_setalert Pod2_TCL_1 high 
+	ai2_setalert Pod2_TCL_2 high 
+	ai2_setalert Pod2_BOS_1 high 
+
+# EXECUTE ALARM PATHS
+	ai2_dopath Pod2_TCL_1 Pod2_End_TCL_1
+	ai2_dopath Pod2_TCL_2 Pod2_End_TCL_2
+	ai2_dopath Pod2_BOS_1 Pod2_End_BOS_1
+	ai2_dopath Pod2_Sci_1 Pod2_End_Sci_1
+
+# MAKE ALARM PATHS THEIR JOBS
+	ai2_setjobstate Pod2_TCL_1
+	ai2_setjobstate Pod2_TCL_2
+	ai2_setjobstate Pod2_BOS_1
+
+	ai2_setjobstate Pod2_Sci_1
+
+# TRIP ALARM FOR BADDIES TO PURSUE KONOKO
+
+	ai2_tripalarm 12 Konoko
+
+	particle lock2_locklight01 do stop
+
+	particle alarm2_emlight01 do start
+
+# DOOR LOCK COMMANDS
+	door_lock 28
+	door_lock 29
+	door_lock 30
+	door_lock 31
+
+	console_reset 2
+
+	fork Pod2_Alarm_Sound
+}
+
+# UNLOCK DOORS FROM CONSOLE
+
+func void Pod2_UnlockDoors(string ai_name)
+{
+	dprint Pod2UnlockDoors
+
+	door_unlock 28
+	door_unlock 29
+	door_unlock 30
+	door_unlock 31
+	door_lock(11);
+	particle lock99_locklight02 do stop
+
+	input 0
+	cm_interpolate lock2 0
+	sleep 30
+	particle alarm2_emlight01 do stop
+	sleep 30
+	particle lock2_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	console_reset 11
+}
+
+func void chase_after_scan(string ai_name)
+{
+	ai2_dopath Scan_BOS_3 chase_after_3
+	ai2_dopath Scan_BOS_4 chase_after_4
+
+	ai2_setjobstate Scan_BOS_3
+	ai2_setjobstate Scan_BOS_4
+
+	ai2_tripalarm 11 Konoko
+
+	sleep 1200
+
+	ai2_dopath Scan_BOS_1 chase_after_1
+	ai2_dopath Scan_BOS_2 chase_after_2
+
+	ai2_setjobstate Scan_BOS_1
+	ai2_setjobstate Scan_BOS_2
+
+	ai2_tripalarm 9 Konoko
+}
+###################### POD 3 #################################
+func void Pod3_Setup(string ai_name)
+{
+	dprint SetupPod3
+	ai2_spawn Pod3_BOS_1
+	ai2_spawn Pod3_BOS_2
+	ai2_spawn Pod3_BOL_1
+
+	#door_lock 59
+
+	trigvolume_enable Kerr_trig 1
+}
+
+func void Pod3_Unlock_Doors(string ai_name)
+{
+	dprint Pod3UnlockDoors
+
+	door_unlock 59
+
+	input 0
+	sleep 90
+	cm_interpolate lock3 0
+	sleep 60
+	particle lock3_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void Kerr_Console(string ai_name)
+{
+	dprint Kerr_Console
+
+	door_unlock 58
+
+	input 0
+	cm_interpolate lock4 0
+	sleep 60
+	particle lock4_locklight02 do start
+	sleep 150
+	trig_deactivate 2
+	sleep 75
+	cm_reset
+	input 1
+}
+
+###################### LAB 1 #################################
+func void Setup_Lab(string ai_name)
+{
+	dprint SetUpLab
+
+	particle lock5_locklight01 do stop
+
+	door_lock 6
+	door_lock 7
+
+	ai2_spawn LabHall_BOL_1
+	ai2_spawn LabHall_BOL_2
+	ai2_spawn LabHall_BOL_3
+	ai2_spawn LabHall_BOL_4
+	ai2_spawn LabHall_BOL_5
+
+	ai2_spawn Hall_TCS_33
+
+	ai2_spawn Lab1_Sci_1
+	ai2_spawn Lab1_Sci_2
+
+	ai2_spawn Lab2_Sci_1
+	ai2_spawn Lab2_Sci_2
+
+	ai2_spawn Lab3_Sci_1
+	ai2_spawn Lab3_Sci_2
+
+	trigvolume_enable Setup_Security_Trig 0
+	trigvolume_enable(chase_trigger, 0);
+}
+
+func void Lab_Console_1(string ai_name)
+{
+	dprint LabConsole1
+
+	#particle create labalarm1_emlight02
+	particle labalarm1 do start
+
+	ai2_spawn lab_BOS_1
+
+	#ai2_spawn lab_BOS_2
+
+	ai2_tripalarm 1 Konoko
+
+	particle lock4_locklight02 do stop
+	door_lock 58
+
+	neuro_counter = neuro_counter - 1
+
+	input 0
+	cm_interpolate lock5 0
+	sleep 60
+	particle lock5a_locklight01 do start
+	sleep 150
+	cm_reset
+	target_set(1009, 30.0)
+	input 1
+
+	if (neuro_counter eq 0)
+	{
+		Lab_Console_All_Counters();
+	}
+}
+
+func void Lab_Console_2(string ai_name)
+{
+	dprint LabConsole2
+
+	particle labalarm2 do start
+
+	ai2_spawn lab_BOS_2
+
+	#ai2_spawn lab_BOS_4
+
+	ai2_tripalarm 1 Konoko
+
+	target_set(268, 30.0)
+
+	particle lock4_locklight02 do stop
+	door_lock 58
+
+	neuro_counter = neuro_counter - 1
+
+	input 0
+	cm_interpolate lock5 0
+	sleep 60
+	particle lock5b_locklight01 do start
+	sleep 150
+	cm_reset
+	target_set(1009, 30.0)
+	input 1
+
+	if (neuro_counter eq 0)
+	{
+		Lab_Console_All_Counters();
+	}
+}
+
+func void Lab_Console_3(string ai_name)
+{
+	dprint LabConsole3
+
+	ai2_spawn lab_BOS_3
+
+	#ai2_spawn lab_BOS_6
+
+	particle labalarm3 do start
+
+	ai2_tripalarm 1 Konoko
+
+	particle lock4_locklight02 do stop
+	door_lock 58
+
+	target_set(367, 30.0)
+
+	neuro_counter = neuro_counter - 1
+
+	input 0
+	cm_interpolate lock5 0
+	sleep 60
+	particle lock5c_locklight01 do start
+	sleep 150
+	cm_reset
+	target_set(1009, 30.0)
+	input 1
+
+	if (neuro_counter eq 0)
+	{
+		Lab_Console_All_Counters();
+	}
+}
+
+func void Lab_Console_All_Counters(void)
+{
+	dprint PROBE_ROOM_OPEN
+	door_unlock 6
+	door_unlock 7
+
+	kerr_console_music_stop
+}
+
+func void Lab_Unlock_Door_5(string ai_name)
+{
+	dprint Probe_Room_Unlock_Doors
+	door_unlock 1
+# CB: no idea what this was, maybe it was the same as the current 66_01
+#	sound_dialog_play c13_49a_01konoko
+	input 0
+	cm_interpolate lock6 0
+	sleep 60
+	particle lock6_locklight02 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	trigvolume_enable Setup_Security_Trig 1
+	trigvolume_enable(chase_trigger, 1);
+}
+#######################DURING THE SCAN#########################
+func void Scan_Guards(string ai_name)
+{
+	dprint Scan_Guards
+
+	ai2_spawn Scan_BOS_1
+	ai2_spawn Scan_BOS_2
+	ai2_spawn Scan_BOS_3
+	ai2_spawn Scan_BOS_4
+
+	#chr_teleport LabHall_BOL_1 274
+	#chr_teleport LabHall_BOL_4 275
+
+	chr_teleport LabHall_BOL_5 272
+	chr_teleport Hall_TCS_33 7018
+
+	#chr_teleport LabHall_BOL_2 264
+	#chr_teleport LabHall_BOL_3 7004
+
+	#ai2_forget LabHall_BOL_1
+	#ai2_forget LabHall_BOL_2
+	#ai2_forget LabHall_BOL_3
+	#ai2_forget LabHall_BOL_4
+
+	ai2_forget LabHall_BOL_5
+	ai2_forget Hall_TCS_33
+
+	ai2_dopath LabHall_BOL_1 Scan_BOL_1
+	ai2_dopath LabHall_BOL_2 Scan_BOL_2
+	ai2_dopath LabHall_BOL_3 Scan_BOL_3
+	ai2_dopath LabHall_BOL_4 Scan_BOL_4
+	ai2_dopath LabHall_BOL_5 Scan_BOL_5
+	ai2_dopath Hall_TCS_33 Scan_Hall_TCS_33
+
+	ai2_setjobstate LabHall_BOL_1
+	ai2_setjobstate LabHall_BOL_2
+	ai2_setjobstate LabHall_BOL_3
+	ai2_setjobstate LabHall_BOL_4
+	ai2_setjobstate Hall_TCS_33
+
+	fork get_her
+}
+
+func void get_her(string ai_name)
+{
+	dprint get_her_timer_start
+
+	sleep 18000
+
+	ai2_tripalarm 5 Konoko
+
+	ai2_dopath LabHall_BOL_1 get_her_1
+	ai2_dopath LabHall_BOL_2 get_her_2
+
+	ai2_setjobstate LabHall_BOL_1
+	ai2_setjobstate LabHall_BOL_2
+
+	sleep 18000
+
+	ai2_tripalarm 7 Konoko
+
+	ai2_dopath LabHall_BOL_3 Scan_BOL_3
+	ai2_dopath LabHall_BOL_4 Scan_BOL_4
+
+	ai2_setjobstate LabHall_BOL_3
+	ai2_setjobstate LabHall_BOL_4
+
+	sleep 18000
+
+	ai2_tripalarm 9 Konoko
+
+	ai2_dopath Scan_BOS_1 get_her_1
+	ai2_dopath Scan_BOS_2 get_her_2
+
+	ai2_setjobstate Scan_BOS_1
+	ai2_setjobstate Scan_BOS_2
+
+	sleep 18000
+
+	ai2_tripalarm 11 Konoko
+
+	ai2_dopath Scan_BOS_3 get_her_3
+	ai2_dopath Scan_BOS_4 get_her_4
+
+	ai2_setjobstate Scan_BOS_3
+	ai2_setjobstate Scan_BOS_4
+}
+
+func void endgether(string ai_name)
+{
+	ai2_attack Final_BOL_1 Konoko
+}
+########################### SECURITY #########################
+func void Setup_Security(string ai_name)
+{
+	dprint Setup_Security
+
+	ai2_spawn Sec_BOS_1
+	ai2_spawn Sec_BOS_2
+	ai2_spawn Sec_BOL_1
+
+	trigvolume_enable Ambush_Trigger_1 1
+
+	door_lock 7
+
+	particle lock8_locklight02 do stop
+
+	door_lock 54
+	particle lock7_locklight02 do stop
+
+	post_scan_music_stop
+}
+
+func void Unlock_Door_7(string ai_name)
+{
+	dprint Unlock_Door_7
+
+	door_unlock 54
+
+	input 0
+	cm_interpolate lock7 0
+	sleep 60
+	particle lock7_locklight02 do start
+	sleep 150
+	cm_reset
+	target_set(360, 30.0)
+	input 1
+
+	post_scan_music_stop
+}
+
+func void Sec_Ambush_1(string ai_name)
+{
+	dprint AMBUSH
+	trig_deactivate 3
+	trig_deactivate 4
+	turret_deactivate 2
+	turret_deactivate 3
+
+	door_unlock 7
+	door_unlock 36
+	particle lock8_locklight02 do start
+
+	door_lock 54
+	particle lock7_locklight02 do stop
+	
+	ai2_spawn Sec_Ambush_BOS_1
+	ai2_spawn Sec_Ambush_BOL_1
+
+	ai2_attack Sec_Ambush_BOS_1 Konoko
+	ai2_attack Sec_Ambush_BOL_1 Konoko
+
+	#ai2_spawn Sec_Ambush_BOS_2
+	#ai2_spawn Sec_Ambush_BOL_2
+}
+
+
+func void nextwave_1(string ai_name)
+{
+	ambush_counter = ambush_counter - 1
+
+	if (ambush_counter eq 0)
+	{
+		Sec_Ambush_2();
+	}
+}
+
+func void nextwave_2(string ai_name)
+{
+	ambush_counter = ambush_counter - 1
+
+	if (ambush_counter eq 0)
+	{
+		Sec_Ambush_2();
+	}
+}
+
+func void closethedoor(string ai_name)
+{
+	door_lock 7
+	door_lock 36
+
+	particle lock8_locklight02 do stop
+}
+
+func void Sec_Ambush_2(string ai_name)
+{
+	dprint AMBUSH2
+
+	door_unlock 7
+	door_unlock 36
+
+	particle lock8_locklight02 do start
+
+	ai2_spawn Sec_Ambush_BOS_2
+	ai2_spawn Sec_Ambush_BOL_2
+
+	ai2_attack Sec_Ambush_BOS_2 Konoko
+	ai2_attack Sec_Ambush_BOL_2 Konoko
+}
+
+######################### FINAL #########################
+
+func void Setup_Final(string ai_name)
+{
+	dprint Setup_Final
+
+	ai2_spawn Final_BOS_1
+	ai2_spawn Final_BOL_1
+
+	ai2_spawn Final_Thug_1
+	ai2_spawn Final_Thug_2
+
+	trigvolume_enable end 0
+}
+
+func void end(string ai_name)
+{
+	dprint END
+
+	fork Outro
+	
+	ai2_forget Final_BOS_1
+	ai2_forget Final_BOL_1
+	ai2_forget Final_BOL_2
+
+	ai2_forget Sec_Ambush_BOS_1
+	ai2_forget Sec_Ambush_BOS_2
+	ai2_forget Sec_Ambush_BOL_1
+	ai2_forget Sec_Ambush_BOL_1
+
+	ai2_forget Final_Thug_1
+	ai2_forget Final_Thug_2
+
+	ai2_dopath Final_BOS_1 End_BOS_1
+	ai2_dopath Final_BOL_1 End_BOL_1
+	ai2_dopath Final_BOL_2 End_BOL_2
+
+	ai2_dopath Sec_Ambush_BOS_1 End_BOS_1
+	ai2_dopath Sec_Ambush_BOS_2 End_BOS_1
+	ai2_dopath Sec_Ambush_BOL_1 End_BOL_1
+	ai2_dopath Sec_Ambush_BOL_2 End_BOL_1
+
+	ai2_dopath Final_Thug_1 End_Thug_1
+	ai2_dopath Final_Thug_2 End_Thug_1
+
+	ai2_setjobstate Final_BOS_1
+	ai2_setjobstate Final_BOL_1
+	ai2_setjobstate Final_BOL_2
+
+	ai2_setjobstate Sec_Ambush_BOS_1
+	ai2_setjobstate Sec_Ambush_BOS_2
+
+	ai2_setjobstate Sec_Ambush_BOL_1
+	ai2_setjobstate Sec_Ambush_BOL_2
+
+	ai2_setjobstate Final_Thug_1
+	ai2_setjobstate Final_Thug_2
+}
+
+##############################################################
+
+# COUNTDOWN TO FINAL CUTSCENE
+
+func void check_1(string ai_name)
+{
+	dprint circle_squared
+	final_count = final_count - 1
+	if (final_count eq 0)
+	{
+	trigvolume_enable ending 1
+	}
+}
+
+func void check_2(string ai_name)
+{
+	dprint circle_squared
+	final_count = final_count - 1
+	if (final_count eq 0)
+	{
+	trigvolume_enable ending 1
+	}
+}
+
+func void mid_guards(string ai_name)
+{
+	dprint final_guards
+	ai2_spawn Final_BOL_2
+	ai2_spawn Final_Thug_9
+
+	ai2_attack Final_BOL_2 Konoko
+}
+
+func void end_guards(string ai_name)
+{
+	dprint final_guards
+	ai2_spawn end_guard_1
+	ai2_spawn end_guard_2
+	ai2_spawn Final_Thug_10
+}
+
+
+####################################################################
+
+func void set_objective_1(void)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set(1261, 30.0)
+}
+
+func void set_objective_2(string chr_index)
+{
+	dprint set_objective_2
+	objective_set(2)
+	target_set(366, 30.0)
+}
+
+func void set_objective_3(string chr_index)
+{
+	dprint set_objective_3
+	objective_set(3)
+	target_set(346, 30.0)
+}
+
+func void set_objective_4(string chr_index)
+{
+	dprint set_objective_4
+	objective_set(4)
+	target_set(222, 30.0)
+}
+
+func void kerr_died(string ai_name)
+{
+	if (has_probed eq 0)
+	{
+		you_lose();
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void level_14a(void)
+{
+	dprint set_text_14a
+	text_console level_14a
+	console_reset 12
+}
+
+func void level_14b(void)
+{
+	dprint set_text_14b
+	text_console level_14b
+	console_reset 6
+}
+
+
+################## ANIM SCRIPTS ##########################################
+func void patrolscript0001 (string ai_name)
+{
+	playback_block Pod1_TCL_1 alarm1 interp 20
+}
+
+func void patrolscript0002 (string ai_name)
+{
+	playback_block Pod1_TCL_2 alarm2 interp 20
+}
+
+func void patrolscript0003 (string ai_name)
+{
+	playback_block Pod2_TCL_1 pod2alarm1 interp 20
+}
+
+func void patrolscript0004 (string ai_name)
+{
+	playback_block Pod2_TCL_2 pod2alarm2 interp 20
+}
+
+func void patrolscript0009 (string ai_name)
+{
+	particle lock99_locklight02 do start
+	door_unlock 11
+	sleep 540
+	particle lock99_locklight02 do stop
+	door_lock 11
+}
+
+func void patrolscript0010 (string ai_name)
+{
+	particle lock99_locklight02 do start
+	door_unlock 11
+# WAIT AND RELOCK DOORS
+	sleep 540
+	particle lock99_locklight02 do stop
+	door_lock 11
+}
+
+func void kerr_console_music(void)
+{
+	sound_music_start mus_ambgrv2 0.8
+}
+
+func void kerr_console_music_stop(void)
+{
+	dprint stopping_kerr_console_music
+	sound_music_stop mus_ambgrv2
+}
+
+func void post_scan_music_start(void)
+{
+	dprint startting posctuscene
+	sound_music_start mus_xtr1 0.7
+}
+
+func void post_scan_music_stop(void)
+{
+	sound_music_stop mus_xtr1
+}
+
+################## VAT MONOLOGUE LOGIC ##########################
+
+var int played_vat_monologue = 0;
+
+func void prepare_vat_monologue(void)
+{
+	trigvolume_enable tv_vat_monologue_1 1
+	trigvolume_enable tv_vat_monologue_2 1
+}
+
+func void set_vat_monologue_variable(void)
+{
+	played_vat_monologue = 1;
+}
+
+func void play_vat_monologue(string ai_name)
+{
+	if (played_vat_monologue eq 0)
+	{
+		# this is a hack to get around the way that the scripting
+		# language mistakenly sets variables that are inside an
+		# if clause that isn't being run
+		set_vat_monologue_variable();
+
+		sleep 90
+
+		EndScan();
+	}
+}
+
+################## END LEVEL LOGIC FOR TRIGGER ###################
+
+func void check_outro(string ai_name)
+{
+	trigvolume_enable tv_check_outro 0
+	
+	if(FTS_variable eq 0)
+	{
+		if(trigvolume_count (77) eq 0)
+		{
+			sleep 120
+			trigvolume_enable ending 1
+			trigvolume_enable ending2 1
+		}
+		if(trigvolume_count (77) ne 0)
+		{
+			sleep 90
+			trigvolume_enable tv_check_outro 1
+		}
+	}
+	sleep 90
+	trigvolume_enable tv_check_outro 1
+}
+
+func void final_check_for_crane(string ai_name)
+{
+	final_check = final_check + 1
+}
+
+func void FTS(string ai_name)
+{
+	FTS_variable = FTS_variable - 1
+}
Index: /nikanabo/current/bsl/original/IGMD/neuro/neuro_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/neuro/neuro_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/neuro/neuro_main.bsl	(revision 185)
@@ -0,0 +1,23 @@
+#
+# neuro_main.bsl
+#
+
+func void
+main(void)
+{
+	gl_fog_blue=.15
+	gl_fog_red=.15
+	gl_fog_green=.15
+	gl_fog_start=.985
+	gs_farclipplane_set 4000
+		obj_create 401 409
+		env_anim 401 409
+		obj_create 71 74
+	level_start
+
+	if (save_point eq 0)
+	{
+		neuro_cs_intro
+		save_game 1 autosave
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/neuro/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/neuro/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/neuro/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,102 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+
+#lab 1
+func void lab1_start(string ai_name)
+{
+	dprint lab1_start
+	particle lab1 do start
+}
+func void lab1_stop(string ai_name)
+{
+	dprint lab1_stop
+	particle lab1 do stop
+}
+#lab2
+func void lab2_start(string ai_name)
+{
+	dprint lab2_start
+	particle lab2 do start
+}
+func void lab2_stop(string ai_name)
+{
+	dprint lab2_stop
+	particle lab2 do stop
+}
+#lab3
+func void lab3_start(string ai_name)
+{
+	dprint lab3_start
+	particle lab3 do start
+}
+func void lab3_stop(string ai_name)
+{
+	dprint lab3_stop
+	particle lab3 do stop
+}
+#Particles for the exterior of lab3
+func void part1_start(string ai_name)
+{
+	dprint part1_start
+	particle part1 do start
+}
+func void part1_stop(string ai_name)
+{
+	dprint part1_stop
+	particle part1 do stop
+}
+#Particles for the exterior of lab2
+func void part2_start(string ai_name)
+{
+	dprint part2_start
+	particle part2 do start
+}
+func void part2_stop(string ai_name)
+{
+	dprint part2_stop
+	particle part2 do stop
+}
+#Particles for the exterior of lab1
+func void part3_start(string ai_name)
+{
+	dprint part3_start
+	particle part3 do start
+}
+func void part3_stop(string ai_name)
+{
+	dprint part3_stop
+	particle part3 do stop
+}
+#particles for the vats in the end of the level
+func void vat1_start(string ai_name)
+{
+	dprint vat1_start
+	particle vat1 start
+}
+func void vat1_stop(string ai_name)
+{
+	dprint vat1_stop
+	particle vat1 stop
+}
+func void vat2_start(string ai_name)
+{
+	dprint vat2_start
+	particle vat2 start
+}
+func void vat2_stop(string ai_name)
+{
+	dprint vat2_stop
+	particle vat2 stop
+}
+func void vat3_start(string ai_name)
+{
+	dprint vat3_and_4_start
+	particle vat3 start
+	particle vat4 start
+}
+func void vat3_stop(string ai_name)
+{
+	dprint vat3_stop
+	particle vat3 stop
+}
Index: /nikanabo/current/bsl/original/IGMD/power/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,26 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+
+#power1
+func void power1_start(string ai_name)
+{
+	dprint power1_start
+	particle power1 do start
+}
+func void power1_stop(string ai_name)
+{
+	dprint power1_stop
+	particle power1 do stop
+}
+#power2
+func void power2_start(string ai_name)
+{
+	dprint power2_start
+	particle power2 do start
+}
+func void power2_stop(string ai_name)
+{
+	dprint power2_stop
+	particle power2 do stop
+}
Index: /nikanabo/current/bsl/original/IGMD/power/power_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power/power_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power/power_cutscene.bsl	(revision 185)
@@ -0,0 +1,428 @@
+#
+#
+# power_cutscene.bsl
+#
+
+func void
+intro(
+	void)
+{
+	# CB: begin_cutscene does a silent ai2_allpassive 1 as part of its cutscene setup,
+	# so we need to remove this if we want to have AIs walking around under their own
+	# control during a cutscene
+	fade_out 0 0 0 0
+	cm_interpolate Camout01 0
+	obj_create 100 104
+	chr_create 1000 start
+	chr_create 1001 start
+	playback 1000 IntroGrifTCTF
+	playback 1001 IntroKonTCTF
+	sleep f7
+	begin_cutscene
+	cutscene_sync off 
+	ai2_allpassive 0
+
+	ai2_spawn A1_intro01
+	ai2_spawn A1_intro02
+	ai2_makeignoreplayer A1_intro01 1
+	ai2_makeignoreplayer A1_intro02 1			
+	#fade_out 0 0 0 0
+	#Setup Konoko and Griffin talking			
+	sleep f60
+
+#	Force holster by Wu
+	chr_forceholster char_0 1
+
+	fade_in 120
+	chr_nocollision(0, 1);
+	#Setup shot
+	cm_anim both Camout01
+	cm_wait
+	#KOnoko standing on top
+	cm_anim both Camout02
+	chr_envanim 0 KonBipedBox01
+	chr_animate 0 KONOKOidle1 300
+	env_setanim 100 StandRightWing
+	env_setanim 101 StandLeftWing
+	env_setanim 102 StandBody
+	env_setanim 103 StandRightTail
+	env_setanim 104 StandLeftTail
+	#Konoko and Griffin talking
+	sleep f120
+	sound_dialog_play c08_27_01konoko
+	cinematic_start (KONtalking, 180, 180, 15, 1, 15, false)
+	sound_dialog_play_block pause
+	sound_dialog_play c08_27_02griffin
+	cinematic_start (GRIFtalking, 180, 180, 16, 3, 15, true)
+	cm_interpolate_block IntroCamTBoth 0
+	sound_dialog_play_block pause
+	sound_dialog_play c08_27_03konoko
+	cinematic_stop (KONtalking, 15, 20)
+	cinematic_start (KONintense, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	sound_dialog_play c08_27_04griffin
+	sound_dialog_play_block pause
+	sound_dialog_play c08_27_05konoko
+	sound_dialog_play_block pause
+	cm_interpolate_block IntroCamTGrif 0
+	sound_dialog_play c08_27_06griffin
+	cinematic_stop (GRIFtalking, 16, 20)
+	cinematic_start (GRIFtalkangry, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	cm_interpolate IntroCamTKon 0
+
+	# start the wind as the dialog ends, sync to that
+	cutscene_sync on
+	sound_dialog_play c08_27_07konoko
+	cinematic_stop (GRIFtalkangry, 16, 20)
+	cinematic_stop (KONintense, 15, 20)
+	cinematic_start (KONangry, 180, 180, 15, 1, 20, false)
+	sleep 200
+	sound_ambient_start pp_wind_loop 0.1
+	sound_ambient_volume pp_wind_loop 0.8 1.0
+	sleep 50
+	cutscene_sync off
+	#Jumping off the building
+	chr_envanim 0 KonBipedBox02 norotation
+	cm_anim both Camout03
+	#sound_ambient_start pp09_wingsa
+	chr_animate 0 KONOKOlev9_intro_jump
+	env_setanim 100 JumpRightWing
+	env_setanim 101 JumpLeftWing
+	env_setanim 102 JumpBody
+	env_setanim 103 JumpRightTail
+	env_setanim 104 JumpLeftTail
+	sleep f120
+	sound_ambient_start pp09_wingsa
+#	october 25, 2000 this pause was breaking the scene
+#	sound_dialog_play_block pause
+	cinematic_stop (KONangry, 15, 20)
+	#sleep f100	
+	cm_anim_block both Camout04
+	#Transport A1_intro02 to new location
+	chr_teleport A1_intro02 1105
+	#Gliding
+	#music_intro
+	sleep f100
+	sound_ambient_start pp09_wingsb
+	chr_envanim_block 0 KonBipedBox03
+	cm_anim both Camout05
+	chr_animate 0 KONOKOlev9_intro_glide 360
+	env_setanim 100 GlideRightWing
+	env_setanim 101 GlideLeftWing
+	env_setanim 102 GlideBody
+	env_setanim 103 GlideRightTail
+	env_setanim 104 GlideLeftTail
+	#Landing
+	chr_envanim_block 0 KonBipedBox04 norotation
+	#gl_fog_start=.98
+	#gs_farclipplane_set 2000
+	cm_anim both Camout06
+	chr_animate 0 KONOKOlev9_intro_land
+
+	env_setanim 100 LandRightWing
+	env_setanim 101 LandLeftWing
+	env_setanim 102 LandBody
+	env_setanim 103 LandRightTail
+	env_setanim 104 LandLeftTail
+	sleep 30
+	sound_ambient_volume pp_wind_loop 0.0 1.0
+	sleep 60
+	sound_ambient_stop pp_wind_loop
+	sound_ambient_start pp09_wingsc
+	cm_wait
+	playback 0 IntroKonokoSet01
+	obj_kill 100 104
+	sleep f5
+	cm_reset
+	chr_nocollision 0 0
+	end_cutscene
+	env_show 100 1
+	env_show 101 1
+	env_show 102 1
+	env_show 103 1
+	env_show 104 1
+	chr_delete ai_12
+	chr_delete ai_13
+	chr_delete 1000
+	chr_delete 1001
+	ai2_makeignoreplayer A1_intro01 0
+	ai2_makeignoreplayer A1_intro02 0
+	#Transport A1_intro02 to new location again
+	chr_teleport A1_intro02 1104
+	s1
+	music_intro
+	music_intro_timer
+}
+
+func void
+camcontrol(
+	void)
+{
+	cm_anim both Camout01
+	cm_anim both Camout02
+	cm_anim both Camout03
+	cm_anim both Camout04
+	cm_anim both Camout05
+	cm_anim both Camout06
+	cm_wait
+	letterbox 0
+	cm_jello 1
+	cm_reset
+	chr_nocollision 0 0
+	input 1
+}
+
+func void
+Muro(
+	void)
+{
+	begin_cutscene
+
+	sound_music_start mus_sad1 0.1
+	sound_music_volume mus_sad1 0.3 2
+
+	cutscene_sync off
+	sleep f10
+	cm_anim both Elev1Cam01
+	playback 0 Elev1KonokoSet01
+	cutscene_sync on
+	sound_ambient_start c12_20_16elevator
+	sleep f5
+	chr_nocollision 0 1
+	chr_envanim 0 Elev1KonBox01 norotation
+	obj_create 801 801
+	obj_shade 801 801 .4 .4 .4
+	env_show 801 0
+	env_setanim 801 Elev101
+	sleep 200
+
+	#Shinatama crying here
+
+	sound_dialog_play c08_28_05shinscream1
+	sound_music_volume mus_sad1 1.0 0.5
+
+	cinematic_start (SHINtortured, 180, 180, 20, 7, 15, false)
+
+	sleep 60
+	sound_music_volume mus_sad1 0.8 0.5	
+	sleep 100
+
+	fade_out 0 0 0 10
+	sleep f10
+	#Muro torturing shinatama
+	fade_in 10
+	particle torture do start
+	ai2_spawn MuroMuro
+	ai2_spawn MuroShinatama
+	ai2_spawn MuroComguy
+	playback MuroMuro MuroMuroSet
+	playback MuroComguy MuroComguySet
+
+	sound_dialog_play c08_28_06shinscream2
+
+	chr_envanim MuroShinatama ShinBox02 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin02 180
+	cutscene_sync off
+	cm_interpolate MuroCamShin02 0
+	sound_ambient_start c12_26_20shin_tort
+	cm_interpolate_block MuroCamShin01 800
+	sleep f120
+	chr_envanim MuroShinatama ShinBox03 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin03 12
+	sleep f12
+	particle torture do stop
+	chr_envanim MuroShinatama ShinBox04 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin04 1000 12
+	sound_dialog_play_block pause
+	cinematic_stop (SHINtortured, 19,20)
+	##Muro talks
+	sound_dialog_play c08_28_01muro
+	cinematic_start (MUROtalking, 180, 180, 16, 3, 15, true)
+	cm_interpolate MuroCamMuro 0
+	sound_dialog_play_block pause
+	##Shin screams
+	particle torture do start
+	sound_ambient_start c12_26_20shin_torta
+	#chr_envanim MuroShinatama ShinBox01 norotation
+	#chr_animate MuroShinatama SHINATlev9_Shin01 12
+	#sleep f12
+	chr_envanim MuroShinatama ShinBox02 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin02 180
+
+	sound_dialog_play shinscream_new
+
+	cinematic_start (SHINtortured, 180, 180, 19, 20, 10, false)
+	sleep f130
+	particle torture do stop
+	chr_envanim MuroShinatama ShinBox04 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin04 1200 10
+	sleep f30
+	##Muro talks again
+	cm_interpolate MuroCamMuro01 0
+	cm_interpolate_block MuroCamMuro02 1400
+	sound_dialog_play c08_28_02muro
+	cinematic_stop (SHINtortured, 18,20)
+	sound_dialog_play_block pause
+	sleep f10
+	particle torture do start
+	sound_ambient_start c12_26_20shin_torta
+
+	sound_dialog_play shinscream_new2
+
+	sound_dialog_play_block pause
+	particle torture do stop
+	sleep f10
+	sound_dialog_play c08_28_03muro
+	sound_dialog_play_block pause
+	chr_envanim MuroShinatama ShinBox04 norotation
+	chr_animate MuroShinatama SHINATlev9_Shin04 1200 10
+	sleep f5
+
+	sound_dialog_play shinscreams_6
+
+	sound_dialog_play_block pause
+	sound_dialog_play c08_28_04muro
+	sound_dialog_play_block pause
+	cinematic_stop (MUROtalking, 16,15)
+
+	sound_dialog_play muro_laff2
+
+	sleep f80
+	particle torture do start
+	sound_ambient_start c12_26_20shin_torta
+	sleep f15
+
+	sound_dialog_play_interrupt shinscreams_4
+
+	cinematic_start (SHINtortured, 180, 180, 20, 19, 10, false)
+	sleep f20
+	fade_out 0 0 0 10
+	sleep f10
+	particle torture do stop
+	fade_in 10
+	#Konoko finishes riding elevator
+	chr_envanim 0 Elev1KonBox02 norotation
+	env_setanim 801 Elev102
+	cm_anim both Elev1Cam02
+	sound_ambient_start c13_07_22elevatora 
+	sleep f295
+	env_show 802 1
+	obj_kill 801 801
+	cm_reset
+	playback 0 Elev1KonokoSet
+	sleep f1
+	chr_nocollision 0 0
+	end_cutscene
+
+	chr_delete MuroComguy
+	chr_delete MuroMuro
+	chr_delete MuroShinatama
+}
+
+
+
+func void
+Elev2(
+	void)
+{
+	begin_cutscene
+	sleep f30
+	cutscene_sync off
+	chr_nocollision 0 1
+	playback 0 Elev2KonokoSet
+	cm_anim both Elev2Cam01
+	cutscene_sync on
+	sound_ambient_start c13_07_22elevator
+	chr_envanim 0 Elev2KonBox01
+	env_show 821 0
+	obj_create 821 821
+	obj_shade 821 821 .4 .4 .4
+	env_setanim 821 Elev201
+	cm_wait
+	obj_kill 821 821
+	env_show 822 1
+	chr_nocollision 0 0
+	cm_reset
+	end_cutscene
+}
+
+
+
+func void
+Torture(
+	void)
+{
+	#input 0
+	cm_interpolate TortureCam01 80
+	sleep f180
+	cm_reset 80
+	#input 1
+}
+
+
+func void
+outro(
+	void)
+{
+	sleep f30
+	begin_cutscene jello
+	cutscene_sync off
+	#oni SPECcial effect
+	chr_animate 0 KONOKOpowerup
+	cinematic_start (KONtransform, 180, 180, 15, 2, 15, false)
+	sleep f220
+	fade_out 0 0 0 10
+	sleep f10
+	fade_in 10
+	ai2_spawn OutroKerr
+	ai2_spawn OutroGrif
+	ai2_spawn OutroCop
+	playback OutroCop ShinCopSet
+	playback OutroGrif ShinGrifSet
+	playback OutroKerr ShinKerrSet
+	cinematic_stop (KONtransform, 16, 30)
+	cm_interpolate ShinCamCop 0
+	cm_interpolate_block ShinCamCopFace 1600
+	sleep f20
+	sound_dialog_play c08_29_01scigoon1
+	cinematic_start (COPtalking, 180, 180, 16, 3, 20, false)
+	sound_dialog_play_block pause
+	cinematic_stop (COPtalking, 16, 20)
+	cm_interpolate ShinCamGrif 0
+	cm_interpolate_block ShinCamGrifFace 1800
+	sound_dialog_play c08_29_02griffin
+	cinematic_start (GRIFtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block pause
+	sleep f20
+	playback 0 OutroKonoko01
+	cinematic_stop (GRIFtalking, 19, 20)
+	fade_out 0 0 0 10
+	sleep f10
+	fade_in 10
+	#doors start to open
+	obj_create 131 133
+	env_anim 131 133
+	env_show 134 0
+	env_show 135 0
+	env_show 136 0
+	cm_interpolate OutroCam01 0
+	cutscene_sync on
+	sound_ambient_start c03_55_18bigdoor
+	cm_interpolate_block OutroCam02 700
+	sleep f200
+	playback 0 OutroKonoko02
+	sleep f200
+	#Konoko sees doors opening
+	#playback 0 OutroKonoko02
+	cm_interpolate OutroCam03 0
+	sleep f90
+	#playback 0 OutroKonoko02
+	sleep f40
+	cm_interpolate OutroCam04 0
+	sleep f180
+	fade_out 0 0 0 120
+	sleep f120
+	win
+}
+
Index: /nikanabo/current/bsl/original/IGMD/power/power_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power/power_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power/power_main.bsl	(revision 185)
@@ -0,0 +1,36 @@
+#
+# power_main.bsl
+#
+
+func void
+main(
+	void)
+{
+	env_show 100 0
+	env_show 101 0
+	env_show 102 0
+	env_show 103 0
+	env_show 104 0
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.99
+	gs_farclipplane_set 3000	
+	#hide elevator gunk
+	env_show 802 0
+	env_show 822 0
+
+	my_save_point = save_point
+	
+	start
+
+	if (my_save_point eq 0)
+	{
+		fork intro();
+	}
+}
+
+#func void chase1(int chr_index)
+#{
+#}
+	
Index: /nikanabo/current/bsl/original/IGMD/power/power_objectives.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power/power_objectives.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power/power_objectives.bsl	(revision 185)
@@ -0,0 +1,214 @@
+#
+# power_objectives.bsl
+#
+# SCRIPTS TO SET LEVEL OBJECTIVES/HINTS
+#
+var int cop;
+var int nocop;
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set(5007, 30.0)
+}
+
+func void copdied(string ai_name)
+{
+	dprint copdied
+	nocop = 1
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective_3
+	objective_set(3)
+	cop = 1
+}
+
+func void target02(string ai_name)
+{
+	dprint target02
+	input 0
+	chr_invincible char_0 1
+
+
+	if(trigvolume_count(28) ne 0)
+	{
+	cm_interpolate bluedoor 0
+	sleep 60
+	}
+		
+	if(blue01 eq 0)
+	{
+	cm_interpolate bluedoor 0
+	sleep 60
+	}
+
+	if (blue01 eq 1)
+	{
+		if (trigvolume_count(28) eq 0)
+		{
+			ai2_passive A1_s_blue01 1
+			chr_teleport A1_s_blue01 7001
+			cm_interpolate bluedoor 0
+			sleep 60
+			ai2_passive A1_s_blue01 0
+			ai2_dopath A1_s_blue01 patrol_31_bluedoor
+			particle blue_locklight01 do start
+			particle b2_locklight01 do start
+			sleep 180
+		} 
+	}
+
+	particle blue_locklight01 do start
+	particle b2_locklight01 do start
+	sleep 60
+	cm_reset
+	chr_invincible char_0 0
+	input 1
+	target_set(2001, 30.0)
+#	ai2_spawn A1_s_red01
+	ai2_spawn A1_s_red02
+	trigvolume_enable trigger_volume_12 1
+}
+
+func void target03(string ai_name)
+{
+	dprint target03
+	ai2_spawn char_1
+	target_set(5007, 30.0)
+
+}
+
+func void target04(string ai_name)
+{
+	dprint target04
+	target_set(108, 30.0)
+
+}
+
+func void target05(string ai_name)
+{
+	dprint target05_07_09
+	ai2_spawn whiteneut
+	ai2_spawn B1_s_Red01
+	ai2_spawn B2_s_blue06
+	target_set(133, 30.0)
+	sleep 60
+
+	music_stop
+}
+
+func void target06(string ai_name)
+{
+	dprint target06
+	particle green_locklight01 do start
+	target_set(2005, 30.0)
+	sleep 120
+	trigvolume_enable trigger_volume_13 1
+	music_stop
+}
+
+func void target08(string ai_name)
+{
+	dprint target08
+	particle white_locklight01 do start
+	target_set(3001, 30.0)
+
+}
+
+func void target10(string ai_name)
+{
+	dprint target10
+	target_set(5008, 30.0)
+
+}
+
+func void target11(string ai_name)
+{
+	dprint target02
+	target_set(5009, 30.0)
+
+}
+
+func void target12(string ai_name)
+{
+	dprint target12
+	target_set(119, 30.0)
+
+}
+
+func void target13(string ai_name)
+{
+	dprint target13_16_18
+	target_set(128, 30.0)
+}
+
+func void target14(string ai_name)
+{
+	dprint target14
+	particle red_locklight01 do start
+	target_set(2085, 30.0)
+
+}
+
+func void target15(string ai_name)
+{
+	dprint target15
+	target_set(125, 30.0)
+
+}
+
+func void target17(string ai_name)
+{
+	dprint target17
+	particle yellow_locklight01 do start
+	target_set(3094, 30.0)
+
+}
+
+func void target19(string ai_name)
+{
+	dprint target19
+	target_set(5010, 30.0)
+
+}
+
+func void target20(string ai_name)
+{
+	dprint target20
+	target_set(5006, 30.0)
+
+}
+
+func void unlock_bwhite(string ai_name)
+{
+	dprint unlock_bwhite
+	particle bwhite_locklight01 do start
+	s5
+# checks to see if cop has already talked to konoko
+	if (cop eq 0)
+	{
+# if not, then see if the cop is dead
+		if(nocop eq 1)
+		{
+# if so, then go ahead and give next objective from console 4
+			sleep 180
+			set_objective_3
+		}
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+func void you_win(int char_index)
+{
+	outro
+	win
+}
Index: /nikanabo/current/bsl/original/IGMD/power/power_spawn.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power/power_spawn.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power/power_spawn.bsl	(revision 185)
@@ -0,0 +1,750 @@
+#	power_spawn
+#	spawn units and trigger volumes
+
+var int counter = 8;
+var int my_save_point = 0;
+var int blue01 = 1;
+var int music_counter = 0;
+var int pipe;
+var int pipe2;
+var int count_respawn1=0;
+var int count_respawn2=0;
+
+# music #
+
+func void music_intro(void)
+{
+	sound_music_start mus_main01 .75
+	music_counter = 2
+}
+
+func void music_muro(void)
+{
+	sound_music_start mus_sad1 .8
+#	this music stopped in target05 in objective scripts
+}
+
+func void music_pipe(void)
+{
+	sound_music_start mus_asian .75
+#	this music stopped in target13 in objective scripts
+}
+
+func void music_battle(void)
+{
+	sound_music_start mus_fiteb .75
+#	this music stopped in check_death script
+}
+
+func void music_intro_timer(void)
+{
+	sleep 4500
+
+	if (music_counter ne 0) 
+	{
+		dprint music_force_stop
+		music_counter = 0
+		music_stop
+	}
+}
+
+func void die_for_art(string ai_name)
+{
+	dprint DFA_1
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		music_stop
+	}
+
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_main01
+	sound_music_stop mus_sad1
+	sound_music_stop mus_asian
+	sound_music_stop mus_fiteb
+}
+
+# start and objectives #
+
+func void start(string ai_name)
+{
+	dprint XXX_start_script_XXX
+	particle power1 do start
+	particle power2 do start
+	trigvolume_enable trigger_volume_02 0
+	trigvolume_enable trigger_volume_06 0
+	trigvolume_enable trigger_volume_12 0
+	trigvolume_enable trigger_volume_13 0
+	trigvolume_enable trigger_volume_40 0
+
+	if (my_save_point eq 0)
+	{
+		set_objective_1
+	}
+
+	if (my_save_point eq 1)
+	{
+		dprint restore1
+		ai2_spawn A1_intro01
+		ai2_spawn A1_intro02
+		restore_game
+		music_intro	
+		objective_set 1 silent
+		target_set(5007, 30.0)
+		music_intro_timer
+	}
+
+	if (my_save_point eq 2)
+	{
+		dprint restore2
+		env_show 802 1
+		ai2_spawn B1_s_green01
+		ai2_spawn new_dummy1
+		ai2_spawn C2_blue25
+		chr_delete A1_intro01
+		chr_delete A1_intro02
+		chr_delete A1_s_blue01
+		target_set(1083,30.0)
+		trigvolume_enable trigger_volume_35 0
+		music_muro
+		ai2_spawn B1_s_blue05
+		ai2_dopath B1_s_blue05 patrol_08_blue05b
+		ai2_setjobstate B1_s_blue05
+		chr_teleport B1_s_blue05 1046
+		restore_game
+		objective_set 1 silent
+	}
+
+	if (my_save_point eq 3)
+	{
+		dprint restore3
+		particle red_locklight01 do start
+		door_unlock 38
+		console_deactivate 7
+		ai2_spawn D2_blue60
+		ai2_spawn D1_neut10
+		ai2_spawn new_5
+		ai2_spawn D2_blue61
+		chr_delete A1_intro01
+		chr_delete A1_intro02
+		chr_delete A1_s_blue01
+		target_set(125,30.0)
+		trigvolume_enable trigger_volume_25 0
+		restore_game
+		objective_set 2 silent
+	}
+
+	if (my_save_point eq 4)
+	{
+		dprint restore4
+		particle red_locklight01 do start
+		door_unlock 38
+		console_deactivate 7
+		ai2_spawn D2_blue61
+		ai2_spawn D2_blue60
+		ai2_spawn new_5
+		ai2_spawn D1_neut10
+		chr_delete A1_intro01
+		chr_delete A1_intro02
+		chr_delete A1_s_blue01
+		target13
+		trigvolume_enable trigger_volume_30 0
+		trigvolume_enable trigger_volume_17 0
+		trigvolume_enable trigger_volume_25 0
+		restore_game
+		objective_set 2 silent
+		pipe = 100;
+	}
+
+	if (my_save_point eq 5)
+	{
+		dprint restore5
+		counter = 7;
+		target20
+		ai2_spawn F_blue1
+		chr_delete A1_intro01
+		chr_delete A1_intro02
+		chr_delete A1_s_blue01
+		console_deactivate 8
+		door_unlock 4
+		particle bwhite_locklight01 do start
+		trigvolume_enable trigger_volume_07 0
+		restore_game
+		objective_set 3 silent
+		pipe = 100;
+	}
+}
+
+func void blue01_dies(string ai_name)
+{
+	blue01 = 0
+}
+
+func void script_respawn1(void)
+{
+	if(trigvolume_count (42) eq 0)
+	{
+		count_respawn1 = count_respawn1 + 1;
+		if(count_respawn1 eq 1)
+		{
+			dprint rs1a
+			ai2_spawn respawn1
+			chr_giveweapon respawn1 w7_scc
+		}
+		if(count_respawn1 eq 2)
+		{
+			dprint rs1b
+			ai2_spawn respawn1
+			chr_giveweapon respawn1 w3_phr
+			ai2_dopath patrol_08_blue05
+			ai2_setjobstate respawn1
+		}
+		if(count_respawn1 eq 3)
+		{
+			dprint rs1c
+			ai2_spawn respawn1
+			chr_giveweapon respawn1 w2_sap
+		}
+	}
+}
+
+func void script_respawn2(void)
+{
+	if(trigvolume_count (42) eq 0)
+	{
+		count_respawn2 = count_respawn2 + 1;
+		if(count_respawn2 eq 1)
+		{
+			dprint rs2a
+			ai2_spawn respawn2
+			chr_giveweapon respawn2 w3_phr
+		}
+		if(count_respawn2 eq 2)
+		{
+			dprint rs2b
+			ai2_spawn respawn2
+			chr_giveweapon respawn2 w2_sap
+			ai2_dopath patrol_19_blue20b
+			ai2_setjobstate respawn2
+		}
+		if(count_respawn2 eq 3)
+		{
+			dprint rs2c
+			ai2_spawn respawn2
+			chr_giveweapon respawn2 w2_sap
+		}
+	}
+}
+
+func void script_respawn3(void)
+{
+	if(trigvolume_count (42) eq 0)
+	{
+		ai2_spawn C1_red21
+	}
+}
+func void tv01(string ai_name)
+{
+	dprint tv01 B2
+	ai2_spawn C1_blue22
+	ai2_spawn B2_s_blue08
+	ai2_spawn B2_s_tank04
+		
+}
+
+func void tv02(string ai_name)
+{
+	dprint tv02
+
+	if (trigvolume_count(32) ne 0)
+	{
+		trigvolume_reset trigger_volume_02
+	}
+
+	if (trigvolume_count(32) eq 0)
+	{
+	ai2_makeignoreplayer sniper1 1
+	ai2_dopath sniper1 patrol_53
+	ai2_setjobstate sniper1
+#	ai2_spawn B2_s_blue06
+	ai2_spawn B1_s_blue05
+#	ai2_spawn B1_s_Red01
+	ai2_spawn B1_s_green01
+	ai2_spawn new_dummy1
+	ai2_spawn C1_blue22
+	ai2_spawn C2_blue25
+#	ai2_spawn B1_neut01
+	trigvolume_corpse 32
+	Muro
+	target_set(1083, 30.0)
+	chr_delete A1_intro01
+	chr_delete A1_intro02
+	chr_delete A1_s_blue01
+	chr_delete A1_s_red01
+	chr_delete A1_s_red02
+	chr_delete A2_s_blue01
+	chr_delete A2_s_blue03
+	chr_delete A2_s_blue09
+#	chr_delete A2_s_blue10
+	chr_delete A2_s_tank01
+	chr_delete A2_s_tank02
+	chr_delete char_1
+	chr_delete sniper1
+	chr_delete A2_s_blue13
+	chr_delete A2_s_red03
+	chr_delete A2_s_red04
+	chr_delete new_1
+	chr_delete new_2
+	chr_delete new_3
+	chr_delete new_4
+	chr_delete whiteneut
+	chr_delete B3_s_green02
+	}
+}
+
+func void tv03(string ai_name)
+{
+	dprint tv03
+	ai2_spawn A2_s_blue09
+#	ai2_spawn A2_s_blue10
+#	ai2_spawn A2_s_red04
+
+}
+
+func void ontv02(string ai_name)
+{
+	dprint ontv02
+	trigvolume_enable trigger_volume_02 1
+	particle el_red1 kill
+	particle el_1_locklight01 do start
+}
+
+func void tv04(string ai_name)
+{
+	dprint tv04
+	ai2_spawn A2_s_tank01
+	ai2_spawn A2_s_blue13
+#	ai2_spawn A2_s_tank02
+	ai2_spawn A2_s_blue01
+	ai2_spawn A2_s_red03
+#	ai2_spawn A2_s_blue03
+		
+}
+
+func void tv05(string ai_name)
+{
+	dprint tv05_B3_C1
+	ai2_spawn B3_s_green02
+	ai2_spawn C1_blue20
+#	Torture
+}
+
+func void ontv06(string ai_name)
+{
+	dprint ontv06
+	trigvolume_enable trigger_volume_06 1
+	particle el_2_locklight01 do start
+}
+
+func void start_elevator2_music(void)
+{
+	sound_music_start mus_space01 0.75
+}
+
+func void stop_elevator2_music(void)
+{
+	sound_music_stop mus_space01
+}
+
+func void tv06(string ai_name)
+{
+	dprint tv06_C3
+
+	if (trigvolume_count(31) ne 0)
+	{
+		trigvolume_reset trigger_volume_06
+	}
+
+	if (trigvolume_count(31) eq 0)
+	{
+		start_elevator2_music
+
+		ai2_spawn D1_neut05
+		trigvolume_corpse 31
+		Elev2
+		target_set(128,30.0)
+		chr_delete respawn1
+		chr_delete respawn2
+		chr_delete B1_neut01
+		chr_delete B1_s_blue05
+		chr_delete B1_s_green01
+		chr_delete B1_s_Red01
+		chr_delete B2_s_blue06
+		chr_delete B2_s_blue07
+		chr_delete B2_s_blue08
+		chr_delete B2_s_tank04
+		chr_delete B3_green02
+		chr_delete C1_blue20
+		chr_delete C1_blue22
+		chr_delete C1_red21
+		chr_delete C2_blue25
+		chr_delete C2_red26
+		chr_delete C2_tank24
+		chr_delete new_dummy1
+		objective_set(2)
+	}
+}
+
+func void power_lull_1(string ai_name)
+{	
+	dprint pipe_discharged
+	ai2_neutralbehavior D1_neut02 none
+	pipe = pipe + 1
+
+	if (pipe eq 1)
+	{
+		stop_elevator2_music
+
+		input 0
+		music_pipe
+		cm_interpolate pipe_view 180
+		particle power1 do stop
+		sleep 270
+		cm_reset
+		input 1
+		timer_start 25 power_lull_1b
+		if(my_save_point ne 3)
+		{
+			s3
+		}
+	}
+
+	if(pipe ne 1)
+	{
+		particle power1 do stop
+		timer_start 20 power_lull_1b
+	}	
+}
+
+func void power_lull_1b(void)
+{	
+	dprint pipe_recharged
+	music_stop
+	particle power1 do start
+	sleep 300
+	console_reset 9
+}
+
+func void power_deactivate(void)
+{	
+	dprint power_deactivate
+	ai2_doalarm D1_neut02 9
+	ai2_dopath D1_neut02 patrol_80
+	ai2_setjobstate D1_neut02
+}
+
+func void power_lull_2(string ai_name)
+{	
+	dprint pipe_discharged
+	pipe2 =  pipe2 + 1
+	if (pipe2 eq 1)
+	{
+		music_pipe
+		ai2_spawn new_67
+	}
+	particle power2 do stop
+	ai2_spawn new_10
+	ai2_spawn D3_tank65
+	timer_start 20 power_lull_2b
+}
+
+func void power_lull_2b(void)
+{	
+	dprint pipe_recharged
+	music_stop
+	particle power2 do start
+	sleep 300
+	console_reset 11
+}
+
+func void tv07(string ai_name)
+{
+	dprint tv07
+	target20
+	chr_delete sci_maniac
+	chr_delete D1_blue50
+	chr_delete D1_neut02
+	chr_delete D1_neut05
+	chr_delete D1_neut10
+	chr_delete D1_red30
+	chr_delete D2_blue60
+	chr_delete D2_blue61
+	chr_delete new_5
+	chr_delete D2_red62
+	chr_delete D2_tank63
+	chr_delete new_8
+	chr_delete D3_red66
+	chr_delete D3_tank65
+	chr_delete new_1
+	chr_delete new_2
+	chr_delete new_3
+	chr_delete new_4
+	chr_delete new_6
+	chr_delete new_7
+	ai2_spawn F_friend
+	ai2_spawn F_blue73
+	ai2_spawn F_blue1
+
+}
+
+func void tv08(string ai_name)
+{
+	dprint tv08_chamber_four
+	ai2_spawn end01
+	ai2_spawn end02
+	ai2_spawn end03
+	sleep 60
+	ai2_dopath F_tank70 patrol_5004
+	ai2_setjobstate F_tank70
+	ai2_dopath F_blue69 patrol_5005
+	ai2_setjobstate F_blue69
+	ai2_dopath F_blue2 patrol_5004
+	ai2_setjobstate F_blue2
+	ai2_dopath F_blue1 patrol_5006
+	ai2_setjobstate F_blue1
+	ai2_dopath F_blue73 patrol_5006
+	ai2_setjobstate F_blue73
+	ai2_attack F_tank70 char_0
+	ai2_attack F_blue69 char_0
+	ai2_attack F_blue2 char_0
+	ai2_attack F_blue1 char_0
+	ai2_attack F_blue73 char_0
+}
+
+func check_death(string ai_name)
+{
+	dprint check_death
+	counter = counter - 1
+	if (counter eq 0)
+	{
+		dprint counterdone
+		sound_music_volume mus_fiteb 0 3
+		music_stop
+		sleep 120		
+		you_win
+	}
+}
+
+func void tv09(string ai_name)
+{
+	dprint tv09_chamber_one
+
+}
+
+func void tv10(string ai_name)
+{
+	dprint tv10_chamber_two
+	ai2_spawn F_blue69
+	ai2_spawn F_blue2
+}
+
+func void spawn2tube(string ai_name)
+{
+	dprint spawn2tube
+	ai2_spawn D2_tank63
+	ai2_spawn new_8
+	ai2_spawn sci_maniac
+}
+
+func void tv11(string ai_name)
+{
+	dprint tv11_chamber_three
+	ai2_spawn F_tank70
+
+}
+
+func void tv25(string ai_name)
+{
+	dprint tv25
+#	ai2_spawn D1_blue50
+	ai2_spawn D1_red30
+	ai2_spawn D1_neut02
+	ai2_spawn D2_blue60
+	ai2_spawn D1_neut10
+	ai2_spawn new_5
+	ai2_spawn D2_blue61
+}
+
+func void change_patrol(string ai_name)
+{
+	dprint change_patrol
+	ai2_dopath A1_s_red02 patrol_45
+	ai2_setjobstate A1_s_red02
+}
+
+func void spawn_sniper1(string ai_name)
+{
+	dprint spawn_sniper1
+	ai2_spawn sniper1
+	ai2_makeignoreplayer sniper1 1
+	playback_block sniper1 sniper1_jump
+	ai2_makeignoreplayer sniper1 0
+	ai2_dopath sniper1 patrol_52
+	ai2_setjobstate sniper1
+	sleep 600
+	hurt_sniper1
+}
+
+func void hurt_sniper1(string ai_name)
+{
+	dprint hurt_sniper1
+	ai2_makeignoreplayer sniper1 1
+	ai2_dopath sniper1 patrol_53
+	ai2_setjobstate sniper1
+}
+
+func void tv33(string ai_name)
+{
+	dprint neutral_leaves
+	ai2_makeignoreplayer A2_s_red04 1
+	ai2_dopath A2_s_red04 patrol_54
+	ai2_setjobstate A2_s_red04
+}
+
+func void tv34(string ai_name)
+{
+	dprint spawnneutral
+	ai2_spawn A2_s_red04 
+}
+
+func void t36(string ai_name)
+{
+	dprint t36
+	ai2_spawn sbg_1
+	ai2_spawn sbg_2
+	ai2_spawn sbg_3
+}
+
+func void t37(string ai_name)
+{
+	dprint t37
+	ai2_spawn new_1
+	ai2_spawn new_2
+}
+
+func void t38(string ai_name)
+{
+	dprint t38
+	ai2_spawn new_3
+	ai2_spawn new_4
+}
+
+func void t39(string ai_name)
+{
+	dprint t39
+	trigvolume_enable trigger_volume_40 1 
+}
+
+func void t40(string ai_name)
+{
+	dprint t40
+	ai2_spawn new_6
+	ai2_spawn new_7
+}
+
+###################
+#	save game	#
+###################
+
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME1	
+
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME2
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME3
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME4
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+func void s5(string ai_name)
+{
+	dprint SAVEDGAME5
+
+	if (my_save_point ne 5)
+	{
+		save_game 5 autosave
+	}
+}
+###################
+# 	console	#
+###################
+
+func void console_pipe(void)
+{
+	text_console level_9d
+	console_reset 13
+}
+
+func void text9a(void)
+{
+	dprint level_9a
+	text_console level_9a
+	console_reset 2
+}
+
+func void text9b(void)
+{
+	dprint level_9b
+	text_console level_9b
+	console_reset 5
+}
+
+func void text9c(void)
+{
+	dprint level_9c
+	text_console level_9c
+	console_reset 14
+}
+
+func void patrolscript0031(string ai_name)
+{
+	dprint sayline
+	sound_dialog_play c18_70_04striker
+	sound_dialog_play_block
+}
Index: /nikanabo/current/bsl/original/IGMD/power_II/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power_II/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power_II/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,180 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+
+####################################
+##             ROOM 1             ##
+####################################
+func void particle_room1_start(string ai_name)
+{
+	dprint start_room1_particles
+	particle room1 do start
+}
+func void particle_room1_stop(string ai_name)
+{
+	dprint stop_room1_particles
+	particle room1 do stop
+}
+
+####################################
+##             ROOM 2             ##
+####################################
+func void particle_room2_start(string ai_name)
+{
+	dprint start_room2_particles
+	particle room2 do start
+}
+func void particle_room2_stop(string ai_name)
+{
+	dprint stop_room2_particles
+	particle room2 do stop
+}
+
+####################################
+##             ROOM 3             ##
+####################################
+func void particle_room3_start(string ai_name)
+{
+	dprint start_room3_particles
+	particle room3 do start
+}
+func void particle_room3_stop(string ai_name)
+{
+	dprint stop_room3_particles
+	particle room3 do stop
+}
+
+####################################
+##             ROOM 4             ##
+####################################
+func void particle_room4_start(string ai_name)
+{
+	dprint start_room4_particles
+	particle room4 do start
+}
+func void particle_room4_stop(string ai_name)
+{
+	dprint stop_room4_particles
+	particle room4 do stop
+}
+
+####################################
+##             ROOM 5             ##
+####################################
+func void particle_room5_start(string ai_name)
+{
+	dprint start_room5_particles
+	particle room5 do start
+}
+func void particle_room5_stop(string ai_name)
+{
+	dprint stop_room5_particles
+	particle room5 do stop
+}
+
+####################################
+##           vat room             ##
+####################################
+func void particle_vatroom1_start(string ai_name)
+{
+	dprint start_vatroom1_particles
+	particle vatroom1 do start
+}
+func void particle_vatroom1_stop(string ai_name)
+{
+	dprint stop_vatroom1_particles
+	particle vatroom1 do stop
+}
+
+####################################
+# first energy sprinkler activator #
+# this one starts over the first   #
+# vat.                             #
+# the particle name is "zap1"      #
+####################################
+
+var int zap=1;
+
+func void zap_start(string ai_name)
+{
+	dprint zap_on
+	
+	trigvolume_enable zap1 0
+
+	if (zap eq 1)
+	{
+	particle zap1 do start
+	sleep 120
+	particle zap1 stop
+	}
+	
+	if (zap eq 1)
+	{
+	particle zap2 start
+	sleep 120
+	particle zap2 stop
+	}
+	
+	if (zap eq 1)
+	{
+	particle zap3 start
+	sleep 120
+	particle zap3 stop
+	}
+
+	# CB: this delay ensures we don't execute every frame
+	sleep 60
+	trigvolume_enable zap1 1
+}
+
+func void zap_timer_1(string ai_name)
+{
+	dprint do_zap_timer_1
+	zap = 0
+	timer_start 15 zap_start_again
+}
+
+func void zap_timer_2(string ai_name)
+{
+	dprint do_zap_timer_2
+	zap = 0
+	timer_start 10 zap_start_again
+}
+
+func void zap_timer_3(string ai_name)
+{
+	dprint do_zap_timer_3
+	zap = 0
+	timer_start 5 zap_start_again
+}
+
+func void zap_start_again(string ai_name)
+{
+	dprint zap_on_again
+	zap = 1
+	console_reset 4
+}
+
+# FINAL PIPE
+func void pipe3_start(string ai_name)
+{
+	dprint pipe_started
+	particle pipe3 do start
+}
+
+
+func void zap_kill(string ai_name)
+{
+	dprint zap_die
+	particle zap1 kill
+	particle zap2 kill
+	particle zap3 kill
+}
+
+func void zap_create(string ai_name)
+{
+	dprint zap_live
+	particle zap1 create
+	particle zap2 create
+	particle zap3 create
+}
Index: /nikanabo/current/bsl/original/IGMD/power_II/power2_spawn.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power_II/power2_spawn.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power_II/power2_spawn.bsl	(revision 185)
@@ -0,0 +1,689 @@
+### POWER PLANT II LEVEL LOGIC ###
+
+### START, SAVE & OBJECTIVES ###
+
+var int inside_final_cutscene = 0;
+
+func void start(string ai_name)
+{
+	particle save3_locklight01 do start
+
+	if (save_point eq 0)
+		{
+		my_save_point = 0
+		trigvolume_enable trigger_volume_07 0
+		particle_room1_start
+		particle doorA_locklight01 do stop
+		ai2_spawn ambush_striker_10
+		ai2_spawn ambush_striker_11
+		set_objective_1
+		chr_invincible ShinShin 1
+		chr_unstoppable ShinShin 1
+		}
+	if (save_point eq 1)
+		{
+		my_save_point = 1;
+		dprint restore1_active
+		trigvolume_enable room3_particle_control 0
+		door_lock 3
+		particle Shindoor_locklight01 do stop
+		particle room4 do start
+		ai2_spawn A3_n05
+		restore_game
+		set_objective_3
+		}
+	if (save_point eq 2)
+		{
+		my_save_point = 2;
+		dprint restore2_active
+		particle doorA_locklight01 do stop
+		particle doorB_locklight01 do start
+		door_lock 15
+		trigvolume_enable save2 0
+		ai2_spawn vat_bot_1
+		ai2_spawn vat_bot_2
+		ai2_spawn vat_bot_3
+		ai2_spawn vat_bot_4
+		ai2_spawn vat_bot_5
+		chr_weapon_immune(vat_bot_1);
+		chr_weapon_immune(vat_bot_2);
+		chr_weapon_immune(vat_bot_3);
+		chr_weapon_immune(vat_bot_4);
+		chr_weapon_immune(vat_bot_5);
+		restore_game
+		set_objective_4
+		sound_music_start atm_cl12 0.75
+		}
+	if (save_point eq 3)
+		{
+		my_save_point = 3;
+		dprint restore3_active
+		particle save3_locklight01 do stop
+		door_lock 23
+		door_lock 28
+		ai2_spawn E1_sr28
+		ai2_spawn E1_sr30
+		ai2_spawn E1_sb29
+		ai2_spawn ambush_comguy_1
+		ai2_spawn E1_n31
+		ai2_spawn E1_n32
+		ai2_spawn E1_n37
+		trigvolume_enable save_point3 0
+		trigvolume_enable p11b_vol 0
+		restore_game
+		pipe3_start
+		set_objective_5
+		}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void new_save1(string ai_name)
+{
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void save_point_1(string ai_name)
+{
+	dprint savegame_1	
+	door_lock 3
+	particle Shindoor_locklight01 do stop
+}
+
+func void save_point_2(string ai_name)
+{
+	dprint savegame_2
+	save_game 2 autosave
+}
+
+func void save_point_3(string ai_name)
+{
+	dprint savegame_3	
+	save_game 3 autosave
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective1
+	objective_set(1)
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective2
+	objective_set(2)
+	target_set(7020,60.00)
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective3
+	objective_set(3)
+	target_set(0,0)
+}
+
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective4
+	objective_set(4)
+	trigvolume_enable setobjective_4 0
+}
+
+func void set_objective_5(string ai_name)
+{
+	dprint set_objective5
+	objective_set(5)
+	trigvolume_enable setobjective_5 0
+}
+
+### MUSIC ###
+
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+	if (0 ne music_counter) 
+		{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+		}	
+}
+
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void striker_lullaby_1(string ai_name)
+{
+	dprint striker_lullaby1
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+}
+
+func void striker_lullaby_2(string ai_name)
+{
+	dprint striker_lullaby2
+	music_counter = music_counter - 1
+	if (music_counter eq 0)
+		{
+		all_music_counters();
+		}
+}
+
+func void all_music_counters(void)
+{
+	dprint ELVIS_HAS_LEFT_THE_BUILDING
+	sound_music_stop mus_trt
+	sound_music_stop mus_sad1
+	sound_music_stop atm_cl10
+	sound_music_stop atm_ft66
+	sound_music_stop atm_cl09
+	sound_music_stop atm_cl11
+	sound_music_stop mus_xtr2
+	sound_music_stop mus_lz
+}
+
+### TEXT CONSOLES ###
+
+func void level10a(string chr_index)
+{
+	dprint text10a
+	text_console level_10a
+	console_reset 2
+}
+
+func void level10b(string chr_index)
+{
+	dprint text10b
+	text_console level_10b
+	console_reset 7
+}
+
+### GAMEPLAY PROGRESSION ###
+
+# STRIKER BACKUPS
+func void backup_1(string ai_name)
+{
+	dprint backup1
+	ai2_spawn backup_striker1
+	particle blast1_locklight01 do start
+	door_unlock 1
+	door_open 1
+}
+
+func void backup_2(string ai_name)
+{
+	dprint backup2
+	ai2_spawn backup_striker2
+	particle blast2_locklight01 do start
+	door_unlock 2
+	door_open 2
+}
+	
+
+# COME TO ME
+func void come_to_me(string ai_name)
+{
+	dprint go_to_konoko
+	ai2_dopath ambush_striker1 come_to_me 1
+	ai2_dopath ambush_striker2 come_to_me 1
+	ai2_dopath A1_t02 come_to_me 1
+	ai2_dopath A1_sr01 come_to_me 1
+	ai2_dopath ambush_striker1 come_to_me 1
+	ai2_dopath ambush_striker2 come_to_me 1
+}
+
+# SHIN CUTSCENE CHECK
+func void shin_check(string ai_name)
+{
+	var int inside_count;
+	dprint shin_cutscene_check
+	trigvolume_enable trigger_volume_03 0
+
+	inside_count = trigvolume_count(32);
+
+	if (inside_count ne 0)
+	{
+		sleep 60
+		trigvolume_enable trigger_volume_03 1
+	}
+
+	if (inside_count eq 0)
+	{
+		Shin
+	}
+}
+
+func void t43(string ai_name)
+{
+	dprint konoko_dies
+	inroom = 1
+}
+
+func void t43b(string ai_name)
+{
+	dprint konoko_lives
+	inroom = 0
+}
+
+func void delete_script(string ai_name)
+{
+	dprint dead_or_not
+	chr_delete ai_name
+}
+
+func void shin_dies(void)
+{
+	dprint KABOOM
+	particle ShinBomb do explode
+	fade_out 1 1 1 30
+	if (inroom eq 1)
+	{
+		chr_set_health 0 0
+	}
+
+	trigvolume_kill 64
+
+	chr_delete ShinShin
+	fade_in 60
+	door_lock 3
+	particle Shindoor_locklight01 do stop
+	set_objective_3	
+}
+
+func void p1(string ai_name)
+{
+	dprint p1_trigger_entered
+	sound_music_stop mus_trt
+	sound_music_start atm_cl09 1.0
+	ai2_spawn A1_sr01
+	ai2_lookatme A1_sr01	
+	ai2_spawn A1_t02
+	ai2_lookatme A1_t02
+	sleep 120
+	door_lock 1
+	door_lock 2
+}
+
+func void open_ambush1(string ai_name)
+{
+	dprint ambush_1
+	particle blast1_locklight01 do start
+	door_unlock 1
+	ai2_spawn ambush_striker1
+}
+
+func void open_ambush2(string ai_name)
+{
+	dprint ambush_2
+	particle blast2_locklight01 do start
+	door_unlock 2
+	ai2_spawn ambush_striker2
+}
+
+func void p2(string ai_name)
+{
+	dprint p2
+	ai2_spawn A2_r03
+	playback A2_r03 redjump
+	ai2_lookatme A2_r03
+	ai2_spawn aerial_red_2
+	ai2_passive aerial_red_2 1
+	playback aerial_red_2 redjump2
+	ai2_passive aerial_red_2 0
+	ai2_lookatme aerial_red_2
+	ai2_spawn red_guard_1
+	ai2_dopath A1_sr01 patrol_31
+	ai2_dopath A1_t02	patrol_31
+	ai2_setjobstate A1_sr01
+	ai2_setjobstate A1_t02 patrol_31	
+	sleep 120	
+}
+
+func void p5(string ai_name)
+{
+	dprint p5
+	ai2_spawn A3_n05
+	ai2_spawn A3_sb06
+	ai2_spawn A4_n07
+}
+
+func void p6(string ai_name)
+{
+	dprint p6
+	ai2_spawn A4_sr08
+	ai2_spawn B1_c07
+}
+
+func void enableP7(string ai_name)
+{
+	dprint enableP7
+	trigvolume_enable trigger_volume_07 1
+}
+
+func void do_console_1(string ai_name)
+{
+	dprint do_console
+	ai2_doalarm A3_n05 1
+}
+
+func void p8(string ai_name)
+{
+	dprint p8
+	ai2_spawn B2_sb09
+	ai2_spawn B2_n10
+	trigvolume_enable trigger_volume_07 0
+	trigvolume_enable trigger_volume_08 0	
+}
+
+func void p9(string ai_name)
+{
+	dprint p9
+	ai2_spawn C1_c16
+	ai2_spawn C1_t11	
+	ai2_spawn C1_sb12
+	ai2_spawn C1_t13	
+	ai2_spawn C2_sg15
+	ai2_spawn C2_sr17
+	ai2_spawn C2_sb14
+	ai2_spawn C2_t19		
+	particle room1 stop
+}
+
+func void red_ambush(string ai_name)
+{
+	dprint ambush_red
+	ai2_spawn ambush_red_1
+}
+
+func void p10(string ai_name)
+{
+	dprint p10
+	ai2_spawn D1_sr20
+	ai2_spawn D1_sb21	
+}
+
+func void p11(string ai_name)
+{
+	dprint p11
+	particle room6 do start
+	pipe3_start
+}
+func void p11b(string ai_name)
+{
+	dprint p11b
+	particle room6 do stop
+}
+
+func void striker_guards(string ai_name)
+{
+	dprint spawn_strikers
+	ai2_spawn striker_guard_1
+	ai2_spawn striker_guard_2
+}
+
+func void spawn_EC_guards(string ai_name)
+{
+	dprint spawn_guards
+	ai2_spawn E1_sb29
+	ai2_spawn E1_c33
+	ai2_spawn E1_c40
+	ai2_spawn E1_f34
+	ai2_spawn E1_f40
+	ai2_spawn E1_f35
+}
+
+func void final_guards(string ai_name)
+{
+	dprint last_guards_activated
+	ai2_spawn final_guard_1
+	ai2_spawn final_guard_2
+}
+
+func void p12(string ai_name)
+{
+	dprint p12
+	ai2_spawn D2_sb26
+	playback D2_sb26 piperun
+	ai2_spawn pipe_guard_1
+	ai2_spawn pipe_guard_2
+}
+
+func void p13(string ai_name)
+{
+	dprint p13
+	ai2_spawn E1_sr28
+	ai2_spawn E1_sb29
+	ai2_spawn E1_sr30
+	ai2_spawn ambush_comguy_1
+	ai2_spawn E1_n31
+	ai2_spawn E1_n32
+	ai2_spawn E1_n37
+	particle elev1_locklight01 do stop
+	particle elev2_locklight01 do stop
+}
+
+func void p14(string ai_name)
+{
+	dprint p14
+	chr_teleport 0 105
+	ai2_spawn F_r40
+	particle pipe3 do start
+}
+
+func void p36(string ai_name)
+{
+	dprint spawned_muro_runner_p36
+	ai2_spawn muro_runner
+	ai2_spawn muro_runner2
+}
+
+func void p39(string ai_name)
+{
+	dprint p39
+	ai2_spawn F_r40
+}
+
+func void cross_fire(string ai_name)
+{
+	dprint crossfire
+	ai2_spawn D2_sg24
+	ai2_spawn D2_f25	
+}
+
+func void tctf_control(string ai_name)
+{
+	dprint tctfcontrol_start
+	sound_music_start mus_amasian 1.0
+	input 0
+	letterbox 1
+	door_unlock 38
+	ai2_spawn E2_sr38
+	ai2_spawn E2_sr39
+	particle elev1_locklight01 do start
+	particle elev2_locklight01 do start
+	cm_interpolate tctf_3 0
+	cm_interpolate_block tctf_1 300
+	cm_interpolate_block tctf_2 150
+	sleep 180
+	cm_reset
+	letterbox 0
+	input 1
+	door_unlock 37
+}
+
+func void warnbigroom(string ai_name)
+{
+	dprint warnbigroom
+	ai2_tripalarm 1	
+}
+
+func void zap_cinematic(string ai_name)
+{
+	dprint doorA
+	input 0
+	begin_cutscene
+	sound_music_start atm_cl12 0.75
+	particle zap1 create
+	particle zap1 start
+	cm_interpolate zap_cinematic1 0
+	cm_interpolate_block zap_cinematic3 700
+	sleep 750
+	cm_interpolate zap_cinematic4 0	
+	sleep 60
+	particle doorA_locklight01 do start
+	sleep 150
+	door_unlock 15	
+	cm_reset
+	end_cutscene
+	input 1
+	ai2_spawn vat_bot_1
+	ai2_spawn vat_bot_2
+	ai2_spawn vat_bot_3
+	ai2_spawn vat_bot_4
+	ai2_spawn vat_bot_5
+	chr_weapon_immune(vat_bot_1);
+	chr_weapon_immune(vat_bot_2);
+	chr_weapon_immune(vat_bot_3);
+	chr_weapon_immune(vat_bot_4);
+	chr_weapon_immune(vat_bot_5);
+	particle doorB_locklight01 do start
+}
+
+func void change_patrol_1(string ai_name)
+{
+	dprint change_patrol
+	ai2_dopath vat_bot_2 vat_bot_2b 1
+}
+
+func void change_patrol_2(string ai_name)
+{
+	dprint change_patrol
+	ai2_dopath vat_bot_3 vat_bot_3b 1
+} 
+
+func void change_patrol_3(string ai_name)
+{
+	dprint change_patrol
+	ai2_dopath vat_bot_5 vat_bot_5b 1
+}
+
+func void spark_sound_off(string ai_name)
+{
+	dprint spark_music_off
+	sound_music_stop atm_cl12
+}
+
+# YOUR DEATH IS ASSURED
+func void dont_even_try_it(string ai_name)
+{
+	chr_set_health 0 0
+}
+
+### SPECIAL PARTICLES ###
+
+func void killmuro(string ai_name)
+{
+	dprint killedmuro
+	chr_delete muro_runner
+	chr_delete muro_runner2
+	sound_music_stop atm_cl11
+	ai2_spawn A4_n07
+}
+
+func void pipe1a(string ai_name)
+{	
+	dprint pipe1_discharged
+	ai2_passive A3_n05 1
+	particle room4 do stop
+	timer_start 30 pipe1b
+	sound_music_start atm_cl11
+}
+
+func void pipe1b(void)
+{	
+	dprint pipe1_recharged
+	particle room4 do start
+	console_reset 1
+
+	pipe1_music_off();
+}
+
+func void pipe1_music_off(void)
+{	
+	dprint pipe1_music_off
+	sound_music_stop atm_cl11
+}
+
+func void pipe2a(void)
+{	
+	dprint pipe2_discharged
+	particle room6 do stop
+	timer_start 29 pipe2b
+	sound_music_start atm_cl11
+}
+
+func void pipe2b(void)
+{	
+	dprint pipe2_recharged
+	particle room6 do start
+	console_reset 8
+
+	pipe2_music_off();
+}
+
+func void pipe2_music_off(void)
+{	
+	dprint pipe2_music_off
+	sound_music_stop atm_cl11
+}
+
+func void pipe3(void)
+{	
+	dprint pipe_discharged
+	timer_start 19 pipe3b
+	sound_music_volume mus_amasian 0.0 2.0
+	particle pipe3 kill
+	sound_music_start atm_cl11
+	sound_music_stop mus_amasian
+}
+
+func void pipe3b(void)
+{	
+	if (inside_final_cutscene eq 0)
+		{
+		dprint pipe_recharged
+		particle pipe3 create
+		particle pipe3 do start
+		console_reset 15
+		}
+}
+
+func void final_cutscene_trumps_particles(void)
+{
+	inside_final_cutscene = 1;
+	particle pipe3 kill
+}
+
+### Level scripted by Joseph ###
Index: /nikanabo/current/bsl/original/IGMD/power_II/powerII_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power_II/powerII_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power_II/powerII_cutscene.bsl	(revision 185)
@@ -0,0 +1,533 @@
+#
+#
+# power_cutscene.bsl
+#
+
+func void
+intro(
+	void)
+{
+	ai2_passive ShinShin 1
+	ai2_makeblind ShinShin 1
+	ai2_makedeaf ShinShin 1
+	chr_lock_active ShinShin
+	chr_unstoppable ShinShin 1
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam01 0
+	sleep f14
+	begin_cutscene
+	sleep f60
+	#Konoko in big space
+	playback 0 IntroKonoko01
+
+	sound_music_start mus_trt
+	music_script_start
+
+	cm_interpolate IntroCam01 0
+	fade_in 60
+	sleep f60
+	cm_interpolate IntroCam02 300
+	sleep f400
+	cm_reset
+	letterbox 0
+	chr_nocollision ShinShin 1
+	sleep f10
+	playback ShinShin ShinShinSet
+	end_cutscene
+	sleep f90
+	ai2_setmovementmode ShinShin creep
+}
+
+
+
+func void
+Shin(
+	void)
+{
+	sleep 60
+	begin_cutscene
+	
+	sound_music_stop atm_cl09
+	sound_music_start mus_xtr2 0.50
+
+	#Shinatama sitting in chair
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_sit 1000 12
+	cm_interpolate ShinCam00 120
+	sleep f180
+	#Konoko kneels next to Shinatama
+	chr_envanim 0 ShinKonBox01 norotation
+	chr_animate 0 KONOKOlev10_Kneel
+	cm_anim both ShinCam01
+	cm_wait
+	sound_dialog_play c09_31_01konoko
+	cinematic_start (KONtalking, 180, 180, 20, 9, 20, true)
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sound_dialog_play_block
+	#Konoko kneeling next to Shinatama
+	cm_interpolate ShinCam02 0
+	cm_interpolate_block ShinCam03 1200
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_sit 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sound_dialog_play c09_31_02shinatama
+	cinematic_start (SHINdamaged, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	sound_dialog_play c09_31_03konoko
+	sound_dialog_play_block
+	sound_dialog_play c09_31_04shinatama
+	sound_dialog_play_block
+	sound_dialog_play c09_31_05konoko
+	sound_dialog_play_block
+	#Camera showing both of them	
+	cm_interpolate ShinCamBoth01 0
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_sit 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	cm_interpolate_block ShinCam01 1500
+	sound_dialog_play c09_31_06shinatama
+	sound_dialog_play_block
+	sound_dialog_play c09_31_07konoko
+	sound_dialog_play_block
+	cm_interpolate ShinCamShinNo 0
+	cm_interpolate ShinCamShinNo2 900
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_sit 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sound_dialog_play c09_31_08shinatama
+	sound_dialog_play_block
+	sound_dialog_play c09_31_09konoko
+	sound_dialog_play_block
+	cinematic_stop (KONtalking, 20, 20)
+	cinematic_stop (SHINdamaged, 19, 20)
+	#TCTF Griffin talking
+	chr_create 1010 start
+	chr_create 1011 start
+	chr_create 1012 start
+	ai2_spawn Honey
+	ai2_passive Honey 1
+	playback Honey ShinFemSet
+	playback 1010 ShinCopSet
+	playback 1011 ShinGrifSet
+	playback 1012 ShinKerrSet
+	sleep f20
+	chr_animate 1010 COMGUYlev10_console1 120
+	cm_interpolate ShinCamCop 0
+	chr_animate_block 1010 COMGUYlev10_console2 1000
+	sound_dialog_play c09_31_10scigoon3
+	cinematic_start (COPtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block
+	cm_interpolate ShinCamGrif 1600
+	sound_dialog_play c09_31_11griffin
+	cinematic_start (GRIFtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	sound_dialog_play c09_31_12scigoon1
+	sound_dialog_play_block
+	cinematic_stop (COPtalking, 16, 20)
+	cm_interpolate ShinCamKerrFace 0
+	sound_dialog_play c09_31_13kerr
+	cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block
+	cinematic_stop (KERRtalking, 20, 20)
+	cm_interpolate ShinCamGrifFace 0
+	sound_dialog_play c09_31_14griffin
+	sound_dialog_play_block
+	cm_interpolate ShinCamCopFace 2400
+	sound_dialog_play c09_31_15scigoonwom
+	cinematic_start (CIVIL4talking, 180, 180, 15, 1, 20, true)
+	sound_dialog_play_block
+	cinematic_stop (CIVIL4talking, 15, 20)
+	cm_interpolate ShinCamKerrFace 0
+	sound_dialog_play c09_31_16kerr
+	cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block
+	cm_interpolate ShinCamGrif 0
+	cm_interpolate_block ShinCamGrif02 1200
+	sound_dialog_play c09_31_17griffin
+	cinematic_stop (GRIFtalking, 19, 20)
+	cinematic_start (GRIFtalkangry, 180, 180, 19, 7, 20, false)
+	sound_dialog_play_block
+	cinematic_stop (KERRtalking, 20, 20)
+	cinematic_stop (GRIFtalkangry, 19, 20)
+	#Shinatama tenses up
+	playback 0 ShinKonokoSet
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_sit 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	cm_interpolate ShinCamShinNo2 0
+	cm_interpolate_block ShinCamShinNo 800
+	sleep f60
+	chr_animate ShinShin SHINATlev10_SitSpaz 60
+	cutscene_sync mark
+	sound_ambient_start c05_46_24shinwake
+	sleep f60
+	chr_animate ShinShin SHINATlev10_Sit2 200
+	sound_dialog_play c09_31_18konoko
+	cinematic_start (KONtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block
+	#Konoko asks what's wrong
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	cm_interpolate ShinCamKonNo3 0
+	#Shinatama says to get the flock out of there
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	cm_interpolate ShinCamShinNo 800
+	sound_dialog_play c09_31_19shinatama
+	cinematic_start (SHINdamaged, 180, 180, 19, 7, 20, false)
+	cm_interpolate ShinCamKonNo 0
+	#I can't delay it much longer
+	cm_interpolate ShinCamShinNo3 2000
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	sound_dialog_play c09_31_21shinatama
+	sound_dialog_play_block
+	#KONOKO I won't leave you
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sound_dialog_play c09_31_22konoko
+	sound_dialog_play_block
+	#bye Konoko
+	cm_interpolate ShinCamShinNo3 0
+	chr_envanim 0 ShinKonBox02 norotation
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	sound_dialog_play c09_31_23shinatama
+	sound_dialog_play_block
+	#KONOKO says no
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sound_dialog_play c09_31_24konoko
+	sound_dialog_play_block
+	chr_envanim ShinShin ShinBox01 norotation
+	chr_animate ShinShin SHINATlev10_Sit2 1000
+	sound_dialog_play c09_31_25shinatama
+	sound_dialog_play_block
+	cinematic_stop (SHINdamaged, 19, 20)
+	#goodbye shinatama
+	chr_envanim 0 ShinKonBox04 norotation
+	chr_animate 0 KONOKOlev10_Kneel_end
+	sleep f30
+	cm_interpolate ShinCamKonNo 180
+	sleep f30
+	playback 0 ShinKonokoSet
+	sleep f70
+	sound_dialog_play c09_31_26konoko
+	sound_dialog_play_block
+	cinematic_stop (KONtalking, 20, 20)
+
+	sound_music_volume mus_xtr2 0.0 5.0
+	sound_music_start atm_cl10 0.0
+	sound_music_volume atm_cl10 1.0 5.0
+	sound_music_stop mus_xtr2
+
+	set_objective_2	
+
+	cm_reset
+	end_cutscene
+	chr_delete 1010
+	chr_delete 1011
+	chr_delete 1012
+	chr_delete Honey	
+#	START TIMER (added by wu)
+
+	particle blast1_locklight01 do stop
+	particle blast2_locklight01 do stop
+	door_lock 1
+	door_lock 2
+
+	door_unlock 3
+	particle Shindoor_locklight01 do start
+	ai2_spawn A2_sb04
+	sound_dialog_play c09_31_27shinatama
+	sound_dialog_play_block pause
+	#timer_start 30 shin_dies
+	sleep f600
+	sound_dialog_play c09_31_28shinatama
+	sleep f600
+	sound_dialog_play c09_31_29shinatama
+	sleep f330
+	sound_dialog_play_block pause
+	sleep f15
+	
+	sound_music_stop atm_cl10
+	cutscene_sync mark
+	sound_ambient_start c06_45_04_explo
+	sleep f10
+	shin_dies
+	#particle ShinBomb do explode
+	
+		
+}
+
+
+func void
+elevator(
+	void)
+{
+	begin_cutscene
+	sleep f40
+	chr_envanim 0 ElevatorKonBox01
+	cm_anim both ElevatorCam01
+	sleep 40
+	cutscene_sync mark
+	sound_ambient_start c07_21_20elevator
+	cm_wait
+	env_show 778 1
+	env_shade 778 778 .3 .3 .3
+	playback 0 ElevatorTop
+	cm_reset
+	end_cutscene
+}
+
+func void
+temp(
+	void)
+{
+	chr_envanim 0 ShinKonBox04 norotation
+	chr_animate 0 KONOKOlev10_Kneeling 1000
+	sleep f40
+	chr_animate 0 KONOKOlev10_Kneel_end
+}
+
+func void
+outro(
+	void)
+{
+	# if you didn't disable the console, we still need to kill that music
+	sound_music_volume mus_amasian 0.0 2.0
+	sound_music_stop mus_amasian
+
+	final_cutscene_trumps_particles
+
+	begin_cutscene
+	chr_delete F_r40
+	
+	sound_music_volume atm_cl11 0.0 1.0
+	sound_music_start mus_lz 1.0
+	sound_music_stop atm_cl11
+
+	particle pipe3 kill
+	
+	cm_interpolate OutroCamEnter01 0
+	cm_interpolate_block OutroCamEnter02 500
+	ai2_spawn TCTF1053
+	ai2_spawn TCTF1054
+	ai2_spawn TCTF1051
+	ai2_spawn TCTF1052
+	chr_lock_active 1051
+	chr_lock_active 1052
+	chr_lock_active 1053
+	chr_lock_active 1054
+	#ai2_passive 1053 1
+	#ai2_passive 1054 1
+	#ai2_makeblind 1053 1
+	#ai2_makeblind 1054 1
+	playback TCTF1053 OutroLiteEnter
+	sleep f30
+	playback TCTF1054 OutroLiteEnter
+	sleep f60
+	playback TCTF1051 OutroSwatEnter
+	sleep f30
+	chr_nocollision TCTF1052 1
+	playback TCTF1052 OutroSwatEnter
+	sleep f180
+	chr_nocollision TCTF1052 0
+	#TCTF says I know How to Stop Her
+	playback 0 OutroKonokoRun
+	cm_interpolate OutroCamBooth01 0
+	sleep f5
+	cm_interpolate OutroCamBooth02 400
+	#chr_create 1053 start
+	#chr_create 1054 start
+	playback TCTF1053 OutroTCTF3Set
+	playback TCTF1054 OutroTCTF4Set
+	sleep f60
+	#chr_create 1051 start
+	#chr_create 1052 start
+	playback TCTF1051 OutroTCTF1Enter
+	playback TCTF1052 OutroTCTF2Enter
+	sleep f380
+	#TCTF Guys hit the fan
+	cm_interpolate OutroCamBooth03 0
+	sleep f20
+	sound_dialog_play c09_32_03tctf
+	cinematic_start (TCTFtalking, 180, 180, 15, 1, 15, false)
+	sleep 240
+	chr_animate TCTF1054 COMGUYlev10_console
+	sleep f60
+	#sound_ambient_start console
+	sleep f30
+	cinematic_stop (TCTFtalking, 15, 25)
+	#Konoko stops in front as fan starts
+	playback 0 OutroKonokoStop
+	sleep f70
+	cm_anim both OutroCam01
+	env_anim 81 82
+	cutscene_sync mark
+	sound_ambient_start c14_14_26_basic
+	sound_ambient_start c14_42_09_effectsa
+	sleep f300
+	#TCTF guys run towards the Fan and then Stop
+	playback TCTF1051 OutroTCTFTurn
+	playback TCTF1052 OutroTCTF2Turn
+	sleep f120
+	cm_interpolate OutroCamTurn01 0
+	env_setanim 81 FanHub02
+	env_setanim 82 FanBlade02
+	cm_interpolate_block OutroCamTurn02 180
+	sleep f240
+	#Those Dudes run away 
+	particle OutroWind do start
+	playback TCTF1051 OutroTCTF2Flee
+	playback TCTF1052 OutroTCTFBlown
+	chr_envanim 0 OutroKonBox01 norotation
+	chr_animate 0 KONOKOlev10_Blown01
+	cm_interpolate OutroCamBlow01 0
+	cm_interpolate_block OutroCamBlow02 240
+	sleep f100
+	cutscene_sync mark
+	sound_ambient_start c14_30_15_wind
+	sleep f130
+	chr_animate TCTF1052 TCTFlev10_Blown 240 8
+	sleep f235
+	#Konoko starts to get blown away
+	sleep f2
+	cm_anim both OutroCamBlown
+	chr_envanim 0 OutroKonBox01 norotation
+	chr_animate 0 KONOKOlev10_Blown01
+	#Konoko Grabs handrail, tctf flies into fan
+	cm_wait
+	chr_envanim 0 OutroKonBox02 norotation
+	chr_animate 0 KONOKOlev10_Grab
+	chr_envanim TCTF1052 OutroTCTFBox01
+	chr_animate TCTF1052 STRIKEjump_flail 340
+	cm_anim both OutroCamGrab
+	#Konoko work her way up rail
+	cm_wait
+	cutscene_sync mark
+	sound_ambient_start c14_42_09_effectsb
+	chr_set_health TCTF1052 0
+	chr_envanim 0 OutroKonBox05 norotation
+	chr_animate 0 KONOKOlev10_OutroHand
+	cm_anim both OutroCamHand05
+	#Konoko works her way up rail
+	#cm_wait
+	#chr_envanim 0 OutroKonBox06 norotation
+	#chr_animate 0 KONOKOlev10_OutroHand
+	#cm_anim both OutroCamHand06
+	#TCTF says she got away	
+	#Konoko makes it towards safety
+	#cm_wait
+	#chr_envanim 0 OutroKonBox07 norotation
+	#chr_animate 0 KONOKOlev10_OutroHand
+	#cm_anim both OutroCamHand07
+	#sleep f240
+	#TCTF Griffin talking
+	cm_wait
+	chr_create 1010 start
+	chr_create 1011 start
+	chr_create 1012 start
+	playback 1010 ShinCopSet
+	playback 1011 ShinGrifSet
+	playback 1012 ShinKerrSet
+	cm_interpolate ShinCamGrifFace 0
+	sound_ambient_volume c14_14_26_basic 0 .5
+	sound_ambient_volume c14_30_15_wind 0 .5
+	sleep f20
+	sound_ambient_stop c14_14_26_basic
+	sound_ambient_stop c14_30_15_wind
+	sound_dialog_play c09_33_01griffin
+	cinematic_start (GRIFtalking, 180, 180, 19, 7, 20, false)
+	#chr_animate 1010 COMGUYlev10_console1 120
+	sound_dialog_play_block
+	cm_interpolate ShinCamCop 0
+	cm_interpolate_block ShinCamCopFace 2000
+	chr_animate 1010 COMGUYlev10_console2 1500
+
+	sound_music_volume mus_lz 0.65 2.0
+
+	sound_dialog_play c09_33_02scigoon1
+	cinematic_start (COPtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block
+	sound_dialog_play c09_33_03griffin
+	sound_dialog_play_block
+	sound_dialog_play c09_33_04scigoon1
+	sound_dialog_play_block
+	cinematic_stop (COPtalking, 16, 20)
+	sound_dialog_play c09_33_05griffin
+	sound_dialog_play_block
+	cm_interpolate ShinCamKerrFace 0
+	sound_dialog_play c09_33_06kerr
+	cinematic_start (KERRtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block
+	cinematic_stop (KERRtalking, 20, 20)
+	cm_interpolate ShinCamGrifFace 0
+	sound_dialog_play c09_33_07griffin
+	sound_dialog_play_block
+	sound_dialog_play c09_33_09griffin
+	sound_dialog_play_block
+	sleep 30
+	#Konoko overhears that she's rogue
+	playback 0 OutroKonokoWatch
+	chr_animate 0 KONOKOwatch_radio 400
+	sound_ambient_start c14_30_15_wind
+	cm_interpolate OutroCamWatch01 0
+	cm_interpolate_block OutroCamWatch02 300
+	sound_dialog_play c09_33_09agriffin
+	sound_dialog_play_block
+	cinematic_stop (GRIFtalking, 19, 20)
+
+	sound_music_volume mus_lz 1.0 1.0
+
+	chr_animate 0 KONOKOlev10_watch_run 60
+	sleep f60
+	fade_out 0 0 0 120
+	sound_ambient_volume c14_30_15_wind 0 2
+	sleep f120
+	sound_ambient_stop c14_30_15_wind
+	end_cutscene
+	win
+}
+
+
+
+func void splash(string character)
+{
+  var bool eggman;
+
+  eggman = chr_is_player(character);
+
+  if (eggman eq 0)
+  {
+    chr_animate(character, KONOKOacid);
+    sleep f10
+    chr_set_health(character, 0);
+  }
+
+  if (eggman eq 1)
+  {
+    	cm_detach
+    	chr_animate(character, KONOKOacid);
+	sleep f10
+	sound_impulse_play konoko_gruesome_death
+	chr_set_health(character, 0);
+  }
+}
+
+func void
+detachcam(
+	void)
+{
+	#cm_detach
+}
+
Index: /nikanabo/current/bsl/original/IGMD/power_II/power_II_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/power_II/power_II_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/power_II/power_II_main.bsl	(revision 185)
@@ -0,0 +1,26 @@
+#
+# power_main.bsl
+#
+
+var int inroom=0;
+var int in_blue=0;
+var int my_save_point=0;
+var int blue_striker=1;
+
+func void main(void)
+{
+	obj_create 81 82
+	env_shade 777 777 .4 .4 .4
+	env_show 778 0
+	gl_fog_blue=.15
+	gl_fog_red=.15
+	gl_fog_green=.15
+	gl_fog_start=.99
+	gs_farclipplane_set 2500
+	start
+	if (my_save_point eq 0)
+	{
+		fork intro
+	}
+}
+
Index: /nikanabo/current/bsl/original/IGMD/roof/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/roof/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/roof/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,521 @@
+###################################building 1
+func void rain1(string ai_name)
+{
+	dprint b1r1of3
+	particle b01_rain1 start
+	particle b01_rain2 stop
+}
+func void rain2(string ai_name)
+{
+	dprint b1r2of3
+	particle b01_rain1 stop
+	particle b01_rain2 start
+	particle b01_rain3 stop
+}
+func void rain3(string ai_name)
+{
+	dprint b1r3of3
+	particle b01_rain2 stop
+	particle b01_rain3 start
+	particle b02_rain1 stop
+}
+###################################building 2
+func void rain4(string ai_name)
+{
+	dprint b2r1of2
+	particle b01_rain3 stop
+	particle b02_rain1 start
+	particle b02_rain2 stop
+}
+func void rain5(string ai_name)
+{
+	dprint b2r2of2
+	particle b02_rain1 stop
+	particle b02_rain2 start
+	particle b03_rain1 stop
+}
+###################################building 3
+func void rain6(string ai_name)
+{
+	dprint b3r1of3
+	particle b02_rain2 stop
+	particle b03_rain1 start
+	particle b03_rain2 stop
+}
+func void rain7(string ai_name)
+{
+	dprint b3r2of3
+	particle b03_rain1 stop
+	particle b03_rain2 start
+	particle b03_rain3 stop
+}
+func void rain8(string ai_name)
+{
+	dprint b3r3of3
+	particle b02_rain2 stop
+	particle b03_rain3 start
+	particle b03_rain1 stop
+}
+###################################building 4/6
+func void rain9(string ai_name)
+{
+	dprint b4r1of6
+	particle b03_rain3 stop
+	particle b04_rain1 start
+	particle b04_rain2 stop
+}
+func void rain10(string ai_name)
+{
+	dprint b4r2of6
+	particle b04_rain1 stop
+	particle b04_rain2 start
+	particle b04_rain3 stop
+}
+func void rain11(string ai_name)
+{
+	dprint b4r3of6
+	particle b04_rain2 stop
+	particle b04_rain3 start
+	particle b04_rain4 stop
+}
+func void rain12(string ai_name)
+{
+	dprint b4r4of6
+	particle b04_rain3 stop
+	particle b04_rain4 start
+	particle b04_rain5 stop
+}
+func void rain13(string ai_name)
+{
+	dprint b4r5of6
+	particle b04_rain4 stop
+	particle b04_rain5 start
+	particle b04_rain6 stop
+}
+func void rain14(string ai_name)
+{
+	dprint b4r6of6
+	particle b04_rain5 stop
+	particle b04_rain6 start
+	particle b06_rain1 stop
+}
+###################################building 6/6
+func void rain15(string ai_name)
+{
+	dprint b6r1of6
+	particle b04_rain6 stop
+	particle b06_rain1 start
+	particle b06_rain2 stop
+}
+func void rain16(string ai_name)
+{
+	dprint b6r2of6
+	particle b06_rain1 stop
+	particle b06_rain2 start
+	particle b06_rain3 stop
+}
+func void rain17(string ai_name)
+{
+	dprint b6r3of6
+	particle b06_rain2 stop
+	particle b06_rain3 start
+	particle b06_rain4 stop
+}
+func void rain18(string ai_name)
+{
+	dprint b6r4of6
+	particle b06_rain3 stop
+	particle b06_rain4 start
+	particle b06_rain5 stop
+}
+func void rain19(string ai_name)
+{
+	dprint b6r5of6
+	particle b06_rain4 stop
+	particle b06_rain5 start
+	particle b06_rain6 stop
+}
+func void rain20(string ai_name)
+{
+	dprint b6r6of6
+	particle b06_rain5 stop
+	particle b06_rain6 start
+	particle b06_rain5 stop
+}
+func void rain21(string ai_name)
+{
+	dprint b6_off
+	particle b06_rain6 stop
+}
+################# kill lower clouds ###########
+func void cloudkiller(string ai_name)
+{
+	dprint makingLowCloudsDie
+	particle b01a die
+	particle b01b die
+	particle b01c die
+	particle b01d die
+	particle b01e die
+	particle b01f die
+	particle b01g die
+	particle b01h die
+	particle b01i die
+	particle b01j die
+	particle b01k die
+	particle b01l die
+	particle b01m die
+	particle b01n die
+	particle b01o die
+	particle b01p die
+	particle b01q die
+	particle b01r die
+	particle b01s die
+	particle b01t die
+	particle b01u die
+	particle b01v die
+	particle b01w die
+	particle b01x die
+	particle b01y die
+	particle b01z die
+	particle b02a die
+	particle b02b die
+	particle b02c die
+	particle b02d die
+	particle b02e die
+	particle b02f die
+	particle b02g die
+	particle b02h die
+	particle b02i die
+	particle b02j die
+	particle b02k die
+	particle b02l die
+	particle b02m die
+	particle b02n die
+	particle b02o die
+	particle b02p die
+	particle b02q die
+	particle b02r die
+	particle b02s die
+	particle b02t die
+	particle b02u die
+	particle b02v die
+	particle b02w die
+	particle b02x die
+	particle b02y die
+	particle b02z die
+	particle b03a die
+	particle b03b die
+	particle b03c die
+	particle b03d die
+	particle b03e die
+	particle b03f die
+	particle b03g die
+	particle b03h die
+	particle b03i die
+	particle b03j die
+	particle b03k die
+	particle b03l die
+	particle b03m die
+	particle b03n die
+	particle b03o die
+	particle b03p die
+	particle b03q die
+	particle b03r die
+	particle b03s die
+	particle b03t die
+	particle b03u die
+	particle b03v die
+	particle b03w die
+	particle b03x die
+	particle b03y die
+	particle b03z die
+	particle b04a die
+	particle b04b die
+	particle b04c die
+	particle b04d die
+	particle b04e die
+	particle b04f die
+	particle b04g die
+	particle b04h die
+	particle b04i die
+	particle b04j die
+	particle b04k die
+	particle b04l die
+	particle b04m die
+	particle b04n die
+	particle b04o die
+	particle b04p die
+	particle b04q die
+	particle b04r die
+	particle b04s die
+	particle b04t die
+	particle b04u die
+	particle b04v die
+	particle b04w die
+	particle b04x die
+	particle b04y die
+	particle b04z die
+}
+###################################lightningFlashes	
+func void b01(string ai_name)
+{
+	dprint Building01_flash
+	particle b01a start
+	sleep f9
+	particle b01a start
+	sleep f9
+	particle b01a start
+	sleep f9
+	particle b01b start
+	sleep f9
+	particle b01b start
+	sleep f9
+	particle b01b start
+	sleep f9
+	particle b01c start
+	sleep f9
+	particle b01c start
+	sleep f9
+	particle b01c start
+	sleep f9
+	particle b01d start
+	sleep f9
+	particle b01d start
+	sleep f9
+	particle b01d start
+	sleep f9
+	particle b01d start
+	sleep f9
+
+}
+func void b02(string ai_name)
+{
+	dprint Building02_flash
+	particle b02a start
+	sleep f2
+	particle b02a start
+	sleep f3
+	particle b02a start
+	sleep f3
+	particle b02a start
+	sleep f5
+	particle b02b start
+	sleep f5
+	particle b02b start
+	sleep f6
+	particle b02b start
+	sleep f6
+	particle b02b start
+	sleep f6
+	particle b02c start
+	sleep f5
+	particle b02d start
+	sleep f5
+	particle b02d start
+	sleep f4
+	particle b02e start
+	sleep f4
+	particle b02e start
+	sleep f4
+	particle b02f start
+	sleep f3
+	particle b02f start
+	sleep f3
+	particle b02f start
+	sleep f5
+	particle b02g start
+	sleep f5
+	particle b02h start
+	sleep f4
+	particle b02i start
+	sleep f4
+	particle b02j start
+	sleep f6
+	particle b02j start
+	sleep f6
+	particle b02k start
+	sleep f7
+	particle b02k start
+	sleep f6
+	particle b02l start
+	sleep f5
+	particle b02m start
+	sleep f4
+	particle b02m start
+	sleep f3
+	particle b02m start
+	sleep f5
+	particle b02n start
+	sleep f6
+	particle b02n start
+}
+func void b03a(string ai_name)
+{
+	dprint Building03_flash
+	particle b03a start
+	sleep f5
+	particle b03b start
+	sleep f5
+	particle b03a start
+	sleep f5
+	particle b03b start
+	sleep f5
+	particle b03b start
+	sleep f5
+	particle b03c start
+	sleep f5
+	particle b03c start
+	sleep f5
+	particle b03c start
+	sleep f5
+	particle b03d start
+	sleep f5
+	particle b03d start
+	sleep f5
+	particle b03d start
+	sleep f5
+	particle b03d start
+	sleep f5
+	particle b03e start
+	sleep f5
+	particle b03e start
+	sleep f5
+	particle b03f start
+	sleep f5
+	particle b03f start
+	sleep f5
+	particle b03f start
+	sleep f5
+	particle b03g start
+	sleep f5
+	particle b03g start
+	sleep f5
+	particle b03g start
+	sleep f5
+	particle b03g start
+	sleep f5
+	particle b03g start
+	sleep f5
+	particle b03h start
+	sleep f5
+	particle b03h start
+	sleep f5
+}
+func void b03b(string ai_name)
+{
+	dprint Building03_flash
+	particle b03i start
+	sleep f5
+	particle b03i start
+	sleep f5
+	particle b03j start
+	sleep f5
+	particle b03j start
+	sleep f5
+	particle b03i start
+	sleep f5
+	particle b03k start
+	sleep f5
+	particle b03k start
+	sleep f5
+	particle b03k start
+	sleep f5
+	particle b03l start
+	sleep f5
+	particle b03l start
+	sleep f5
+	particle b03m start
+	sleep f5
+	particle b03n start
+	sleep f5
+	particle b03o start
+	sleep f5
+	particle b03n start
+	sleep f5
+	particle b03m start
+	sleep f5
+	particle b03l start
+	sleep f5
+	particle b03l start
+	sleep f5
+	particle b03l start
+	sleep f5
+	particle b03k start
+	sleep f5
+	particle b03k start
+	sleep f5
+	particle b03j start
+	sleep f5
+	particle b03i start
+	sleep f5
+	particle b03i start
+	sleep f5
+	particle b03h start
+	sleep f5
+}
+
+func void l1(string ai_name)
+{
+	dprint Flash
+	particle c01 start
+	sleep f9
+	particle c01 start
+	sleep f9
+	particle c01 start
+	sleep f9
+	particle c02 start
+	sleep f9
+	particle c02 start
+	sleep f7
+	particle c03 start
+	particle c04 start
+	sleep f7
+	particle c04 start
+	sleep f7
+	particle c04 start
+	sleep f7
+	particle c02 start
+	sleep f7
+	particle c02 start
+	sleep f7
+	particle c01 start
+	particle c05 start
+}
+func void l2(string ai_name)
+{
+	dprint Flash
+	particle c06 start
+	sleep f7
+	particle c07 start
+	sleep f7
+	particle c08 start
+	sleep f7
+	particle c09 start
+	sleep f7
+	particle c10 start
+	sleep f7
+	particle c11 start
+	sleep f7
+	particle c12 start
+	sleep f7
+	particle c11 start
+	sleep f7
+	particle c10 start
+	sleep f7
+	particle c09 start
+	sleep f7
+	particle c08 start
+	sleep f7
+	particle c07 start
+	sleep f7
+
+}
+######################################
+### NINJA CLOUD COVER START SCRIPT ###
+######################################
+func void storm(string ai_name)
+{
+	dprint Starting_Storm
+	particle storm create
+	particle wind start
+}
Index: /nikanabo/current/bsl/original/IGMD/roof/roof.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/roof/roof.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/roof/roof.bsl	(revision 185)
@@ -0,0 +1,942 @@
+#	rooftop
+#	scripts for level 12 by wu
+#	
+#	LEGEND
+#
+#	character naming convention: X_Yx
+#	where X = area letter (A=first area, B=second area, etc.)
+#	      Y = character type (N=ninja, T=tanker, S=striker, R=red, etc.)
+#		x = character number, usually same as character's initial patrol id
+#
+#	trigger volume scripts: t##, where ## refers to trigger volume id
+#	
+#	CONTENTS
+#	
+#	1.variables defined
+#	1b.music scripts
+#	2.start and objectives scripts
+#	3.save game scripts
+#	4.cut scene scripts
+#	5.console scripts
+#	6.trigger volume scripts
+
+###############################
+#	variables defined 	#
+###############################
+
+var int my_save_point=0;
+var int ninja1=0;
+var int ninja2=0;
+var int strike1=0;
+var int strike1b=0;
+var int strike2=0;
+var int strike3=0;
+#var int elv1_check=0;
+var int invading_counter=3;
+var int done_with_intro_cutscene = 0;
+var int go_hide;
+var int go_hide2;
+
+###############################
+#		music		 	#
+###############################
+
+func void music_first(void)
+{
+	sound_music_start mus_cool19 0.0
+	sound_music_volume mus_cool19 0.75 3.0
+#	stopped at tanker death or timer
+}
+
+func void music_first_timer(void)
+{
+	sleep 1800
+	music_stop
+}
+
+func void music_gauntlet(void)
+{
+	sound_music_start mus_atm_cl12lp 0.0
+	sound_music_volume mus_atm_cl12lp 0.75 3.0
+#	this music stopped in t14
+}
+
+func void music_billboard(void)
+{
+	sound_music_start mus_low1 0.0
+	sound_music_start mus_low1 0.75 3
+#	this music stopped in ta2_54 script
+}
+
+func void music_battle(void)
+{
+	sound_music_start mus_fitec
+#	this music stopped in outro
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_cool19
+	sound_music_stop mus_atm_cl12lp
+	sound_music_stop mus_low1
+	sound_music_stop mus_fitec
+}
+
+###############################
+#	start and objectives	#
+###############################
+func void start(string ai_name)
+{
+	dprint start	
+	
+	particle el1_locklight01 do start
+	door_lock 6
+
+	my_save_point = save_point;
+
+	if (my_save_point eq 0)
+	{
+		set_objective_1
+		powerup_spawn lsi 605 
+	}
+
+	if (my_save_point eq 1)
+	{
+		dprint restore1
+		set_objective_1
+		done_with_intro_cutscene = 1;
+		fork intro_taunt
+		restore_game
+		powerup_spawn lsi 605 
+	}
+
+	if (my_save_point eq 2)
+	{
+		done_with_intro_cutscene = 1;
+		dprint restore2
+		set_objective_1
+		chr_delete A_Sr9
+		chr_delete A_N1
+		chr_delete IntroNinja
+		ai2_spawn C_T16
+		ai2_spawn C_Sr15
+		ai2_spawn C_R55
+		ai2_spawn C_N57
+		trigvolume_enable trigger_volume_13 0
+		door_lock 3
+		restore_game
+		powerup_spawn lsi 605 
+	}
+
+	if (my_save_point eq 3)
+	{
+		done_with_intro_cutscene = 1;
+		dprint restore3
+		set_objective_3
+		chr_delete A_Sr9
+		chr_delete A_N1
+		chr_delete IntroNinja
+		trigvolume_enable trigger_volume_79 0
+		restore_game
+	}
+
+	if (my_save_point eq 4)
+	{
+		done_with_intro_cutscene = 1;
+		dprint restore4
+		chr_delete A_Sr9
+		chr_delete A_N1
+		chr_delete IntroNinja
+		trigvolume_enable trigger_volume_28 0
+		ai2_spawn OutroNinja
+		chr_boss_shield OutroNinja
+		music_battle
+		gs_farclipplane_set 500
+		door_lock 2
+		restore_game
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set (7006,0.0)
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective_2
+	objective_set(2)
+	target_set (7006,0.0)
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective_3
+	objective_set(3)
+	target_set (7006,0.0)
+}
+
+###################
+#	save game	#
+###################
+
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME1	
+
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME2	
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME3	
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME4	
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+##########################
+#	cut scene scripts  #
+##########################
+
+func void t12(string ai_name)
+{
+	dprint t12_elevator
+	if (trigvolume_count(62) eq 0)
+	{
+		trigvolume_enable trigger_volume_12 0
+		sleep 7
+		trigvolume_corpse 62
+		dprint delete_oldAI
+		chr_delete B_R11
+		chr_delete B_R12a
+		chr_delete B_Sr10
+		chr_delete B_Sr10a
+		chr_delete B_T13
+		chr_delete B_Sr12
+		chr_delete B_N17
+		chr_delete B_N18	
+		chr_delete A_N8
+		chr_delete A_T4
+		chr_delete A_Sr3
+		chr_delete C_N17
+		chr_delete C_N18
+		Elevator
+		target_set(47,0.0)
+		ai2_spawn C_Sr15
+		ai2_spawn C_T16
+		ai2_spawn C_R55
+		ai2_spawn C_N57
+	}
+}
+
+func void t17(string ai_name)
+{
+	dprint t17_KonokoZip
+	if (chr_has_lsi(0))
+	{
+		KonokoZip
+		chr_delete D_C19
+		chr_delete D_C60
+		chr_delete D_N25
+		chr_delete D_R21
+		chr_delete D_Sb20
+		chr_delete D_Sb22
+		chr_delete D_Sb23
+		chr_delete D_Sr24
+		chr_delete D_Sr26
+		chr_delete D_Sr27
+		chr_delete D_Sr38
+		chr_delete D_T28
+		set_objective_3
+	}
+}
+
+func void t27(string ai_name)
+{
+	dprint t27_ElevatorFinalFight
+	ai2_spawn SuperNinja
+#	Elevator cut scene
+#	I'm backing him into a corner.  This isn't going to be pretty..."
+
+	chr_teleport 0 96
+
+}
+
+
+###################
+#	console	#
+###################
+
+#########################
+#  trigger volume stuff #
+#########################
+
+func void t28(string ai_name)
+{
+	chr_wait_animtype char_0 Pickup_Object
+	particle obj_zip create
+}
+
+func void runup(void)
+{
+	ai2_dopath B_Sr10 patrol_10z
+	ai2_setjobstate B_Sr10
+}
+
+func void t1(string ai_name)
+{
+	dprint t1 
+	ai2_dopath A_N1 patrol_02
+	ai2_setjobstate A_N1
+	ai2_dopath IntroNinja patrol_40
+	ai2_setjobstate IntroNinja
+	if (strike1b eq 1)
+	{	
+		dprint strike1b
+		ai2_dopath A_Sr9 patrol_09
+		ai2_setjobstate A_Sr9
+	}
+	sleep 300
+	if (ninja1 ne 0)
+	{
+		dprint ninja1_failed_trying_again
+		ai2_dopath IntroNinja patrol_40
+		ai2_setjobstate IntroNinja
+	}
+
+	if (ninja2 ne 0)
+	{
+		dprint ninja2_failed_trying_again
+		ai2_dopath A_N1 patrol_02
+		ai2_setjobstate A_N1
+	}
+}
+
+func void patrolscript0001(string ai_name)
+{
+	dprint patrolscript0001_t1
+	playback_block IntroNinja ninja_jump5 interp 30
+#	ai2_makeignoreplayer A_N1 0
+}
+
+func void patrolscript0002(string ai_name)
+{
+	dprint patrolscript0002_t1
+	playback_block A_N1 ninja_jump interp 30
+#	ai2_makeignoreplayer A_N1 0
+}
+
+func void t2(string ai_name)
+{
+	dprint t2
+	trigvolume_enable trigger_volume_03 0
+	ai2_spawn A_C5
+}
+
+func void t3(string ai_name)
+{
+	dprint t3
+	trigvolume_enable trigger_volume_02 0
+	ai2_spawn A_Sr3
+}
+
+func void t4(string ai_name)
+{
+	dprint t4	
+	trigvolume_enable trigger_volume_05 0
+	ai2_spawn A_T6
+	chr_delete A_Sr9
+	chr_delete A_N1
+	chr_delete IntroNinja
+
+}
+
+func void patrolscript0004(string ai_name)
+{
+	dprint patrolscript0004	
+	playback_block A_T6 tanker2 interp 20
+
+}
+
+func void t5(string ai_name)
+{
+	dprint t5	
+	trigvolume_enable trigger_volume_04 0
+	ai2_spawn A_T4
+	chr_delete A_Sr9
+	chr_delete A_N1
+	chr_delete IntroNinja
+
+}
+
+func void patrolscript0005(string ai_name)
+{
+	dprint patrolscript0005	
+	playback_block A_T4 tanker1 interp 20
+
+}
+
+func void t6(string ai_name)
+{
+	dprint t6
+	ai2_spawn A_N7
+	trigvolume_enable trigger_volume_07_copy 0
+
+}
+
+func void t7(string ai_name)
+{
+	dprint t7
+	ai2_spawn A_N8
+	trigvolume_enable trigger_volume_06 0
+}
+
+func void t8(string ai_name)
+{
+	dprint t8
+	ai2_spawn B_Sr10
+	ai2_spawn B_Sr10a
+	ai2_spawn B_R11
+	ai2_spawn B_R12a
+	ai2_dopath A_T6 patrol_42
+	ai2_setjobstate A_T6
+	ai2_dopath A_T4 patrol_42
+	ai2_setjobstate A_T4
+#	ai2_dopath A_Sr3 patrol_44
+	ai2_setjobstate A_Sr3
+#	ai2_dopath A_C5 patrol_44
+	ai2_setjobstate A_C5
+	ai2_dopath A_N7 patrol_45
+	ai2_setjobstate A_N7
+	ai2_dopath A_N8 patrol_45
+	ai2_setjobstate A_N8
+}
+
+func void t9(string ai_name)
+{
+	dprint t9
+	ai2_spawn E_N37
+	ai2_makeignoreplayer E_N37 1
+	playback_block E_N37 ninja_jump2
+	ai2_makeignoreplayer E_N37 0
+	ai2_attack E_N37 char_0
+}
+
+func void t10(string ai_name)
+{
+	dprint t10
+	# "I lost him. Wait! There he is."
+	sound_dialog_play c11_39_03konoko
+	ai2_spawn B_Sr12
+	ai2_spawn B_T13
+	ai2_spawn B_SuperNinja
+	chr_boss_shield B_SuperNinja
+	chr_unstoppable B_SuperNinja 1
+	chr_neutral B_SuperNinja 1
+	playback_block B_SuperNinja superninja1 interp 20
+	sleep 60
+	chr_delete B_SuperNinja
+
+}
+
+func void t11(string ai_name)
+{
+	dprint t11
+	ai2_spawn C_N17
+	ai2_spawn C_N18
+	ai2_dopath B_T13 patrol_41
+	ai2_setjobstate B_T13
+}
+
+func void patrolscript0011(string ai_name)
+{
+	dprint patrolscript0011
+	playback_block B_T13 tanker_jump interp 30
+
+}
+
+func void t14(string ai_name)
+{
+	dprint t14
+	music_stop
+	target_set (1,0.0)
+	chr_delete C_N57
+	chr_delete C_Sr15
+	chr_delete C_T16
+	chr_delete C_R55
+	ai2_dopath D_Sb20 patrol_35
+	ai2_spawn D_Sr38
+	ai2_spawn D_C60
+}
+
+func void patrolscript0014(string ai_name)
+{
+	dprint patrolscript0014	
+	playback_block D_Sb20 striker_jump interp 20
+}
+
+func void t15(string ai_name)
+{
+	dprint t15
+	ai2_spawn E_N14
+	ai2_spawn E_N14a
+	ai2_passive E_N14 1
+	#ai2_passive E_N14a 1
+	ai2_spawn NinjaZip
+	ai2_passive NinjaZip 1
+	chr_unstoppable NinjaZip 1
+	playback NinjaZip NinjaZipSet
+	playback E_N14 Ninja02Set
+
+}
+
+#func void patrolscript0016(string ai_name)
+#{
+#	dprint patrolscript0016	
+#	playback_block E_N14 LSIninja interp 20
+#}
+
+func void t18(string ai_name)
+{
+	dprint t18
+	music_gauntlet
+	ai2_spawn D_C19
+	ai2_spawn D_Sb20
+	ai2_spawn D_R21
+	ai2_spawn D_Sb22
+	ai2_spawn D_Sb23
+	ai2_spawn D_Sr24
+}
+
+func void t19(string ai_name)
+{
+	dprint t19
+	music_billboard
+	ai2_spawn D_N25
+	ai2_spawn C_R61
+}
+
+func void t20(string ai_name)
+{
+	dprint t20
+	music_stop
+	ai2_spawn D_Sr26
+	ai2_spawn D_Sr27
+	ai2_spawn D_T28
+}
+
+func void cantescape_dialog(void)
+{
+	sleep 120
+	# "He can't escape me. But why?"
+	sound_dialog_play c11_39_04konoko
+}
+
+func void t21(string ai_name)
+{
+	dprint t21_E_SuperNinja
+	fork cantescape_dialog
+	ai2_spawn E_N29
+	ai2_spawn E_Sb31
+	ai2_spawn E_Sr63
+	ai2_spawn E_Sr64
+	ai2_spawn E_R65
+	ai2_spawn E_SuperNinja
+	chr_boss_shield E_SuperNinja
+	chr_unstoppable E_SuperNinja
+	playback_block E_SuperNinja superninja2 interp 20
+	sleep 60
+	chr_delete E_SuperNinja
+
+}
+
+func void t22(string ai_name)
+{
+	dprint t22
+	ai2_dopath IntroNinja patrol_39
+	ai2_setjobstate IntroNinja
+
+}
+
+func void patrolscript0022(string ai_name)
+{
+	dprint patrolscript0022
+	playback_block IntroNinja ninja_jump4 interp 20
+
+}
+
+func void t23(string ai_name)
+{
+	dprint t23
+	ai2_spawn E_Sr30
+
+}
+
+func void t24(string ai_name)
+{
+	dprint t24
+	# "He knows I can feel him. That we are... rivals? Natural enemies?"
+	sound_dialog_play c11_39_08konoko
+	ai2_spawn E_R32
+	ai2_dopath E_Sr33 patrol_34
+	ai2_setjobstate E_Sr33
+}
+
+func void t25(string ai_name)
+{
+	dprint t25
+	ai2_spawn E_Sr33
+	ai2_dopath E_Sr30 patrol_34
+	ai2_setjobstate E_Sr30
+}
+
+func void t29(string ai_name)
+{
+	dprint t29
+	# "There's something familar about him, I can't quite place it."
+	sound_dialog_play c11_39_05konoko
+}
+
+func void t30(string ai_name)
+{
+	dprint t30_D_SuperNinja
+	# "Where... ? Ah! Over there!"
+	sound_dialog_play c11_39_01konoko
+	ai2_spawn D_SuperNinja
+	chr_boss_shield D_SuperNinja
+	chr_unstoppable D_SuperNinja 1
+	playback_block D_SuperNinja superninja1b interp 20
+	sleep 60
+	chr_delete D_SuperNinja
+
+}
+
+func void t31(string ai_name)
+{
+	dprint t31
+	ai2_spawn A_N43
+}
+
+func void t32in(string ai_name)
+{
+	dprint t32in
+	ninja1 = ninja1 + 1
+}
+
+func void t32out(string ai_name)
+{
+	dprint t32out
+	ninja1 = ninja1 - 1
+}
+
+func void t33in(string ai_name)
+{
+	dprint t33in
+	ninja2 = ninja2 + 1
+}
+
+func void t33out(string ai_name)
+{
+	dprint t33out
+	ninja2 = ninja2 - 1
+}
+
+func void ninja1_die(string ai_name)
+{
+	dprint ninja1_die
+	ninja1 = 0
+}
+
+func void ninja2_die(string ai_name)
+{
+	dprint ninja2_die
+	ninja2 = 0
+}
+
+func void t57(string ai_name)
+{
+	dprint t57
+	strike1=1
+	sleep 120
+	if (strike1 eq 1)
+	{
+		ai2_dopath A_Sr9 patrol_48
+		ai2_setjobstate A_Sr9
+	}
+}
+
+func void t57b(string ai_name)
+{
+	dprint t57b
+	strike1=0
+	strike1b=1
+}
+
+
+func void t58(string ai_name)
+{
+	dprint t58
+	music_first
+#	ai2_makeignoreplayer A_Sr9 1
+#	ai2_makeignoreplayer A_N1 1
+#	ai2_makeignoreplayer IntroNinja 1
+	ai2_dopath A_Sr9 patrol_49
+	ai2_setjobstate A_Sr9
+	ai2_dopath A_N1 patrol_50
+	ai2_setjobstate A_N1
+	ai2_dopath IntroNinja patrol_51
+	ai2_setjobstate IntroNinja
+#	sleep 15
+#	ai2_makeignoreplayer A_Sr9 0
+#	ai2_makeignoreplayer A_N1 0
+#	ai2_makeignoreplayer IntroNinja 0
+	music_first_timer
+
+}
+
+func void t83(string ai_name)
+{
+	dprint checking
+	go_hide =  go_hide + 1;
+	if(trigvolume_count (83) ne 0)
+	{
+		dprint t83
+		if(go_hide eq 0)
+		{
+			ai2_makeignoreplayer (ai_name,1)
+			ai2_dopath (ai_name,patrol_13b)
+			ai2_setjobstate (ai_name)
+			ai2_forget (ai_name)
+			sleep 60
+			ai2_makeignoreplayer (ai_name,0)
+		}
+		if(go_hide eq 1)
+		{
+			ai2_makeignoreplayer (ai_name,1)
+			ai2_dopath (ai_name,patrol_12b) 
+			ai2_setjobstate (ai_name)
+			ai2_forget (ai_name)
+			sleep 60
+			ai2_makeignoreplayer (ai_name,0)
+		}
+	}
+}
+
+func void t83b(string ai_name)
+{
+	dprint t83B
+	go_hide =  go_hide - 1;
+}
+
+func void t84(string ai_name)
+{
+	dprint checking
+	go_hide2 =  go_hide2 + 1;
+	sleep 60
+	if(trigvolume_count (84) ne 0)
+	{
+		dprint t84
+		if(go_hide2 eq 0)
+		{
+			ai2_makeignoreplayer (ai_name,1)
+			ai2_dopath (ai_name,patrol_69)
+			ai2_setjobstate (ai_name)
+			ai2_forget (ai_name)
+			sleep 60
+			ai2_makeignoreplayer (ai_name,0)
+		}
+		if(go_hide2 eq 1)
+		{
+			ai2_makeignoreplayer (ai_name,1)
+			ai2_dopath (ai_name,patrol_70) 
+			ai2_setjobstate (ai_name)
+			ai2_forget (ai_name)
+			sleep 60
+			ai2_makeignoreplayer (ai_name,0)
+		}
+		if(go_hide2 eq 2)
+		{
+			ai2_makeignoreplayer (ai_name,1)
+			ai2_dopath (ai_name,patrol_71) 
+			ai2_setjobstate (ai_name)
+			ai2_forget (ai_name)
+			sleep 60
+			ai2_makeignoreplayer (ai_name,0)
+		}
+	}
+}
+
+func void t84b(string ai_name)
+{
+	dprint t84B
+	go_hide2 =  go_hide2 - 1;
+}
+
+func void t85(string ai_name)
+{
+	dprint t85
+	ai2_spawn sbg_ninja
+}
+func void t59(string ai_name)
+{
+	dprint t59
+	strike2=1
+	sleep 120
+	if (strike2 eq 1)
+	{
+		ai2_dopath A_Sr3 patrol_52
+		ai2_setjobstate A_Sr3
+		ai2_dopath A_C5 patrol_52
+		ai2_setjobstate A_C5
+	}
+}
+
+func void t59b(string ai_name)
+{
+	dprint t59b
+	strike2=0
+}
+
+func void t60(string ai_name)
+{
+	dprint t60
+	strike3=1
+	sleep 120
+	if (strike3 eq 1)
+	{
+		ai2_dopath B_Sr12 patrol_53
+		ai2_setjobstate B_Sr12
+	}
+}
+
+func void t60b(string ai_name)
+{
+	dprint t60b
+	strike3=0
+}
+
+func void t63(string ai_name)
+{
+	if (trigvolume_count(64) eq 0)
+	{
+		trigvolume_enable trigger_volume_63 0
+		dprint t63
+		chr_delete E_R32
+		chr_delete E_Sr33
+		chr_delete E_Sr30
+		door_unlock 6
+	}
+}
+
+func void t65(string ai_name)
+{
+	dprint t65
+	chr_teleport C_R55 7013
+	ai2_dopath C_R55 patrol_56
+	ai2_setjobstate C_R55
+}
+
+func void t77(string ai_name)
+{
+	dprint t77
+	ai2_dopath D_R21 patrol_58
+}
+
+func void t78(string ai_name)
+{
+	dprint t78
+	ai2_dopath D_R21 patrol_59
+}
+
+func void minus_invading_counter(string ai_name)
+{
+	invading_counter = invading_counter - 1
+
+	if (invading_counter eq 0)
+	{
+		invading_dialog();
+	}
+}
+
+func void invading_dialog(void)
+{
+	invading_counter = 0;
+	trigvolume_enable trigger_volume_95 0
+
+	sleep 90
+	# "It's like this is his territory, and I'm invading."
+	sound_dialog_play c11_39_06konoko
+}
+
+func void t95(string ai_name)
+{
+	dprint t95
+
+	invading_dialog();
+}
+
+func void t96(string ai_name)
+{
+	dprint t96
+	# "He's... angry! I can _taste_ his frustration."
+	sound_dialog_play c11_39_07konoko
+}
+
+func void patrolscript0077(string ai_name)
+{
+	dprint 0077
+	ai2_dopath D_R21 patrol_21
+	ai2_setjobstate D_R21
+}
+
+func void t80(string ai_name)
+{
+	dprint t78
+	ai2_spawn E_C62
+	playback E_C62 com
+	
+}
+
Index: /nikanabo/current/bsl/original/IGMD/roof/roof_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/roof/roof_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/roof/roof_cutscene.bsl	(revision 185)
@@ -0,0 +1,340 @@
+#
+#
+# roof_cutscene.bsl
+#
+
+func void intro_roll_sounds(void)
+{
+	sleep 252
+	sound_impulse_play kon_roll
+	sleep 3
+	sound_impulse_play kon_roll
+}
+
+func void
+intro_taunt(
+	void)
+{
+	chr_envanim_stop IntroNinja
+	chr_teleport IntroNinja 600
+	chr_facetoflag IntroNinja 600
+	chr_animate IntroNinja NINCOMcrouch_idle
+
+	ai2_passive IntroNinja 1
+	ai2_setmovementmode IntroNinja creep
+	sleep f40
+	playback_block IntroNinja IntroNinja
+	ai2_passive IntroNinja 0
+
+	ai2_attack IntroNinja 0
+}
+
+func void
+intro(
+	void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam01 0
+	sleep 14
+	begin_cutscene
+	ai2_spawn IntroNinja
+	#sound_ambient_start c08_11_19zip
+	sleep 30
+	fade_in 120
+	obj_create 81 81
+	env_anim 81 81
+	cm_anim both IntroCam01
+	chr_envanim 0 IntroKonBip01 norotation
+	chr_animate 0 KONOKOlev12_Intro
+	chr_envanim IntroNinja IntroNinBip01 norotation
+	chr_animate IntroNinja NINJAlev12_Intro
+	fork intro_roll_sounds
+	sleep f30
+	sound_ambient_start c08_11_19zip
+	cm_anim_block both IntroCam02
+	cm_wait
+	cm_reset
+	playback 0 IntroKonoko
+	done_with_intro_cutscene = 1;
+	trigvolume_reset death_fall_trigger_67
+	end_cutscene
+	fork intro_taunt
+	s1
+}
+
+func void
+camcontrol(
+	void)
+{
+	cm_anim both IntroCam01
+	cm_anim_block both IntroCam02
+	cm_wait
+}
+
+
+
+func void
+Elevator(
+	void)
+{
+	begin_cutscene
+	sleep 10
+	# "It's strange, I can almost feel him out there, creeping from shadow to shadow..."
+	sound_dialog_play c11_39_02konoko
+	playback 0 ElevatorKonokoSet
+	cm_interpolate ElevatorCam01 0
+	sleep 10
+	chr_envanim 0 ElevatorKonBox01
+	obj_create 31 31
+	obj_shade 31 31 .4 .4 .4
+	env_anim 31 31
+	sound_ambient_start first_elevator
+	cm_anim both ElevatorCam01
+	sleep 220
+	obj_kill 31 31
+	env_show 31 1
+	cm_reset
+	sleep 10
+	end_cutscene
+}
+
+
+
+
+func void
+NinjaZip(
+	void)
+{
+	chr_envanim NinjaZip ZipNinjaBipBox norotation
+	chr_animate NinjaZip NINJAlev12_zip
+	obj_create 72 72
+	env_anim 72 72
+	sleep 60
+	playback E_N14 Ninja02Jump
+	sleep 80
+	ai2_passive E_N14 0
+	sleep 100
+	playback NinjaZip NinjaZipLeave
+	sleep 120
+	chr_delete NinjaZip
+}
+
+func void
+KonokoZip(
+	void)
+{
+	particle obj_zip kill
+	begin_cutscene
+	sleep 10
+	cm_anim both KonZipCam01
+	chr_envanim 0 ZipKonBipBox norotation
+	chr_animate 0 KONOKOlev12_zip
+	obj_create 71 71
+	env_anim 71 71
+	sleep 55
+	sound_ambient_start c08_11_19zip
+	sleep 235
+
+	# CB: kill ninja's zip so we don't get Z fighting on superposed objects
+	obj_kill 72 72
+
+	cm_reset
+	end_cutscene
+}
+
+func void pretty_sayline(void)
+{
+	sleep 180
+	# "I'm backing him into a corner. This isn't going to be pretty."
+	sound_dialog_play c11_39_09konoko
+	sound_dialog_play_block pause
+	sleep 30
+	door_open 2
+	door_jam 2
+}
+
+func void
+ninja(
+	void)
+{
+	begin_cutscene
+	sleep 10
+	fork pretty_sayline
+	fork storm
+	ai2_spawn OutroNinja
+	chr_boss_shield OutroNinja
+	ai2_allpassive 1
+	playback OutroNinja SuperNinjaSet
+	chr_nocollision OutroNinja 1
+	#konokoenters elevator
+	#cm_interpolate SuperCam00 0
+	#playback 0 SuperKonokoEnter
+	chr_envanim 0 SuperKonBox01
+	gs_farclipplane_set 500
+	obj_create 41 41
+	obj_shade 41 41 .4 .4 .4
+	env_anim 41 41
+	sound_ambient_start c08_20_27elevator
+	cm_anim both SuperCam00
+	cm_wait
+	obj_kill 41 41
+	env_show 41 1
+	cm_interpolate SuperNinjaCam01 180
+	sleep 120
+	#all you have done is force me to fight
+	sound_dialog_play c11_40_01superninja
+	cinematic_start (BOSS2face, 180, 180, 19, 7, 20, false)
+	sleep 60
+	playback 0 SuperKonokoSet
+	sound_dialog_play_block pause
+	#Konoko who are you
+	cm_interpolate SuperCamKonokoSet 0
+	door_close 2
+	door_lock 2
+	sound_dialog_play c11_40_02konoko
+	cinematic_start (KONtalking, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (KONtalking, 20, 20)
+	#Super Ninja goes around
+	playback OutroNinja SuperNinjaWalk
+	sleep 40
+	playback 0 SuperKonokoWalk
+	#ninja talks
+	sound_dialog_play c11_40_03superninja
+	cinematic_stop (BOSS2face, 7, 0)
+	cinematic_start (BOSS2face, 180, 180, 7, 9, 2, false)
+	cm_interpolate SuperCamWalkOut02 0
+	cm_interpolate_block SuperCamWalkOut02b 800
+	sound_dialog_play_block pause
+	#konoko answers
+	sound_dialog_play c11_40_04konoko
+	cinematic_start (KONtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (KONtalking, 16, 20)
+	#super ninja we writhe
+	sound_dialog_play c11_40_05superninja
+	#cm_interpolate_block SuperCamWalkOut02b 800
+	sound_dialog_play_block pause
+	cm_interpolate SuperCamWalkOut02b 800
+	#Konoko says you're a thug
+	sound_dialog_play c11_40_06konoko
+	cinematic_start (KONangry, 180, 180, 16, 3, 20, true)
+	cm_interpolate SuperCamWalkOut03 0
+	cm_interpolate_block SuperCamWalkOut03b 600
+	sound_dialog_play_block pause
+	cinematic_stop (KONtalking, 16, 20)
+	#ninja says we'll see about that
+	sound_dialog_play c11_40_07superninja
+	sound_dialog_play_block pause
+	cinematic_stop (BOSS2face, 19, 15)
+	#gameplay setup
+	playback 0 SuperKonokoEnd
+	cm_reset
+	end_cutscene
+	sleep 20
+	chr_animate OutroNinja NINCOMteleport_in 47
+	music_battle
+	sleep 40
+	playback OutroNinja SuperNinjaDone
+	chr_animate OutroNinja NINCOMteleport_out 31
+	chr_nocollision OutroNinja 0
+
+	dprint SAVEDGAME4	
+	save_game 4 autosave
+}
+
+
+func void
+test(
+	void)
+{
+	chr_envanim 0 ZipKonBipBox norotation
+	sleep 120
+	playback 0 IntroKonoko
+}
+
+
+func void
+deathfall(
+	void)
+{
+	if (done_with_intro_cutscene eq 1)
+	{
+		sleep 30
+		cm_detach
+		sleep 30
+		chr_set_health 0 0
+	}
+}
+
+
+func void
+outro(
+	void)
+{
+	sound_music_volume mus_fitec 0.0 1.0
+	music_stop
+	begin_cutscene
+	chr_animate OutroNinja NINCOMteleport_in 31	
+	sleep 10
+	#spawn teleported Ninja and add some glowy bits
+	chr_envanim OutroNinja OutroNinjaBox01
+	chr_animate OutroNinja NINCOMteleport_out 31
+	sleep 10
+	cm_interpolate OutroCam01 0
+	sleep 10
+	chr_envanim OutroNinja OutroNinjaBox01 norotation
+	chr_animate OutroNinja NINJAlev12_Outro1
+	sound_ambient_start ninja_cd_scene
+	cm_anim both OutroCam01
+	sleep 208
+	obj_create 481 481
+	env_anim 481 481
+	cm_interpolate OutroCamDisk 90
+	chr_envanim OutroNinja OutroNinjaBox02 norotation
+	chr_animate OutroNinja NINJAlev12_Outro2 900
+	#Konoko patrol to flag 2000
+	#chr_teleport 0 2000
+	playback 0 OutroKonoko01
+	sleep 100
+	sleep 70
+	#camera cut here to Konoko's face
+	cm_interpolate OutroCam02 0
+	#sleep 30
+	#playback 0 OutroKonoko02
+	sleep 50
+	cinematic_start (KONtalking, 180, 180, 18, 6, 15, true)
+	sound_dialog_play c11_41_01konoko
+	sleep 300
+	#camera cut here to Konoko and Ninja
+	cm_interpolate OutroCam03 0
+	cm_interpolate_block OutroCam04 800
+	chr_envanim OutroNinja OutroNinjaBox02 norotation
+	chr_animate OutroNinja NINJAlev12_Outro2 1300
+	sound_dialog_play_block
+	# Camera cut as Konoko steps on Ninja
+	#Add sound of Konoko saying she has nothing in common
+	sound_dialog_play c11_41_01bkonoko
+	cinematic_stop (KONtalking, 18, 20)
+	cinematic_start (KONintense, 180, 180, 18, 6, 15, true)
+	cm_anim both OutroCam05
+	chr_envanim 0 OutroKonBox01 norotation
+	chr_animate 0 KONOKOlev12_Outro1
+	chr_envanim OutroNinja OutroNinjaBox03 norotation
+	chr_animate OutroNinja NINJAlev12_Outro3
+	sleep 175
+	sound_ambient_start c09_36_26neckbreak
+	sleep 100
+	#Camera cut to Konoko's face
+	playback 0 OutroKonoko02
+	chr_animate OutroNinja STRIKEfallen_front 540
+	cm_interpolate OutroCam06 0
+	sleep 60
+	sound_dialog_play c11_41_02konoko
+	cinematic_stop (KONintense, 18, 10)
+	sleep 60
+	fade_out 0 0 0 120	
+	sleep 120
+	win
+}
+
Index: /nikanabo/current/bsl/original/IGMD/roof/roof_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/roof/roof_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/roof/roof_main.bsl	(revision 185)
@@ -0,0 +1,22 @@
+#
+# power_main.bsl
+#
+
+func void
+main(
+	void)
+{
+	env_shade 1500 1501 .9 .8 .9
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.975
+	gs_farclipplane_set 900
+	start
+	if (my_save_point eq 0)
+	{
+		fork intro	
+	}
+	env_show 31 0
+	env_show 41 0
+}
Index: /nikanabo/current/bsl/original/IGMD/state/state_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/state/state_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/state/state_cutscene.bsl	(revision 185)
@@ -0,0 +1,411 @@
+#
+# state_cutscene.bsl
+#
+
+var int face_count_dead;
+
+func void
+state_cs_intro(
+	void)
+{
+	trigvolume_enable trig_vol_17 0
+	trigvolume_enable trig_vol_19 0
+	trigvolume_enable trigger_volume_99 0
+	begin_cutscene
+	cutscene_sync off
+	fade_out 0 0 0 0
+	sleep 120
+	#Griffin talks
+	cinematic_start(GRIFtalkangry, 180, 180, 16, 3, 30, true)
+	sound_dialog_play c10_34_01griffin
+	sound_dialog_play_block pause
+	#Kerr responds
+	sleep 20
+	#cinematic_start(KERRtalking, 180, 180, 19, 7, 10, false)
+	cinematic_start(KERRtalking, 180, 180, 15, 1, 10, false)
+	sound_dialog_play c10_34_02kerr
+	sound_dialog_play_block pause
+	#Griffin talks again
+	sleep 20
+	sound_dialog_play c10_34_03griffin
+	sleep 400
+
+	#Make characters for cut-scene
+	sound_music_start mus_main02_hd 1.0
+	chr_create 102 start
+	sleep 10
+	#ninja runs out of scene
+	playback 102 IntroNinja
+	playback 0 IntroKonoko
+	chr_nocollision 0 1
+	fade_in 120
+	cm_anim both Camout01
+	sleep 120
+	cinematic_stop (GRIFtalkangry, 16, 10)
+	cinematic_stop (KERRtalking, 15, 10)
+	cm_wait
+	chr_delete 102	
+	cm_anim both Camout02
+	cm_wait
+	cm_interpolate Camin03 0
+	#change this amount to work with cutscene
+	sleep 170	
+	sleep 60
+	#security shows up behind Konoko
+	ai2_spawn IntroSec1
+	ai2_spawn IntroSec2
+	sleep 10
+	cm_interpolate Camin04 0
+	playback 0 IntroKonoko02
+	sleep 30
+	sound_dialog_play c10_34_05secguard2
+	sound_dialog_play_block pause
+	chr_animate IntroSec2 SECURIlev11_intro
+	cm_interpolate Camin05 0
+	#put security guard talking here
+	cinematic_start(SEC2talking, 180, 180, 15, 1, 30, true)
+	sound_dialog_play c10_34_04secguard1
+	sound_dialog_play_block pause
+	#Konoko says I don't have time for this
+	cm_interpolate IntroCamNotime 0
+	cinematic_start (KONintense, 180, 180, 20, 8, 20, true)
+	sound_dialog_play c10_34_06konoko
+	sound_dialog_play_block pause
+	#Security says something
+	sound_dialog_play c10_34_07secguard1
+	sound_dialog_play_block pause
+	cinematic_stop (SEC2talking, 15, 30)
+	#your call
+	cm_interpolate IntroCamCall01 0
+	cm_interpolate_block IntroCamCall02 90
+	sleep 70
+	sound_dialog_play c10_34_08konoko
+	sound_dialog_play_block pause
+	cinematic_stop (KONintense, 20,20)
+	sleep 20
+	cm_reset 0
+	#chr_delete 102
+	chr_nocollision 0 0
+	trigvolume_enable trig_vol_17 1
+	trigvolume_enable trig_vol_19 1
+	trigvolume_enable trigger_volume_99 1
+	end_cutscene
+	set_objective_1
+}
+
+
+func void
+dog(string ai_name)
+{
+	particle obj1 kill
+	begin_cutscene
+	chr_forceholster 0 1
+	chr_nocollision 0 1
+	sleep 30
+	#Konoko uses console
+	playback 0 DogKonokoSet
+	cm_interpolate DogCamLeftHigh 0
+	cm_interpolate_block DogCamRightHigh 400
+	sleep 10
+	chr_animate 0 KONOKOlev11_cnsl_start 68
+	chr_animate_block 0 KONOKOlev11_cnsl_idle 300
+	#sleep 30
+	#Konoko talks
+	cinematic_start (KONintense, 180, 180, 19, 7, 20, false)
+	sound_dialog_play c10_35_01aKonoko
+	sleep 90
+	chr_animate 0 KONOKOlev11_cnsl_type 120
+	chr_animate_block 0 KONOKOlev11_cnsl_idle 800 8
+	sleep 120
+	cm_interpolate DogCamRight 0
+	cm_interpolate_block DogCamLeft 500
+	#Konoko senses the watchdog
+	sound_dialog_play_block c10_35_01bKonoko
+	chr_animate 0 KONOKOlev11_cnsl_type 120
+	chr_animate_block 0 KONOKOlev11_cnsl_type 800 8
+	#camera switches to show Ninja
+	chr_create 1030 start
+	playback 1030 DogNinjaSet
+	chr_animate 1030 NINJAlev11_cnsl_type 400
+	cm_interpolate DogCamNinjaRight 0
+	cm_interpolate_block DogCamNinjaLeft 360
+	sleep 360
+	#Konoko says no
+	cm_interpolate DogCamLeftHigh 0
+	cm_interpolate_block DogCamRight 800
+	sound_dialog_play_block c10_35_01cKonoko
+	chr_animate 0 KONOKOlev11_cnsl_idle 240 8
+	sleep 180
+	#Konoko wonders who hacker was
+	chr_animate_block 0 KONOKOlev11_cnsl_stop	
+	#Gameplay resumes
+	chr_delete 1030
+	sound_dialog_play_block pause
+	cinematic_stop (KONintense, 15, 30)
+	end_cutscene
+	cm_reset
+	chr_nocollision 0 0
+	playback DogKonokoEnd
+#	save_game_2
+
+	trig_activate 12
+	trig_activate 13
+	trig_activate 14
+
+	door_unlock 82
+
+	set_objective_5
+	set_target_2
+
+	console_activate 1
+	console_activate 6
+}
+
+func void
+Nwindow_ninja(string ai_name)
+{
+	#spawn character 1030 before Konoko enters the room
+	chr_create 1030 start
+	chr_neutral 1030 1
+	playback 1030 WindowNinjaSet
+}
+
+func void
+window_ninja(string ai_name)
+{
+	trigvolume_enable Cut_outro 0
+	chr_create 1030 start
+	chr_neutral 1030 1
+	playback 1030 WindowNinjaSet
+	begin_cutscene
+	cm_interpolate WindowCamSet 70
+	ai2_takecontrol 1
+	ai2_setmovementmode 0 walk
+	ai2_movetoflag 0 289
+	sleep f60
+	cm_interpolate WindowCamStart 120
+	sound_music_start mus_pursuit_hd
+	sleep 120
+	#Ninja turns around
+	cm_anim both WindowCam00
+	ai2_takecontrol 0
+	chr_envanim 1030 WindowNinjaBox02 norotation
+	chr_animate 1030 NINJAlev11_windowturn
+	obj_create 481 481
+	obj_show 481 481
+	env_anim 481 481
+	#Konoko says give me back those files
+	cm_wait
+	playback 0 WindowKonoko01
+	cm_interpolate WindowCam02 0
+	sleep 30
+	#cinematic_start (KONintense, 180, 180, 17, 6, 30, false)
+	#sound_dialog_play lev11_WindowKon
+	#sound_dialog_play_block pause
+	#cinematic_stop (KONintense, 18, 30)
+	sleep 60
+	playback 0 WindowKonoko02
+	#Ninja backs towards window and flies out)
+	env_setanim 481 Disk02
+	chr_envanim 1030 WindowNinjaBox01 norotation
+	chr_animate 1030 NINJAlev11_window
+	cm_anim both WindowCam03
+	sleep 185
+	#break glass here
+	sound_impulse_play glass_big
+	particle WindowCharge do explode
+	cm_wait
+	cm_reset
+	end_cutscene
+	sleep 60
+	chr_delete 1030
+	ai2_spawn WindowNinjaRun
+	ai2_passive WindowNinjaRun 1
+	chr_unstoppable WindowNinjaRun 1
+	ai2_spawn creepy_ninja_4
+	chr_lock_active WindowNinjaRun
+	#make ninja no collision with particles
+	playback WindowNinjaRun WindowNinjaRun
+	obj_kill 481 481
+	target_set(1030, 0.0)
+	sleep f210
+	playback WindowNinjaRun JumpNinjaSet
+	sleep f10
+	playback WindowNinjaRun JumpNinjaSet
+	#chr_delete WindowNinjaRun
+}
+
+func void
+WindowNinjaDelete(string ai_name)
+{
+	#chr_delete WindowNinjaRun 
+}
+
+func void
+FaceSet(string ai_name)
+{
+	playback WindowNinjaRun
+	ai2_spawn FaceNinja
+	ai2_spawn FaceNinja2
+	ai2_passive FaceNinja 1
+	ai2_passive FaceNinja2 1
+	ai2_passive FaceNinja3 1
+	playback FaceNinja FaceNinjaSet
+	playback FaceNinja FaceNinjaJump
+	sleep 60
+	#chr_delete WindowNinjaRun 
+	ai2_passive FaceNinja 0
+	ai2_passive FaceNinja2 0
+	ai2_passive FaceNinja3 0
+	trigvolume_enable Cut_outro 0
+}
+
+func void
+JumpNinja(string ai_name)
+{
+	chr_nocollision WindowNinjaRun 1
+	chr_animate WindowNinjaRun KONOKOlev11_jump -1
+	sleep f135
+	chr_delete WindowNinjaRun
+}
+
+func void
+JumpKonoko(string ai_name)
+{
+	begin_cutscene
+	chr_animate 0 KONOKOlev11_jump -1
+	sleep f135
+}
+
+#func void
+#Face(string ai_name)
+#{
+#	playback FaceNinja FaceNinjaJump
+#	sleep 60
+#	#chr_delete WindowNinjaRun 
+#	ai2_passive FaceNinja 0
+#	sleep 60
+#}
+
+
+func void
+outro_makeNinja(string ai_name)
+{
+	chr_create 111 start
+	chr_create 110 start
+	chr_neutral 110 1
+	chr_neutral 111 1
+	playback 110 OutroNinja
+	playback 111 OutroSuperNinja
+}
+
+func void
+outro(string ai_name)
+{
+	particle obj2 kill
+	sound_music_stop mus_pursuit_hd
+	begin_cutscene
+	sleep f30
+	chr_nocollision 0 1
+	chr_create 111 start
+	chr_create 110 start
+	chr_neutral 110 1
+	chr_neutral 111 1
+	playback 110 OutroNinja
+	playback 111 OutroSuperNinja
+	cm_interpolate JumpCamKonoko01 0
+	playback 0 JumpKonokoSet
+	cm_interpolate_block JumpCamKonoko02 90
+	sleep f10
+	chr_animate 0 KONOKOlev11_jump -1
+	sleep f100
+	chr_nocollision 0 0
+	sleep f10
+	playback 0 JumpKonokoDown
+	cm_interpolate OutroCamSet 0
+	#chr_forceholster 0 1
+	sleep f90
+	cm_interpolate OutroCam01 140
+	sleep 60
+	chr_animate 111 NINCOMstartle_bk1
+	sleep 80
+	cinematic_start (BOSS2face, 180, 180, 17, 6, 30, false)
+	sound_dialog_play c10_37_01superninja
+	sound_dialog_play_block pause
+	cinematic_stop(BOSS2face, 17, 30)
+	#ninja jumps onto line
+	obj_create 71 71
+	cm_anim both OutroCam02
+	env_anim 71 71
+	chr_envanim 111 OutroNinjaBox01 norotation
+	chr_animate 111 NINJAlev11_outrozip01
+	playback 110 OutroNinja02
+	cutscene_sync_mark
+	sound_ambient_start c12_14_07zipa
+	sleep 170
+	cm_interpolate OutroCam03 0
+	playback 0 OutroKonoko
+	#kill character 111 here
+	chr_delete 111
+	sleep 60
+	#KONOKO jumps on back of Ninja
+	env_anim 71 71
+	chr_envanim_block 110 OutroNinjaBox01 norotation
+	chr_animate 110 NINJAlev11_outrozip01
+	chr_envanim 0 OutroKonBox01 norotation
+	chr_animate 0 KONOKOlev11_outrozip01
+	cm_anim both OutroCam04
+	cutscene_sync_mark
+	sound_ambient_start c12_14_07zipb
+	cm_wait
+	cm_anim both OutroCam05
+	env_setanim 71 Zipthing02
+	chr_envanim 110 OutroNinjaBox02 norotation
+	chr_animate 110 NINJAlev11_outrozip02
+	chr_envanim 0 OutroKonBox02 norotation
+	chr_animate 0 KONOKOlev11_outrozip02
+	sleep 60
+	fade_out 0 0 0 60
+	sleep 90
+	win
+}
+
+func void
+Floor2Unlock(string ai_name)
+{
+	input 0
+	cm_interpolate Floor2Unlock 0
+	sleep 150
+	cm_reset
+	door_unlock 54
+	particle lock1_locklight01 do start
+	input 1
+}
+
+func void
+DataArchiveUnlock(string ai_name)
+{
+	door_unlock 7
+	ai2_spawn fl1_target_1
+	input 0
+	sound_music_start mus_heart
+	fork music_force_stop
+	cm_interpolate DataArchiveUnlock 0
+	trigvolume_enable shut_off_vault_music 1
+	particle obj1 create
+	sleep 150
+	cm_reset
+	input 1
+}
+
+func void
+you_lose(string ai_name)
+{
+	sound_music_stop mus_main02_hd
+	sound_music_stop mus_heart
+	sound_music_stop mus_pursuit
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
Index: /nikanabo/current/bsl/original/IGMD/state/state_level_logic.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/state/state_level_logic.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/state/state_level_logic.bsl	(revision 185)
@@ -0,0 +1,607 @@
+#
+# state_spawn_guards.bsl
+#
+# LEVEL LOGIC
+#
+################## MUSIC TEST ################################
+func void level_start(string ai_name)
+{
+# These functions are used when the game is restored.
+
+	if (my_save_point eq 0)
+	{
+		dprint SAVE_POINT_0
+#		USE THIS FUNC TO SET UP TRAINING SEQUENCE AGAIN
+
+		ai2_spawn neutral_1
+		ai2_spawn fl2_secguard_1
+		powerup_spawn ammo 131
+		powerup_spawn hypo 132
+	}
+
+	if (my_save_point eq 1)
+	{
+		dprint RESTORE_SAVE_POINT_1
+		fl1_spawn_guards
+
+		ai2_spawn neutral_1
+		ai2_spawn fl2_secguard_1
+		powerup_spawn ammo 131
+		powerup_spawn hypo 132
+
+		objective_set(1);
+		particle(lock99_locklight01, do, start);
+		console_deactivate 10
+		trigvolume_enable(trigger_volume_09, 0);
+		restore_game
+	}
+
+	if (my_save_point eq 2)
+	{
+		dprint RESTORE_SAVE_POINT_2
+
+		particle obj1 create
+		particle obj1 start
+
+		trigvolume_enable(Cut_dog, 1);
+		trigvolume_enable(trigger_volume_11, 1);
+		trigvolume_enable(trigger_volume_12, 1);
+		trigvolume_enable(trigger_volume_14, 1);
+		trigvolume_enable(trigger_volume_15, 1);
+		trigvolume_enable(trigger_volume_10, 1);
+
+		trigvolume_enable(shut_off_vault_music, 0);
+		trigvolume_enable(trigger_volume_09, 0);
+		trigvolume_enable(trigger_volume_08, 0);
+		trigvolume_enable(trigger_volume_02, 0);
+		trigvolume_enable(trigger_volume_01, 0);
+
+		trigvolume_enable(save_trig_right, 0);
+		trigvolume_enable(save_trig_left, 0);
+
+		objective_set 4 silent
+
+		target_set(267, 30.0)
+
+		#change_flGUARD_CORRIDOR_lights	
+
+		door_lock(3);
+		door_lock(77);
+
+		door_unlock(15);
+		door_unlock(14);
+		door_unlock(7);
+		door_unlock(5);
+		door_unlock(75);
+		door_unlock(59);
+		door_unlock(54);
+		door_unlock(67);
+		door_unlock(68);
+		door_unlock(76);
+		door_unlock(23);
+		door_unlock(42);
+
+		trig_activate 1
+		trig_activate 2
+		#trig_activate 14
+
+		#console_activate 6
+		#console_activate 7
+		#console_activate 9
+
+		console_deactivate 11
+		console_deactivate 4
+		console_deactivate 88
+		console_deactivate 82
+		console_deactivate 5
+		console_deactivate 3
+		console_deactivate 6
+		console_deactivate 1
+		console_deactivate 2
+
+		particle lock1_locklight01 do start
+		particle lock2_locklight01 do start
+		particle lock3_locklight01 do start
+		particle lock4_locklight01 do start
+		particle lock5a_locklight01 do start
+		particle lock5b_locklight01 do start
+		particle lock5c_locklight01 do start
+		particle lock99_locklight01 do start
+
+		particle lock6_locklight01 do stop
+
+		env_shade 271 272 .4 .4 .2
+
+		restore_game
+#		objective_set(3);
+	}
+}
+
+# This is an example of a save game console.
+
+func void save_game_1(string player_name)
+{
+	dprint saveit_1
+	save_game 1 autosave
+}
+
+func void save_game_2_right(string player_name)
+{
+	dprint saveit_2
+	save_game 2 autosave
+	trigvolume_enable save_trig_left 0
+}
+
+func void save_game_2_left(string player_name)
+{
+	dprint saveit_2
+	save_game 2 autosave
+	trigvolume_enable save_trig_right 0
+}
+
+##############################################################
+var int music_counter;
+
+func void music_force_stop(void)
+{
+	sleep 4500
+
+	if (0 ne music_counter) 
+	{
+		dprint music_force_stop
+		music_counter = 0
+		all_music_counters
+	}
+}
+func void music_script_start(void)
+{
+	music_counter = 2
+}
+
+func void die_for_art_1(string ai_name)
+{
+	dprint DFA_1
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+
+}
+func void die_for_art_2(string ai_name)
+{
+	dprint DFA_2
+	music_counter = music_counter - 1
+
+	if (music_counter eq 0)
+	{
+		all_music_counters();
+	}
+
+}
+func void all_music_counters(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_main02
+	sound_music_stop mus_heart
+	sound_music_stop mus_main02_hd
+}
+
+func void fl1_spawn_guards(string ai_name)
+{
+#	dprint FL1_SPAWN_GUARDS
+	ai2_spawn fl1_secguard_1
+	ai2_spawn fl1_secguard_2
+	ai2_spawn fl1_secguard_4
+	trigvolume_enable shut_off_vault_music 0
+}
+
+func void fl2_spawn_secguard_2(string ai_name)
+{
+#	dprint FL2_SPAWN_GUARDS
+	ai2_spawn fl2_secguard_2
+	ai2_spawn fl2_secguard_7
+	ai2_spawn fl2_balcony_2
+
+	ai2_spawn neutral_2
+	ai2_spawn neutral_4
+}
+
+func void fl2_spawn_secguard_3(string ai_name)
+{
+#	dprint FL2_SPAWN_ASSAULT_GUARDS
+	ai2_spawn fl2_secguard_3
+	ai2_spawn fl2_secguard_6
+	ai2_spawn fl2_balcony_1
+}
+
+# THESE ARE THE THIRD FLOOR/ROOF GUYS
+
+func void spawn_fl3_guards(string ai_name)
+{
+#	dprint FLROOF_SPAWN_GUARDS
+	ai2_spawn fl3_secguard_1
+	ai2_spawn fl3_secguard_2
+	ai2_spawn fl3_secguard_6
+	ai2_spawn flROOF_sniper_1
+	ai2_spawn Roof_BOSWAT_1
+
+	ai2_spawn neutral_3
+	ai2_spawn neutral_6
+}
+
+# THESE ARE THE COMPUTER ROOM GUYS
+
+func void spawn_flBASEMENT_guards(string ai_name)
+{
+#	dprint FLROOF_SPAWN_GUARDS
+	ai2_spawn flBASEMENT_guard_1
+	ai2_spawn flBASEMENT_guard_2
+}
+
+# THESE ARE THE COMPUTER ROOM GUYS
+
+func void spawn_flRAMP_guards(string ai_name)
+{
+#	dprint FLROOF_SPAWN_GUARDS
+	ai2_spawn flRAMP_guard_1
+	ai2_spawn flRAMP_guard_2
+	trigvolume_enable ninja_ambush_top_trig 0
+	trigvolume_enable ninja_ambush_bot_trig 0
+	particle lock46_locklight01 do start
+}
+
+func void spawn_outside_left_snipers(string ai_name)
+{
+#	dprint FL2_SPAWN_GUARDS
+	ai2_spawn flOUTSIDE_A_sniper_1
+	ai2_spawn flOUTSIDE_A_sniper_2
+	ai2_spawn flOUTSIDE_B_sniper_1
+	ai2_spawn flOUTSIDE_C_sniper_1
+}
+
+func void spawn_outside_right_snipers(string ai_name)
+{
+#	dprint FL2_SPAWN_GUARDS
+	ai2_spawn flOUTSIDE_E_sniper_1
+	ai2_spawn flOUTSIDE_E_sniper_2
+	ai2_spawn flOUTSIDE_D_sniper_1
+	ai2_spawn flOUTSIDE_D_sniper_2
+}
+
+func void spawn_targets(string ai_name)
+{
+#	dprint FL2_SPAWN_GUARDS
+	ai2_spawn fl2_target_2
+}
+
+func void do_neutral_1_run(string ai_name)
+{
+	ai2_neutralbehavior neutral_1 none
+	ai2_setmovementmode neutral_1 run_noaim
+	ai2_dopath neutral_1 neutral_1_run
+	ai2_setjobstate neutral_1
+}
+
+func void do_neutral_2_run(string ai_name)
+{
+	ai2_neutralbehavior neutral_2 none
+	ai2_dopath neutral_2 neutral_2_run
+	ai2_setjobstate neutral_2
+}
+
+func void do_neutral_3_run(string ai_name)
+{
+	ai2_neutralbehavior neutral_3 none
+	ai2_dopath neutral_3 neutral_3_run
+	ai2_setjobstate neutral_3
+}
+
+func void unlock_secret_1(string ai_name)
+{
+	input 0
+	cm_interpolate secret1 0
+	sleep 60
+	console_activate 7
+	#particle lock69a_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	ai2_spawn secret_guard_1
+	ai2_spawn secret_guard_2
+}
+
+func void unlock_secret_2(string ai_name)
+{
+	door_unlock 34
+	door_unlock 36
+
+	# CB: ensure ramp guards do not see ninja and go after him!
+	ai2_passive flRAMP_guard_1 1
+	ai2_passive flRAMP_guard_2 1
+
+	ai2_spawn cutscene_ninja_1
+	input 0
+	cm_interpolate secret2 0
+	sleep 60
+	particle lock7_locklight01 do start
+	sleep 15
+	trig_deactivate 12
+	sleep 150
+	cm_reset
+	input 1
+
+	chr_delete cutscene_ninja_1
+	ai2_passive flRAMP_guard_1 0
+	ai2_passive flRAMP_guard_2 0
+
+	trigvolume_enable ninja_ambush_top_trig 1
+	trigvolume_enable ninja_ambush_bot_trig 1
+}
+
+func void ninja_ambush(string ai_name)
+{
+	trigvolume_enable ninja_ambush_top_trig 0	
+	trigvolume_enable ninja_ambush_bot_trig 0	
+
+	ai2_spawn ambush_ninja_1
+	ai2_spawn creepy_ninja_1
+	ai2_spawn creepy_ninja_3
+}
+
+func void hall_1(string ai_name)
+{
+	input 0
+	cm_interpolate hall1 0
+	sleep 60
+	door_unlock 77
+	door_unlock 38
+	door_unlock 22
+	door_unlock 3
+	particle lock6_locklight01 do start
+	particle lock7_locklight01 do stop
+	sleep 150
+	cm_reset
+	input 1
+
+	trig_deactivate 1
+	trig_deactivate 2
+}
+
+func void top_1(string ai_name)
+{
+	input 0
+	#cm_interpolate hall1 0
+	sleep 60
+	door_unlock 35
+	door_unlock 38
+	door_unlock 22
+	door_unlock 3
+	particle lock6_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	trig_activate 12
+	trig_activate 13
+	trig_activate 14
+
+	trig_deactivate 1
+	trig_deactivate 2
+}
+
+func void downstairs(string ai_name)
+{
+	trig_deactivate 14
+	door_unlock 8
+	door_unlock 9
+	particle lock23_locklight01 do start
+	ai2_spawn creepy_ninja_5
+	ai2_spawn creepy_ninja_6
+}
+
+func void upstairs(string ai_name)
+{
+	trig_deactivate 13
+	door_unlock 35
+	particle lock65_locklight01 do start
+}
+
+var int door_counter=3;
+
+func void seclock_music_start(void)
+{
+	if (door_counter eq 3)
+	{
+		sound_music_start mus_lz 0.75
+	}
+}
+
+func void seclock_decrement_counter(void)
+{
+	door_counter = door_counter - 1
+
+
+	if (door_counter eq 0)
+	{
+		sound_music_stop mus_lz
+		unlock_roof();
+	}
+}
+
+func void seclock1(string ai_name)
+{
+	seclock_music_start
+
+	input 0
+	cm_interpolate security 0
+	sleep 60
+	particle lock5a_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	seclock_decrement_counter
+}
+
+func void seclock2(string ai_name)
+{
+	seclock_music_start
+
+	input 0
+	cm_interpolate security 0
+	sleep 60
+	particle lock5b_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	seclock_decrement_counter
+}
+
+func void seclock3(string ai_name)
+{
+	seclock_music_start
+
+	input 0
+	cm_interpolate security 0
+	sleep 60
+	particle lock5c_locklight01 do start
+	sleep 150
+	cm_reset
+	input 1
+
+	seclock_decrement_counter
+}
+
+func void unlock_roof(string ai_name)
+{
+	door_unlock 23
+	door_unlock 42
+}
+
+#
+# state_door_lock_lights.bsl
+#
+# SCRIPTS TO CHANGE THE LOCKED LIGHTS ON DOORS
+#
+# TURN FROM GREEN TO RED: do stop
+
+func void change_fl2_lights(string ai_name)
+{
+#	dprint WHATEVER YOU WANT
+	sleep 60
+	particle lock2_locklight01 do start
+}
+
+func void change_fl3_lights(string ai_name)
+{
+	particle lock3_locklight01 do start
+	ai2_spawn fl3_mook_1
+	ai2_spawn fl3_mook_2
+}
+
+func void change_flDATA_ARCHIVE_lights(string ai_name)
+{
+	sleep 60
+	particle lock4_locklight01 do start
+}
+
+func void change_flCOMMAND_CENTER_lights(string ai_name)
+{
+	particle lock5_locklight01 do start
+}
+
+func void change_flGUARD_CORRIDOR_lights(string ai_name)
+{
+	particle lock6_locklight01 do start
+}
+
+func void change_flDIG_OFFICES_lights(string ai_name)
+{
+	particle lock7_locklight01 do start
+}
+
+
+func void grifftext(string chr_index)
+{
+	dprint text2a
+	text_console level_11a
+	console_reset 9
+}
+
+
+#
+# state_spawn_guards.bsl
+#
+# SCRIPTS TO SPAWN SECURITY GUARDS
+#
+
+func void set_objective_1(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(1)
+	target_set(127, 30.0)
+}
+
+func void set_objective_2(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(2)
+}
+
+func void set_objective_3(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(3)
+}
+
+func void set_objective_4(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(4)
+	target_set(267, 30.0)
+}
+
+func void set_objective_5(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(5)
+}
+
+func void set_objective_6(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	objective_set(6)
+}
+
+func void set_target_1(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	target_set(267, 30.0)
+}
+
+func void set_target_2(string ai_name)
+{
+#	dprint WHATEVER I WANT
+	target_set(1030, 30.0)
+}
+###wuscripts
+func void check_outro(string ai_name)
+{
+	trigvolume_enable tv_check_outro 0
+	if(trigvolume_count (24) eq 0)
+	{
+		trigvolume_enable Cut_outro 1
+		particle obj2 create
+		target_set(126,30.0)
+	}
+	if(trigvolume_count (24) ne 0)
+	{
+		sleep 60
+		trigvolume_enable tv_check_outro 1
+	}
+}
+		
Index: /nikanabo/current/bsl/original/IGMD/state/state_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/state/state_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/state/state_main.bsl	(revision 185)
@@ -0,0 +1,25 @@
+#
+# state_main.bsl
+#
+var int my_save_point;
+
+func void main(void)
+{
+
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.99
+	gs_farclipplane_set 3000	
+
+	my_save_point = save_point;
+
+	level_start
+
+	if (my_save_point eq 0)
+	{
+		particle lock99_locklight01 do start
+		music_script_start();
+		state_cs_intro
+	}
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf/particle_scripts.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/particle_scripts.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/particle_scripts.bsl	(revision 185)
@@ -0,0 +1,107 @@
+#partice scripts
+#alex okita
+#turns on and off particles for rooms
+
+#room1
+func void room1_start(string ai_name)
+{
+	dprint room1_start
+	particle room1 start
+	particle smoke start
+}
+func void room1_stop(string ai_name)
+{
+	dprint room1_stop
+	particle room1 stop
+}
+#room2
+func void room2_start(string ai_name)
+{
+	dprint room2_start
+	particle room2 start
+}
+func void room2_stop(string ai_name)
+{
+	dprint room2_stop
+	particle room2 stop
+}
+
+#room3
+func void room3_start(string ai_name)
+{
+	dprint room3_start
+	particle room3 start
+}
+func void room3_stop(string ai_name)
+{
+	dprint room3_stop
+	particle room3 stop
+}
+
+#room4
+func void room4_start(string ai_name)
+{
+	dprint room4_start
+	particle room4 start
+}
+func void room4_stop(string ai_name)
+{
+	dprint room4_stop
+	particle room4 stop
+}
+
+#room5
+func void room5_start(string ai_name)
+{
+	dprint room5_start
+	particle room5 start
+}
+func void room5_stop(string ai_name)
+{
+	dprint room5_stop
+	particle room5 stop
+}
+
+#room4
+func void room6_start(string ai_name)
+{
+	dprint room6_start
+	particle room6 start
+}
+func void room6_stop(string ai_name)
+{
+	dprint room6_stop
+	particle room6 stop
+}
+
+#room7
+func void room7_start(string ai_name)
+{
+	dprint room7_start
+	particle room7 start
+}
+func void room7_stop(string ai_name)
+{
+	dprint room7_stop
+	particle room7 stop
+}
+
+#room8
+func void room8_start(string ai_name)
+{
+	dprint room8_start
+	particle room8 start
+}
+func void room8_stop(string ai_name)
+{
+	dprint room8_stop
+	particle room8 stop
+	particle smoke stop
+}
+
+func void fire_damage(string ai_name)
+{	
+	dprint fire_hurt_konoko
+	chr_poison (ai_name, 5, 30, 30);
+}
+
Index: /nikanabo/current/bsl/original/IGMD/tctf/tctf_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/tctf_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/tctf_cutscene.bsl	(revision 185)
@@ -0,0 +1,682 @@
+#
+# tctf_cutscene.bsl
+#
+
+func void
+Cut01(
+	void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam01 0
+	sleep 8
+	begin_cutscene
+	sleep 1
+	sound_ambient_start cs_tctf8_01
+	fork Soundcue
+	env_show 99 0	
+	sleep 40
+	#hides motorcycle gunk
+	env_show 110 0
+	env_show 111 0
+	env_show 112 0
+	#hides	van	gunk
+	env_show 444 0
+	env_show	101	0
+	env_show	103	0
+	env_show	104	0
+	env_show	105	0
+	env_show	106	0
+	env_show	107	0
+	env_show	108	0	
+	#hides	curtain	wall
+	#start cutscene	
+	#fade_in 120
+	cm_anim both IntroCam01	
+	#cycle	and	konoko	animate					
+	chr_envanim 0 IntroKonBox01			
+	chr_animate 0 KONOKOcycle_ride 560
+	obj_create 10 12
+	obj_create 1 8		
+	env_anim	10	12
+	fade_in 120
+	#sound_ambient_start cs_tctf8_01
+	#fork Soundcue
+	#Konoko looking at TCTF
+	chr_envanim_block 0 IntroKonBox02
+	cm_anim both IntroCam02
+	chr_animate 0 KONOKOlev8_IntroKon01
+	#show helicopters circling
+	cm_anim_block both IntroCam03
+	obj_create 601 606
+	obj_create 701 706
+	env_anim 601 606
+	env_anim 701 706
+	#sleep 
+	#sound_ambient_play cs_tctf8_02
+	#Van animate
+	cm_anim_block both IntroCam04
+	env_anim 1 8
+	#sleep 20
+	particle object_Blackvan_FB_VanHeadlight do start
+	#Vancrash
+	cm_anim_block both IntroCam05
+	#sound_ambient_start cs_tctf8_03
+	env_setanim 1 Blackvan_FB01
+	env_setanim 3 Blackvan_LR01
+	env_setanim 4 Blackvan_TB01
+	env_setanim 5 Blackvan_W01
+	env_setanim 6 Blackvan_WB01
+	env_setanim 7 Blackvan_doors0201
+	env_setanim 8 Blackvan_doors0301
+	sleep 287
+	#turn off unbroken curtain wall
+	env_show 98 0
+	env_show 398 0
+	particle LobbyWall do explode
+	#turn on broken	curtain	wall
+	env_show 99 1
+	#camera shows lobby doors closing and lights flashing
+	cm_interpolate_block IntroLobbyCam00 0
+	particle LobbyAlarm create
+	#hide	object	van		
+	obj_kill 1 8
+	#show	gunk	van		
+	env_show	101	1				
+	env_show	103	1
+	env_show	104	1
+	env_show	105	1
+	env_show	106	1
+	env_show	107	1
+	env_show	108	1
+	env_show 444 1
+	#Strikers run into Lobby space
+	ai2_spawn IntroStriker01
+	ai2_spawn IntroStriker02
+	playback IntroStriker01 IntroStrikerLobby
+	cm_interpolate_block IntroLobbyCam01 220
+	env_show 97 0
+	sleep 50
+	obj_create 321 325
+	env_anim 321 322
+	playback IntroStriker02 IntroStrikerLobby
+	sleep 190
+	#Show alarms flashing and blast doors closing
+	cm_interpolate_block IntroDoorCam02 0
+	cutscene_sync mark 
+	sound_ambient_start cs_tctf8_03
+	env_anim 323 325
+	sleep 200
+	#Konoko sees doors closing
+	chr_delete IntroStriker01
+	chr_delete IntroStriker02
+	cm_anim_block both IntroCam06
+	chr_envanim 0 IntroKonBox03 norotation
+	chr_animate 0 KONOKOlev8_IntroKon03
+	env_setanim 10 motorcycle03
+	env_setanim 11 hubs03
+	env_setanim 12 hubs_rear03
+	env_anim 323 325
+	#Konoko rides towards closing doors
+	chr_envanim_block 0 IntroKonBox04
+	chr_animate 0 KONOKOcycle_ride 246
+	env_setanim 10 motorcycle04
+	env_setanim 11 hubs04
+	env_setanim 12 hubs_rear04
+	cm_anim both IntroCam07
+	#Konoko slides under the doors
+	chr_envanim_block 0 IntroKonBox05 norotation
+	chr_animate 0 KONOKOlev8_IntroKon05
+	env_setanim 10 motorcycle05
+	env_setanim 11 hubs05
+	env_setanim 12 hubs_rear05
+	cm_anim both IntroCam08
+	#Konoko game start
+	cm_wait
+	playback 0 IntroKonoko
+	cinematic_start(KONintense, 180,180,15, 1, 15, false)
+	sound_dialog_play c07_22_01konoko
+	cm_reset
+	sleep 1
+	#hide motorcycle object
+	obj_kill 10 12
+	#kill helicopter objects
+	obj_kill 601 606
+	obj_kill 701 706
+	#hide door objects
+	obj_kill 321 325
+	#show gunk motorcycle
+	env_show 110 1
+	env_show 111 1
+	env_show 112 1
+	#show door gunk
+	env_show 321 1
+	env_show 322 1
+	env_show 323 1
+	env_show 324 1
+	env_show 325 1
+	env_shade 321 325 .3 .3 .3
+	#gameplay	settings			
+	end_cutscene
+	sound_dialog_play_block pause
+	music_intro
+	sleep 60
+	cinematic_stop(KONintense, 15, 15)
+	ai2_spawn lobby_striker_01
+	ai2_spawn lobby_striker_02
+	ai2_spawn lobby_striker_03
+	s1
+	sleep 120
+	particle LobbyAlarm kill
+}
+
+func void
+Soundcue(void)
+{
+	sleep 1146
+	sound_ambient_start cs_tctf8_02
+	cutscene_sync mark 
+
+}
+
+func void
+Attack(void)
+{
+	begin_cutscene
+	particle Attack do start
+	fade_out 0 0 0 30
+	ai2_spawn AttackCivil01
+	ai2_spawn AttackCivil02
+	ai2_spawn AttackStriker01
+	ai2_spawn AttackStriker02
+	ai2_setmovementmode AttackStriker01 run
+	ai2_setmovementmode AttackStriker02 run
+	chr_create 1054 start
+	playback AttackCivil01 AttackGeneric01
+	playback AttackCivil02 AttackCop01
+	playback AttackStriker01 AttackStriker01
+	playback AttackStriker02 AttackStriker02
+	playback 1054 AttackComguy01
+	sleep 30
+	chr_animate AttackCivil01 KONPANcrouch_idle1 1000
+	fade_in 30
+	sleep 1
+	chr_animate 1054 COMGUYtalk_radio 1660
+	cm_interpolate AttackCam01 0
+	sleep 60
+	cm_interpolate AttackCam02 400
+	sleep 300
+	cinematic_start(COMGUYtalking, 180,180, 19, 7, 20, false)
+	sound_dialog_play c07_23_01synhench1
+	sound_dialog_play_block pause
+	cinematic_stop (COMGUYtalking, 19, 30)
+	sleep 10
+	end_cutscene
+	fade_out 0 0 0 30
+	sleep 30
+	cm_reset
+	fade_in 30
+	#kill characters 1050-1054
+	chr_delete AttackCivil01
+	chr_delete AttackCivil02
+	chr_delete AttackStriker01
+	chr_delete AttackStriker02
+	chr_delete 1054
+	particle Attack do stop
+	music_attack
+
+	# CB: after 10 seconds, play shinatama dialog "they're attacking the command center"
+	sleep 600
+	sound_dialog_play c00_01_105shinatama
+	sound_dialog_play_block
+}
+
+
+
+func void
+Kidnap(
+	void)
+{
+	particle Kidnap do start
+	begin_cutscene
+	fade_out 0 0 0 30
+	sleep 30
+	
+	#Shinatama caught up in destruction
+	chr_create 1101 start
+	chr_envanim 1101 KidnapShinBox02
+	chr_animate 1101 SHINATsit_idle 3000
+
+	#create the strikers
+	chr_create 1103 start
+	chr_create 1104 start
+	playback 1103 KidnapStriker01
+	playback 1104 KidnapStriker02
+
+	#run the camera
+	dprint run_the_camera
+	cm_interpolate KidnapCam01 0
+	cm_interpolate_block KidnapCam02 300
+	fade_in 30
+	sleep 360
+
+	#Shinatama looks up to see SubBoss1
+	dprint shinatama_looks_up
+	chr_envanim 1101 KidnapShinBox02
+	chr_animate 1101 SHINATsit_idle 610
+
+	#cm_anim both KidnapCam03
+	cm_interpolate KidnapCam03 0
+	cm_interpolate_block KidnapHelpCam02 300
+	cinematic_start(SHINhelpme, 180,180, 15, 1, 20, false)
+	sound_dialog_play c07_24_02shinatama
+
+	#create barabus as passsive
+	dprint create_barabus
+	ai2_spawn barabus
+	chr_boss_shield barabus
+	ai2_passive barabus 1
+	chr_lock_active barabus
+	playback barabus KidnapSubBoss01
+
+	dprint sound_dialog_pause
+	sound_dialog_play_block pause
+	cinematic_stop (SHINhelpme, 19, 30)
+
+	#SubBoss grabs Shinatama
+	dprint barabus_grabs_shinatama
+	chr_envanim 1101 KidnapShinBox01 norotation
+	chr_animate 1101 SHINATlev8_Kidnap01 -1
+	chr_envanim barabus KidnapStrBox01 norotation
+	chr_animate barabus STRIKElev8_Kidnap01 -1
+	cutscene_sync mark
+	sound_ambient_start c09_32_09shin_kidnap
+	cinematic_start(BOSS01menacing, 180,180, 20, 9, 20, false)
+	sound_dialog_play c07_24_01barabas
+	cm_anim both KidnapCam04
+	sleep 60
+	particle KidnapSpark do start
+	sleep 5
+	particle KidnapSpark do stop
+	sleep 20
+	cinematic_stop (BOSS01menacing, 19, 30)
+	fade_out 0 0 0 30
+	chr_delete 1101
+	chr_delete 1103
+	chr_delete 1104
+	sleep 30
+	chr_delete barabus
+	cm_reset
+	fade_in 30
+	end_cutscene
+	particle Kidnap do stop
+}
+
+
+func void
+Elevator(
+	void)
+{
+	begin_cutscene
+	#hide gunk and show elevator objects
+	env_show 501 0
+	env_show 502 0
+	env_show 503 0
+	env_show 504 0
+	obj_create 781 781
+	obj_create 501 504
+	obj_force_draw 781 781
+	obj_force_draw 501 504
+	#KONOKO cuts the cables
+	chr_invincible 0 1
+	chr_nocollision 0 1
+	cm_anim both ElevatorCam01
+	chr_envanim 0 ElevatorKonBox01 norotation
+	chr_animate 0 KONOKOlev8_Elevator01
+	env_anim 781 781
+	env_anim 501 504
+	sleep f40
+	cutscene_sync mark
+	sound_ambient_start c10_00_10_torch
+	sleep 100
+	particle ElevatorSpark do start
+	sound_ambient_start c09_32_09shin_kidnap
+	sleep 85
+	particle ElevatorSpark do stop
+	cutscene_sync mark
+	sound_ambient_start c10_01_29_elevator
+	sleep 45
+	particle ElevatorSpark2 do start
+	sound_ambient_start c09_32_09shin_kidnap
+	sleep 70
+	particle ElevatorSpark2 do stop
+	#Elevator falls and KONOKO rises
+	chr_envanim_block 0 ElevatorKonBox02 norotation
+	obj_kill 781 781
+	chr_animate 0 KONOKOlev8_Elevator02
+	env_setanim 501 Elevator_fall
+	env_setanim 502 Elevator_brace_fall
+	env_setanim 503 Elevator_cable01_fall
+	env_setanim 504 Elevator_cable02_fall
+	cm_anim both ElevatorCam02
+	sleep 60
+	particle ElevatorDust do explode
+	sleep 5
+	particle ElevatorDust do explode
+	#KONOKO stops at top
+	chr_envanim_block 0 ElevatorKonBox03 norotation
+	chr_animate 0 KONOKOlev8_Elevator03
+	env_setanim 503 Elevator_cable01_stop
+	cm_anim both ElevatorCam03
+	#KONOKOleaps out of shaft
+	chr_envanim_block 0 ElevatorKonBox04 norotation
+	chr_animate 0 KONOKOlev8_Elevator04
+	cm_anim both ElevatorCam04
+	#hide objects and show gunk
+	obj_kill 501 504
+	env_show 601 1
+	env_show 602 1
+	cm_wait
+	playback 0 ElevatorEndSet
+	cm_reset
+	chr_invincible 0 0
+	chr_nocollision 0 0
+	end_cutscene
+	sleep 5
+}
+
+
+func void
+helicopter(
+	void)
+{
+	obj_create 901 906
+	particle EndDust create
+}
+
+func void helicopter_sound_start(void)
+{
+	sound_ambient_start c08_heli 1.0
+}
+
+func void helicopter_sound_stop(void)
+{
+	sleep 680
+	sound_ambient_volume c08_heli 0.0 12
+	sleep 600
+	sound_ambient_stop c08_heli
+}
+
+func void helicopter_fly_away(void)
+{
+	fork helicopter_sound_stop
+
+	#helicopter
+	chr_create 1019 start
+	chr_create 1020 start
+	chr_create 1021 start						
+	chr_envanim 1019 HeliOutroShinBox01						
+	chr_envanim 1020 HeliOutroStrBox01						
+	chr_envanim 1021 HeliOutroStrBox02						
+	chr_animate 1019 SHINATstand_heli 1000
+	chr_animate 1020 STRIKEstand_heli 1000				
+	chr_animate 1021 STRIKEcrouch_idle 1000
+	env_anim 901 906
+}
+
+func void
+HeliOutroRight(
+	void)
+{
+	cutscene_sync mark
+	helicopter_sound_start
+	ai2_takecontrol 1
+	ai2_passive sh_s12b 1
+	ai2_passive sh_s12 1
+	ai2_passive sh_s12c 1
+	ai2_movetoflag 0 1900
+	begin_cutscene
+	chr_delete sh_s12b
+	chr_delete sh_s12
+	chr_delete sh_s12c
+	ai2_kill
+	sleep 10
+	helicopter_fly_away
+	cm_interpolate HeliOutroRight 200
+	sleep 200
+	cm_anim both HeliOutroCam012
+	sleep 100
+	ai2_takecontrol 0
+	input 0
+	playback 0 HeliOutroKonoko02
+	cinematic_start(KONtalking, 180,180, 16, 3, 15, true)
+	sound_dialog_play c07_25_01konoko
+	sound_dialog_play_block pause
+	fork HeliOutro
+}
+
+
+func void
+HeliOutroMid(
+	void)
+{
+	cutscene_sync mark
+	helicopter_sound_start
+	ai2_takecontrol 1
+	ai2_passive sh_s12b 1
+	ai2_passive sh_s12c 1
+	ai2_passive sh_s12 1
+	ai2_movetoflag 0 1900
+	begin_cutscene
+	chr_delete sh_s12c
+	chr_delete sh_s12b
+	chr_delete sh_s12
+	ai2_kill
+	sleep 10
+	helicopter_fly_away
+	cm_interpolate HeliOutroMid 100
+	sleep 100
+	cm_interpolate HeliOutroCam01 100
+	cm_anim_block both HeliOutroCam01
+	sleep 200
+	ai2_takecontrol 0
+	input 0
+	playback 0 HeliOutroKonoko02
+	cinematic_start(KONtalking, 180,180, 16, 3, 15, true)
+	sound_dialog_play c07_25_01konoko
+	sound_dialog_play_block pause
+	fork HeliOutro
+}
+
+func void
+HeliOutroMidLt(
+	void)
+{
+	cutscene_sync mark
+	helicopter_sound_start
+	ai2_takecontrol 1
+	ai2_passive sh_s12c 1
+	ai2_passive sh_s12b 1
+	ai2_passive sh_s12 1
+	ai2_movetoflag 0 1900
+	begin_cutscene
+	chr_delete sh_s12c
+	chr_delete sh_s12b
+	chr_delete sh_s12
+	ai2_kill
+	sleep 10
+	helicopter_fly_away
+	cm_interpolate HeliOutroMidLt 100
+	sleep 100
+	cm_interpolate HeliOutroCam01 100
+	cm_anim_block both HeliOutroCam01
+	#patrol Konoko to flag #1010
+	sleep 200
+	ai2_takecontrol 0
+	input 0
+	playback 0 HeliOutroKonoko02
+	cinematic_start(KONtalking, 180,180, 16, 3, 15, true)
+	sound_dialog_play c07_25_01konoko
+	sound_dialog_play_block pause
+	fork HeliOutro
+}
+
+func void
+HeliOutroLeft(
+	void)
+{
+	cutscene_sync mark
+	helicopter_sound_start
+	ai2_takecontrol 1
+	ai2_passive sh_s12c 1
+	ai2_passive sh_s12b 1
+	ai2_passive sh_s12 1
+	ai2_movetoflag 0 1900
+	begin_cutscene
+	chr_delete sh_s12c
+	chr_delete sh_s12b
+	chr_delete sh_s12
+	ai2_kill
+	sleep 10
+	helicopter_fly_away
+	cm_interpolate HeliOutroLeft 200
+	sleep 200
+	cm_anim both HeliOutroCam012
+	sleep 200
+	ai2_takecontrol 0
+	input 0
+	playback 0 HeliOutroKonoko02
+	cinematic_start(KONtalking, 180,180, 20, 9, 15, true)
+	sound_dialog_play c07_25_01konoko
+	sound_dialog_play_block pause
+	fork HeliOutro
+}
+
+
+func void
+HeliOutro(
+void)
+{
+	particle EndDust kill
+	target_set(1,0.0)
+	#Subboss shows up behind konoko
+	cm_interpolate_block HeliOutroCam02 0
+	chr_delete 1019
+	chr_delete 1020
+	chr_delete 1021
+	playback 0 HeliOutroKonoko01
+	ai2_spawn barabus
+	chr_boss_shield barabus
+	playback barabus HeliOutroBoss01
+	sleep 40
+	chr_animate 0 KONCOMstartle_bk2
+	cinematic_stop (KONtalking, 20, 40)
+	cinematic_start(KONintense, 180,180, 20, 9, 40, false)
+	sound_dialog_play c07_25_02konoko
+	sound_dialog_play_block pause
+	#subboss taunts Konoko
+	cm_interpolate HeliOutroCam03 0
+	sleep 30
+	cinematic_start(BOSS1talking, 180,180,19, 7, 25, false)
+	sound_dialog_play c07_25_03barabas
+	sound_dialog_play_block pause
+	#"KONOKO, let's get it on!!!!!"
+	cinematic_stop (BOSS1talking, 19, 40)
+	#camera of Konoko's face
+	cm_interpolate HeliCamKonFace 60
+	sound_dialog_play c07_25_04konoko
+	sound_dialog_play_block pause
+	sleep 30
+	cinematic_stop (KONintense, 19, 30)
+	#resume gameplay
+	cm_reset
+	letterbox 0
+	input 1
+	chr_neutral 1010 0
+	obj_kill 901 906
+	ai2_takecontrol 0
+	end_cutscene
+	music_battle
+	s4
+}
+
+
+func void
+final(
+void)
+{
+	music_stop
+	begin_cutscene
+	sleep 120
+	sound_dialog_play c07_26a_01konokofx
+	chr_animate 0 KONOKOpowerup
+	sleep 240
+	cinematic_start (KONtalking, 180, 180, 19, 7, 20, false)
+	sound_dialog_play c07_26_01konoko
+	sound_dialog_play_block
+	cinematic_stop (KONtalking, 19, 20)
+	fade_out 0 0 0 120
+	sleep 120
+	win
+}
+
+func void
+BarabasNorth(string barabas)
+{
+	cutscene_sync mark
+	sound_ambient_start c11_10_14bar_jet
+	playback barabus BarabasNorth
+	ai2_barabbas_retrievegun barabus
+	sleep 60
+	chr_envanim barabus BarabasNorthBox norotation
+	chr_animate barabus BARABnorth
+	sleep 105
+	#particle BarabasNorth do start
+}
+
+
+
+func void
+BarabasSouth(string barabas)
+{
+	cutscene_sync mark
+	sound_ambient_start c11_10_14bar_jet
+	playback barabus BarabasSouth
+	ai2_barabbas_retrievegun barabus
+	sleep 60
+	chr_envanim barabus BarabasSouthBox norotation
+	chr_animate barabus BARABsouth
+	sleep 105
+	#particle BarabasSouth do start
+}
+
+
+func void
+BarabasEast(string barabas)
+{
+	cutscene_sync mark
+	sound_ambient_start c11_10_14bar_jet
+	playback barabus BarabasEast
+	ai2_barabbas_retrievegun barabus
+	sleep 60
+	chr_envanim barabus BarabasEastBox norotation
+	chr_animate barabus BARABeast
+	sleep 105
+	#particle BarabasEast do start
+}
+
+
+
+func void
+BarabasWest(string barabas)
+{
+	cutscene_sync mark
+	sound_ambient_start c11_10_14bar_jet
+	playback barabus BarabasWest
+	ai2_barabbas_retrievegun barabus
+	sleep 60
+	chr_envanim barabus BarabasWestBox norotation
+	chr_animate barabus BARABwest
+	sleep 105
+	#particle BarabasWest do start
+
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf/tctf_door_lock_lights.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/tctf_door_lock_lights.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/tctf_door_lock_lights.bsl	(revision 185)
@@ -0,0 +1,31 @@
+#
+# tctf_door_lock_lights.bsl
+#
+# SCRIPTS TO CHANGE THE LOCKED LIGHTS ON DOORS
+#
+# GREEN TO RED: do stop
+# RED TO GREEN: do start
+
+func void floor4_lock(void)
+{
+	music_stop
+	input 0
+	fade_out 0 0 0 30
+	cm_interpolate floor4_lock 0
+	fade_in 30
+	sleep 60
+	particle floor4_lock_locklight01 do start
+	sleep 90
+	fade_out 0 0 0 30
+	cm_reset
+	fade_in 30
+	input 1
+	target_set(60,30.0)
+	sound_dialog_play_block c00_01_28shinatama
+}
+
+func void shin_lock(void)
+{
+	particle shin_lock_locklight01 do start
+	particle roof_locklight01 do start
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf/tctf_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/tctf_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/tctf_main.bsl	(revision 185)
@@ -0,0 +1,28 @@
+#
+# tctf_main.bsl
+#
+
+func void
+main(
+	void)
+{	
+
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.995
+	gs_farclipplane_set 5000
+	env_show 601 0
+	env_show 602 0	
+	env_show 321 0
+	env_show 322 0
+	env_show 323 0
+	env_show 324 0
+	env_show 325 0			
+	start
+	if (my_save_point eq 0)
+	{
+		Cut01
+	}
+}
+	
Index: /nikanabo/current/bsl/original/IGMD/tctf/tctf_objectives.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/tctf_objectives.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/tctf_objectives.bsl	(revision 185)
@@ -0,0 +1,98 @@
+#
+# tctf_objectives.bsl
+#
+# SCRIPTS TO SET LEVEL OBJECTIVES/HINTS
+#
+func void set_objective_1(void)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set(323,30.0)
+}
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective_2
+	objective_set(2)
+	target_set(1111, 30.0)
+
+}
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective_3
+	objective_set(3)
+	target_set(60,30.0)
+}
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective_4
+	if(elev_count ne 1)
+	{
+		trigvolume_enable trigger_volume_81 1
+		objective_set(4)
+		particle obj1 create
+		target_set(9999, 30.0)
+	}
+}
+
+func void set_objective_5(string ai_name)
+{
+	dprint set_objective_5
+	objective_set(5)
+	target_set(58,30.0)
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+func void you_win(int char_index)
+{
+	win
+}
+
+### TEXT CONSOLES ###
+
+func void level_8a(void)
+{
+	dprint text_8a
+	text_console level_8a
+	console_reset 17
+}
+
+func void level_8b(void)
+{
+	dprint text_8b
+	text_console level_8b
+	console_reset 12
+}
+
+func void level_8c(void)
+{
+	dprint text_8c
+	text_console level_8c
+	console_reset 14
+}
+
+func void level_8d(void)
+{
+	dprint text_8d
+	text_console level_8d
+	console_reset 16
+}
+
+func void level_8e(void)
+{
+	dprint text_8e
+	text_console level_8e
+	console_reset 15
+}
+
+func void level_8f(void)
+{
+	dprint text_8f
+	text_console level_8f
+	console_reset 13
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf/tctf_spawn_syndicate.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf/tctf_spawn_syndicate.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf/tctf_spawn_syndicate.bsl	(revision 185)
@@ -0,0 +1,1071 @@
+#
+# tctf_spawn_syndicate.bsl
+#
+# SCRIPTS TO SPAWN SYNDICATE UNITS
+#
+
+var int my_save_point=0;
+var int striker_count=0;
+var int music_counter = 0;
+var int counter = 0;
+var int elev_count=0;
+var int shut_down_t103;
+var int count_follow;
+
+# music #
+
+func void music_intro(void)
+{
+	sound_music_start mus_asianb
+}
+
+func void music_intro_stop(void)
+{
+	sound_music_stop mus_asianb
+}
+
+func void music_attack(void)
+{
+	sound_music_start mus_pursuit 0
+	sound_music_volume mus_pursuit 0.75 3.0
+#	this music stopped in floor4_lock script
+}
+
+func void music_kidnap(void)
+{
+	dprint kidnapmusic
+	sound_music_start mus_om01 0.0
+	sound_music_volume mus_om01 0.75 3.0
+#	this music stopped in ta2_54 script
+}
+
+func void music_battle(void)
+{
+	sound_music_start mus_asianb 0
+	sound_music_volume mus_asianb 2
+#	this music stopped in final script
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_asianb
+	sound_music_stop mus_pursuit
+	sound_music_stop mus_om01
+#	sound_music_stop mus_asianb
+}
+
+
+###############################
+#	start and objectives   	#
+###############################
+func void start(string ai_name)
+{
+	dprint start
+
+	trig_deactivate	1	
+	trig_deactivate	2	
+	trig_deactivate	3	
+	trig_deactivate	4	
+	trig_deactivate	5
+	trig_deactivate	6
+	trig_deactivate	7
+	trig_deactivate	8
+	trig_deactivate	9
+	trig_deactivate	10
+	trig_deactivate	60
+	trig_deactivate	61
+	trig_deactivate	62
+	trig_deactivate	63
+	trig_deactivate	64
+	trig_deactivate	65
+	trig_deactivate	70
+	trig_deactivate	71
+	trig_deactivate	72
+	trig_deactivate	73
+	trig_deactivate	74
+	trig_deactivate	75
+	trig_deactivate	302	
+	trig_deactivate	303	
+	trig_deactivate	100
+	trig_deactivate	101	
+	trig_deactivate	500	
+	trig_deactivate	501	
+	trig_deactivate	502	
+	trig_deactivate	503	
+	trig_deactivate	400	
+	trig_deactivate	510
+	trig_deactivate 511
+	trig_deactivate	512	
+	trig_deactivate	520
+	trig_deactivate	521
+	trig_deactivate	522
+	trig_deactivate	310
+	trig_deactivate	320
+	trig_deactivate	98
+	trig_deactivate	99
+	trigvolume_enable trigger_volume_81 0
+	trigvolume_enable z_40t 0
+	trigvolume_enable zz_40t 0
+	trigvolume_enable zzz_40t 0
+	trigvolume_enable zzzz_40t 0
+	trigvolume_enable tv_61t 0
+
+	if (save_point eq 0)
+	{
+		my_save_point=0;	
+		set_objective_1
+		particle security_locklight01 do start
+		particle smoke start
+	}
+
+	if (save_point eq 1)
+	{
+		my_save_point=1;	
+		dprint restore1
+		set_objective_1
+		particle smoke start
+		particle security_locklight01 do start
+		env_show 398 0
+		#turn off unbroken curtain wall
+		env_show 98 0
+		#turn on broken curtain wall
+		env_show 99 1
+		#show gunk van 
+		env_show 101 1 
+		env_show 103 1
+		env_show 104 1
+		env_show 105 1
+		env_show 106 1
+		env_show 107 1
+		env_show 108 1
+		env_show 444 1
+		env_show 97 0
+		#show gunk motorcycle
+		env_show 110 1
+		env_show 111 1
+		env_show 112 1
+		#show door gunk
+		env_show 321 1
+		env_show 322 1
+		env_show 323 1
+		env_show 324 1
+		env_show 325 1
+		env_shade 321 325 .3 .3 .3
+		ai2_spawn lobby_striker_01
+		ai2_spawn lobby_striker_02
+		ai2_spawn lobby_striker_03
+		music_intro
+		restore_game
+		sleep 7
+		sound_dialog_play c07_22_01konoko
+		particle LobbyWall do explode
+	}
+
+	if (save_point eq 2)
+		{
+		my_save_point=2;	
+		dprint restore2
+		set_objective_3
+		trigvolume_enable tv_58t 0
+		door_lock 41
+		chr_delete lobby_victim
+		trigvolume_enable trigger_volume_80 0
+		music_kidnap
+		restore_game
+		}
+
+	if (save_point eq 3)
+	{
+		my_save_point=3;	
+		dprint restore3
+		trigvolume_enable t86 0
+		set_objective_5
+		trigvolume_enable tsh_55t 0
+		#Hide elevator gunk 
+		env_show 501 0 
+		env_show 502 0 
+		env_show 503 0 
+		env_show 504 0 
+		#Show new elevator gunk 
+		env_show 601 1 
+		env_show 602 1 
+		fork tsh_55
+		restore_game
+		trigvolume_enable tv_58t 0
+	}
+
+	if (save_point eq 4)
+		{
+		my_save_point=4;	
+		dprint restore4
+		set_objective_5
+		trigvolume_enable tsh_60t 0
+		trigvolume_enable tr_66t 0
+		trigvolume_enable tr_67t 0
+		trigvolume_enable tr_65t 0
+		trigvolume_enable tr_64t 0
+		ai2_spawn barabus
+		chr_boss_shield barabus
+		target_set(1,0.0)
+		restore_game
+		}
+
+}
+
+func void striker_spawn(string ai_name)
+{
+	dprint striker_spawn
+	striker_count =  striker_count + 1
+}
+
+func void striker_die(string ai_name)
+{
+	dprint striker_die
+	striker_count =  striker_count - 1
+}
+
+#########################
+#	trigger volumes	#
+#########################
+
+func void t102(string ai_name)
+{
+	ai2_spawn mbo_sniper
+	ai2_spawn mbo_target
+}
+
+func void t103(string ai_name)
+{
+	dprint t103
+	trigvolume_enable trigger_volume_103 0
+	sleep 7
+	if(elev_count ne 1)
+	{
+		if (chr_has_lsi(0))
+		{
+			trigvolume_enable trigger_volume_81 1
+			objective_set(4)
+			particle obj1 create
+			target_set(9999, 30.0)
+			shut_down_t103 = 1;
+		}
+	}
+	if(shut_down_t103 eq 0)
+	{
+		sleep 60
+		trigvolume_enable trigger_volume_103 1
+	}
+}
+
+func void spawnL2_4(string ai_name)
+{
+	dprint spawnL2_4
+	ai2_spawn lobby_striker_04
+	playback lobby_striker_04 lobbystriker_roll
+	trigvolume_enable u_36t 0
+	
+}
+
+func void spawnL1_6(string ai_name)
+{
+	dprint spawnL1_6
+	ai2_spawn lobby_striker_06
+	trigvolume_enable tv_50t 0
+
+}
+
+func void spawnG2_7(string ai_name)
+{
+	dprint spawnG2_7
+	ai2_spawn garage_striker_01
+	ai2_spawn garage_striker_02
+	
+}
+
+func void spawnG3_8(string ai_name)
+{
+	dprint spawnG3_8
+	if (striker_count eq 0)
+	{
+		ai2_spawn garage_striker_03
+		ai2_makeignoreplayer garage_striker_03 1
+		ai2_spawn garage_striker_04
+		ai2_spawn garage_striker_05
+		playback_block garage_striker_03 garage_jump
+		ai2_makeignoreplayer garage_striker_03 0
+	}
+	if (striker_count ne 0)
+	{
+		ai2_spawn garage_striker_03
+		ai2_makeignoreplayer garage_striker_03 1
+		playback_block garage_striker_03 garage_jump
+		ai2_makeignoreplayer garage_striker_03 0
+	}
+}
+
+func void spawnG3_11(string ai_name)
+{
+	dprint spawnG3_11
+	ai2_spawn garage_striker_07
+	ai2_passive garage_striker_07 1
+	ai2_spawn garage_striker_08
+	playback garage_striker_07 garage_taunt
+	ai2_passive garage_striker_07 0
+
+}
+
+func void spawnG3_12(string ai_name)
+{
+	dprint spawnG3_12
+	
+	if (striker_count eq 0)
+	{
+		ai2_spawn garage_striker_09
+		ai2_spawn garage_striker_10
+	}
+	if (striker_count ne 0)
+	{
+		ai2_spawn garage_striker_09
+	}
+}
+
+func void killG2_08(string ai_name)
+{
+	dprint killG2_08
+	trigvolume_enable trigger_volume_G2_08 0 
+	
+}
+
+func void killG2_10(string ai_name)
+{
+	dprint killG2_10
+	trigvolume_enable trigger_volume_G2_10 0 
+	
+}
+
+func void killG3_11(string ai_name)
+{
+	dprint killG3_11
+	trigvolume_enable trigger_volume_G3_11 0 
+	
+}
+
+func void killG3_12(string ai_name)
+{
+	dprint killG3_12
+	trigvolume_enable trigger_volume_G3_12 0 
+	
+}
+
+func void a_18(string ai_name)
+{
+	dprint a_18
+	trigvolume_enable b_19t 0 
+	trigvolume_enable c_13t 0 
+
+}
+
+func void b_19(string ai_name)
+{
+	dprint b_19
+	ai2_spawn lobby_striker_30
+	ai2_spawn lobby_striker_31
+	playback lobby_striker_31 lobby_roll2
+#	ai2_spawn lobby_striker_33
+#	ai2_spawn lobby_tctf_02
+	trigvolume_enable d_20t 0
+}
+
+func void c_13(string ai_name)
+{
+	dprint c_13
+	ai2_spawn lobby_striker_20
+	ai2_spawn lobby_striker_21
+	ai2_spawn lobby_fodder01
+	ai2_spawn lobby_striker_05
+	trigvolume_enable vv_38t 0
+	trigvolume_enable a_18t 0
+	music_stop
+}
+
+func void d_20(string ai_name)
+{
+	dprint d_20
+	ai2_spawn l2_s46
+	ai2_spawn l2_s44
+	playback_block l2_s44 lobby_roll3
+
+}
+
+func void e_21(string ai_name)
+{
+	dprint e_21
+	ai2_spawn lobby_striker_34
+	ai2_spawn lobby_victim05
+	ai2_spawn lobby_victim06
+	trigvolume_enable l_27t 0
+}
+
+func void f_22(string ai_name)
+{
+	dprint f_22
+	ai2_spawn lobby_striker_05
+	trigvolume_enable vv_38t 0
+	ai2_spawn lobby_striker_20
+	ai2_spawn lobby_fodder01
+	ai2_spawn lobby_striker_21
+
+}
+
+func void g_23(string ai_name)
+{
+	dprint g_23
+	ai2_spawn L2s_01
+	ai2_spawn L2s_02
+	ai2_spawn L2s_03
+	ai2_spawn L2tctf_01
+	ai2_spawn L2tctf_02
+	music_stop
+	trigvolume_enable trigger_volume_w_39 0
+
+}
+
+func void h_06(string ai_name)
+{
+	dprint h_06
+	ai2_spawn L2s_10
+	ai2_spawn Ls_15
+	ai2_spawn Ltctf_55
+	ai2_dopath L2tctf_01 patrol_L2_13
+	ai2_dopath L2tctf_02 patrol_L2_13
+
+}
+
+func void i_24(string ai_name)
+{
+	dprint i_24
+	trigvolume_enable j_25t 0
+	trigvolume_enable h_06t 0
+
+}
+
+func void j_25(string ai_name)
+{
+	dprint j_25
+	ai2_spawn L2s_11
+
+}
+
+func void k_26(string ai_name)
+{
+	dprint k_26
+	trigvolume_enable l_27t 1
+
+}
+
+func void l_27(string ai_name)
+{
+	dprint l_27
+	ai2_spawn L3s_40
+	ai2_spawn L3s_41
+#	ai2_spawn L3s_42
+
+}
+
+func void m_28(string ai_name)
+{
+	dprint m_28
+	ai2_spawn Lv_40
+	ai2_spawn Lv_41
+	ai2_spawn Lc_43
+	ai2_spawn Ls_44
+	trigvolume_enable s_34t 1
+
+}
+
+func void n_29(string ai_name)
+{
+	dprint n_29
+	ai2_spawn Lc_50
+	ai2_spawn Ls_51
+	ai2_spawn Ls_12
+
+}
+
+func void o_30(string ai_name)
+{
+	dprint o_30
+	ai2_spawn Ls_60
+	ai2_spawn a_v2
+	
+}
+
+func void p_31(string ai_name)
+{
+	dprint p_31
+	trigvolume_enable trigger_volume_L2_4 1
+
+}
+
+func void s_34(string ai_name)
+{
+	dprint s_34
+	ai2_spawn Lcom_01
+
+}
+
+func void t_35(string ai_name)
+{
+	dprint t_35
+	trigvolume_enable s_34t 0
+
+}
+
+func void u_36(string ai_name)
+{
+	dprint u_36
+	ai2_spawn cat1_02
+	trigvolume_enable trigger_volume_L2_4 0
+}
+
+func void v_37(string ai_name)
+{
+	dprint v_37
+	ai2_spawn cat1_01
+	trigvolume_enable vv_38t 0
+	
+}
+
+func void t98(string ai_name)
+{
+	dprint t98
+	ai2_spawn a_v4
+}
+
+func void vv_38(string ai_name)
+{
+	dprint vv_38
+	ai2_spawn lobby_striker_05
+	ai2_spawn lobby_striker_20
+	ai2_spawn lobby_striker_21
+	ai2_spawn lobby_fodder01
+	trigvolume_enable v_37t 0
+
+}
+
+func void w_39(string ai_name)
+{
+	dprint w_39
+	ai2_spawn s2_t01
+	ai2_spawn s2_t02
+	ai2_spawn s2_s01
+	ai2_spawn s2_s02
+	ai2_spawn s2_s03
+#	ai2_spawn s2_c01
+	ai2_spawn s2_s05
+	ai2_spawn s2_t05
+	trigvolume_enable g_23t 0
+
+}
+
+func void x_05(string ai_name)
+{
+	dprint x_05
+	ai2_spawn l_c01
+	ai2_lookatme l_c01
+	ai2_passive l_c01 1
+	playback l_c01 lobby_runout
+	ai2_passive l_c01 0
+	trigvolume_enable trigger_volume_L1_6_9 0
+
+}
+
+func void y_32(string ai_name)
+{
+	dprint y_32
+	ai2_spawn l_t01
+	playback l_t01 lobby_backroll
+	sleep 15
+	ai2_spawn l_s02
+	ai2_spawn l_s03
+	trigvolume_enable tv_47t 0
+
+}
+
+func void unlock_follow(void)
+{
+	dprint unlockfollow
+	count_follow = count_follow + 1;
+	if(count_follow eq 2)
+	{
+		trigvolume_enable z_40t 1
+		trigvolume_enable zz_40t 1
+		trigvolume_enable zzz_40t 1
+		trigvolume_enable zzzz_40t 1
+		trigvolume_enable tv_61t 1
+	}
+}
+
+func void patrolscript2222(void)
+{
+	dprint lookatplayer
+	ai2_lookatchar l_t01 char_0
+	ai2_lookatchar l_t23 char_0
+}
+	
+func void z01(string ai_name)
+{
+	dprint z01
+
+	ai2_dopath l_t01 l_t01_01
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_04
+	ai2_setjobstate l_t23
+
+}
+
+func void z02(string ai_name)
+{
+	dprint z02
+	ai2_dopath l_t01 l_t01_04
+	ai2_setjobstate l_t01
+	
+	ai2_dopath l_t23 l_t23_02
+	ai2_setjobstate l_t23
+}
+
+func void z03(string ai_name)
+{
+	dprint z03
+	ai2_dopath l_t01 l_t01_05
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_01
+	ai2_setjobstate l_t23
+}
+
+func void z04(string ai_name)
+{
+	dprint z04	
+	ai2_dopath l_t01 l_t01_06
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_06
+	ai2_setjobstate l_t23
+}
+
+func void z05(string ai_name)
+{
+	dprint z05
+	ai2_dopath l_t01 l_t01_07
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_07
+	ai2_setjobstate l_t23
+}
+
+func void z06(string ai_name)
+{
+	dprint z06
+	ai2_dopath l_t01 l_t01_08
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_08
+	ai2_setjobstate l_t23
+}
+
+func void z_40(string ai_name)
+{
+	dprint z_40
+	ai2_followme l_t01
+	ai2_lookatme l_t01
+	ai2_followme l_t23
+	ai2_lookatme l_t23
+	ai2_followme s2_t05
+	ai2_lookatme s2_t05
+	ai2_followme s2_t02
+	ai2_lookatme s2_t02
+	ai2_followme s2_t01
+	ai2_lookatme s2_t01
+	ai2_followme L2tctf_02
+	ai2_lookatme L2tctf_02
+	ai2_followme L2tctf_01
+	ai2_lookatme L2tctf_01
+	ai2_followme Lc_43
+	ai2_lookatme Lc_43
+
+}
+
+func void tv_44(string ai_name)
+{
+	dprint tv_44
+	ai2_spawn l_c10
+	ai2_dopath l_t01 l_t01_02
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_03
+	ai2_setjobstate l_t23
+}
+
+func void tv_45(string ai_name)
+{
+	dprint tv_45
+	ai2_spawn a_v1
+	ai2_spawn l_s22
+	ai2_spawn l_s23
+	ai2_dopath l_t01 l_t01_03
+	ai2_setjobstate l_t01
+
+	ai2_dopath l_t23 l_t23_05
+	ai2_setjobstate l_t23
+
+}
+
+func void tv_46(string ai_name)
+{
+	dprint tv_46
+	ai2_spawn l_s24
+	ai2_spawn l_t23
+	trigvolume_enable tv_47t 1
+	ai2_dopath l_t01 l_t01_06
+	ai2_setjobstate l_t01
+}
+
+func void tv_47(string ai_name)
+{
+	dprint tv_47
+	ai2_spawn l_s27
+
+}
+
+func void tv_48(string ai_name)
+{
+	dprint tv_48
+	ai2_spawn l2_s46
+
+}
+
+func void tv_49(string ai_name)
+{
+	dprint tv_49
+	ai2_spawn l2_s47
+
+}
+
+func void tv_50(string ai_name)
+{
+	dprint tv_50
+	ai2_spawn l_s99
+	ai2_spawn l_s98
+	music_stop
+
+}
+
+func void tv_51(string ai_name)
+{
+	dprint tv_51
+	ai2_spawn l4_red1
+	ai2_spawn l4_t1
+	ai2_spawn l4_s1
+	ai2_spawn l4_s67
+	ai2_spawn l4_t2
+	ai2_spawn l4_s2
+	ai2_spawn l4_s3	
+	ai2_spawn l4_f1
+	ai2_spawn l4_f2
+	ai2_spawn l4_f3
+	ai2_kill l4_f1
+	ai2_kill l4_f2
+	ai2_kill l4_f3
+	ai2_spawn l4_c66
+	ai2_kill l4_c66
+	
+}
+
+func void tv_52(string ai_name)
+{
+	dprint tv_52
+	particle smoke stop
+	ai2_spawn a_t03
+	ai2_passive a_t03 1
+	playback a_t03 atrium_run
+	sleep 7
+	ai2_spawn a_t06
+	sleep 7
+	ai2_spawn a_s02
+	sleep 7
+	ai2_spawn a_s03
+	sleep 7
+	ai2_spawn a_red1
+	ai2_passive a_t03 0
+	chr_set_health a_t05 900
+	chr_set_health a_t06 900
+	chr_set_health a_s02 900
+	chr_set_health a_s03 900
+}
+func void new_atrium(string ai_name)
+{
+	ai2_spawn a_s07
+	ai2_spawn a_s05
+	ai2_spawn a_v3
+}
+
+func void ta_53(string ai_name)
+{
+	dprint ta_53
+	ai2_spawn a_t05
+	ai2_dopath a_s03 patrol_7043
+	ai2_setjobstate a_s03
+	ai2_dopath a_s02 patrol_7030
+	ai2_setjobstate a_s02
+	ai2_dopath a_t06 patrol_7034
+	ai2_setjobstate a_t06
+	ai2_dopath a_t05 patrol_7042
+	ai2_setjobstate a_t05
+	chr_set_health a_t05 40
+	chr_set_health a_t06 30
+	chr_set_health a_s02 80
+	chr_set_health a_s03 80
+	sleep 2000
+	dprint no_more_tctf
+	counter = 100
+
+}
+
+func void ta_53b(string ai_name)
+{
+	dprint ta_53b
+	chr_set_health a_t05 80
+	chr_set_health a_t06 60
+	chr_set_health a_s02 70
+	chr_set_health a_s03 80
+}
+
+func void ta2_54(string ai_name)
+{
+	dprint ta2_54
+	ai2_spawn a2_t1
+	ai2_spawn a2_red1
+	ai2_spawn LSI
+	chr_invincible LSI 1
+	sleep 240
+	music_stop
+}
+
+func void tsh_55(string ai_name)
+{
+	dprint tsh_55
+	ai2_spawn sh_tank1
+	ai2_spawn sh_red1
+	ai2_spawn sh_s3
+	ai2_spawn sh_s4
+	ai2_spawn sh_s4b
+	set_objective_5
+	sleep 120
+	ai2_attack sh_s3 char_0
+}
+
+func void t62(string ai_name)
+{
+	dprint t62
+	ai2_spawn sh_s1
+	ai2_spawn sh_s2
+	ai2_spawn sh_s6
+}
+
+func void femcop_holster(string ai_name)
+{
+	dprint holstergun
+	chr_forceholster Lc_43 1
+}
+
+func void t72(string ai_name)
+{
+	dprint t72
+	ai2_spawn sh_com1
+	ai2_spawn sh_tank2
+	ai2_spawn sh_s9
+}
+
+func void tv57(string ai_name)
+{
+	dprint tv57
+	Attack
+	target_set(59,30.0)
+}
+
+func void goAttack(string ai_name)
+{
+	music_intro_stop
+
+	dprint goAttack
+	trigvolume_enable tv_57t 1
+	input 0
+	fade_out 0 0 0 30
+	chr_delete l_c01
+	chr_delete lobby_striker_01
+	chr_delete lobby_striker_02
+	chr_delete garage_striker_01
+	chr_delete garage_striker_02
+	chr_delete garage_striker_03
+	chr_delete garage_striker_04
+	chr_delete garage_striker_05
+	chr_delete garage_striker_06
+	chr_delete garage_striker_07
+	chr_delete garage_striker_08
+	chr_delete garage_striker_09
+	chr_delete garage_striker_10
+	chr_delete l_s98
+	chr_delete l_s99	
+	cm_interpolate stair_lock 0
+	fade_in 30
+	sleep 60
+	particle stair_lock_locklight01 do start
+	sleep 90
+	fade_out 0 0 0 30
+	cm_reset
+	fade_in 30
+	input 1
+	set_objective_2
+	ai2_spawn tanker_stairdoor
+	sound_dialog_play c00_01_27shinatama
+}
+
+func void tsh_60(string ai_name)
+{
+	dprint tsh_60
+	ai2_spawn sh_s12
+	ai2_spawn sh_s12b
+	helicopter
+}
+
+func void ta_62(string ai_name)
+{
+	dprint ta_62
+	if (chr_has_lsi(0))
+	{	
+		trigvolume_enable trigger_volume_81 0
+		particle obj1 kill
+		ai2_kill
+		elev_count = 1;
+		sleep 10
+		Elevator
+	}
+}
+
+func void tv_58(string ai_name)
+{
+	dprint tv_58
+	door_lock 41
+	particle security_locklight01 do stop
+	ai2_kill
+	Kidnap
+	set_objective_3
+	s2
+}
+
+func void tv_68(string ai_name)
+{
+	dprint tv_68
+	ai2_spawn b_victim
+}
+
+func void tr_64(string ai_name)
+{
+	dprint tr_64
+	target_set(58,0.0)
+	HeliOutroRight
+	trigvolume_enable tr_65t 0
+	trigvolume_enable tr_66t 0
+	trigvolume_enable tr_67t 0
+
+}
+
+func void tr_65(string ai_name)
+{
+	dprint tr_65
+	target_set(58,0.0)
+	HeliOutroLeft
+	trigvolume_enable tr_64t 0
+	trigvolume_enable tr_66t 0
+	trigvolume_enable tr_67t 0
+
+}
+
+func void tr_66(string ai_name)
+{
+	dprint tr_66
+	target_set(58,0.0)
+	HeliOutroMid
+	trigvolume_enable tr_65t 0
+	trigvolume_enable tr_64t 0
+	trigvolume_enable tr_67t 0
+
+}
+
+func void tr_67(string ai_name)
+{
+	dprint tr_67
+	target_set(58,0.0)
+	HeliOutroMidLt
+	trigvolume_enable tr_65t 0
+	trigvolume_enable tr_66t 0
+	trigvolume_enable tr_64t 0
+
+}
+
+func void t100(string ai_name)
+{
+	dprint t100
+	ai2_spawn roof_tctf1
+	ai2_spawn sh_s12c
+}
+#####################
+#	save scripts  #
+#####################
+
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME	
+	save_game 1 autosave
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME	
+	save_game 2 autosave
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME	
+	save_game 3 autosave
+}
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME	
+	save_game 4 autosave
+}
+
+func void check_death(string ai_name)
+{
+	dprint check_death
+	counter = counter - 1
+	if (trigvolume_count(99) eq 0)
+	{	
+		if(counter eq 0)
+		{
+			sleep 210
+			ai2_spawn a_t99
+		}
+	}
+}
+
+func void spawn(string ai_name)
+{
+	dprint spawn	
+	counter = counter + 1
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf2.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf2.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf2.bsl	(revision 185)
@@ -0,0 +1,2024 @@
+#	tctf2_spawn
+#	scripts for level 18 by wu
+
+var int counter=3;
+var int my_save_point=0;
+var int counterA=0;
+var int counterB=0;
+var int counterC=0;
+var int counterD=0;
+var int counterDestroy=0;
+var int lastdoor_count=0;
+var int sub1 = 0;
+var int sub2 = 0;
+var int sub3 = 0;
+var int ld1;
+var int ld2;
+var int ld3;
+var int audio_counter = 3;
+
+#########
+# music #
+#########
+func void music_intro(void)
+{
+	sound_music_start mus_main03 1.0
+#	this music stopped in t2 script
+}
+
+func void music_chair(void)
+{
+	dprint music_chair
+	sound_music_start mus_wls 1.0
+#	this music stopped in 11 and 11b script
+}
+
+func void music_atrium(void)
+{
+	dprint music_atrium
+	sound_music_start mus_trt .8
+#	this music stopped in check_power script
+}
+
+func void music_zom(void)
+{
+	dprint music_zom
+	sound_music_start mus_sv 0.75
+#	this music stopped in Zom script
+}
+
+func void music_stop(void)
+{
+	dprint STOP_THE_MUSIC
+	sound_music_stop mus_main03
+	sound_music_stop mus_wls
+	sound_music_stop mus_trt
+	sound_music_stop mus_sv
+}
+
+func void spawnA(void)
+{
+		dprint spawn_zone_A
+
+		ai2_spawn A_L19
+		ai2_spawn l1
+		ai2_spawn l3
+		ai2_spawn A_L12
+		ai2_spawn A_Lbo13
+		ai2_spawn A_L8
+		ai2_spawn l7
+}
+###############################
+#	start and objectives    #
+###############################
+func void start(string ai_name)
+{
+	dprint start
+	trig_deactivate	1	
+	trig_deactivate	2	
+	trig_deactivate	3	
+	trig_deactivate	4	
+	trig_deactivate	5
+	trig_deactivate	6
+	trig_deactivate	7
+	trig_deactivate	8
+	trig_deactivate	9
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+	trig_deactivate	98
+	trig_deactivate	99
+	trig_deactivate	10
+	trig_deactivate	302	
+	trig_deactivate	303	
+	trig_deactivate	315
+	trig_deactivate	320	
+	trig_deactivate	100
+	trig_deactivate	101	
+	trig_deactivate	500	
+	trig_deactivate	501	
+	trig_deactivate	502	
+	trig_deactivate	503	
+	trig_deactivate	400		
+	trig_deactivate	510
+	trig_deactivate 511
+	trig_deactivate	512	
+	trig_deactivate	520
+	trig_deactivate	521
+	trig_deactivate	522
+	door_unlock 65
+	door_unlock 71
+#	door_unlock 59
+	door_unlock 61	
+	door_unlock 67
+	door_lock 7
+	door_lock 4
+	door_lock 5
+	door_lock 8
+	door_lock 6
+	door_lock 9
+	console_deactivate 3
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice1 0
+	trigvolume_enable shinzom_voice2 0
+	trigvolume_enable shinzom_voice3 0
+	trigvolume_enable shinzom_voice4 0
+
+	particle griffin_locklight01 do start
+	particle door42_locklight01 do start
+	particle stair_lock_locklight01 do start
+	particle roof_doors_locklight01 do start
+	trigvolume_enable trigger_volume_29 0
+	trigvolume_enable trigger_volume_35 0
+	trigvolume_enable trigger_volume_39 0
+	trigvolume_enable trigger_volume_36 0
+	trigvolume_enable trigger_volume_41 0
+
+	my_save_point = save_point;
+
+	if (my_save_point eq 0)
+	{
+		objective_set(1)
+		target_set(590,30.0)
+
+		Intro	
+		spawnA
+	}
+
+	if (my_save_point eq 1)
+	{
+		dprint restore1
+		objective_set(1)
+		env_show 403 0 
+		target_set(590,30.0)
+		spawnA
+		music_intro
+		restore_game
+	}
+
+	if (my_save_point eq 2)
+	{
+		dprint restore2
+		objective_set(2)
+		target_set(593,30.0)
+		trigvolume_enable trigger_volume_06 0
+		ai2_spawn B_S22
+
+		particle shin_lock_locklight01 do start
+		door_unlock 48
+		door_unlock 14
+		trig_activate	6
+		trig_activate	7
+		trig_activate	99
+		trig_activate	98
+		restore_game
+	}
+
+	if (my_save_point eq 3)
+	{
+		dprint restore3
+		particle shin_lock_locklight01 do stop
+		door_lock 14
+		objective_set(2)
+		trigvolume_enable trigger_volume_46 0
+		trigvolume_enable trigger_volume_47 0
+		trig_deactivate	60
+		trig_deactivate	61
+		trig_deactivate	62
+		trig_deactivate	63
+		trig_deactivate	64
+		trig_deactivate	65
+		trig_deactivate	70
+		trig_deactivate	71
+		trig_deactivate	72
+		trig_deactivate	73
+		trig_deactivate	74
+		trig_deactivate	75
+		trig_deactivate 91
+		trig_deactivate 92
+		trig_deactivate 93
+		trig_deactivate	98
+		trig_deactivate	99
+		trig_deactivate	6
+		trig_deactivate	7
+		target_set(587,30.0)
+		restore_game
+		spine1
+		sleep 7
+		spine2
+		sleep 7
+		spine3
+	}
+
+	if (my_save_point eq 4)
+	{
+		dprint restore4
+		objective_set(3)
+		target_set(596,30.0)
+		trig_deactivate	60
+		trig_deactivate	61
+		trig_deactivate	62
+		trig_deactivate	63
+		trig_deactivate	64
+		trig_deactivate	65
+		trig_deactivate	70
+		trig_deactivate	71
+		trig_deactivate	72
+		trig_deactivate	73
+		trig_deactivate	74
+		trig_deactivate	75
+		trig_deactivate 91
+		trig_deactivate 92
+		trig_deactivate 93
+		trig_deactivate	98
+		trig_deactivate	99
+		trig_deactivate	6
+		trig_deactivate	7
+		door_lock 42
+		particle door42_locklight01 do stop
+		ai2_spawn D_N74
+		restore_game
+	}
+
+	if (my_save_point eq 5)
+	{
+		dprint restore5
+		objective_set(4)
+		trigvolume_enable trigger_volume_42 0
+		trigvolume_enable trigger_volume_35 0
+		particle ZomShin_door_locklight01 do stop
+		door_lock 16
+
+		#TCTF II cutscene "Base"
+		env_show 171 1
+		env_show 172 1
+		env_show 173 1
+		env_show 174 1
+		particle Forcefield do start
+		particle zombiesteam start
+		sound_ambient_start zomshin_amb_loop 1.0
+		music_zom
+
+		#these next lines place griffin where he should be
+		dprint place_griffin_and_holster
+		ai2_spawn ZomGrif
+		ai2_makeignoreplayer ZomGrif 1
+		# make sure that griffin is aiming his weapon!
+		ai2_setmovementmode ZomGrif walk
+		# ai2_passive ZomGrif 1
+		playback ZomGrif ZomGrifDraw
+
+		# don't call the GrifSpawn function again
+		trigvolume_enable t9 0
+
+		create_zomshin
+		playback ZomShin BaseShin
+
+		restore_game
+
+		zombie_round_2
+	#	chr_teleport 0 589
+	}
+}
+
+func void you_lose(string ai_name)
+{
+	sleep 240
+	fade_out 0 0 0 180 
+	sleep 240
+	lose
+}
+
+func void you_win(int char_index)
+{
+	outro
+	win
+}
+
+func void set_objective_1(string ai_name)
+{
+	dprint set_objective_1
+	objective_set(1)
+	target_set (1,0)
+}
+
+func void set_objective_2(string ai_name)
+{
+	dprint set_objective_2
+	objective_set(2)
+	target_set (1,0)
+}
+
+func void set_objective_3(string ai_name)
+{
+	dprint set_objective_3
+	objective_set(3)
+	target_set (1,0)
+}
+
+func void set_objective_4(string ai_name)
+{
+	dprint set_objective_4
+	objective_set(4)
+	target_set (401,30)
+	particle ZomShin_door_locklight01 do start
+}
+
+
+#################################
+#	cut scene scripts         #
+#################################
+
+func void grifdies(string ai_name)
+{
+	killed_griffen 1
+	OutroKill
+}
+
+func void t35(string ai_name)
+{
+	killed_griffen 0
+	OutroNoKill
+}
+
+func void outta_sight(string ai_name)
+{
+	ai2_dopath n5 patrol_99
+	ai2_setjobstate n5
+}
+
+#########################
+#  trigger volume stuff #
+#########################
+
+func void t68(string ai_name)
+{
+	ai2_spawn mbo_femcop
+}
+
+func void t2(string ai_name)
+{
+	dprint t2_active
+	trigvolume_enable trigger_volume_61 0
+	ai2_spawn n5
+	ai2_spawn A_Sbo14
+	ai2_dopath A_Sbo14 patrol_14
+	ai2_setjobstate A_Sbo14
+	ai2_spawn A_Sbo15
+	sleep 30
+	ai2_dopath A_Sbo15 patrol_14
+	ai2_setjobstate A_Sbo15
+#	ai2_spawn A_Sbo16
+	music_stop
+
+}
+
+func void t61(string ai_name)
+{
+	dprint t61_active
+	trigvolume_enable trigger_volume_02 0
+	ai2_spawn n5
+	ai2_spawn A_Sbo14
+	ai2_spawn A_Sbo15
+	music_stop
+}
+
+func void t3(string ai_name)
+{
+	dprint t3_active
+	ai2_dopath A_n17 patrol_16
+	ai2_setjobstate A_n17
+
+}
+
+func void t4(string ai_name)
+{
+	dprint t4_active
+	ai2_spawn A_L18
+}
+
+func void t6(string ai_name)
+{
+	dprint t6_active
+	ai2_spawn A_L20
+	ai2_spawn A_L21	
+	ai2_spawn B_S22
+	ai2_makeignoreplayer B_S22 1
+	trig_activate	6
+	trig_activate	7
+	trig_activate	99
+	trig_activate	98
+	target_set(593,30.0)
+}
+
+func void t7(string ai_name)
+{
+	dprint t7_active
+	ai2_dopath B_S22 patrol_23
+	ai2_setjobstate B_S22
+	ai2_makeignoreplayer B_S22 0
+	ai2_spawn B_N28	
+}
+
+func void t7b(string ai_name)
+{
+	dprint t7b_active
+	ai2_spawn B_Lbo26
+	playback_block B_Lbo26 run1 interp 20
+	sleep 20
+	ai2_dopath B_Lbo26 patrol_27
+	ai2_setjobstate B_Lbo26
+		
+}
+
+func void t8(string ai_name)
+{
+	dprint t8_active
+	chr_delete A_L19
+	chr_delete l1
+	chr_delete l3
+	chr_delete A_L12
+	chr_delete A_Lbo13
+	chr_delete A_L8
+	chr_delete l7
+	chr_delete n5
+	chr_delete A_T25
+	chr_delete A_n17
+	chr_delete A_N31
+	ai2_spawn B_Sbo38
+	ai2_spawn B_S36	
+	ai2_makeignoreplayer B_S36 1
+	ai2_spawn B_L40
+	ai2_spawn B_L41
+	music_chair
+	sleep 90
+	substation_monologue
+}
+
+func void t9(string ai_name)
+{
+	dprint t9_spawning_griffin
+#	ai2_spawn ZomGrif
+	GrifSpawn
+	target_set (1,0.0)
+}
+
+func void t10(string ai_name)
+{
+	dprint t10_active
+	ai2_spawn B_S29
+}
+
+func void t11(string ai_name)
+{
+	dprint t11_active
+	ai2_dopath B_S36 patrol_38
+	ai2_setjobstate B_S36
+	ai2_makeignoreplayer B_Sbo38 0
+#	ai2_makeignoreplayer B_Sbo35 0
+	ai2_makeignoreplayer B_S36 0
+	ai2_makeignoreplayer B_S37 0
+	ai2_spawn B_Lbo76
+#	ai2_spawn B_Lbo77
+	ai2_spawn B_C34
+	ai2_spawn B_C33
+	ai2_spawn B_C32
+	trigvolume_enable trigger_volume_11_copy 0
+	music_stop
+}
+
+func void t59(string ai_name)
+{
+	ai2_spawn B_L30
+	ai2_spawn B_L95
+	ai2_spawn B_Lbo27
+}
+
+func void t60(string ai_name)
+{
+	ai2_spawn B_C32
+	ai2_spawn B_C34
+	ai2_spawn B_C33
+	ai2_makeignoreplayer B_S36 0
+}
+
+func void t67(string ai_name)
+{
+	ai2_spawn B_S43
+}
+
+func void t11b(string ai_name)
+{
+	dprint t11b_active
+	ai2_dopath B_S36 patrol_38
+	ai2_setjobstate B_S36
+	ai2_makeignoreplayer B_Sbo38 0
+#	ai2_makeignoreplayer B_Sbo35 0
+	ai2_makeignoreplayer B_S36 0
+	ai2_makeignoreplayer B_S37 0
+	ai2_spawn B_Lbo76
+#	ai2_spawn B_Lbo77
+	trigvolume_enable trigger_volume_11 0
+	music_stop
+}
+
+func void t12(string ai_name)
+{
+	dprint t12_active
+	ai2_dopath B_N28 patrol_42
+	ai2_setjobstate B_N28
+}
+
+func void t14(string ai_name)
+{
+	dprint t14_active
+	ai2_spawn C_Sbo44
+#	ai2_spawn C_C46
+	ai2_spawn C_C47
+	ai2_spawn C_N48
+#	ai2_spawn C_L50
+#	ai2_makeignoreplayer C_L50 1
+#	ai2_spawn C_L51
+#	ai2_makeignoreplayer C_L51 1
+
+}
+
+func void t15(string ai_name)
+{
+	dprint t15_active
+	ai2_lookatme C_L51
+	ai2_dopath C_L51 patrol_51
+	ai2_setjobstate C_L51
+	ai2_makeignoreplayer C_L51 0
+	sleep 90
+	ai2_lookatme C_L50
+	ai2_dopath C_L50 patrol_50
+	ai2_setjobstate C_L50 
+	ai2_makeignoreplayer C_L50 0
+
+}
+
+func void t16(string ai_name)
+{
+	dprint t16_active
+	ai2_makeignoreplayer C_L50 0
+	ai2_makeignoreplayer C_L51 0
+
+}
+
+func void t17(string ai_name)
+{
+	dprint t17_active
+	ai2_makeignoreplayer C_N55 0
+	ai2_spawn C_Sbo56
+
+}
+
+func void t18(string ai_name)
+{
+	dprint t18_active
+	ai2_spawn C_S57
+
+}
+
+func void t19(string ai_name)
+{
+	dprint t19_active
+	ai2_spawn C_S58
+	ai2_spawn C_S59
+
+}
+
+func void t20(string ai_name)
+{
+	dprint t20_active
+#	sleep 200
+	ai2_spawn C_Lbo62
+	ai2_spawn C_Sbo61
+
+}
+
+func void t21(string ai_name)
+{
+	dprint t21_active
+	ai2_spawn C_Sbo63
+	ai2_spawn C_Sbo64
+
+}
+
+func void t22(string ai_name)
+{
+	dprint t22_active
+	ai2_makeignoreplayer C_C65 0
+
+}
+
+func void t23(string ai_name)
+{
+	dprint t23_active
+	ai2_spawn C_L71
+	ai2_spawn C_S72
+	ai2_spawn C_N74
+
+}
+
+func void t25(string ai_name)
+{
+	dprint t25_active
+	ai2_spawn D_C70
+	ai2_makeignoreplayer D_C70 1
+	ai2_spawn D_Sbo71
+	ai2_spawn D_Sbo72
+	ai2_spawn D_Sbo73
+	ai2_spawn D_Sbo75
+	ai2_spawn D_N76
+
+}
+
+func void t26(string ai_name)
+{
+	dprint t26_active
+	ai2_spawn D_L74
+	ai2_spawn new_1
+}
+
+func void t28(string ai_name)
+{
+	dprint t28_active
+	ai2_spawn D_S78
+	ai2_spawn D_S79
+	trigvolume_enable trigger_volume_29 1
+
+}
+
+func void t29(string ai_name)
+{
+	dprint t29_active
+	ai2_spawn D_Lbo81
+	ai2_spawn D_S82
+
+}
+
+func void t30(string ai_name)
+{
+	dprint t30_active
+	ai2_spawn D_L80
+
+}
+
+func void t31(string ai_name)
+{
+	dprint t31_active
+	ai2_spawn D_S83
+	ai2_spawn D_L84
+	ai2_spawn D_Lbo85
+	ai2_spawn D_Sbo86
+	trigvolume_enable trigger_volume_32 0
+}
+
+func void t32(string ai_name)
+{
+	dprint t32_active
+	ai2_spawn D_L88
+	ai2_spawn D_S87
+	ai2_spawn D_Sbo86
+	trigvolume_enable trigger_volume_31 0
+	target_set(599,30.0)
+}
+
+
+func void t33(string ai_name)
+{
+	dprint t33_active
+	door_lock 97
+	particle lastdoor1_locklight01 do stop
+	particle lastdoor2_locklight01 do stop
+	particle lastdoor3_locklight01 do stop
+	#play doorsound
+}
+
+func void t34(string ai_name)
+{
+	dprint t34_active
+	ai2_spawn D_Sbo75
+	ai2_spawn D_Sbo92
+	ai2_spawn D_L91
+	ai2_spawn D_S90
+	ai2_spawn D_S89
+}
+
+func void t37(string ai_name)
+{
+	dprint t37_active
+	ai2_makeignoreplayer D_C70 0
+
+}
+
+func void t38(string ai_name)
+{
+	dprint t38
+#	ai2_spawn B_N31
+
+}
+
+func void t41(string ai_name)
+{
+	dprint t41_active
+	target_set(596,30.0)
+}
+
+func void t42(string ai_name)
+{
+	dprint t42_active
+	door_lock 16
+	particle ZomShin_door_locklight01 do stop
+	trigvolume_enable trigger_volume_35 0
+	Base
+	s5
+}
+
+func void t43(string ai_name)
+{
+	dprint t43_active
+	ai2_spawn B_S96
+}
+
+func void t44(string ai_name)
+{
+	dprint t44
+	target_set(598,30.0)
+}
+
+func void t45(string ai_name)
+{
+	dprint t45_active
+	target_set(587,30.0)
+	door_lock 14
+	particle shin_lock_locklight01 do stop
+	console_activate 3
+#	play door lock sound
+	trig_deactivate	60
+	trig_deactivate	61
+	trig_deactivate	62
+	trig_deactivate	63
+	trig_deactivate	64
+	trig_deactivate	65
+	trig_deactivate	70
+	trig_deactivate	71
+	trig_deactivate	72
+	trig_deactivate	73
+	trig_deactivate	74
+	trig_deactivate	75
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+	trig_deactivate	98
+	trig_deactivate	99
+	trig_deactivate	6
+	trig_deactivate	7
+	if (trigvolume_count(20) eq 0)
+	{
+		dprint delete_B_AI
+		chr_delete B_L95
+		chr_delete B_Lbo27
+		chr_delete B_S29
+		chr_delete B_L30
+		chr_delete B_Sbo38
+		chr_delete B_S36	
+		chr_delete B_S37
+		chr_delete B_L40
+		chr_delete B_L41
+		chr_delete B_Lbo39
+		chr_delete B_S43
+		chr_delete B_C32
+		chr_delete B_C33
+		chr_delete B_C34
+		chr_delete B_Lbo26
+		chr_delete B_S96
+		chr_delete B_Lbo76
+		chr_delete B_S22
+		chr_delete B_N31
+		chr_delete B_Lbo77
+	}
+	dprint delete_A_AI
+	chr_delete A_L20
+	chr_delete A_L21
+	chr_delete A_Sbo15
+	chr_delete A_Sbo14
+	chr_delete A_L19
+	chr_delete l1
+	chr_delete l3
+	chr_delete A_L12
+	chr_delete A_Lbo13
+	chr_delete A_L8
+	chr_delete l7
+	chr_delete n5
+	chr_delete A_T25
+	chr_delete B_N28
+	chr_delete A_n17
+	chr_delete A_N31
+}
+
+func void attack_konoko(string ai_name)
+{
+	ai2_attack new_1 A_player
+}
+
+func void substation_monologue(void)
+{
+	dprint playkonokoline
+	sound_dialog_play c14_54_24konoko
+	cinematic_start (KONtalkangryfront, 180, 180, 19, 7, 20)
+	sound_dialog_play_block
+	sleep f60
+	cinematic_stop (KONtalkangryfront, 19, 20)
+
+	objective_set(2, silent)
+}
+
+func void save3_and_spine(string ai_name)
+{
+	s3
+	spine1
+	sleep 7
+	spine2
+	sleep 7
+	spine3
+}
+func void t45b(string ai_name)
+{
+	dprint t45b_modified_by_okita
+	ai2_spawn C_L51
+	ai2_spawn C_L50
+	ai2_spawn C_C65
+	ai2_spawn C_N66
+	ai2_spawn C_Sbo93
+	ai2_spawn C_N60
+	ai2_spawn C_N55
+	ai2_makeignoreplayer C_L50 1
+	ai2_makeignoreplayer C_L51 1
+	ai2_makeignoreplayer C_N55 1
+	ai2_makeignoreplayer C_C65 1
+	trig_activate	1	
+	trig_activate	2	
+	trig_activate	3	
+	trig_activate	4	
+	trig_activate	5
+	trig_activate	8		
+	trig_activate	303	
+	trig_activate	100
+	trig_activate	101	
+	trig_activate	500	
+	trig_activate	400	
+	trig_activate	503
+	trig_activate	502
+	trig_activate	501
+	trig_activate	510
+	trig_activate 	511
+	trig_activate	512	
+	trig_activate	520
+	trig_activate	521
+	trig_activate	522
+	trig_activate	320
+	trig_activate	315
+	trig_activate	302	
+	music_atrium	
+}
+################ begin #################
+########## okita's modification ########
+########################################
+func void spine1(void)
+{
+	dprint spine1_start
+
+	if (sub1 eq 0)
+	{
+		particle spine1 start
+		particle spinesound1 start
+	}
+}
+
+func void spine2(void)
+{
+	dprint spine2_start
+
+	if (sub2 eq 0)
+	{
+		particle spine2 start
+		particle spinesound2 start
+	}
+}
+
+func void spine3(void)
+{
+	dprint spine3_start
+
+	if (sub3 eq 0)
+	{
+		particle spine3 start
+		particle spinesound3 start
+	}
+}
+################  end  #################
+########## okita's modification ########
+########################################
+func void patrolscript0001(void)
+{
+	playback_block B_S22 taunt1 interp 20
+}
+
+func void B_S22_run (string ai_name)
+{
+	ai2_dopath B_S22 patrol_24
+	ai2_setjobstate B_S22
+}
+
+func void A_T25_run (string ai_name)
+{
+	ai2_dopath A_T25 patrol_25
+	ai2_setjobstate A_T25
+}
+
+func void t39(string ai_name)
+{
+	target_set(598,30.0)
+}
+
+func void t48(string ai_name)
+{
+	ai2_spawn D_S101
+	ai2_spawn D_C100
+}
+#########################################
+#      		console/special	    #
+#########################################
+func void unlock14(string ai_name)
+{
+	dprint unlock14_active
+	door_unlock 14
+	particle shin_lock_locklight01 do start
+}
+
+func void console_android(void)
+{
+	text_console level_18b
+	console_reset 16
+}
+
+func void console_zombie(void)
+{
+	text_console level_18a
+	console_reset 17
+}
+
+func void console1(string ai_name)
+{
+	dprint console1_active
+	text_console level_18c
+	console_reset 14
+	console_activate 14
+}
+
+func void console2(string ai_name)
+{
+	dprint console2_active
+	text_console level_18d
+	console_reset 15
+}
+
+func void level_18e(string ai_name)
+{
+	dprint text_18e
+	text_console level_18e
+	console_reset 1
+	console_activate 1
+}
+
+func void lastdoor_console(string ai_name)
+{	
+	dprint lastdoor_console
+	lastdoor_count = lastdoor_count + 1
+	if (lastdoor_count eq 1)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor3_locklight01 do start
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+	}
+	if (lastdoor_count eq 2)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor2_locklight01 do start
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+	}
+	if (lastdoor_count eq 3)
+	{
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate lastdoor_cam 0
+		fade_in 30
+		sleep 60
+		particle lastdoor1_locklight01 do start
+		set_objective_4
+		target_set(401,30.0)
+		sleep 30
+		fade_out 0 0 0 30
+		cm_reset
+		input 1
+		fade_in 30
+		trigvolume_enable trigger_volume_40 0
+		door_unlock 97
+	}
+
+}
+
+func void refuse_script(string ai_name)
+{	
+	dprint refuse
+	ai2_dopath C_N48 patrol_98
+}
+
+func void patrolscript0098(string ai_name)
+{	
+	dprint patrolscript0098
+	ai2_doalarm C_N48 10
+}
+
+func void shin_lock(string ai_name)
+{
+	particle shin_lock_locklight01 do start
+}
+
+func void stair_lock(string ai_name)
+{
+	particle stair_lock_locklight01 do start
+}
+
+func void roof(string ai_name)
+{
+	particle roof_locklight01 do start
+	particle shin_lock_locklight01 do start
+	ai2_spawn A_T25
+
+}
+
+func void floor4_lock(string ai_name)
+{
+	particle floor4_lock_locklight01 do start
+	trigvolume_enable trigger_volume_39 1
+
+}
+
+func void roof_doors(string ai_name)
+{
+	particle roof_doors_locklight01 do start
+
+}
+
+func void roof_door2(string ai_name)
+{
+	particle roof_door2_locklight01 do start
+	ai2_spawn A_n17
+}
+
+func void enable_t29(string ai_name)
+{
+	trigvolume_enable trigger_volume_29 1
+
+}
+
+func void t40(string ai_name)
+{
+	dprint t40_active
+	if(sub1 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count(49) eq 0)
+			{
+				trigvolume_enable trigger_volume_40 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(49) eq 0)
+			{
+				trigvolume_enable trigger_volume_40 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func void t50(string ai_name)
+{
+	dprint t50_active
+	if(sub2 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count(51) eq 0)
+			{
+
+				trigvolume_enable trigger_volume_50 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(51) eq 0)
+			{
+				trigvolume_enable trigger_volume_50 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func void t53(string ai_name)
+{
+	dprint t53_active
+	if(sub3 ne 1)
+	{
+		if (audio_counter eq 2)
+		{
+			if(trigvolume_count (54) eq 0)
+			{
+				trigvolume_enable trigger_volume_53 0
+				sound_dialog_play c14_54_26konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+		if (audio_counter eq 3)
+		{
+			if(trigvolume_count(54) eq 0)
+			{
+				trigvolume_enable trigger_volume_53 0
+				sound_dialog_play c14_54_25konoko
+				sound_dialog_play_block pause
+				audio_counter = audio_counter - 1;
+			}
+		}
+	}
+}
+
+func powersub1(string ai_name)
+{
+	dprint powersub1_active
+	sub1 = 1;
+	particle spine1 stop
+	particle spinesound1 stop
+
+	if(sub3 eq 0)
+	{
+		target_set(594,30.0)
+	}
+	if(sub3 ne 0)
+	{
+		if(sub2 eq 0)
+		{
+			target_set(595,30.0)
+		}
+	}
+	check_power
+}
+
+func powersub2(string ai_name)
+{
+	dprint powersub2_active
+	particle spine2 do stop
+	particle spinesound2 stop
+	sub2 = 1;
+	if(sub3 eq 0)
+	{
+		target_set(594,30.0)
+	}
+	if(sub3 ne 0)
+	{
+		if(sub1 eq 0)
+		{
+			target_set(587,30.0)
+		}
+	}
+	check_power
+}
+
+func powersub3(string ai_name)
+{
+	dprint powersub3_active
+	sub3 = 1;
+	particle spine3 do stop
+	particle spinesound3 stop
+	if(sub2 eq 0)
+	{
+		target_set(595,30.0)
+	}
+
+	if(sub2 ne 0)
+	{
+		if(sub1 eq 0)
+		{
+			target_set(587,30.0)
+		}
+	}
+	check_power
+}
+
+func check_power(string ai_name)
+{
+	dprint check_power_active
+	counter = counter - 1
+	if (counter eq 1)
+	{
+		sound_dialog_play c14_54_27konoko
+		sound_dialog_play_block pause
+	}
+
+	if (counter eq 0)
+	{
+		dprint power_down
+		trigvolume_enable trigger_volume_36 1
+		trigvolume_enable trigger_volume_41 1
+		input 0
+		fade_out 0 0 0 30
+		cm_interpolate substation 0
+		fade_in 30
+	#	sleep 180
+		trig_deactivate	1	
+		trig_deactivate	2	
+		trig_deactivate	3	
+		trig_deactivate	4	
+		trig_deactivate	5
+		trig_deactivate	8		
+		trig_deactivate	303	
+		trig_deactivate	100
+		trig_deactivate	101	
+		trig_deactivate	500	
+		trig_deactivate	400	
+		sleep 15
+		trig_deactivate	503
+		sleep 5
+		trig_deactivate	502
+		sleep 5
+		trig_deactivate	501
+		sleep 15	
+		trig_deactivate	510
+		sleep 5
+		trig_deactivate 	511
+		sleep 5	
+		trig_deactivate	512	
+		sleep 15
+		trig_deactivate	520
+		sleep 5	
+		trig_deactivate	521
+		sleep 5	
+		trig_deactivate	522
+		sleep 15
+		trig_deactivate	320
+		sleep 15
+		trig_deactivate	315
+		sleep 15
+		trig_deactivate	302	
+		door_unlock	16
+		particle ZomShin_door_locklight do start
+		sleep 120
+		fade_out 0 0 0 240
+		cm_reset
+		input 1
+		target_set(403, 30.0)
+		fade_in 30
+		music_stop
+		objective_set(3)
+	}
+}
+
+func void lastdoor1(string ai_name)
+{
+	ld1=1
+	if(ld2 eq 0)
+	{
+		target_set(599,30.0)
+	}
+	if (ld2 ne 0)
+	{
+		if(ld3 eq 0)
+		{
+			target_set(598,30.0)
+		}
+	}
+}
+
+func void lastdoor2(string ai_name)
+{
+	ld2=1
+	if(ld3 eq 0)
+	{
+		target_set(598,30.0)
+	}
+	if(ld3 ne 0)
+	{
+		if(ld1 eq 0)
+		{
+			target_set(597,30.0)
+		}
+	}
+}
+
+func void lastdoor3(string ai_name)
+{
+	ld3=1
+	if(ld2 eq 0)
+	{
+		target_set(599,30.0)
+	}
+	if(ld2 ne 0)
+	{
+		if(ld1 eq 0)
+		{
+			target_set(597,30.0)
+		}
+	}
+}
+
+#########################
+#	save game	      #
+#########################
+func void s1(string ai_name)
+{
+	dprint SAVEDGAME1	
+
+	if (my_save_point ne 1)
+	{
+		save_game 1 autosave
+	}
+}
+
+func void s2(string ai_name)
+{
+	dprint SAVEDGAME2	
+
+	if (my_save_point ne 2)
+	{
+		save_game 2 autosave
+	}
+}
+
+func void s3(string ai_name)
+{
+	dprint SAVEDGAME3	
+
+	if (my_save_point ne 3)
+	{
+		save_game 3 autosave
+	}
+}
+
+func void s4(string ai_name)
+{
+	dprint SAVEDGAME4	
+
+	if (my_save_point ne 4)
+	{
+		save_game 4 autosave
+	}
+}
+
+func void s5(string ai_name)
+{
+	dprint SAVEDGAME5	
+
+	if (my_save_point ne 5)
+	{
+		save_game 5 autosave
+	}
+}
+
+###############################################
+#####   FURIOUS ZOMBIE SHINATAMA FIGHT   ######
+###############################################
+
+var int console_count = 4;
+var int zombie_counter_var = 0;
+
+func void zombie_counter(string player_name)
+{
+	console_count = console_count - 1;
+
+	door_lock 16	
+
+	if (console_count eq 0)
+	{
+		console_count = 4;
+
+		dprint zombie_counter
+		zombie_counter_var = zombie_counter_var + 1;
+
+		if (zombie_counter_var eq 0)
+		{
+			zombie_round_2
+		}
+
+		if (zombie_counter_var eq 1)
+		{
+			zombie_round_3
+		}
+
+		if (zombie_counter_var eq 2)
+		{
+			zombie_round_4
+		}
+
+		if (zombie_counter_var eq 3)
+		{
+			zombie_round_5
+		}
+	}
+}
+
+func void t52(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_102
+}
+
+func void t55(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_103
+}
+
+func void t56(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_104
+}
+
+func void t57(string ai_name)
+{
+	ai2_dopath ZomGrif patrol_105
+}
+
+func void t58(string ai_name)
+{
+	ai2_spawn C_Lbo53
+	ai2_spawn C_Sbo52
+}
+
+func void zombie_dialog_round3(void)
+{
+	sound_dialog_play c14_51_07shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+func void zombie_dialog_round4(void)
+{
+	sound_dialog_play c14_51_08shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+func void zombie_dialog_round5(void)
+{
+	sound_dialog_play c14_51_09shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+}
+
+# CB: this round is not called any longer! only zombie rounds 2-5 are used now
+# ZOMBIE ROUND 1
+func void zombie_round_1(string ai_name)
+{
+	dprint zombie_round_1
+
+	particle zombie1 create
+	particle zombie1 start
+
+	ai2_allpassive 1
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	sleep 120
+
+	trig_show 91
+	trig_show 92
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	sleep 30
+
+#	trig_speed 202 .2
+#	trig_speed 204 .2
+#	trig_hide 2023
+#	trig_hide 2013
+
+#	particle ????? start
+#	particle ????? start
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_makeignoreplayer ZomGrif 1
+}
+
+# CB: this round has all the old zombie round 2 setup including camera angles
+# OLD ZOMBIE ROUND 2
+func void old_zombie_round_2(string ai_name)
+{
+	dprint zombie_round_2
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	particle zombie1 create
+	particle zombie1 start
+
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_1
+
+	sleep 15
+	trig_hide 91
+	sleep 15
+	trig_hide 92
+	sleep 15
+	trig_hide 93
+
+	sleep 120
+
+	trig_show 210
+	trig_show 310
+	trig_show 410
+	trig_show 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	sleep 90
+	
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_makeignoreplayer ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}	
+
+# CB: this round is the new zombie round 2 setup which is tabulae rasa
+# and fit to be called from a save point, or from the cutscene
+# ZOMBIE ROUND 2
+func void zombie_round_2(string ai_name)
+{
+	dprint zombie_round_2_active
+
+	particle zombie1 create
+	particle zombie1 start
+
+	ai2_allpassive 1
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	sleep 120
+
+	trig_show 210
+	trig_show 310
+	trig_show 410
+	trig_show 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice1 1
+	trigvolume_enable shinzom_voice2 1
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	ai2_makeignoreplayer ZomGrif 1
+}	
+
+# ZOMBIE ROUND 3
+func void zombie_round_3(string ai_name)
+{
+	dprint zombie_round_3_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice3 1
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	sleep 10
+	particle zombie1 create
+	particle zombie1 start
+
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_2
+
+	sleep 15
+	trig_hide 91
+	sleep 15
+	trig_hide 92
+	sleep 15
+	trig_hide 93
+
+	trig_deactivate 210
+	trig_deactivate 310
+	trig_deactivate 410
+	trig_deactivate 510
+
+	fork zombie_dialog_round3
+	sleep 120
+
+	trig_reset 91
+	trig_reset 92
+	trig_reset 93
+
+	sleep 15
+	trig_show 91
+	sleep 15
+	trig_show 92
+	sleep 15
+	trig_show 93
+
+	trig_activate 91
+	trig_activate 92
+	trig_activate 93
+
+	trig_reset 210
+	trig_reset 310
+	trig_reset 410
+	trig_reset 510
+
+	trig_activate 210
+	trig_activate 310
+	trig_activate 410
+	trig_activate 510
+
+	trig_show 2101
+	trig_show 3101
+	trig_show 4101
+	trig_show 5101
+
+	trig_activate 2101
+	trig_activate 3101
+	trig_activate 4101
+	trig_activate 5101
+
+	trig_speed 210 .3
+	trig_speed 310 .3
+	trig_speed 410 .3
+	trig_speed 510 .3
+
+	trig_speed 2101 .3
+	trig_speed 3101 .3
+	trig_speed 4101 .3
+	trig_speed 5101 .3
+
+	sleep 90
+
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	# ai2_passive ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}
+
+## ZOMBIE ROUND 4
+func void zombie_round_4(string ai_name)
+{
+	dprint zombie_round_4_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+	input 0
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	particle zombie1 kill
+
+	# incidental zombie shinatama dialog
+	trigvolume_enable shinzom_voice4 1
+
+	sleep 90
+
+	cm_interpolate zombie_hint 0
+
+	sleep 30
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	sleep 30
+	particle zombie1 create
+	particle zombie1 start
+
+	fork zombie_dialog_round4
+	sleep 120
+
+	trig_deactivate 91
+	trig_deactivate 92
+	trig_deactivate 93
+
+	dprint trig_off_3
+
+	trig_hide 91
+	trig_hide 92
+	trig_hide 93
+
+	trig_deactivate 210
+	trig_deactivate 310
+	trig_deactivate 410
+	trig_deactivate 510
+
+	trig_hide 210
+	trig_hide 310
+	trig_hide 410
+	trig_hide 510
+
+	trig_deactivate 2101
+	trig_deactivate 3101
+	trig_deactivate 4101
+	trig_deactivate 5101
+
+	trig_hide 2101
+	trig_hide 3101
+	trig_hide 4101
+	trig_hide 5101
+
+	sleep 120
+		
+	trig_show 214
+	trig_show 314
+	trig_show 414
+	trig_show 514
+
+	sleep 15
+
+	trig_show 94
+
+	sleep 15
+
+	trig_show 910
+
+	trig_activate 214
+	trig_activate 314
+	trig_activate 414
+	trig_activate 514
+
+	trig_activate 910
+	trig_activate 94
+
+	trig_speed 214 .15
+	trig_speed 314 .15
+	trig_speed 414 .15
+	trig_speed 514 .15
+
+	trig_speed 910 .35
+	trig_speed 94 .35
+		
+	sleep 90
+	
+	cm_reset
+	input 1
+	sleep 90
+	ai2_allpassive 0
+	# # ai2_passive ZomGrif 1
+
+	console_reset 399
+	console_reset 400
+	console_reset 401
+	console_reset 402
+}
+
+########## ZOMBIE ROUND 5 - YOU WIN ############
+
+func void zombie_round_5(string ai_name)
+{
+	dprint zombie_round_5_active
+
+	ai2_allpassive 1
+	turret_deactivate 330
+	turret_deactivate 333
+	turret_deactivate 336
+
+	trig_hide 214
+	trig_hide 414
+
+	trig_activate 210
+	trig_activate 410	
+
+	# CB: kill all weapon particles
+	p3_removedangerous
+
+	input 0
+
+	begin_cutscene	
+
+	music_stop
+
+	sleep 60
+
+	cm_interpolate zombie_death 0
+	
+	fork zombie_dialog_round5
+	sleep 90
+
+	trig_speed 9 1
+	trig_speed 10 2
+	trig_speed 910 2.5
+	trig_speed 94 .5
+	trig_speed 210 2
+	sleep 90	
+	trig_speed 410 2
+	sleep 90	
+	trig_speed 514 1
+	trig_speed 410 1
+	sleep 90
+	trig_speed 314 2
+	sleep 90
+	trig_speed 210 1
+
+	sleep 60
+	trig_hide 210
+	trig_hide 9
+	trig_speed 10 .2
+	sleep 60	
+	trig_hide 314
+	trig_hide 910
+	sleep 60	
+	trig_speed 514 .2
+	trig_hide 410
+	trig_hide 10
+	trig_hide 94
+	sleep 60
+	trig_hide 514
+	sleep 60
+	trig_hide 93
+	particle zombie1 kill
+	sound_ambient_start shin_zom_shutdown 1.0
+	sleep 10
+	particle zombie1 create
+	particle zombie1 start
+	sleep 20
+	particle zombie1 kill
+	particle zombie1 create
+	particle zombie1 start
+	sleep 30
+	particle zombie1 kill
+	particle zombiesteam stop
+	particle zombient stop
+	
+	sleep 90
+
+#	Hardy, if griffin has to see konoko after or during the zom cutscene, 
+#	make sure this next line makes it into the shorter zombie shin scripts --mike
+
+	ai2_makeignoreplayer ZomGrif 0
+	Zom
+}
+
+
+
+############################################################
+########### INCIDENTAL SHINATAMA ZOMBIE DIALOG #############
+############################################################
+
+func void shinzom_voice1(string ai_name)
+{
+	sound_dialog_play c00_01_102shinatama
+}
+
+func void shinzom_voice2(string ai_name)
+{
+	sound_dialog_play c00_01_101shinatama
+}
+
+func void shinzom_voice3(string ai_name)
+{
+	sound_dialog_play c00_01_100shinatama
+}
+
+func void shinzom_voice4(string ai_name)
+{
+	sound_dialog_play c00_01_103shinatama
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_cutscene.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_cutscene.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_cutscene.bsl	(revision 185)
@@ -0,0 +1,419 @@
+#
+# tctf_cutscene.bsl
+#
+
+func void
+Intro(
+	void)
+{
+	fade_out 0 0 0 0
+	cm_interpolate IntroCam01 0
+	sleep f14
+	begin_cutscene weapon
+	marketing_line_off=1
+	letterbox 1
+	sleep f60
+	invincible=1
+	obj_create 401 402
+	obj_create 404 407
+	fade_in 90
+	#Outside shot of TCTF
+	cm_interpolate IntroCam01 0
+	playback 0 IntroKonokoSet
+	sleep f300
+	#Griffin and Guy talking
+	chr_create 1201 start
+	chr_create 1202 start
+	playback 1202 IntroTCTF01
+	#make this box animation last as long as conversation
+	chr_envanim 1201 IntroGriffinBox01
+	chr_animate 1201 COMGUYsit_idle1 1800
+	#Conversation between the two
+	cm_interpolate IntroCam02 0
+	sound_dialog_play c14_50_01scigoon1
+	cinematic_start (COPtalking, 180, 180, 15, 1, 20, false)
+	sound_dialog_play_block pause
+	cm_interpolate IntroCamGriffin 0
+	sound_dialog_play c14_50_02griffin
+	cinematic_start (GRIFtalking, 180, 180, 16, 3, 20, true)
+	sound_dialog_play_block pause
+	#TCTF walks out
+	sound_music_start atm_low_perc2 0.8
+	cm_interpolate IntroCam02 0
+	playback 1202 IntroTCTF02
+	sound_dialog_play c14_50_03scigoon1
+	sleep f240
+	cinematic_stop (COPtalking, 15, 20)
+	cinematic_stop (GRIFtalking, 15, 20)
+	sleep f60
+	door_open 70
+	door_jam 70
+	sleep f100
+	#KONOKO on roof
+	playback 0 IntroKonoko01
+	cm_interpolate IntroCamInside01 0
+	cm_interpolate_block IntroCamInside02 400
+	sleep f400
+	cm_anim both IntroCamRoof
+	sleep f210
+	#Konoko falls into view
+	cm_anim both IntroCamFall01
+	chr_envanim 0 IntroKonBox01 norotation
+	chr_animate 0 KONOKOlev18_IntroFall01 140
+	#Griffin gets surprised
+	chr_delete 1202
+	cm_anim_block both IntroCamStand01
+	chr_envanim 1201 IntroGriffinBox02 norotation
+	chr_animate 1201 GRIFINlev18_IntroStand 110
+	env_anim 401 401
+	sleep f88
+	#Konoko enters office
+	playback 0 IntroKonoko02
+	cm_interpolate_block IntroCamKonAim01 0
+	cm_interpolate_block IntroCamKonAim02 350
+	sleep f140
+	cinematic_start(KONangryfront, 180, 180, 18, 6, 30, true)
+	sound_dialog_play c14_50_04konoko
+	sound_dialog_play_block pause
+	cinematic_stop (KONangryfront, 18, 30)
+	#Conversation with Griffin
+	playback 1201 IntroGriffin
+	cm_interpolate IntroCamGriffin02 0
+	cinematic_start(GRIFtalkangry, 180,180,18,6,30, true)
+	sound_dialog_play c14_50_05griffin
+	sound_dialog_play_block pause
+	cinematic_stop (GRIFtalkangry, 18, 30)
+	#Griffin's office goes down
+	sound_music_volume atm_low_perc2 0.0 0.5
+	sound_music_stop atm_low_perc2
+	music_intro
+	env_show 403 0
+	obj_create 403 403
+	cm_anim both IntroCamEscape01
+	chr_envanim 1201 IntroGriffinBox03 norotation
+	env_setanim 401 IntroChair02
+	env_anim 402 407
+	cutscene_sync mark
+	sound_ambient_start c14_46_11grifdesk
+	sleep f16
+	playback 0 IntroKonokoAim fromhere
+	cm_anim_block both IntroCamEscape02
+	cm_wait
+	cm_reset
+	obj_kill 401 407
+	# look out Stefan is editing scripts; yo foolios need to turn back on the laser sight :O)
+	marketing_line_off=0
+	end_cutscene
+	invincible=0
+	chr_delete 1201
+	door_unjam 70
+	door_close 70
+	# who is a foolio? the foo or the foo who follows him?
+	s1
+}
+
+
+func void
+GrifSpawn(
+	void)
+{
+	ai2_spawn ZomGrif
+	chr_invincible ZomGrif 1
+	sleep f2
+	ai2_passive ZomGrif 1
+	ai2_setmovementmode ZomGrif walk
+	playback ZomGrif ZomGrifDraw
+}
+
+func void create_zomshin(void)
+{
+	ai2_spawn ZomShin
+	ai2_passive ZomShin 1
+	chr_shadow ZomShin 0
+	chr_invincible ZomShin 1
+	chr_unstoppable ZomShin 1
+	chr_nocollision ZomShin 1
+	chr_neutral ZomShin 1
+	chr_lock_active ZomShin
+}
+
+func void
+Base(
+	void)
+{
+	begin_cutscene
+	#place Griffin here earlier
+	#chr_neutral ZomGrif 1
+	sleep f20
+	#playback ZomGrif BaseGriffin01
+	cm_interpolate BaseCam01 180
+	sleep f210
+	#place Konoko
+	playback 0 BaseKonoko01
+	cm_interpolate BaseCam02 0
+	cm_interpolate_block BaseCam04 500
+	sound_dialog_play c14_51_01konoko
+	cinematic_start(KONangryfront, 180,180,19,7,20, true)
+	sound_dialog_play_block pause
+	cinematic_stop (KONangryfront, 19, 20)
+	cm_interpolate BaseCam01 0
+	cm_interpolate_block BaseCam03 600
+	sound_dialog_play c14_51_02griffin
+	cinematic_start(GRIFtalkangry, 180,180,20,9,20, true)
+	sound_dialog_play_block pause
+	cutscene_sync mark
+	sound_ambient_start c15_04_23_effects
+	sound_dialog_play c14_51_03griffin
+	#Shinzom comes out of ground
+	create_zomshin
+	chr_envanim ZomShin ChairShinBox01
+	obj_create 171 174
+	env_anim 171 174
+	obj_shade 171 174 .5 .5 .5
+	cm_anim both ChairCamZomUp
+	#chr_create ZomShin start
+	#chr_neutral ZomShin 1
+	sleep f270
+	particle zombiespark pulse
+
+	cm_wait
+
+	particle zombient start
+	#hide Chair object, show chair gunk
+	env_show 171 1
+	env_show 172 1
+	env_show 173 1
+	env_show 174 1
+	obj_kill 171 174
+	cm_interpolate BaseCamShin01 0
+	playback ZomShin BaseShin
+	cm_interpolate_block BaseCamShin02 300
+	sound_dialog_play_block
+	cinematic_stop (GRIFtalkangry, 20, 20)
+	sound_dialog_play c14_51_04shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,7,20, false)
+	sound_dialog_play_block
+	cinematic_stop (SHINZOMlistening, 19, 20)
+	sleep f30
+	particle Forcefield do start
+	sound_ambient_start zomshin_amb_loop 0.1
+	sound_ambient_volume zomshin_amb_loop 1.0 1.0
+	cm_interpolate BaseCam02 0
+	sound_dialog_play c14_51_05konoko
+	cinematic_start(KONscared, 180,180,20,9,20, true)
+	sound_dialog_play_block
+	cinematic_stop (KONscared, 20, 20)
+	playback ZomShin BaseShin
+	cm_interpolate_block BaseCamShin02 0
+	sound_dialog_play c14_51_06shinatama
+	cinematic_start(SHINZOMlistening, 180,180,19,7,20, false)
+	particle zombiesteam start
+	sound_dialog_play_block pause
+	cinematic_stop (SHINZOMlistening, 19, 20)
+#	cm_reset
+#	trig_show 9
+#	trig_activate 9
+	end_cutscene
+	music_zom
+	ai2_passive ZomShin 1
+	ai2_makeignoreplayer ZomGrif 1
+	zombie_round_2
+#	ai2_allpassive 1
+#	remove line below after zomshin puzzle is fixed
+#	Zom
+}
+
+func void fade_out_zom_amb(void)
+{
+	sound_ambient_volume zomshin_amb_loop 0.0 1.0
+	sleep 60
+	sound_ambient_stop zomshin_amb_loop
+}
+
+func void
+Zom(
+	void)
+{
+	env_show 1010 0
+	particle Forcefield do stop
+	fork fade_out_zom_amb
+	begin_cutscene
+	marketing_line_off=1
+	#Shinatama will already be created
+	#show the destruction of the turrets and the forcefield around Griffin
+	#cm_interpolate ZomCamGrif01 0
+	ai2_setmovementmode ZomGrif walk
+	playback ZomGrif ZomGrifDrawSet
+	#sleep f120
+	#Shinatama gets up out of chair
+	chr_shadow ZomShin 1
+	chr_invincible ZomShin 0
+	chr_unstoppable ZomShin 0
+	chr_envanim ZomShin ZomShinBox01 norotation
+	chr_animate ZomShin SHINZOMlev18_Free
+	cm_anim both ZomCamFree01
+	sleep f90
+	cutscene_sync mark
+	sound_ambient_start c_shin_escape
+	cm_wait
+	#Griffin says "what are you doing?"
+	cm_interpolate ZomCamGrif01 0
+	sound_dialog_play c14_52_01griffin
+	cinematic_start(GRIFtalkangry, 180,180,19,7,20, false)
+	sound_dialog_play_block
+	cinematic_stop(GRIFtalkangry, 19,20)
+	#Shinatama approaches Griffin
+	cm_interpolate ZomCamShinStart 0
+	playback ZomShin ZomShinSet
+	chr_animate ZomShin SHINZOMwalk1 180
+	chr_nocollision ZomShin 0
+	sleep f175
+	#Griffin says GET BACK OR I'll SHOOT
+	#cm_interpolate ZomCamGrif01 0
+	#playback ZomGrif ZomGrifDrawSet
+	#sleep f120
+	#Shin keeps coming
+	#cm_interpolate ZomCamShinApproach 0
+	playback ZomShin ZomShinWalk
+	chr_animate ZomShin SHINZOMwalk1 600
+	#sleep f120
+	#Griffin draws weapon
+	cm_interpolate ZomCamGrif01 0
+	playback ZomGrif ZomGrifDrawSet
+	sleep f30
+	#sound_dialog_play c14_52_01bgriffin
+	playback ZomGrif ZomGrifDraw
+	sleep f60
+	#konoko drops weapon
+	playback 0 ZomKonokoDrop
+	#Shinatama Approaches Griffin
+	cm_interpolate ZomCamBoth 0
+	sleep f180
+	#Griffin shoots
+	cm_interpolate ZomCamGrifShoot 0
+	playback ZomGrif ZomGrifShoot
+	sleep f50
+	#Shinatama gets hit
+	cm_interpolate ZomCamShinDie 0
+	chr_animate ZomShin SHINZOMshot 126
+	sound_ambient_start c_shin_die 1.0
+	sleep f120
+	#Show Griffin over Shinatama
+	cm_interpolate ZomCamDead 0
+	playback ZomGrif ZomGriffinKilled
+	chr_animate ZomShin SHINZOMfallen_front 1000
+	sleep f10
+	cm_interpolate ZomCamKonokoBehind 270
+	playback 0 ZomKonokoBehind
+	sleep f280
+	#Griffin turns and gets thrown
+	# CB: we force omnipotent off because it breaks this cutscene (you kill
+	# griffin prematurely)
+	omnipotent = 0
+	chr_invincible ZomGrif 0
+	ai2_kill ZomShin
+	chr_neutral ZomGrif 0
+	cm_interpolate ZomCamThrow 0
+	playback ZomGrif ZomGriffinTurn
+	playback 0 ZomKonokoThrow
+	sleep f140
+	#Knoko holds him down
+	cm_interpolate ZomCamKonokoAim02 0
+	chr_neutral ZomGrif 1
+	chr_envanim ZomGrif ZomGriffinBox01 norotation
+	chr_envanim 0 ZomKonokoBox01 norotation
+	chr_animate 0 KONOKOlev18_ZomAim 300
+	chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	sound_dialog_play c14_52_02konoko
+	cinematic_start(KONangryfront, 180,180,19,7,20, false)
+	sound_dialog_play_block pause
+	#Looking down at griffin
+	#chr_envanim 0 ZomKonokoBox01 norotation
+	#chr_envanim ZomGrif ZomGriffinBox01 norotation
+	#chr_animate 0 KONOKOlev18_ZomAim 300
+	#chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	#cm_interpolate ZomCamKonokoAim01 0
+	#KONoko gets off Griffin
+	#cm_interpolate ZomCamKonokoAim02 0
+	chr_envanim 0 ZomKonokoBox02 norotation
+	chr_envanim ZomGrif ZomGriffinBox01 norotation
+	chr_animate ZomGrif GRIFINlev18_ZomAim 500
+	chr_animate 0 KONOKOlev18_ZomUp 120
+	#sound_dialog_play c14_52_04konoko
+	#Griffin gets up put the gun down
+	sleep f100
+	cm_interpolate ZomCamGriffinUp 0
+	chr_envanim ZomGrif ZomGriffinBox02 norotation
+	chr_animate ZomGrif GRIFINlev18_ZomUp
+	sound_dialog_play c14_52_03griffin
+	cinematic_start(GRIFbeatup, 180, 180, 20, 9, 20, true)
+	sound_dialog_play_block pause
+	#Konoko I'm a rogue agent, very dangerous
+	playback 0 ZomKonokoFace
+	cm_interpolate ZomCamKonokoFace 0
+	sound_dialog_play c14_52_04konoko
+	sound_dialog_play_block pause
+	#Griffin says youre a monster
+	cm_interpolate ZomCamGriffinFace 0
+	playback ZomGrif ZomGriffinFace
+	sound_dialog_play c14_52_05griffin
+	sound_dialog_play_block pause
+	#for you, badly
+	cm_interpolate ZomCamKonokoFace 0
+	sound_dialog_play c14_52_06konoko
+	sound_dialog_play_block pause
+	#Griffin says youre a monster
+	cm_interpolate ZomCamGriffinFace 0
+	sound_dialog_play c14_52_07griffin
+	sound_dialog_play_block pause
+	cinematic_stop(GRIFbeatup, 20, 20)
+	cinematic_stop(KONangryfront, 19, 20)
+	#Give player back control
+	cm_reset
+	end_cutscene
+	ai2_allpassive 1
+	chr_set_health ZomGrif 1
+	marketing_line_off=0
+	trigvolume_enable trigger_volume_35 1
+	objective_set(5)
+}
+
+func void
+OutroKill(
+	void)
+{
+	sound_music_start mus_wls 1.0
+	begin_cutscene jello
+	sleep f40
+	sound_dialog_play c14_53_01konoko
+	cinematic_start(KONintense, 180,180,19,8,20, false)
+	sound_dialog_play_block
+	cinematic_stop (KONintense, 19, 20)
+	fade_out 0 0 0 120
+	sleep f120
+	end_cutscene
+	win
+}
+
+
+func void
+OutroNoKill(
+	void)
+{
+	begin_cutscene jello
+	cm_detach
+	ai2_takecontrol 1
+	ai2_lookatchar 0 ZomGrif
+	ai2_lookatchar ZomGrif 0
+	sound_music_start mus_sad1
+	sound_dialog_play c14_54_01konoko
+	cinematic_start(KONlistening, 180,180,19,8,20, false)
+	sleep f120
+	cm_interpolate BaseCam01 180
+	sound_dialog_play_block
+	cinematic_stop (KONlistening, 19, 20)
+	fade_out 0 0 0 120
+	sleep f120
+	end_cutscene
+	win
+}
Index: /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_main.bsl
===================================================================
--- /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_main.bsl	(revision 185)
+++ /nikanabo/current/bsl/original/IGMD/tctf_ii/tctf_ii_main.bsl	(revision 185)
@@ -0,0 +1,49 @@
+#
+# tctf_ii_main.bsl
+#
+
+func void main(void)
+{
+	env_shade 321 325 .3 .3 .3
+	gl_fog_blue=0
+	gl_fog_red=0
+	gl_fog_green=0
+	gl_fog_start=.995
+	gs_farclipplane_set 5000
+	#hide trigger for Base
+	trig_hide 9
+	#Hide Chair Gunk
+	env_show 171 0
+	env_show 172 0
+	env_show 173 0
+	env_show 174 0
+
+##### THEESE TRIGGERS ARE FOR ZOMBIE SHINATAMA ############
+
+	trig_hide 91
+	trig_hide 92
+	trig_hide 93
+	trig_hide 94
+
+	trig_hide 910
+
+	trig_hide 10
+
+	trig_hide 210
+	trig_hide 2101
+	trig_hide 214
+
+	trig_hide 310
+	trig_hide 3101
+	trig_hide 314
+
+	trig_hide 410
+	trig_hide 4101
+	trig_hide 414
+
+	trig_hide 510
+	trig_hide 5101
+	trig_hide 514
+	
+	start
+}
Index: /nikanabo/current/bsl/original/readme.txt
===================================================================
--- /nikanabo/current/bsl/original/readme.txt	(revision 185)
+++ /nikanabo/current/bsl/original/readme.txt	(revision 185)
@@ -0,0 +1,1 @@
+Original level logic for PC retail.
Index: /nikanabo/current/bsl/original/winstall.bat
===================================================================
--- /nikanabo/current/bsl/original/winstall.bat	(revision 185)
+++ /nikanabo/current/bsl/original/winstall.bat	(revision 185)
@@ -0,0 +1,14 @@
+echo off
+cd ..\mybackup
+IF NOT EXIST backupok.txt (
+    echo Level logic not backed up.
+    cd ..\original
+) ELSE (
+    echo Installing original level logic...
+    cd ..\..\..\GameDataFolder
+    rmdir /s /q IGMD
+    xcopy ..\nikanabo\bsl\original\IGMD IGMD /s /k /i
+    cd ..\nikanabo\bsl\original
+    echo Original level logic installed.
+)
+PAUSE
Index: /nikanabo/current/bsl/original/xinstall.sh
===================================================================
--- /nikanabo/current/bsl/original/xinstall.sh	(revision 185)
+++ /nikanabo/current/bsl/original/xinstall.sh	(revision 185)
@@ -0,0 +1,13 @@
+#!/bin/sh
+cd ../mybackup
+if [ ! -e backupok.txt ]
+    echo "User level logic not backed up."
+    cd ../original
+else
+    echo "Installing original level logic..."
+    cd ../../../GameDataFolder
+    rm -rf IGMD
+    cp -r ../nikanabo/bsl/original/IGMD .
+    cd ../nikanabo/bsl/original
+    echo "Original level logic installed."
+fi
Index: /nikanabo/current/bsl/readme.txt
===================================================================
--- /nikanabo/current/bsl/readme.txt	(revision 185)
+++ /nikanabo/current/bsl/readme.txt	(revision 185)
@@ -0,0 +1,10 @@
+Here you'll find various scripted mods.
+
+The original level logic is provided 
+(just run an installer in "original")
+There are minor differences between 
+the original logic for Mac and PC.
+(only in the final SP of tctf_ii)
+
+Check out ssg's cutscene-free version.
+Other mods will be available later.
Index: /nikanabo/current/dat/demoni/readme.txt
===================================================================
--- /nikanabo/current/dat/demoni/readme.txt	(revision 185)
+++ /nikanabo/current/dat/demoni/readme.txt	(revision 185)
@@ -0,0 +1,17 @@
+Enhanced game content for the PC demo.
+(Made with Oni Un/Packer and Xdelta3)
+
+level0_Demoni
+Unlocked all of Konoko's combos
+Fixed STRCOMcrouch_punch_fw
+Strikers and Comguys run faster ^^
+(Tankers, Thugs and Elites won't)
+Added weapons and firing modes.
+
+level1_Demoni
+comguy1 and comguy2 are Ninjas ^^
+Ninjas run faster than Konoko :)
+Dummy trio = Kojiro & friends.
+(melee profiles = Ninja hard)
+Death functions etc for those 3.
+Just type ai2_spawnall for now.
Index: /nikanabo/current/dat/demoni/wauthor.bat
===================================================================
--- /nikanabo/current/dat/demoni/wauthor.bat	(revision 185)
+++ /nikanabo/current/dat/demoni/wauthor.bat	(revision 185)
@@ -0,0 +1,23 @@
+echo off
+cd ..\..\xdelta
+IF NOT EXIST xdelta3.exe (
+    echo Couldn't find Xdelta3!
+) ELSE (
+    echo Xdelta3 detected!
+    echo Creating DemOni patches...
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.dat ..\..\GameDataFolder\level0_Final.dat ..\dat\demoni\level0_Demoni_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.dat ..\..\GameDataFolder\level1_Final.dat ..\dat\demoni\level1_Demoni_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.dat ..\..\GameDataFolder\level2_Final.dat ..\dat\demoni\level2_Demoni_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.dat ..\..\GameDataFolder\level4_Final.dat ..\dat\demoni\level4_Demoni_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.raw ..\..\GameDataFolder\level0_Final.raw ..\dat\demoni\level0_Demoni_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.raw ..\..\GameDataFolder\level1_Final.raw ..\dat\demoni\level1_Demoni_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.raw ..\..\GameDataFolder\level2_Final.raw ..\dat\demoni\level2_Demoni_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.raw ..\..\GameDataFolder\level4_Final.raw ..\dat\demoni\level4_Demoni_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.sep ..\..\GameDataFolder\level0_Final.sep ..\dat\demoni\level0_Demoni_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.sep ..\..\GameDataFolder\level1_Final.sep ..\dat\demoni\level1_Demoni_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.sep ..\..\GameDataFolder\level2_Final.sep ..\dat\demoni\level2_Demoni_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.sep ..\..\GameDataFolder\level4_Final.sep ..\dat\demoni\level4_Demoni_.sep.x3d
+    echo DemOni patches created.
+)
+cd ..\dat\demoni
+PAUSE
Index: /nikanabo/current/dat/demoni/winstall.bat
===================================================================
--- /nikanabo/current/dat/demoni/winstall.bat	(revision 185)
+++ /nikanabo/current/dat/demoni/winstall.bat	(revision 185)
@@ -0,0 +1,28 @@
+echo off
+cd ..\original
+IF NOT EXIST backupok.txt (
+    echo Please back up your game content.
+    cd ..\demoni
+) ELSE (
+    cd ..\..\xdelta
+    IF NOT EXIST xdelta3.exe (
+        echo Couldn't find Xdelta3!
+    ) ELSE (
+        echo Xdelta3 detected!
+        echo Applying DemOni patches...
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.dat ..\dat\demoni\level0_Demoni.dat.x3d ..\..\GameDataFolder\level0_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.dat ..\dat\demoni\level1_Demoni.dat.x3d ..\..\GameDataFolder\level1_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.dat ..\dat\demoni\level2_Demoni.dat.x3d ..\..\GameDataFolder\level2_Final.dat 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.dat ..\dat\demoni\level4_Demoni.dat.x3d ..\..\GameDataFolder\level4_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.raw ..\dat\demoni\level0_Demoni.raw.x3d ..\..\GameDataFolder\level0_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.raw ..\dat\demoni\level1_Demoni.raw.x3d ..\..\GameDataFolder\level1_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.raw ..\dat\demoni\level2_Demoni.raw.x3d ..\..\GameDataFolder\level2_Final.raw 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.raw ..\dat\demoni\level4_Demoni.raw.x3d ..\..\GameDataFolder\level4_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.sep ..\dat\demoni\level0_Demoni.sep.x3d ..\..\GameDataFolder\level0_Final.sep
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.sep ..\dat\demoni\level1_Demoni.sep.x3d ..\..\GameDataFolder\level1_Final.sep
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.sep ..\dat\demoni\level2_Demoni.sep.x3d ..\..\GameDataFolder\level2_Final.sep 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.sep ..\dat\demoni\level4_Demoni.sep.x3d ..\..\GameDataFolder\level4_Final.sep
+    )
+    cd ..\dat\demoni
+)
+PAUSE
Index: /nikanabo/current/dat/demoni/xauthor.sh
===================================================================
--- /nikanabo/current/dat/demoni/xauthor.sh	(revision 185)
+++ /nikanabo/current/dat/demoni/xauthor.sh	(revision 185)
@@ -0,0 +1,22 @@
+#!/bin/sh
+cd ../../xdelta
+if [ ! -e xdelta3.exe ]
+    echo "Couldn't find Xdelta3!"
+else
+    echo "Xdelta3 detected!"
+    echo "Creating DemOni patches..."
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.dat ../../GameDataFolder/level0_Final.dat ../dat/demoni/level0_Demoni.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.dat ../../GameDataFolder/level1_Final.dat ../dat/demoni/level1_Demoni.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.dat ../../GameDataFolder/level2_Final.dat ../dat/demoni/level2_Demoni.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.dat ../../GameDataFolder/level4_Final.dat ../dat/demoni/level4_Demoni.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.raw ../../GameDataFolder/level0_Final.raw ../dat/demoni/level0_Demoni.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.raw ../../GameDataFolder/level1_Final.raw ../dat/demoni/level1_Demoni.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.raw ../../GameDataFolder/level2_Final.raw ../dat/demoni/level2_Demoni.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.raw ../../GameDataFolder/level4_Final.raw ../dat/demoni/level4_Demoni.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.sep ../../GameDataFolder/level0_Final.sep ../dat/demoni/level0_Demoni.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.sep ../../GameDataFolder/level1_Final.sep ../dat/demoni/level1_Demoni.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.sep ../../GameDataFolder/level2_Final.sep ../dat/demoni/level2_Demoni.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.sep ../../GameDataFolder/level4_Final.sep ../dat/demoni/level4_Demoni.sep.x3d
+    echo "DemOni patches created."
+fi
+cd ../dat/demoni
Index: /nikanabo/current/dat/demoni/xinstall.sh
===================================================================
--- /nikanabo/current/dat/demoni/xinstall.sh	(revision 185)
+++ /nikanabo/current/dat/demoni/xinstall.sh	(revision 185)
@@ -0,0 +1,27 @@
+#!/bin/sh
+cd ../original
+if [ ! -e backupok.txt ]
+    echo "Please back up your game content."
+    cd ../demoni
+else
+    cd ../../xdelta
+    if [ ! -e xdelta3.exe ]
+        echo "Couldn't find Xdelta3!"
+    else
+        echo "Xdelta3 detected!"
+        echo "Applying DemOni patches..."
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.dat ../dat/demoni/level0_Demoni.dat.x3d ../../GameDataFolder/level0_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.dat ../dat/demoni/level1_Demoni.dat.x3d ../../GameDataFolder/level1_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.dat ../dat/demoni/level2_Demoni.dat.x3d ../../GameDataFolder/level2_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.dat ../dat/demoni/level4_Demoni.dat.x3d ../../GameDataFolder/level4_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.raw ../dat/demoni/level0_Demoni.raw.x3d ../../GameDataFolder/level0_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.raw ../dat/demoni/level1_Demoni.raw.x3d ../../GameDataFolder/level1_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.raw ../dat/demoni/level2_Demoni.raw.x3d ../../GameDataFolder/level2_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.raw ../dat/demoni/level4_Demoni.raw.x3d ../../GameDataFolder/level4_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.sep ../dat/demoni/level0_Demoni.sep.x3d ../../GameDataFolder/level0_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.sep ../dat/demoni/level1_Demoni.sep.x3d ../../GameDataFolder/level1_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.sep ../dat/demoni/level2_Demoni.sep.x3d ../../GameDataFolder/level2_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.sep ../dat/demoni/level4_Demoni.sep.x3d ../../GameDataFolder/level4_Final.sep
+    fi
+    cd ../dat/demoni
+fi
Index: /nikanabo/current/dat/demonix/readme.txt
===================================================================
--- /nikanabo/current/dat/demonix/readme.txt	(revision 185)
+++ /nikanabo/current/dat/demonix/readme.txt	(revision 185)
@@ -0,0 +1,16 @@
+Enhanced game content for the PC demo.
+(Made with Oni Un/Packer and Xdelta3)
+
+level0_Demoni
+Unlocked all of Konoko's combos
+Fixed STRCOMcrouch_punch_fw
+Strikers and Comguys run faster ^^
+(Tankers, Thugs and Elites won't)
+Added weapons and firing modes.
+
+level1_Demoni
+comguy1 and comguy2 are Ninjas ^^
+Ninjas run faster than Konoko :)
+Dummy trio = Kojiro & friends.
+(melee profiles= Ninja hard)
+Death functions etc for those 3.
Index: /nikanabo/current/dat/demonix/wauthor.bat
===================================================================
--- /nikanabo/current/dat/demonix/wauthor.bat	(revision 185)
+++ /nikanabo/current/dat/demonix/wauthor.bat	(revision 185)
@@ -0,0 +1,23 @@
+echo off
+cd ..\..\xdelta
+IF NOT EXIST xdelta3.exe (
+    echo Couldn't find Xdelta3!
+) ELSE (
+    echo Xdelta3 detected!
+    echo Creating DemOniX patches...
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.dat ..\..\GameDataFolder\level0_Final.dat ..\dat\demonix\level0_DemoniX_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.dat ..\..\GameDataFolder\level1_Final.dat ..\dat\demonix\level1_DemoniX_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.dat ..\..\GameDataFolder\level2_Final.dat ..\dat\demonix\level2_DemoniX_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.dat ..\..\GameDataFolder\level4_Final.dat ..\dat\demonix\level4_DemoniX_.dat.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.raw ..\..\GameDataFolder\level0_Final.raw ..\dat\demonix\level0_DemoniX_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.raw ..\..\GameDataFolder\level1_Final.raw ..\dat\demonix\level1_DemoniX_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.raw ..\..\GameDataFolder\level2_Final.raw ..\dat\demonix\level2_DemoniX_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.raw ..\..\GameDataFolder\level4_Final.raw ..\dat\demonix\level4_DemoniX_.raw.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level0_Final.sep ..\..\GameDataFolder\level0_Final.sep ..\dat\demonix\level0_DemoniX_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level1_Final.sep ..\..\GameDataFolder\level1_Final.sep ..\dat\demonix\level1_DemoniX_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level2_Final.sep ..\..\GameDataFolder\level2_Final.sep ..\dat\demonix\level2_DemoniX_.sep.x3d
+    xdelta3.exe -e -f -s ..\dat\original\level4_Final.sep ..\..\GameDataFolder\level4_Final.sep ..\dat\demonix\level4_DemoniX_.sep.x3d
+    echo DemOniX patches created.
+)
+cd ..\dat\demonix
+PAUSE
Index: /nikanabo/current/dat/demonix/winstall.bat
===================================================================
--- /nikanabo/current/dat/demonix/winstall.bat	(revision 185)
+++ /nikanabo/current/dat/demonix/winstall.bat	(revision 185)
@@ -0,0 +1,28 @@
+echo off
+cd ..\original
+IF NOT EXIST backupok.txt (
+    echo "Please back up your game content."
+    cd ..\demonix
+) ELSE (
+    cd ..\..\xdelta
+    IF NOT EXIST xdelta3.exe (
+        echo "Couldn't find Xdelta3!"
+    ) ELSE (
+        echo "Xdelta3 detected!"
+        echo "Applying DemOniX patches..."
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.dat ..\dat\demonix\level0_DemoniX.dat.x3d ..\..\GameDataFolder\level0_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.dat ..\dat\demonix\level1_DemoniX.dat.x3d ..\..\GameDataFolder\level1_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.dat ..\dat\demonix\level2_DemoniX.dat.x3d ..\..\GameDataFolder\level2_Final.dat 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.dat ..\dat\demonix\level4_DemoniX.dat.x3d ..\..\GameDataFolder\level4_Final.dat
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.raw ..\dat\demonix\level0_DemoniX.raw.x3d ..\..\GameDataFolder\level0_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.raw ..\dat\demonix\level1_DemoniX.raw.x3d ..\..\GameDataFolder\level1_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.raw ..\dat\demonix\level2_DemoniX.raw.x3d ..\..\GameDataFolder\level2_Final.raw 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.raw ..\dat\demonix\level4_DemoniX.raw.x3d ..\..\GameDataFolder\level4_Final.raw
+        xdelta3.exe -d -f -s ..\dat\original\level0_Final.sep ..\dat\demonix\level0_DemoniX.sep.x3d ..\..\GameDataFolder\level0_Final.sep
+        xdelta3.exe -d -f -s ..\dat\original\level1_Final.sep ..\dat\demonix\level1_DemoniX.sep.x3d ..\..\GameDataFolder\level1_Final.sep
+        xdelta3.exe -d -f -s ..\dat\original\level2_Final.sep ..\dat\demonix\level2_DemoniX.sep.x3d ..\..\GameDataFolder\level2_Final.sep 
+        xdelta3.exe -d -f -s ..\dat\original\level4_Final.sep ..\dat\demonix\level4_DemoniX.sep.x3d ..\..\GameDataFolder\level4_Final.sep
+    )
+    cd ..\dat\demonix
+)
+PAUSE
Index: /nikanabo/current/dat/demonix/xauthor.sh
===================================================================
--- /nikanabo/current/dat/demonix/xauthor.sh	(revision 185)
+++ /nikanabo/current/dat/demonix/xauthor.sh	(revision 185)
@@ -0,0 +1,22 @@
+﻿#!/bin/sh
+cd ../../xdelta
+if [ ! -e xdelta3.exe ]
+    echo "Couldn't find Xdelta3!"
+else
+    echo "Xdelta3 detected!"
+    echo "Creating DemOniX patches..."
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.dat ../../GameDataFolder/level0_Final.dat ../dat/demonix/level0_DemOniX_.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.dat ../../GameDataFolder/level1_Final.dat ../dat/demonix/level1_DemOniX_.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.dat ../../GameDataFolder/level2_Final.dat ../dat/demonix/level2_DemOniX_.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.dat ../../GameDataFolder/level4_Final.dat ../dat/demonix/level4_DemOniX_.dat.x3d
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.raw ../../GameDataFolder/level0_Final.raw ../dat/demonix/level0_DemOniX_.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.raw ../../GameDataFolder/level1_Final.raw ../dat/demonix/level1_DemOniX_.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.raw ../../GameDataFolder/level2_Final.raw ../dat/demonix/level2_DemOniX_.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.raw ../../GameDataFolder/level4_Final.raw ../dat/demonix/level4_DemOniX_.raw.x3d
+    xdelta3.exe -e -f -s ../dat/original/level0_Final.sep ../../GameDataFolder/level0_Final.sep ../dat/demonix/level0_DemOniX_.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level1_Final.sep ../../GameDataFolder/level1_Final.sep ../dat/demonix/level1_DemOniX_.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level2_Final.sep ../../GameDataFolder/level2_Final.sep ../dat/demonix/level2_DemOniX_.sep.x3d
+    xdelta3.exe -e -f -s ../dat/original/level4_Final.sep ../../GameDataFolder/level4_Final.sep ../dat/demonix/level4_DemOniX_.sep.x3d
+    echo "DemOniX patches created."
+fi
+cd ../dat/demonix
Index: /nikanabo/current/dat/demonix/xinstall.sh
===================================================================
--- /nikanabo/current/dat/demonix/xinstall.sh	(revision 185)
+++ /nikanabo/current/dat/demonix/xinstall.sh	(revision 185)
@@ -0,0 +1,27 @@
+#!/bin/sh
+cd ../original
+if [ ! -e backupok.txt ]
+    echo "Please back up your game content."
+    cd ../demonix
+else
+    cd ../../xdelta
+    if [ ! -e xdelta3.exe ]
+        echo "Couldn't find Xdelta3!"
+    else
+        echo "Xdelta3 detected!"
+        echo "Applying DemOniX patches..."
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.dat ../dat/demonix/level0_DemOniX.dat.x3d ../../GameDataFolder/level0_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.dat ../dat/demonix/level1_DemOniX.dat.x3d ../../GameDataFolder/level1_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.dat ../dat/demonix/level2_DemOniX.dat.x3d ../../GameDataFolder/level2_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.dat ../dat/demonix/level4_DemOniX.dat.x3d ../../GameDataFolder/level4_Final.dat
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.raw ../dat/demonix/level0_DemOniX.raw.x3d ../../GameDataFolder/level0_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.raw ../dat/demonix/level1_DemOniX.raw.x3d ../../GameDataFolder/level1_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.raw ../dat/demonix/level2_DemOniX.raw.x3d ../../GameDataFolder/level2_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.raw ../dat/demonix/level4_DemOniX.raw.x3d ../../GameDataFolder/level4_Final.raw
+        xdelta3.exe -d -f -s ../dat/original/level0_Final.sep ../dat/demonix/level0_DemOniX.sep.x3d ../../GameDataFolder/level0_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level1_Final.sep ../dat/demonix/level1_DemOniX.sep.x3d ../../GameDataFolder/level1_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level2_Final.sep ../dat/demonix/level2_DemOniX.sep.x3d ../../GameDataFolder/level2_Final.sep
+        xdelta3.exe -d -f -s ../dat/original/level4_Final.sep ../dat/demonix/level4_DemOniX.sep.x3d ../../GameDataFolder/level4_Final.sep
+    fi
+    cd ../dat/demonix
+fi
Index: /nikanabo/current/dat/original/nobackup.txt
===================================================================
--- /nikanabo/current/dat/original/nobackup.txt	(revision 185)
+++ /nikanabo/current/dat/original/nobackup.txt	(revision 185)
@@ -0,0 +1,16 @@
+The name of this file indicates the 
+backup state of your game content.
+
+backupok.txt
+	Your game content logic is backed up
+	here. You can install binary mods.
+
+nobackup.txt
+	Your game content is not backed up.
+	Please run a backup from Oni\nikanabo
+	wbackup.bat	for Windows
+	xbackup.sh	for Mac/Linux
+
+Do not delete this file.
+A backup of the original game content is 
+necessary bor binary mods (patches) to work.
Index: /nikanabo/current/dat/original/readme.txt
===================================================================
--- /nikanabo/current/dat/original/readme.txt	(revision 185)
+++ /nikanabo/current/dat/original/readme.txt	(revision 185)
@@ -0,0 +1,9 @@
+Here you'll find various binary mods.
+
+Before you install a binary mod, you'll have to 
+run a backup from the main "nikanabo" folder.
+
+Xdelta-based mods will only work with certain 
+versions of Oni (e.g., Mac or PC demo).
+(you can set up Xdelta in "nikanabo/xdelta")
+Database-powered mods will be more flexible.
Index: /nikanabo/current/dat/original/winstall.bat
===================================================================
--- /nikanabo/current/dat/original/winstall.bat	(revision 185)
+++ /nikanabo/current/dat/original/winstall.bat	(revision 185)
@@ -0,0 +1,13 @@
+echo off
+IF NOT EXIST backupok.txt (
+    echo Game content not backed up!
+) ELSE (
+    echo Restoring original game content...
+    cd ..\..\..\GameDataFolder
+    copy ..\nikanabo\dat\original\*.dat .
+    copy ..\nikanabo\dat\original\*.raw .
+    copy ..\nikanabo\dat\original\*.sep .
+    cd ..\nikanabo\dat\original
+    echo Original game content restored.
+)
+PAUSE
Index: /nikanabo/current/dat/original/xinstall.sh
===================================================================
--- /nikanabo/current/dat/original/xinstall.sh	(revision 185)
+++ /nikanabo/current/dat/original/xinstall.sh	(revision 185)
@@ -0,0 +1,13 @@
+#!/bin/sh
+if [ ! -e backupok.txt ]
+then
+    echo "Game content not backed up!"
+else
+    echo "Restoring original game content..."
+    cd ../../../GameDataFolder
+    cp ../nikanabo/dat/original/*.dat .
+    cp ../nikanabo/dat/original/*.raw .
+    cp ../nikanabo/dat/original/*.sep .
+    cd ../nikanabo/dat/original
+    echo "Original game content restored."
+fi
Index: /nikanabo/current/readme.txt
===================================================================
--- /nikanabo/current/readme.txt	(revision 185)
+++ /nikanabo/current/readme.txt	(revision 185)
@@ -0,0 +1,61 @@
+Welcome to ONI NI KANABO... (beta ^^)
+This should be Oni/nikanabo/readme.txt
+______________________________
+
+Scripted mods are in the "bsl" folder
+Binary mods are in the "dat" folder
+Xdelta (binary patcher) is in "xdelta".
+
+In every mod's folder you will find 
+- a description of the mod (text file)
+- one or more installers (shell scripts)
+- possibly (later) descriptors for GUI
+- other stuff (screenshots, whatever)
+
+More generally, in every folder you'll 
+find a text file telling you what there 
+is there, and what you're supposed to do.
+______________________________
+
+Windows folks: just click the batch files.
+Mac and Linux folks: terminal only, sorry.
+
+On most UNIX platforms, the current directory 
+AKA "." is not part of the PATH variable, so
+"whatever.sh" won't work. Use "sh whatever.sh" 
+or just "./whatever.sh"
+
+Autocompletion should make things bearable.
+A *portable* GUI is of course very welcome ^^
+______________________________
+
+New mod contributors are invited to pack the 
+whole tree with their mod, like this:
+nikanabo/bsl/mod_name/*.*
+nikanabo/dat/mod_name/*.*
+so users only have to unzip it into "Oni".
+______________________________
+
+BACKUPS : IMPORTANT
+
+Before you install any mod, you'll have to 
+run the proper backup script for your 
+platform, namely:
+	wbackup.bat	for Windows
+	xbackup.sh	for Mac/Linux
+
+The installer scripts provided will complain 
+if the backup is missing (and do nothing).
+______________________________
+
+PERMISSIONS: NOTE TO EXPERTS ^^
+
+Depending on your system, you may 
+need to enable the execute permission 
+manually for the script to run, e.g.: 
+
+chmod +x xbackup.sh
+
+From what I've seen, this is never needed, 
+since non-read-only content seems to get 
+"rwxr-xr-x" by default on Mac and Linux.
Index: /nikanabo/current/wbackup.bat
===================================================================
--- /nikanabo/current/wbackup.bat	(revision 185)
+++ /nikanabo/current/wbackup.bat	(revision 185)
@@ -0,0 +1,36 @@
+echo off
+cd dat\original
+IF NOT EXIST ..\..\..\GameDataFolder (
+    echo Can't find GameDataFolder!
+    echo Make sure this is Oni\nikanabo
+) ELSE (
+    echo GameDataFolder detected!
+    IF EXIST backupok.txt (
+        echo Game content already backed up.
+    ) ELSE (
+        echo Backing up game content...
+        copy ..\..\..\GameDataFolder\*.dat .
+        copy ..\..\..\GameDataFolder\*.raw .
+        copy ..\..\..\GameDataFolder\*.sep .
+        echo Game content backup complete.
+        move nobackup.txt backupok.txt
+    )
+)
+cd ..\..
+cd bsl\mybackup
+IF NOT EXIST ..\..\..\GameDataFolder\IGMD (
+    echo Can't find IGMD folder!
+    echo Make sure this is Oni\nikanabo
+) ELSE (
+    echo IGMD folder detected!
+    IF EXIST backupok.txt (
+        echo Level logic already backed up.
+    ) ELSE (
+        echo Backing up level logic...
+        xcopy ..\..\..\GameDataFolder\IGMD IGMD /s /k /i
+        echo Level logic backup complete.
+        move nobackup.txt backupok.txt
+    )
+)
+cd ..\..
+PAUSE
Index: /nikanabo/current/xbackup.sh
===================================================================
--- /nikanabo/current/xbackup.sh	(revision 185)
+++ /nikanabo/current/xbackup.sh	(revision 185)
@@ -0,0 +1,39 @@
+#!/bin/sh
+cd dat/original
+if [ ! -e ../../../GameDataFolder ]
+then
+    echo "Can't find GameDataFolder!"
+    echo "Make sure this is Oni/nikanabo"
+else
+    echo "GameDataFolder detected!"
+    if [ -e backupok.txt ]
+    then
+        echo "Game content already backed up."
+    else
+        echo "Backing up game content..."
+        cp ../../../GameDataFolder/*.dat .
+        cp ../../../GameDataFolder/*.raw .
+        cp ../../../GameDataFolder/*.sep .
+        echo "Game content backup complete."
+        mv nobackup.txt backupok.txt
+    fi
+fi
+cd ../..
+cd bsl/mybackup
+if [ ! -e ../../../GameDataFolder/IGMD ]
+then
+    echo "Can't find IGMD folder!"
+    echo "Make sure this is Oni/nikanabo"
+else
+    echo "IGMD folder detected!"
+    if [ -e backupok.txt ]
+    then
+        echo "Level logic already backed up."
+    else
+        echo "Backing up level logic..."
+        cp -r ../../../GameDataFolder/IGMD IGMD
+        echo "Level logic backup complete."
+        mv nobackup.txt backupok.txt
+    fi
+fi
+cd ../..
Index: /nikanabo/current/xdelta/diy/COPYING
===================================================================
--- /nikanabo/current/xdelta/diy/COPYING	(revision 185)
+++ /nikanabo/current/xdelta/diy/COPYING	(revision 185)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /nikanabo/current/xdelta/diy/Makefile
===================================================================
--- /nikanabo/current/xdelta/diy/Makefile	(revision 185)
+++ /nikanabo/current/xdelta/diy/Makefile	(revision 185)
@@ -0,0 +1,200 @@
+# xdelta 3 - delta compression tools and library
+# Copyright (C) 2001, 2003, 2004, 2005, 2006.  Joshua P. MacDonald
+
+SOURCES = xdelta3-cfgs.h \
+          xdelta3-decode.h \
+          xdelta3-djw.h \
+          xdelta3-fgk.h \
+          xdelta3-list.h \
+          xdelta3-main.h \
+          xdelta3-python.h \
+          xdelta3-second.h \
+          xdelta3-test.h \
+          xdelta3.c \
+          xdelta3.h
+
+TARGETS = xdelta3-debug \
+	  xdelta3.exe \
+	  xdelta3-debug2 \
+	  xdelta3-debug3 \
+	  xdelta3.o \
+	  xdelta3_wrap.o \
+	  xdelta3module.so \
+	  xdelta3-32 \
+	  xdelta3-64 \
+	  xdelta3-everything \
+	  xdelta3-Opg \
+	  xdelta3-64-O \
+	  xdelta3-Op \
+	  xdelta3-decoder xdelta3-decoder-nomain.o \
+	  xdelta3-nosec.o xdelta3-all.o xdelta3-fgk.o \
+	  xdelta3-noext xdelta3-tools xdelta3-tune \
+	  xdelta3-notools \
+	  xdelta3_wrap.c xdelta3.py \
+	  $(PYTGT) $(SWIGTGT)
+
+PYTHON = python
+
+SWIGTGT = xdelta3module.so
+#SWIGTGT = xdelta3module.dll
+
+PYTGT = build/lib.linux-i686-2.4/xdelta3main.so
+#PYTGT = build/lib.cygwin-1.5.24-i686-2.4/xdelta3main.dll
+
+EXTRA = Makefile COPYING linkxd3lib.c badcopy.c xdelta3.swig \
+        draft-korn-vcdiff.txt xdelta3.vcproj badcopy.vcproj \
+	xdelta3-regtest.py xdelta3-test.py setup.py \
+	examples/Makefile examples/small_page_test.c \
+	xdelta3.py xdelta3_wrap.c
+
+SWIG_FLAGS = -DXD3_DEBUG=0 \
+	      -DEXTERNAL_COMPRESSION=0 \
+	      -DXD3_USE_LARGEFILE64=1 \
+	      -DGENERIC_ENCODE_TABLES=1 \
+              -DSECONDARY_DJW=1 \
+	      -DVCDIFF_TOOLS=1 \
+              -DSWIG_MODULE=1 \
+	      -O3
+
+# $Format: "REL=$Xdelta3Version$" $
+REL=0q
+RELDIR = xdelta3$(REL)
+
+all: xdelta3-debug xdelta3
+
+all-py: all $(PYTGT) $(SWIGTGT)
+
+all-targets: $(TARGETS)
+
+all-targets-test: all-targets test
+
+pytgt: $(PYTGT)
+swigtgt: $(SWIGTGT)
+
+test:
+	./xdelta3-debug test
+
+tar:
+	tar --exclude ".svn" -czf /tmp/$(RELDIR)-tmp.tar.gz $(SOURCES) $(EXTRA)
+	rm -rf /tmp/$(RELDIR)
+	mkdir /tmp/$(RELDIR)
+	(cd /tmp/$(RELDIR) && tar -xzf ../$(RELDIR)-tmp.tar.gz)
+	tar -czf ./$(RELDIR).tar.gz -C /tmp $(RELDIR)
+	+tar -tzf ./$(RELDIR).tar.gz
+	rm -rf /tmp/$(RELDIR)
+
+clean:
+	rm -f $(TARGETS)
+	rm -rf build Debug Release core cifs* *.stackdump *.exe \
+		xdelta3.ncb xdelta3.suo xdelta3.sln
+
+xdelta3: $(SOURCES)
+	$(CC) -O3 -Wall -Wshadow xdelta3.c -lm -o xdelta3.exe \
+              -DXD3_DEBUG=0 \
+              -DXD3_USE_LARGEFILE64=1 \
+              -DREGRESSION_TEST=1 \
+              -DSECONDARY_DJW=1 \
+              -DSECONDARY_FGK=1 \
+              -DXD3_MAIN=1 \
+              -DXD3_POSIX=1
+
+xdelta3-debug: $(SOURCES)
+	$(CC) -g -Wall -Wshadow xdelta3.c -o xdelta3-debug -DXD3_MAIN=1 -DGENERIC_ENCODE_TABLES=1 \
+		-DXD3_USE_LARGEFILE64=1 -DXD3_STDIO=1 -DREGRESSION_TEST=1 -DXD3_DEBUG=1 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -lm
+
+xdelta3-debug2: $(SOURCES)
+	$(CC) -g -Wall -Wshadow xdelta3.c -o xdelta3-debug2 -DXD3_MAIN=1 -DGENERIC_ENCODE_TABLES=1 \
+		-DXD3_USE_LARGEFILE64=1 -DXD3_STDIO=1 -DREGRESSION_TEST=1 -DXD3_DEBUG=2 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -lm
+
+xdelta3-debug3: $(SOURCES)
+	$(CC) -g -Wall -Wshadow xdelta3.c -o xdelta3-debug3 -DXD3_MAIN=1 -DGENERIC_ENCODE_TABLES=1 \
+		-DXD3_USE_LARGEFILE64=1 -DXD3_STDIO=1 -DREGRESSION_TEST=1 -DXD3_DEBUG=3 -DSECONDARY_DJW=1 -DSECONDARY_FGK=1 -lm
+
+$(PYTGT): $(SOURCES) setup.py
+	$(PYTHON) setup.py install --verbose --compile --force
+
+xdelta3_wrap.c xdelta3.py: xdelta3.swig
+	swig -python xdelta3.swig
+
+xdelta3.o: $(SOURCES)
+	$(CC) -g -Wall -Wshadow -c xdelta3.c $(SWIG_FLAGS) -o xdelta3.o
+
+xdelta3_wrap.o: xdelta3_wrap.c
+	$(CC) $(SWIG_FLAGS) \
+              -DHAVE_CONFIG_H \
+	      -I/usr/include/python2.4 \
+	      -I/usr/lib/python2.4/config \
+	      -fpic \
+	      -c -g xdelta3_wrap.c
+
+xdelta3module.dll: xdelta3_wrap.o xdelta3.o
+	gcc -shared -Wl,--enable-auto-image-base xdelta3.o xdelta3_wrap.o -L/usr/lib/python2.4/config -lpython2.4 -o xdelta3module.dll
+	cp $(SWIGTGT) /usr/lib/python2.4/site-packages
+
+xdelta3module.so: xdelta3_wrap.o xdelta3.o
+	ld -shared xdelta3.o xdelta3_wrap.o -o xdelta3module.so /usr/lib/libpython2.4.so -lgcc_s -lc
+
+xdelta3-decoder: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c \
+	    -DXD3_ENCODER=0 -DXD3_MAIN=1 -DSECONDARY_FGK=0 -DSECONDARY_DJW=0 \
+	    -DXD3_STDIO=1 -DEXTERNAL_COMPRESSION=0 -DVCDIFF_TOOLS=0 \
+	    -o xdelta3-decoder
+
+xdelta3-decoder-nomain.o: $(SOURCES) linkxd3lib.c
+	$(CC) -O2 -Wall -Wshadow xdelta3.c linkxd3lib.c \
+	    -DXD3_ENCODER=0 -DSECONDARY_FGK=0 -DSECONDARY_DJW=0 \
+	    -o xdelta3-decoder-nomain.o
+	strip xdelta3-decoder-nomain.o
+
+xdelta3-32: $(SOURCES)
+	$(CC) -g -O2 -Wall -Wshadow xdelta3.c -o xdelta3-32 -DXD3_MAIN=1 -DSECONDARY_DJW=1 -DREGRESSION_TEST=1 -lm
+
+xdelta3-O++: $(SOURCES)
+	$(CXX) -g -O2 -Wall -Wshadow xdelta3.c -o xdelta3-O++ -DXD3_MAIN=1 -DSECONDARY_DJW=1 -DREGRESSION_TEST=1 -lm
+
+xdelta3-Op: $(SOURCES)
+	$(CC) -g -O2 -Wall -Wshadow xdelta3.c -o xdelta3-Op -DXD3_POSIX=1 -DXD3_MAIN=1 -DREGRESSION_TEST=1 -lm
+
+xdelta3-64: $(SOURCES)
+	$(CC) -g -Wall -Wshadow xdelta3.c -o xdelta3-64 -DXD3_POSIX=1 -DXD3_MAIN=1 -DREGRESSION_TEST=1 \
+					-DXD3_DEBUG=0 -DXD3_USE_LARGEFILE64=1 -lm
+
+xdelta3-64-O: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c -o xdelta3-64-O -DXD3_POSIX=1 -DXD3_MAIN=1 \
+					-DXD3_USE_LARGEFILE64=1 -lm
+
+xdelta3-everything: $(SOURCES)
+	$(CC) -g -Wall -Wshadow xdelta3.c -o xdelta3-everything \
+					-DXD3_MAIN=1 -DVCDIFF_TOOLS=1 -DREGRESSION_TEST=1 \
+					-DSECONDARY_FGK=1 -DSECONDARY_DJW=1 \
+					-DGENERIC_ENCODE_TABLES=1 \
+					-DGENERIC_ENCODE_TABLES_COMPUTE=1 \
+					-DXD3_POSIX=1 \
+					-DEXTERNAL_COMPRESSION=1 \
+					-DXD3_DEBUG=1 -lm
+
+xdelta3-tune: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c -o xdelta3-tune -DXD3_MAIN=1 \
+		-DSECONDARY_FGK=1 -DSECONDARY_DJW=1 -DTUNE_HUFFMAN=1
+
+xdelta3-Opg: $(SOURCES)
+	$(CC) -pg -g -O -Wall -Wshadow xdelta3.c -o xdelta3-Opg -DXD3_MAIN=1 \
+		-DSECONDARY_DJW=1 -DXD3_POSIX=1 -DXD3_USE_LARGEFILE64=1
+
+xdelta3-nosec.o: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow -c xdelta3.c -DSECONDARY_FGK=0 -DSECONDARY_DJW=0 -o xdelta3-nosec.o
+
+xdelta3-all.o: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow -c xdelta3.c -DSECONDARY_FGK=1 -DSECONDARY_DJW=1 -o xdelta3-all.o
+
+xdelta3-fgk.o: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow -c xdelta3.c -DSECONDARY_FGK=1 -DSECONDARY_DJW=0 -o xdelta3-fgk.o
+
+xdelta3-noext: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c -DXD3_MAIN=1 -DEXTERNAL_COMPRESSION=0 -o xdelta3-noext
+
+xdelta3-tools: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c -DXD3_MAIN=1 -o xdelta3-tools
+
+xdelta3-notools: $(SOURCES)
+	$(CC) -O2 -Wall -Wshadow xdelta3.c -DXD3_MAIN=1 -DVCDIFF_TOOLS=0 -o xdelta3-notools
Index: /nikanabo/current/xdelta/diy/badcopy.c
===================================================================
--- /nikanabo/current/xdelta/diy/badcopy.c	(revision 185)
+++ /nikanabo/current/xdelta/diy/badcopy.c	(revision 185)
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define BUFSZ (1 << 22)
+
+#ifdef WIN32
+// whatever
+static 
+double drand48() {
+  double r = rand() / (double)RAND_MAX;
+  return r;
+}
+long lrand48() {
+	long l = 0;
+	int i;
+	for (i = 0; i < 32; i++) {
+		l = l ^ (l << 2) ^ (l << 1) ^ rand();
+	}
+	return l;
+}
+#endif
+
+#ifdef _WIN32
+#define XD3_WIN32 1
+#else
+#define XD3_POSIX 1
+#endif
+#define XD3_MAIN 1
+#define main notmain
+#define EXTERNAL_COMPRESSION 0
+#define XD3_USE_LARGEFILE64 1
+#include "xdelta3.c"
+#undef main
+
+
+double error_prob   = 0.0001;
+usize_t mean_change  = 100;
+xoff_t total_change = 0;
+xoff_t total_size   = 0;
+usize_t max_change   = 0;
+usize_t num_change   = 0;
+
+
+static usize_t
+edist (usize_t mean, usize_t max)
+{
+  double mean_d = mean;
+  double erand  = log (1.0 / drand48 ());
+  usize_t x = (usize_t) (mean_d * erand + 0.5);
+
+  return (x < max) ? (x > 0 ? x : 1) : max;
+}
+
+void modify (char *buf, usize_t size)
+{
+  usize_t bufpos = 0, j;
+  usize_t last_end = 0;
+
+  for (;; /* bufpos and j are incremented in the inner loop */)
+    {
+      /* The size of the next modification. */
+      usize_t next_size = edist (mean_change, 1 << 31);
+      /* The expected interval of such a change. */
+      double expect_interval = ((double) next_size * (1.0 - error_prob)) / error_prob;
+      /* The number of bytes until the next modification. */
+      usize_t next_mod  = edist ((usize_t)expect_interval, 1 << 31);
+
+      if (next_size + next_mod + bufpos > size) { break; }
+
+      if (max_change < next_size) { max_change = next_size; }
+
+      bufpos += next_mod;
+
+      fprintf (stderr, "COPY: %I64u-%I64u (%u)\n", 
+		  total_size + (xoff_t)last_end, 
+		  total_size + (xoff_t)bufpos, 
+		  bufpos - last_end);
+      fprintf (stderr, "ADD:  %I64u-%I64u (%u) is change %u\n", 
+		  total_size + (xoff_t)bufpos, 
+		  total_size + (xoff_t)(bufpos + next_size),
+		  next_size, num_change);
+
+      total_change += next_size;
+      num_change   += 1;
+
+      for (j = 0; j < next_size; j += 1, bufpos += 1)
+	{
+	  buf[bufpos] = (char)(lrand48 () >> 3);
+	}
+
+      last_end = bufpos;
+    }
+
+  fprintf (stderr, "COPY: %I64u-%I64u (%u)\n", 
+	  total_size + last_end, 
+	  total_size + size, size - last_end);
+
+  total_size += size;
+}
+
+int main(int argc, char **argv)
+{
+  main_file inp, out;
+  char *buf = malloc(BUFSZ);
+  int c, ret;
+  main_file_init(&inp);
+  main_file_init(&out);
+  option_force = 1;
+  if (argc > 5)
+    {
+      fprintf (stderr, "usage: badcopy [byte_error_prob [mean_error_size]]\n");
+      return 1;
+    }
+
+  if (argc > 4) { mean_change = atoi (argv[4]); }
+  if (argc > 3) { error_prob  = atof (argv[3]); }
+  fprintf (stderr, "mean change = %u; error_prob = %0.10f\n", mean_change, error_prob);
+
+  if ((ret = main_file_open (&inp, argv[1], XO_READ)) != 0) {
+	  return 1;
+  }
+  if ((ret = main_file_open (&out, argv[2], XO_WRITE)) != 0) {
+	  return 1;
+  }
+
+  if (error_prob < 0.0 || error_prob > 1.0)
+    {
+      fprintf (stderr, "warning: error probability out of range\n");
+      return 1;
+    }
+
+  do
+    {
+		if ((ret = main_file_read (&inp, buf, BUFSZ, &c, "read failed")) != 0) {
+			return 1;
+		}
+
+        if (c == 0) { break; }
+
+        modify (buf, c);
+
+		if ((ret = main_file_write (&out, buf, c, "write failed")) != 0) {
+			return 1;
+		}
+    }
+  while (c == BUFSZ);
+
+  if ((ret = main_file_close (&out)))
+    {
+      return 1;
+    }
+
+  fprintf (stderr, "add_prob %f; %u adds; total_change %u of %u bytes; add percentage %f; max add size %u\n",
+	   error_prob, num_change, total_change, total_size, (double) total_change / (double) total_size, max_change);
+
+  return 0;
+}
Index: /nikanabo/current/xdelta/diy/badcopy.vcproj
===================================================================
--- /nikanabo/current/xdelta/diy/badcopy.vcproj	(revision 185)
+++ /nikanabo/current/xdelta/diy/badcopy.vcproj	(revision 185)
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="badcopy"
+	ProjectGUID="{FED2964C-7114-41AC-81EE-68A4D2B67503}"
+	RootNamespace="badcopy"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+			<File
+				RelativePath=".\releases\xdelta30h.ppc-osx.bin"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\badcopy.c"
+				>
+			</File>
+		</Filter>
+		<File
+			RelativePath=".\release\BuildLog.htm"
+			>
+		</File>
+		<File
+			RelativePath=".\debug\BuildLog.htm"
+			>
+		</File>
+		<File
+			RelativePath=".\www\xdelta3-api-guide.html"
+			>
+		</File>
+		<File
+			RelativePath=".\www\xdelta3-cmdline.html"
+			>
+		</File>
+		<File
+			RelativePath=".\www\xdelta3.html"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: /nikanabo/current/xdelta/diy/draft-korn-vcdiff.txt
===================================================================
--- /nikanabo/current/xdelta/diy/draft-korn-vcdiff.txt	(revision 185)
+++ /nikanabo/current/xdelta/diy/draft-korn-vcdiff.txt	(revision 185)
@@ -0,0 +1,1322 @@
+                                                     David G. Korn, AT&T Labs
+				             Joshua P. MacDonald, UC Berkeley
+                                                 Jeffrey C. Mogul, Compaq WRL
+Internet-Draft                                       Kiem-Phong Vo, AT&T Labs
+Expires: 09 November 2002                                    09 November 2001
+
+
+        The VCDIFF Generic Differencing and Compression Data Format
+
+                         draft-korn-vcdiff-06.txt
+
+
+
+Status of this Memo
+
+    This document is an Internet-Draft and is in full conformance
+    with all provisions of Section 10 of RFC2026.
+
+    Internet-Drafts are working documents of the Internet Engineering
+    Task Force (IETF), its areas, and its working groups.  Note that
+    other groups may also distribute working documents as
+    Internet-Drafts.
+
+    Internet-Drafts are draft documents valid for a maximum of six
+    months and may be updated, replaced, or obsoleted by other
+    documents at any time.  It is inappropriate to use Internet-
+    Drafts as reference material or to cite them other than as
+    "work in progress."
+
+    The list of current Internet-Drafts can be accessed at
+    http://www.ietf.org/ietf/1id-abstracts.txt
+
+    The list of Internet-Draft Shadow Directories can be accessed at
+    http://www.ietf.org/shadow.html.
+
+
+Abstract
+
+    This memo describes a general, efficient and portable data format
+    suitable for encoding compressed and/or differencing data so that
+    they can be easily transported among computers.
+
+
+Table of Contents:
+
+    1.  EXECUTIVE SUMMARY ............................................  2
+    2.  CONVENTIONS ..................................................  3
+    3.  DELTA INSTRUCTIONS ...........................................  4
+    4.  DELTA FILE ORGANIZATION ......................................  5
+    5.  DELTA INSTRUCTION ENCODING ...................................  9
+    6.  DECODING A TARGET WINDOW ..................................... 14
+    7.  APPLICATION-DEFINED CODE TABLES .............................. 16
+    8.  PERFORMANCE .................................................. 16
+    9.  FURTHER ISSUES ............................................... 17
+   10.  SUMMARY ...................................................... 18
+   11.  ACKNOWLEDGEMENTS ............................................. 18
+   12.  SECURITY CONSIDERATIONS ...................................... 18
+   13.  SOURCE CODE AVAILABILITY ..................................... 18
+   14.  INTELLECTUAL PROPERTY RIGHTS ................................. 18
+   15.  IANA CONSIDERATIONS .......................................... 19
+   16.  REFERENCES ................................................... 19
+   17.  AUTHOR'S ADDRESS ............................................. 20
+
+
+1.  EXECUTIVE SUMMARY
+
+    Compression and differencing techniques can greatly improve storage
+    and transmission of files and file versions.  Since files are often
+    transported across machines with distinct architectures and performance
+    characteristics, such data should be encoded in a form that is portable
+    and can be decoded with little or no knowledge of the encoders.
+    This document describes Vcdiff, a compact portable encoding format
+    designed for these purposes.
+
+    Data differencing is the process of computing a compact and invertible
+    encoding of a "target file" given a "source file".  Data compression
+    is similar but without the use of source data.  The UNIX utilities diff,
+    compress, and gzip are well-known examples of data differencing and
+    compression tools.  For data differencing, the computed encoding is
+    called a "delta file", and, for data compression, it is called
+    a "compressed file".  Delta and compressed files are good for storage
+    and transmission as they are often smaller than the originals.
+
+    Data differencing and data compression are traditionally treated
+    as distinct types of data processing.  However, as shown in the Vdelta
+    technique by Korn and Vo [1], compression can be thought of as a special
+    case of differencing in which the source data is empty. The basic idea
+    is to unify the string parsing scheme used in the Lempel-Ziv'77 style
+    compressors [2], and the block-move technique of Tichy [3].  Loosely
+    speaking, this works as follows:
+
+        a. Concatenate source and target data.
+        b. Parse the data from left to right as in LZ'77 but
+	   make sure that a parsed segment starts the target data.
+        c. Start to output when reaching target data.
+
+    Parsing is based on string matching algorithms such as suffix trees [4]
+    or hashing with different time and space performance characteristics.
+    Vdelta uses a fast string matching algorithm that requires less memory
+    than other techniques [5,6].  However, even with this algorithm, the
+    memory requirement can still be prohibitive for large files.  A common
+    way to deal with memory limitation is to partition an input file into
+    chunks called "windows" and process them separately. Here, except for
+    unpublished work by Vo, little has been done on designing effective
+    windowing schemes. Current techniques, including Vdelta, simply use
+    source and target windows with corresponding addresses across source
+    and target files.
+
+    String matching and windowing algorithms have large influence on the
+    compression rate of delta and compressed files. However, it is desirable
+    to have a portable encoding format that is independent of such algorithms.
+    This enables construction of client-server applications in which a server
+    may serve clients with unknown computing characteristics.  Unfortunately,
+    all current differencing and compressing tools, including Vdelta, fall
+    short in this respect. Their storage formats are closely intertwined
+    with the implemented string matching and/or windowing algorithms.
+
+    The encoding format Vcdiff proposed here addresses the above issues.
+    Vcdiff achieves the below characteristics:
+
+	Output compactness:
+            The basic encoding format compactly represents compressed or delta
+	    files. Applications can further extend the basic encoding format
+	    with "secondary encoders" to achieve more compression.
+
+	Data portability:
+	    The basic encoding format is free from machine byte order and
+	    word size issues. This allows data to be encoded on one machine
+	    and decoded on a different machine with different architecture.
+
+    	Algorithm genericity:
+	    The decoding algorithm is independent from string matching and
+	    windowing algorithms. This allows competition among implementations
+	    of the encoder while keeping the same decoder.
+
+    	Decoding efficiency:
+	    Except for secondary encoder issues, the decoding algorithm runs
+	    in time proportional to the size of the target file and uses space
+	    proportional to the maximal window size.  Vcdiff differs from more
+	    conventional compressors in that it uses only byte-aligned
+	    data, thus avoiding bit-level operations, which improves
+	    decoding speed at the slight cost of compression efficiency.
+
+    The Vcdiff data format and the algorithms for decoding data shall be
+    described next.  Since Vcdiff treats compression as a special case of
+    differencing, we shall use the term "delta file" to indicate the
+    compressed output for both cases.
+
+
+2. CONVENTIONS
+
+    The basic data unit is a byte.  For portability, Vcdiff shall limit
+    a byte to its lower eight bits even on machines with larger bytes.
+    The bits in a byte are ordered from right to left so that the least
+    significant bit (LSB) has value 1, and the most significant bit (MSB),
+    has value 128.
+
+    For purposes of exposition in this document, we adopt the convention
+    that the LSB is numbered 0, and the MSB is numbered 7.  Bit numbers
+    never appear in the encoded format itself.
+
+    Vcdiff encodes unsigned integer values using a portable variable-sized
+    format (originally introduced in the Sfio library [7]). This encoding
+    treats an integer as a number in base 128. Then, each digit in this
+    representation is encoded in the lower seven bits of a byte. Except for
+    the least significant byte, other bytes have their most significant bit
+    turned on to indicate that there are still more digits in the encoding.
+    The two key properties of this integer encoding that are beneficial
+    to a data compression format are:
+
+	a. The encoding is portable among systems using 8-bit bytes, and
+        b. Small values are encoded compactly.
+
+    For example, consider the value 123456789 which can be represented with
+    four 7-bit digits whose values are 58, 111, 26, 21 in order from most
+    to least significant. Below is the 8-bit byte encoding of these digits.
+    Note that the MSBs of 58, 111 and 26 are on.
+
+                 +-------------------------------------------+
+                 | 10111010 | 11101111 | 10011010 | 00010101 |
+                 +-------------------------------------------+
+                   MSB+58     MSB+111    MSB+26     0+21
+
+
+    Henceforth, the terms "byte" and "integer" will refer to a byte and an
+    unsigned integer as described.
+
+
+    From time to time, algorithms are exhibited to clarify the descriptions
+    of parts of the Vcdiff format. On such occasions, the C language will be
+    used to make precise the algorithms.  The C code shown in this
+    document is meant for clarification only, and is not part of the
+    actual specification of the Vcdiff format.
+
+    In this specification, the key words "MUST", "MUST NOT",
+    "SHOULD", "SHOULD NOT", and "MAY" document are to be interpreted as
+    described in RFC2119 [12].
+
+
+3.  DELTA INSTRUCTIONS
+
+    A large target file is partitioned into non-overlapping sections
+    called "target windows". These target windows are processed separately
+    and sequentially based on their order in the target file.
+
+    A target window T of length t may be compared against some source data
+    segment S of length s. By construction, this source data segment S
+    comes either from the source file, if one is used, or from a part of
+    the target file earlier than T.  In this way, during decoding, S is
+    completely known when T is being decoded.
+
+    The choices of T, t, S and s are made by some window selection algorithm
+    which can greatly affect the size of the encoding. However, as seen later,
+    these choices are encoded so that no knowledge of the window selection
+    algorithm is needed during decoding.
+
+    Assume that S[j] represents the jth byte in S, and T[k] represents
+    the kth byte in T.  Then, for the delta instructions, we treat the data
+    windows S and T as substrings of a superstring U formed by concatenating
+    them like this:
+
+        S[0]S[1]...S[s-1]T[0]T[1]...T[t-1]
+
+    The "address" of a byte in S or T is referred to by its location in U.
+    For example, the address of T[k] is s+k.
+
+    The instructions to encode and direct the reconstruction of a target
+    window are called delta instructions. There are three types:
+
+	ADD: This instruction has two arguments, a size x and a sequence of
+	    x bytes to be copied.
+	COPY: This instruction has two arguments, a size x and an address p
+	    in the string U. The arguments specify the substring of U that
+	    must be copied. We shall assert that such a substring must be
+	    entirely contained in either S or T.
+	RUN: This instruction has two arguments, a size x and a byte b that
+	    will be repeated x times.
+
+    Below are example source and target windows and the delta instructions
+    that encode the target window in terms of the source window.
+
+        a b c d e f g h i j k l m n o p
+        a b c d w x y z e f g h e f g h e f g h e f g h z z z z
+
+        COPY  4, 0
+        ADD   4, w x y z
+        COPY  4, 4
+        COPY 12, 24
+	RUN   4, z
+
+
+    Thus, the first letter 'a' in the target window is at location 16
+    in the superstring. Note that the fourth instruction, "COPY 12, 24",
+    copies data from T itself since address 24 is position 8 in T.
+    This instruction also shows that it is fine to overlap the data to be
+    copied with the data being copied from as long as the latter starts
+    earlier. This enables efficient encoding of periodic sequences,
+    i.e., sequences with regularly repeated subsequences. The RUN instruction
+    is a compact way to encode a sequence repeating the same byte even though
+    such a sequence can be thought of as a periodic sequence with period 1.
+
+    To reconstruct the target window, one simply processes one delta
+    instruction at a time and copy the data either from the source window
+    or the being reconstructed target window based on the type of the
+    instruction and the associated address, if any.
+
+
+4.  DELTA FILE ORGANIZATION
+
+    A Vcdiff delta file starts with a Header section followed by a sequence
+    of Window sections. The Header section includes magic bytes to identify
+    the file type, and information concerning data processing beyond the
+    basic encoding format. The Window sections encode the target windows.
+
+    Below is the overall organization of a delta file. The indented items
+    refine the ones immediately above them. An item in square brackets may
+    or may not be present in the file depending on the information encoded
+    in the Indicator byte above it.
+
+        Header
+	    Header1                                  - byte
+	    Header2                                  - byte
+	    Header3                                  - byte
+	    Header4                                  - byte
+	    Hdr_Indicator                            - byte
+	    [Secondary compressor ID]                - byte
+
+[@@@ Why is compressor ID not an integer? ]
+[@@@ If we aren't defining any secondary compressors yet, then it seems
+that defining the [Secondary compressor ID] and the corresponding
+VCD_DECOMPRESS Hdr_Indicator bit in this draft has no real value.  An
+implementation of this specification won't be able to decode a VCDIFF
+encoded with this option if it doesn't know about any secondary
+compressors.  It seems that you should specify the bits related to
+secondary compressors once you have defined the first a secondary
+compressor.  I can imagine a secondary-compressor might want to supply
+extra information, such as a dictionary of some kind, in which case
+this speculative treatment wouldn't go far enough.]
+
+	    [Length of code table data]              - integer
+	    [Code table data]
+	      	Size of near cache                   - byte
+	        Size of same cache                   - byte
+	        Compressed code table data
+	Window1
+	    Win_Indicator                            - byte
+	    [Source segment size]                    - integer
+	    [Source segment position]                - integer
+            The delta encoding of the target window
+	        Length of the delta encoding         - integer
+	        The delta encoding
+	            Size of the target window        - integer
+	            Delta_Indicator                  - byte
+	            Length of data for ADDs and RUNs - integer
+	            Length of instructions and sizes - integer
+	            Length of addresses for COPYs    - integer
+	            Data section for ADDs and RUNs   - array of bytes
+	            Instructions and sizes section   - array of bytes
+	            Addresses section for COPYs      - array of bytes
+	Window2
+	...
+
+
+
+4.1 The Header Section
+
+    Each delta file starts with a header section organized as below.
+    Note the convention that square-brackets enclose optional items.
+
+	    Header1                                  - byte = 0xE6
+	    Header2                                  - byte = 0xD3
+	    Header3                                  - byte = 0xD4
+
+HMMM
+
+0xD6
+0xC3
+0xC4
+
+	    Header4                                  - byte
+	    Hdr_Indicator                            - byte
+	    [Secondary compressor ID]                - byte
+	    [Length of code table data]              - integer
+	    [Code table data]
+
+    The first three Header bytes are the ASCII characters 'V', 'C' and 'D'
+    with their most significant bits turned on (in hexadecimal, the values
+    are 0xE6, 0xD3, and 0xD4). The fourth Header byte is currently set to
+    zero. In the future, it might be used to indicate the version of Vcdiff.
+
+    The Hdr_Indicator byte shows if there are any initialization data
+    required to aid in the reconstruction of data in the Window sections.
+    This byte MAY have non-zero values for either, both, or neither of
+    the two bits VCD_DECOMPRESS and VCD_CODETABLE below:
+
+	    7 6 5 4 3 2 1 0
+	   +-+-+-+-+-+-+-+-+
+	   | | | | | | | | |
+	   +-+-+-+-+-+-+-+-+
+	                ^ ^
+	                | |
+	                | +-- VCD_DECOMPRESS
+	                +---- VCD_CODETABLE
+
+    If bit 0 (VCD_DECOMPRESS) is non-zero, this indicates that a secondary
+    compressor may have been used to further compress certain parts of the
+    delta encoding data as described in Sections 4.3 and 6. In that case,
+    the ID of the secondary compressor is given next. If this bit is zero,
+    the compressor ID byte is not included.
+
+[@@@ If we aren't defining any secondary compressors yet, then it seems
+this bit has no real value yet..]
+
+    If bit 1 (VCD_CODETABLE) is non-zero, this indicates that an
+    application-defined code table is to be used for decoding the delta
+    instructions. This table itself is compressed.  The length of the data
+    comprising this compressed code table and the data follow next. Section 7
+    discusses application-defined code tables.  If this bit is zero, the code
+    table data length and the code table data are not included.
+
+    If both bits are set, then the compressor ID byte is included
+    before the code table data length and the code table data.
+
+
+4.2 The Format of a Window Section
+
+    Each Window section is organized as follows:
+
+	    Win_Indicator                            - byte
+	    [Source segment length]                  - integer
+	    [Source segment position]                - integer
+            The delta encoding of the target window
+
+
+    Below are the detail of the various items:
+
+[@@@ Here, I want to replace the Win_Indicator with a source-count,
+followed by source-count length/position pairs?]
+
+        Win_Indicator:
+	    This byte is a set of bits, as shown:
+
+	    7 6 5 4 3 2 1 0
+	   +-+-+-+-+-+-+-+-+
+	   | | | | | | | | |
+	   +-+-+-+-+-+-+-+-+
+	                ^ ^
+	                | |
+	                | +-- VCD_SOURCE
+	                +---- VCD_TARGET
+
+
+	    If bit 0 (VCD_SOURCE) is non-zero, this indicates that a segment
+            of data from the "source" file was used as the corresponding
+            source window of data to encode the target window. The decoder
+	    will use this same source data segment to decode the target window.
+
+	    If bit 1 (VCD_TARGET) is non-zero, this indicates that a segment
+            of data from the "target" file was used as the corresponding
+	    source window of data to encode the target window. As above, this
+	    same source data segment is used to decode the target window.
+
+	    The Win_Indicator byte MUST NOT have more than one of the bits
+	    set (non-zero).  It MAY have none of these bits set.
+
+	    If one of these bits is set, the byte is followed by two
+            integers to indicate respectively the length and position of
+            the source data segment in the relevant file.  If the
+            indicator byte is zero, the target window was compressed
+            by itself without comparing against another data segment,
+            and these two integers are not included.
+
+        The delta encoding of the target window:
+            This contains the delta encoding of the target window either
+            in terms of the source data segment (i.e., VCD_SOURCE
+            or VCD_TARGET was set) or by itself if no source window
+            is specified. This data format is discussed next.
+
+
+4.3 The Delta Encoding of a Target Window
+
+    The delta encoding of a target window is organized as follows:
+
+	Length of the delta encoding            - integer
+	The delta encoding
+	    Length of the target window         - integer
+	    Delta_Indicator                     - byte
+	    Length of data for ADDs and RUNs    - integer
+	    Length of instructions section      - integer
+	    Length of addresses for COPYs       - integer
+	    Data section for ADDs and RUNs      - array of bytes
+	    Instructions and sizes section      - array of bytes
+	    Addresses section for COPYs         - array of bytes
+
+
+	Length of the delta encoding:
+	    This integer gives the total number of remaining bytes that
+	    comprise data of the delta encoding for this target window.
+
+        The delta encoding:
+	    This contains the data representing the delta encoding which
+	    is described next.
+
+    	Length of the target window:
+	    This integer indicates the actual size of the target window
+            after decompression. A decoder can use this value to allocate
+            memory to store the uncompressed data.
+
+	Delta_Indicator:
+	    This byte is a set of bits, as shown:
+
+	    7 6 5 4 3 2 1 0
+	   +-+-+-+-+-+-+-+-+
+	   | | | | | | | | |
+	   +-+-+-+-+-+-+-+-+
+	              ^ ^ ^
+	              | | |
+	              | | +-- VCD_DATACOMP
+	              | +---- VCD_INSTCOMP
+	              +------ VCD_ADDRCOMP
+
+		VCD_DATACOMP:	bit value 1.
+		VCD_INSTCOMP:	bit value 2.
+		VCD_ADDRCOMP:	bit value 4.
+
+            As discussed, the delta encoding consists of COPY, ADD and RUN
+            instructions. The ADD and RUN instructions have accompanying
+            unmatched data (that is, data that does not specifically match
+            any data in the source window or in some earlier part of the
+            target window) and the COPY instructions have addresses of where
+	    the matches occur. OPTIONALLY, these types of data MAY be further
+	    compressed using a secondary compressor. Thus, Vcdiff separates
+            the encoding of the delta instructions into three parts:
+
+	        a. The unmatched data in the ADD and RUN instructions,
+	        b. The delta instructions and accompanying sizes, and
+                c. The addresses of the COPY instructions.
+
+            If the bit VCD_DECOMPRESS (Section 4.1) was on, each of these
+            sections may have been compressed using the specified secondary
+            compressor. The bit positions 0 (VCD_DATACOMP), 1 (VCD_INSTCOMP),
+            and 2 (VCD_ADDRCOMP) respectively indicate, if non-zero, that
+            the corresponding parts are compressed. Then, these parts MUST
+	    be decompressed before decoding the delta instructions.
+
+	Length of data for ADDs and RUNs:
+	    This is the length (in bytes) of the section of data storing
+            the unmatched data accompanying the ADD and RUN instructions.
+
+	Length of instructions section:
+	    This is the length (in bytes) of the delta instructions and
+            accompanying sizes.
+
+	Length of addresses for COPYs:
+	    This is the length (in bytes) of the section storing
+            the addresses of the COPY instructions.
+
+    	Data section for ADDs and RUNs:
+	    This sequence of bytes encodes the unmatched data for the ADD
+            and RUN instructions.
+
+	Instructions and sizes section:
+	    This sequence of bytes encodes the instructions and their sizes.
+
+	Addresses section for COPYs:
+	    This sequence of bytes encodes the addresses of the COPY
+	    instructions.
+
+
+5. DELTA INSTRUCTION ENCODING
+
+    The delta instructions described in Section 3 represent the results of
+    string matching. For many data differencing applications in which the
+    changes between source and target data are small, any straightforward
+    representation of these instructions would be adequate.  However, for
+    applications including data compression, it is important to encode
+    these instructions well to achieve good compression rates.  From our
+    experience, the following observations can be made:
+
+    a. The addresses in COPY instructions are locations of matches and
+       often occur close by or even exactly equal to one another. This is
+       because data in local regions are often replicated with minor changes.
+       In turn, this means that coding a newly matched address against some
+       set of recently matched addresses can be beneficial.
+
+    b. The matches are often short in length and separated by small amounts
+       of unmatched data. That is, the lengths of COPY and ADD instructions
+       are often small. This is particularly true of binary data such as
+       executable files or structured data such as HTML or XML. In such cases,
+       compression can be improved by combining the encoding of the sizes
+       and the instruction types as well as combining the encoding of adjacent
+       delta instructions with sufficiently small data sizes.
+
+    The below subsections discuss how the Vcdiff data format provides
+    mechanisms enabling encoders to use the above observations to improve
+    compression rates.
+
+
+5.1 Address Encoding Modes of COPY Instructions
+
+    As mentioned earlier, addresses of COPY instructions often occur close
+    to one another or are exactly equal. To take advantage of this phenomenon
+    and encode addresses of COPY instructions more efficiently, the Vcdiff
+    data format supports the use of two different types of address caches.
+    Both the encoder and decoder maintain these caches, so that decoder's
+    caches remain synchronized with the encoder's caches.
+
+    a. A "near" cache is an array with "s_near" slots, each containing an
+       address used for encoding addresses nearby to previously encoded
+       addresses (in the positive direction only).  The near cache also
+       maintains a "next_slot" index to the near cache.  New entries to the
+       near cache are always inserted in the next_slot index, which maintains
+       a circular buffer of the s_near most recent addresses.
+
+    b. A "same" cache is an array with "s_same" multiple of 256 slots, each
+       containing an address.  The same cache maintains a hash table of recent
+       addresses used for repeated encoding of the exact same address.
+
+
+    By default, the parameters s_near and s_same are respectively set to 4
+    and 3. An encoder MAY modify these values, but then it MUST encode the
+    new values in the encoding itself, as discussed in Section 7, so that
+    the decoder can properly set up its own caches.
+
+    At the start of processing a target window, an implementation
+    (encoder or decoder) initializes all of the slots in both caches
+    to zero.  The next_slot pointer of the near cache is set
+    to point to slot zero.
+
+    Each time a COPY instruction is processed by the encoder or
+    decoder, the implementation's caches are updated as follows, where
+    "addr" is the address in the COPY instruction.
+
+    a. The slot in the near cache referenced by the next_slot
+       index is set to addr.  The next_slot index is then incremented
+       modulo s_near.
+
+    b. The slot in the same cache whose index is addr%(s_same*256)
+       is set to addr. [We use the C notations of % for modulo and
+       * for multiplication.]
+
+
+5.2 Example code for maintaining caches
+
+    To make clear the above description, below are example cache data
+    structures and algorithms to initialize and update them:
+
+        typedef struct _cache_s
+        {
+	    int*  near;      /* array of size s_near        */
+            int   s_near;
+            int   next_slot; /* the circular index for near */
+            int*  same;      /* array of size s_same*256    */
+            int   s_same;
+        } Cache_t;
+
+        cache_init(Cache_t* ka)
+        {
+	    int   i;
+
+            ka->next_slot = 0;
+            for(i = 0; i < ka->s_near; ++i)
+                 ka->near[i] = 0;
+
+            for(i = 0; i < ka->s_same*256; ++i)
+                 ka->same[i] = 0;
+        }
+
+        cache_update(Cache_t* ka, int addr)
+        {
+	    if(ka->s_near > 0)
+            {   ka->near[ka->next_slot] = addr;
+                ka->next_slot = (ka->next_slot + 1) % ka->s_near;
+            }
+
+            if(ka->s_same > 0)
+                ka->same[addr % (ka->s_same*256)] = addr;
+        }
+
+
+5.3 Encoding of COPY instruction addresses
+
+    The address of a COPY instruction is encoded using different modes
+    depending on the type of cached address used, if any.
+
+    Let "addr" be the address of a COPY instruction to be decoded and "here"
+    be the current location in the target data (i.e., the start of the data
+    about to be encoded or decoded).  Let near[j] be the jth element in
+    the near cache, and same[k] be the kth element in the same cache.
+    Below are the possible address modes:
+
+	VCD_SELF: This mode has value 0. The address was encoded by itself
+            as an integer.
+
+	VCD_HERE: This mode has value 1. The address was encoded as
+	    the integer value "here - addr".
+
+	Near modes: The "near modes" are in the range [2,s_near+1]. Let m
+	    be the mode of the address encoding. The address was encoded
+	    as the integer value "addr - near[m-2]".
+
+	Same modes: The "same modes" are in the range
+	    [s_near+2,s_near+s_same+1]. Let m be the mode of the encoding.
+	    The address was encoded as a single byte b such that
+	    "addr == same[(m - (s_near+2))*256 + b]".
+
+
+5.3 Example code for encoding and decoding of COPY instruction addresses
+
+    We show example algorithms below to demonstrate use of address modes more
+    clearly. The encoder has freedom to choose address modes, the sample
+    addr_encode() algorithm merely shows one way of picking the address
+    mode. The decoding algorithm addr_decode() will uniquely decode addresses
+    regardless of the encoder's algorithm choice.
+
+    Note that the address caches are updated immediately after an address is
+    encoded or decoded. In this way, the decoder is always synchronized with
+    the encoder.
+
+        int addr_encode(Cache_t* ka, int addr, int here, int* mode)
+        {
+	    int  i, d, bestd, bestm;
+
+	    /* Attempt to find the address mode that yields the
+	     * smallest integer value for "d", the encoded address
+	     * value, thereby minimizing the encoded size of the
+	     * address. */
+
+            bestd = addr; bestm = VCD_SELF;      /* VCD_SELF == 0 */
+
+            if((d = here-addr) < bestd)
+                { bestd = d; bestm = VCD_HERE; } /* VCD_HERE == 1 */
+
+            for(i = 0; i < ka->s_near; ++i)
+                if((d = addr - ka->near[i]) >= 0 && d < bestd)
+                    { bestd = d; bestm = i+2; }
+
+            if(ka->s_same > 0 && ka->same[d = addr%(ka->s_same*256)] == addr)
+                { bestd = d%256; bestm = ka->s_near + 2 + d/256; }
+
+            cache_update(ka,addr);
+
+            *mode = bestm; /* this returns the address encoding mode */
+            return  bestd; /* this returns the encoded address       */
+        }
+
+    Note that the addr_encode() algorithm chooses the best address mode using a
+    local optimization, but that may not lead to the best encoding efficiency
+    because different modes lead to different instruction encodings, as    described below.
+
+    The functions addrint() and addrbyte() used in addr_decode() obtain from
+    the "Addresses section for COPYs" (Section 4.3) an integer or a byte,
+    respectively. These utilities will not be described here.  We simply
+    recall that an integer is represented as a compact variable-sized string
+    of bytes as described in Section 2 (i.e., base 128).
+
+        int addr_decode(Cache_t* ka, int here, int mode)
+        {   int  addr, m;
+
+            if(mode == VCD_SELF)
+                 addr = addrint();
+            else if(mode == VCD_HERE)
+                 addr = here - addrint();
+            else if((m = mode - 2) >= 0 && m < ka->s_near) /* near cache */
+                 addr = ka->near[m] + addrint();
+            else /* same cache */
+            {    m = mode - (2 + ka->s_near);
+                 addr = ka->same[m*256 + addrbyte()];
+            }
+
+            cache_update(ka, addr);
+
+            return addr;
+        }
+
+
+5.4 Instruction Codes
+
+    As noted, the data sizes associated with delta instructions are often
+    small. Thus, compression efficiency can be improved by combining the sizes
+    and instruction types in a single encoding, as well by combining certain
+    pairs of adjacent delta instructions. Effective choices of when to perform
+    such combinations depend on many factors including the data being processed
+    and the string matching algorithm in use. For example, if many COPY
+    instructions have the same data sizes, it may be worth to encode these
+    instructions more compactly than others.
+
+    The Vcdiff data format is designed so that a decoder does not need to be
+    aware of the choices made in encoding algorithms. This is achieved with the
+    notion of an "instruction code table" containing 256 entries. Each entry
+    defines either a single delta instruction or a pair of instructions that
+    have been combined.  Note that the code table itself only exists in main
+    memory, not in the delta file (unless using an application-defined code
+    table, described in Section 7). The encoded data simply includes the index
+    of each instruction and, since there are only 256 indices, each index
+    can be represented as a single byte.
+
+    Each instruction code entry contains six fields, each of which
+    is a single byte with unsigned value:
+
+            +-----------------------------------------------+
+	    | inst1 | size1 | mode1 | inst2 | size2 | mode2 |
+	    +-----------------------------------------------+
+
+@@@ could be more compact
+
+    Each triple (inst,size,mode) defines a delta instruction. The meanings
+    of these fields are as follows:
+
+    inst: An "inst" field can have one of the four values: NOOP (0), ADD (1),
+	RUN (2) or COPY (3) to indicate the instruction types. NOOP means
+	that no instruction is specified. In this case, both the corresponding
+	size and mode fields will be zero.
+
+    size: A "size" field is zero or positive. A value zero means that the
+	size associated with the instruction is encoded separately as
+	an integer in the "Instructions and sizes section" (Section 6).
+	A positive value for "size" defines the actual data size.
+	Note that since the size is restricted to a byte, the maximum
+	value for any instruction with size implicitly defined in the code
+	table is 255.
+
+    mode: A "mode" field is significant only when the associated delta
+	instruction is a COPY. It defines the mode used to encode the
+	associated addresses. For other instructions, this is always zero.
+
+
+5.5 The Code Table
+
+    Following the discussions on address modes and instruction code tables,
+    we define a "Code Table" to have the data below:
+
+	s_near: the size of the near cache,
+	s_same: the size of the same cache,
+	i_code: the 256-entry instruction code table.
+
+    Vcdiff itself defines a "default code table" in which s_near is 4
+    and s_same is 3. Thus, there are 9 address modes for a COPY instruction.
+    The first two are VCD_SELF (0) and VCD_HERE (1). Modes 2, 3, 4 and 5
+    are for addresses coded against the near cache. And, modes 6, 7  and 8
+    are for addresses coded against the same cache.
+
+    The default instruction code table is depicted below, in a compact
+    representation that we use only for descriptive purposes.  See section 7
+    for the specification of how an instruction code table is represented
+    in the Vcdiff encoding format.  In the depiction, a zero value for
+    size indicates that the size is separately coded. The mode of non-COPY
+    instructions is represented as 0 even though they are not used.
+
+
+         TYPE      SIZE     MODE    TYPE     SIZE     MODE     INDEX
+        ---------------------------------------------------------------
+     1.  RUN         0        0     NOOP       0        0        0
+     2.  ADD    0, [1,17]     0     NOOP       0        0      [1,18]
+     3.  COPY   0, [4,18]     0     NOOP       0        0     [19,34]
+     4.  COPY   0, [4,18]     1     NOOP       0        0     [35,50]
+     5.  COPY   0, [4,18]     2     NOOP       0        0     [51,66]
+     6.  COPY   0, [4,18]     3     NOOP       0        0     [67,82]
+     7.  COPY   0, [4,18]     4     NOOP       0        0     [83,98]
+     8.  COPY   0, [4,18]     5     NOOP       0        0     [99,114]
+     9.  COPY   0, [4,18]     6     NOOP       0        0    [115,130]
+    10.  COPY   0, [4,18]     7     NOOP       0        0    [131,146]
+    11.  COPY   0, [4,18]     8     NOOP       0        0    [147,162]
+    12.  ADD       [1,4]      0     COPY     [4,6]      0    [163,174]
+    13.  ADD       [1,4]      0     COPY     [4,6]      1    [175,186]
+    14.  ADD       [1,4]      0     COPY     [4,6]      2    [187,198]
+    15.  ADD       [1,4]      0     COPY     [4,6]      3    [199,210]
+    16.  ADD       [1,4]      0     COPY     [4,6]      4    [211,222]
+    17.  ADD       [1,4]      0     COPY     [4,6]      5    [223,234]
+    18.  ADD       [1,4]      0     COPY       4        6    [235,238]
+    19.  ADD       [1,4]      0     COPY       4        7    [239,242]
+    20.  ADD       [1,4]      0     COPY       4        8    [243,246]
+    21.  COPY        4      [0,8]   ADD        1        0    [247,255]
+        ---------------------------------------------------------------
+
+    In the above depiction, each numbered line represents one or more
+    entries in the actual instruction code table (recall that an entry in
+    the instruction code table may represent up to two combined delta
+    instructions.) The last column ("INDEX") shows which index value or
+    range of index values of the entries covered by that line. The notation
+    [i,j] means values from i through j, inclusive. The first 6 columns of
+    a line in the depiction describe the pairs of instructions used for
+    the corresponding index value(s).
+
+    If a line in the depiction includes a column entry using the [i,j]
+    notation, this means that the line is instantiated for each value
+    in the range from i to j, inclusive.  The notation "0, [i,j]" means
+    that the line is instantiated for the value 0 and for each value
+    in the range from i to j, inclusive.
+
+    If a line in the depiction includes more than one entry using the [i,j]
+    notation, implying a "nested loop" to convert the line to a range of
+    table entries, the first such [i,j] range specifies the outer loop,
+    and the second specifies the inner loop.
+
+    The below examples should make clear the above description:
+
+    Line 1 shows the single RUN instruction with index 0. As the size field
+    is 0, this RUN instruction always has its actual size encoded separately.
+
+    Line 2 shows the 18 single ADD instructions. The ADD instruction with
+    size field 0 (i.e., the actual size is coded separately) has index 1.
+    ADD instructions with sizes from 1 to 17 use code indices 2 to 18 and
+    their sizes are as given (so they will not be separately encoded.)
+
+    Following the single ADD instructions are the single COPY instructions
+    ordered by their address encoding modes. For example, line 11 shows the
+    COPY instructions with mode 8, i.e., the last of the same cache.
+    In this case, the COPY instruction with size field 0 has index 147.
+    Again, the actual size of this instruction will be coded separately.
+
+    Lines 12 to 21 show the pairs of instructions that are combined together.
+    For example, line 12 depicts the 12 entries in which an ADD instruction
+    is combined with an immediately following COPY instruction. The entries
+    with indices 163, 164, 165 represent the pairs in which the ADD
+    instructions all have size 1 while the COPY instructions has mode
+    0 (VCD_SELF) and sizes 4, 5 and 6 respectively.
+
+    The last line, line 21, shows the eight instruction pairs where the first
+    instruction is a COPY and the second is an ADD. In this case, all COPY
+    instructions have size 4 with mode ranging from 0 to 8 and all the ADD
+    instructions have size 1. Thus, the entry with largest index 255
+    combines a COPY instruction of size 4 and mode 8 with an ADD instruction
+    of size 1.
+
+    The choice of the minimum size 4 for COPY instructions in the default code
+    table was made from experiments that showed that excluding small matches
+    (less then 4 bytes long) improved the compression rates.
+
+
+6. DECODING A TARGET WINDOW
+
+    Section 4.3 discusses that the delta instructions and associated data
+    are encoded in three arrays of bytes:
+
+        Data section for ADDs and RUNs,
+        Instructions and sizes section, and
+        Addresses section for COPYs.
+
+
+    Further, these data sections may have been further compressed by some
+    secondary compressor. Assuming that any such compressed data has been
+    decompressed so that we now have three arrays:
+
+	inst: bytes coding the instructions and sizes.
+        data: unmatched data associated with ADDs and RUNs.
+	addr: bytes coding the addresses of COPYs.
+
+    These arrays are organized as follows:
+
+	inst:
+	    a sequence of (index, [size1], [size2]) tuples, where "index"
+            is an index into the instruction code table, and size1 and size2
+            are integers that MAY or MAY NOT be included in the tuple as
+            follows. The entry with the given "index" in the instruction
+            code table potentially defines two delta instructions. If the
+            first delta instruction is not a VCD_NOOP and its size is zero,
+            then size1 MUST be present. Otherwise, size1 MUST be omitted and
+            the size of the instruction (if it is not VCD_NOOP) is as defined
+            in the table. The presence or absence of size2 is defined
+            similarly with respect to the second delta instruction.
+
+	data:
+	    a sequence of data values, encoded as bytes.
+
+	addr:
+	    a sequence of address values. Addresses are normally encoded as
+            integers as described in Section 2 (i.e., base 128).
+	    Since the same cache emits addresses in the range [0,255],
+	    however, same cache addresses are always encoded as a
+	    single byte.
+
+    To summarize, each tuple in the "inst" array includes an index to some
+    entry in the instruction code table that determines:
+
+    a. Whether one or two instructions were encoded and their types.
+
+    b. If the instructions have their sizes encoded separately, these
+       sizes will follow, in order, in the tuple.
+
+    c. If the instructions have accompanying data, i.e., ADDs or RUNs,
+       their data will be in the array "data".
+
+    d. Similarly, if the instructions are COPYs, the coded addresses are
+       found in the array "addr".
+
+    The decoding procedure simply processes the arrays by reading one code
+    index at a time, looking up the corresponding instruction code entry,
+    then consuming the respective sizes, data and addresses following the
+    directions in this entry. In other words, the decoder maintains an implicit
+    next-element pointer for each array; "consuming" an instruction tuple,
+    data, or address value implies incrementing the associated pointer.
+
+    For example, if during the processing of the target window, the next
+    unconsumed tuple in the inst array has index value 19, then the first
+    instruction is a COPY, whose size is found as the immediately following
+    integer in the inst array.  Since the mode of this COPY instruction is
+    VCD_SELF, the corresponding address is found by consuming the next
+    integer in the addr array.  The data array is left intact. As the second
+    instruction for code index 19 is a NOOP, this tuple is finished.
+
+
+7. APPLICATION-DEFINED CODE TABLES
+
+    Although the default code table used in Vcdiff is good for general
+    purpose encoders, there are times when other code tables may perform
+    better. For example, to code a file with many identical segments of data,
+    it may be advantageous to have a COPY instruction with the specific size
+    of these data segments so that the instruction can be encoded in a single
+    byte. Such a special code table MUST then be encoded in the delta file
+    so that the decoder can reconstruct it before decoding the data.
+
+    Vcdiff allows an application-defined code table to be specified
+    in a delta file with the following data:
+
+	Size of near cache            - byte
+	Size of same cache            - byte
+	Compressed code table data
+
+    The "compressed code table data" encodes the delta between the default
+    code table (source) and the new code table (target) in the same manner as
+    described in Section 4.3 for encoding a target window in terms of a
+    source window. This delta is computed using the following steps:
+
+    a.  Convert the new instruction code table into a string, "code", of
+	1536 bytes using the below steps in order:
+
+        i. Add in order the 256 bytes representing the types of the first
+	   instructions in the instruction pairs.
+       ii. Add in order the 256 bytes representing the types of the second
+	   instructions in the instruction pairs.
+      iii. Add in order the 256 bytes representing the sizes of the first
+	   instructions in the instruction pairs.
+       iv. Add in order the 256 bytes representing the sizes of the second
+	   instructions in the instruction pairs.
+        v. Add in order the 256 bytes representing the modes of the first
+	   instructions in the instruction pairs.
+       vi. Add in order the 256 bytes representing the modes of the second
+	   instructions in the instruction pairs.
+
+    b.  Similarly, convert the default instruction code table into
+	a string "dflt".
+
+    c.  Treat the string "code" as a target window and "dflt" as the
+	corresponding source data and apply an encoding algorithm to
+	compute the delta encoding of "code" in terms of "dflt".
+	This computation MUST use the default code table for encoding
+	the delta instructions.
+
+    The decoder can then reverse the above steps to decode the compressed
+    table data using the method of Section 6, employing the default code
+    table, to generate the new code table.  Note that the decoder does not
+    need to know anything about the details of the encoding algorithm used
+    in step (c). The decoder is still able to decode the new code table
+    because the Vcdiff format is independent from the choice of encoding
+    algorithm, and because the encoder in step (c) uses the known, default
+    code table.
+
+
+8. PERFORMANCE
+
+    The encoding format is compact. For compression only, using the LZ-77
+    string parsing strategy and without any secondary compressors, the typical
+    compression rate is better than Unix compress and close to gzip.  For
+    differencing, the data format is better than all known methods in
+    terms of its stated goal, which is primarily decoding speed and
+    encoding efficiency.
+
+    We compare the performance of compress, gzip and Vcdiff using the
+    archives of three versions of the Gnu C compiler, gcc-2.95.1.tar,
+    gcc-2.95.2.tar and gcc-2.95.3.tar. The experiments were done on an
+    SGI-MIPS3, 400MHZ. Gzip was used at its default compression level.
+    Vcdiff timings were done using the Vcodex/Vcdiff software (Section 13).
+    As string and window matching typically dominates the computation during
+    compression, the Vcdiff compression times were directly due to the
+    algorithms used in the Vcodex/Vcdiff software. However, the decompression
+    times should be generic and representative of any good implementation
+    of the Vcdiff data format. Timing was done by running each program
+    three times and taking the average of the total cpu+system times.
+
+    Below are the different Vcdiff runs:
+
+	Vcdiff: vcdiff is used as compressor only.
+
+	Vcdiff-d: vcdiff is used as a differencer only. That is, it only
+		compares target data against source data.  Since the files
+		involved are large, they are broken into windows. In this
+		case, each target window starting at some file offset in
+		the target file is compared against a source window with
+		the same file offset (in the source file). The source
+		window is also slightly larger than the target window
+		to increase matching opportunities. The -d option also gives
+		a hint to the string matching algorithm of Vcdiff that
+		the two files are very similar with long stretches of matches.
+		The algorithm takes advantage of this to minimize its
+		processing of source data and save time.
+
+	Vcdiff-dc: This is similar to Vcdiff-d but vcdiff can also compare
+		target data against target data as applicable. Thus, vcdiff
+		both computes differences and compresses data. The windowing
+		algorithm is the same as above. However, the above hint is
+		recinded in this case.
+
+	Vcdiff-dcs: This is similar to Vcdiff-dc but the windowing algorithm
+		uses a content-based heuristic to select source data segments
+		that are more likely to match with a given target window.
+		Thus, the source data segment selected for a target window
+		often will not be aligned with the file offsets of this
+		target window.
+
+
+                gcc-2.95.1    gcc-2.95.2    compression   decompression
+    raw size      55746560      55797760
+    compress         -          19939390       13.85s	      7.09s
+    gzip             -          12973443       42.99s         5.35s
+    Vcdiff           -          15358786       20.04s         4.65s
+    Vcdiff-d         -            100971       10.93s         1.92s
+    Vcdiff-dc        -             97246       20.03s         1.84s
+    Vcdiff-dcs       -            256445       44.81s         1.84s
+
+		TABLE 1. Compressing gcc-2.95.2.tar given gcc-2.95.1
+
+
+    TABLE 1 shows the raw sizes of gcc-2.95.1.tar and gcc-2.95.2.tar and the
+    sizes of the compressed results. As a pure compressor, the compression
+    rate for Vcdiff is worse than gzip and better than compress. The last
+    three rows shows that when two file versions are very similar, differencing
+    can have dramatically good compression rates. Vcdiff-d and Vcdiff-dc use
+    the same simple window selection method but Vcdiff-dc also does compression
+    so its output is slightly smaller. Vcdiff-dcs uses a heuristic based on
+    data content to search for source data that likely will match a given target
+    window. Although it does a good job, the heuristic did not always find the
+    best matches which are given by the simple algorithm of Vcdiff-d.  As a
+    result, the output size is slightly larger. Note also that there is a large
+    cost in computing matching windows this way. Finally, the compression times
+    of Vcdiff-d is nearly half of that of Vcdiff-dc. It is tempting to conclude
+    that the compression feature causes the additional time in Vcdiff-dc
+    relative to Vcdiff-d.  However, this is not the case. The hint given to
+    the Vcdiff string matching algorithm that the two files are likely to
+    have very long stretches of matches helps the algorithm to minimize
+    processing of the "source data", thus saving half the time. However, as we
+    shall see below when this hint is wrong, the result is even longer time.
+
+
+                gcc-2.95.2    gcc-2.95.3    compression   decompression
+    raw size      55797760      55787520
+    compress         -          19939453       13.54s	      7.00s
+    gzip             -          12998097       42.63s         5.62s
+    Vcdiff           -          15371737       20.09s         4.74s
+    Vcdiff-d         -          26383849       71.41s         6.41s
+    Vcdiff-dc        -          14461203       42.48s         4.82s
+    Vcdiff-dcs       -           1248543       61.18s         1.99s
+
+		TABLE 2. Compressing gcc-2.95.3.tar given gcc-2.95.2
+
+
+    TABLE 2 shows the raw sizes of gcc-2.95.2.tar and gcc-2.95.3.tar and
+    the sizes of the compressed results. In this case, the tar file of
+    gcc-2.95.3 is rearranged in a way that makes the straightforward method
+    of matching file offsets for source and target windows fail. As a
+    result, Vcdiff-d performs rather dismally both in time and output size.
+    The large time for Vcdiff-d is directly due to fact that the string
+    matching algorithm has to work much harder to find matches when the hint
+    that two files have long matching stretches fails to hold. On the other
+    hand, Vcdiff-dc does both differencing and compression resulting in good
+    output size. Finally, the window searching heuristic used in Vcdiff-dcs is
+    effective in finding the right matching source windows for target windows
+    resulting a small output size. This shows why the data format needs to
+    have a way to specify matching windows to gain performance. Finally,
+    we note that the decoding times are always good regardless of how
+    the string matching or window searching algorithms perform.
+
+
+9. FURTHER ISSUES
+
+    This document does not address a few issues:
+
+    Secondary compressors:
+        As discussed in Section 4.3, certain sections in the delta encoding
+	of a window may be further compressed by a secondary compressor.
+	In our experience, the basic Vcdiff format is adequate for most
+	purposes so that secondary compressors are seldom needed. In
+        particular, for normal use of data differencing where the files to
+	be compared have long stretches of matches, much of the gain in
+	compression rate is already achieved by normal string matching.
+	Thus, the use of secondary compressors is seldom needed in this case.
+	However, for applications beyond differencing of such nearly identical
+	files, secondary compressors may be needed to achieve maximal
+	compressed results.
+
+        Therefore, we recommend to leave the Vcdiff data format defined
+	as in this document so that the use of secondary compressors
+ 	can be implemented when they become needed in the future.
+        The formats of the compressed data via such compressors or any
+	compressors that may be defined in the future are left open to
+	their implementations.  These could include Huffman encoding,
+	arithmetic encoding, and splay tree encoding [8,9].
+
+    Large file system vs. small file system:
+	As discussed in Section 4, a target window in a large file may be
+	compared against some source window in another file or in the same
+	file (from some earlier part). In that case, the file offset of the
+	source window is specified as a variable-sized integer in the delta
+	encoding. There is a possibility that the encoding was computed on
+	a system supporting much larger files than in a system where
+	the data may be decoded (e.g., 64-bit file systems vs. 32-bit file
+	systems). In that case, some target data may not be recoverable.
+	This problem could afflict any compression format, and ought
+	to be resolved with a generic negotiation mechanism in the
+	appropriate protocol(s).
+
+
+10.  SUMMARY
+
+    We have described Vcdiff, a general and portable encoding format for
+    compression and differencing. The format is good in that it allows
+    implementing a decoder without knowledge of the encoders. Further,
+    ignoring the use of secondary compressors not defined within the format,
+    the decoding algorithms runs in linear time and requires working space
+    proportional to window sizes.
+
+
+
+11. ACKNOWLEDGEMENTS
+
+    Thanks are due to Balachander Krishnamurthy, Jeff Mogul and Arthur Van Hoff
+    who provided much encouragement to publicize Vcdiff. In particular, Jeff
+    helped clarifying the description of the data format presented here.
+
+
+
+12. SECURITY CONSIDERATIONS
+
+    Vcdiff only provides a format to encode compressed and differenced data.
+    It does not address any issues concerning how such data are, in fact,
+    stored in a given file system or the run-time memory of a computer system.
+    Therefore, we do not anticipate any security issues with respect to Vcdiff.
+
+
+
+13. SOURCE CODE AVAILABILITY
+
+    Vcdiff is implemented as a data transforming method in Phong Vo's
+    Vcodex library. AT&T Corp. has made the source code for Vcodex available
+    for anyone to use to transmit data via HTTP/1.1 Delta Encoding [10,11].
+    The source code and according license is accessible at the below URL:
+
+          http://www.research.att.com/sw/tools
+
+
+14. INTELLECTUAL PROPERTY RIGHTS
+
+   The IETF has been notified of intellectual property rights claimed in
+   regard to some or all of the specification contained in this
+   document.  For more information consult the online list of claimed
+   rights, at <http://www.ietf.org/ipr.html>.
+
+   The IETF takes no position regarding the validity or scope of any
+   intellectual property or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; neither does it represent that it
+   has made any effort to identify any such rights.  Information on the
+   IETF's procedures with respect to rights in standards-track and
+   standards-related documentation can be found in BCP-11.  Copies of
+   claims of rights made available for publication and any assurances of
+   licenses to be made available, or the result of an attempt made to
+   obtain a general license or permission for the use of such
+   proprietary rights by implementors or users of this specification can
+   be obtained from the IETF Secretariat.
+
+
+
+15. IANA CONSIDERATIONS
+
+   The Internet Assigned Numbers Authority (IANA) administers the number
+   space for Secondary Compressor ID values.  Values and their meaning
+   must be documented in an RFC or other peer-reviewed, permanent, and
+   readily available reference, in sufficient detail so that
+   interoperability between independent implementations is possible.
+   Subject to these constraints, name assignments are First Come, First
+   Served - see RFC2434 [13].  Legal ID values are in the range 1..255.
+
+   This document does not define any values in this number space.
+
+
+16. REFERENCES
+
+    [1] D.G. Korn and K.P. Vo, Vdelta: Differencing and Compression,
+        Practical Reusable Unix Software, Editor B. Krishnamurthy,
+        John Wiley & Sons, Inc., 1995.
+
+    [2] J. Ziv and A. Lempel, A Universal Algorithm for Sequential Data
+        Compression, IEEE Trans. on Information Theory, 23(3):337-343, 1977.
+
+    [3] W. Tichy, The String-to-String Correction Problem with Block Moves,
+        ACM Transactions on Computer Systems, 2(4):309-321, November 1984.
+
+    [4] E.M. McCreight, A Space-Economical Suffix Tree Construction
+        Algorithm, Journal of the ACM, 23:262-272, 1976.
+
+    [5] J.J. Hunt, K.P. Vo, W. Tichy, An Empirical Study of Delta Algorithms,
+        IEEE Software Configuration and Maintenance Workshop, 1996.
+
+    [6] J.J. Hunt, K.P. Vo, W. Tichy, Delta Algorithms: An Empirical Analysis,
+        ACM Trans. on Software Engineering and Methodology, 7:192-214, 1998.
+
+    [7] D.G. Korn, K.P. Vo, Sfio: A buffered I/O Library,
+        Proc. of the Summer '91 Usenix Conference, 1991.
+
+    [8] D. W. Jones, Application of Splay Trees to Data Compression,
+        CACM, 31(8):996:1007.
+
+    [9] M. Nelson, J. Gailly, The Data Compression Book, ISBN 1-55851-434-1,
+        M&T Books, New York, NY, 1995.
+
+   [10] J.C. Mogul, F. Douglis, A. Feldmann, and B. Krishnamurthy,
+        Potential benefits of delta encoding and data compression for HTTP,
+        SIGCOMM '97, Cannes, France, 1997.
+
+   [11] J.C. Mogul, B. Krishnamurthy, F. Douglis, A. Feldmann,
+        Y. Goland, and A. Van Hoff, Delta Encoding in HTTP,
+        IETF, draft-mogul-http-delta-10, 2001.
+
+   [12] S. Bradner, Key words for use in RFCs to Indicate Requirement Levels,
+        RFC 2119, March 1997.
+
+   [13] T. Narten, H. Alvestrand, Guidelines for Writing an IANA
+        Considerations Section in RFCs, RFC2434, October 1998.
+
+
+
+17. AUTHOR'S ADDRESS
+
+    Kiem-Phong Vo (main contact)
+    AT&T Labs, Room D223
+    180 Park Avenue
+    Florham Park, NJ 07932
+    Email: kpv@research.att.com
+    Phone: 1 973 360 8630
+
+    David G. Korn
+    AT&T Labs, Room D237
+    180 Park Avenue
+    Florham Park, NJ 07932
+    Email: dgk@research.att.com
+    Phone: 1 973 360 8602
+
+    Jeffrey C. Mogul
+    Western Research Laboratory
+    Compaq Computer Corporation
+    250 University Avenue
+    Palo Alto, California, 94305, U.S.A.
+    Email: JeffMogul@acm.org
+    Phone: 1 650 617 3304 (email preferred)
+
+    Joshua P. MacDonald
+    Computer Science Division
+    University of California, Berkeley
+    345 Soda Hall
+    Berkeley, CA 94720
+    Email: jmacd@cs.berkeley.edu
Index: /nikanabo/current/xdelta/diy/examples/Makefile
===================================================================
--- /nikanabo/current/xdelta/diy/examples/Makefile	(revision 185)
+++ /nikanabo/current/xdelta/diy/examples/Makefile	(revision 185)
@@ -0,0 +1,9 @@
+CFLAGS = -g -Wall -I ..
+
+SOURCES = small_page_test.c
+
+small_page_test: $(SOURCES)
+	$(CC) $(CFLAGS) small_page_test.c -o small_page_test -DXD3_USE_LARGEFILE64=1 -DSECONDARY_DJW=1 -DXD3_DEBUG=1
+
+clean:
+	rm -f *.exe *.stackdump
Index: /nikanabo/current/xdelta/diy/examples/small_page_test.c
===================================================================
--- /nikanabo/current/xdelta/diy/examples/small_page_test.c	(revision 185)
+++ /nikanabo/current/xdelta/diy/examples/small_page_test.c	(revision 185)
@@ -0,0 +1,198 @@
+/* Copyright (C) 2007 Josh MacDonald */
+
+#include <stdio.h>
+
+#define PAGE_SIZE 4096
+
+#define SPACE_MAX 131072   // how much memory per process
+#define OUTPUT_MAX 1024    // max size for output
+#define XD3_ALLOCSIZE 256  // internal size for various buffers
+#define IOPT_SIZE 128      // instruction buffer
+
+// SPACE_MAX of 32K is sufficient for most inputs with XD3_COMPLEVEL_1
+// XD3_COMPLEVEL_9 requires about 4x more space than XD3_COMPLEVEL_1
+
+#include "xdelta3.h"
+#include "xdelta3.c"
+
+typedef struct _context {
+  uint8_t *buffer;
+  int allocated;
+} context_t;
+
+static int max_allocated = 0;
+
+void*
+process_alloc (void* opaque, usize_t items, usize_t size)
+{
+  context_t *ctx = (context_t*) opaque;
+  usize_t t = items * size;
+  void *ret;
+
+  if (ctx->allocated + t > SPACE_MAX)
+    {
+      return NULL;
+    }
+
+  ret = ctx->buffer + ctx->allocated;
+  ctx->allocated += t;
+  return ret;
+}
+
+void
+process_free (void* opaque, void *ptr)
+{
+}
+
+int
+process_page (int            is_encode,
+	      int          (*func) (xd3_stream *),
+	      const uint8_t *input,
+	      usize_t        input_size,
+	      const uint8_t *source,
+	      uint8_t       *output,
+	      usize_t       *output_size,
+	      usize_t        output_size_max,
+	      int            flags) {
+
+  /* On my x86 this is 1072 of objects on the stack */
+  xd3_stream stream;
+  xd3_config config;
+  xd3_source src;
+  context_t *ctx = calloc(SPACE_MAX, 1);
+  int ret;
+
+  if (ctx == NULL)
+    {
+      printf("calloc failed\n");
+      return -1;
+    }
+
+  ctx->buffer = (uint8_t*)ctx;
+  ctx->allocated = sizeof(*ctx);
+
+  config.flags = flags;
+  config.winsize = PAGE_SIZE;
+  config.sprevsz = PAGE_SIZE;
+  config.srcwin_maxsz = PAGE_SIZE;
+  config.iopt_size = IOPT_SIZE;
+  config.alloc = &process_alloc;
+  config.freef = &process_free;
+  config.opaque = (void*) ctx;
+
+  src.size = PAGE_SIZE;
+  src.blksize = PAGE_SIZE;
+  src.onblk = PAGE_SIZE;
+  src.curblk = source;
+  src.curblkno = 0;
+
+  if ((ret = xd3_config_stream (&stream, &config)) != 0 ||
+      (ret = xd3_set_source (&stream, &src)) != 0 ||
+      (ret = xd3_process_stream (is_encode,
+				 &stream,
+				 func, 1,
+				 input, input_size,
+				 output, output_size,
+				 output_size_max)) != 0)
+    {
+      if (stream.msg != NULL)
+	{
+	  fprintf(stderr, "stream message: %s\n", stream.msg);
+	}
+    }
+
+  xd3_free_stream (&stream);
+  if (max_allocated < ctx->allocated)
+    {
+      max_allocated = ctx->allocated;
+      fprintf(stderr, "max allocated %d\n", max_allocated);
+    }
+
+  free(ctx);
+  return ret;
+}
+
+int test(int stride, int encode_flags)
+{
+  uint8_t frompg[PAGE_SIZE];
+  uint8_t topg[PAGE_SIZE];
+  uint8_t output[OUTPUT_MAX];
+  uint8_t reout[PAGE_SIZE];
+  usize_t output_size;
+  usize_t re_size;
+  int i, j, ret;
+
+  for (i = 0; i < PAGE_SIZE; i++)
+    {
+      topg[i] = frompg[i] = (rand() >> 3 ^ rand() >> 6 ^ rand() >> 9);
+    }
+
+  // change 1 byte every stride
+  if (stride > 0)
+    {
+      for (j = stride; j <= PAGE_SIZE; j += stride)
+	{
+	  topg[j - 1] ^= 0xff;
+	}
+    }
+
+  if ((ret = process_page (1, xd3_encode_input,
+			   topg, PAGE_SIZE,
+			   frompg, output,
+			   &output_size, OUTPUT_MAX,
+			   encode_flags)) != 0)
+    {
+      fprintf (stderr, "encode failed: stride %u flags 0x%x\n", stride, encode_flags);
+      return ret;
+    }
+
+  if ((ret = process_page (0, xd3_decode_input,
+			   output, output_size,
+			   frompg, reout,
+			   &re_size, PAGE_SIZE,
+			   0)) != 0)
+    {
+      fprintf (stderr, "decode failed: stride %u output_size %u flags 0x%x\n",
+	      stride, output_size, encode_flags);
+      return ret;
+    }
+
+  if (output_size > OUTPUT_MAX || re_size != PAGE_SIZE)
+    {
+      fprintf (stderr, "internal error: %u != %u\n", output_size, re_size);
+      return -1;
+    }
+
+  for (i = 0; i < PAGE_SIZE; i++)
+    {
+      if (reout[i] != topg[i])
+	{
+	  fprintf (stderr, "encode-decode error: position %d\n", i);
+	  return -1;
+	}
+    }
+
+  fprintf(stderr, "stride %d flags 0x%x size %u ", stride, encode_flags, output_size);
+  fprintf(stderr, "%s\n", (ret == 0) ? "OK" : "FAIL");
+
+  return 0;
+}
+
+int main()
+{
+  int stride;
+  int level;
+
+  for (level = 1; level < 10; level = (level == 1 ? 3 : level + 3))
+    {
+      int lflag = level << XD3_COMPLEVEL_SHIFT;
+
+      for (stride = 2; stride <= PAGE_SIZE; stride += 2)
+	{
+	  test(stride, lflag);
+	  test(stride, lflag | XD3_SEC_DJW);
+	}
+    }
+
+  return 0;
+}
Index: /nikanabo/current/xdelta/diy/linkxd3lib.c
===================================================================
--- /nikanabo/current/xdelta/diy/linkxd3lib.c	(revision 185)
+++ /nikanabo/current/xdelta/diy/linkxd3lib.c	(revision 185)
@@ -0,0 +1,47 @@
+#include "xdelta3.h"
+
+extern int VVV;
+
+int VVV;
+
+void use(int r)
+{
+  VVV = r;
+}
+
+int main() {
+  xd3_config config;
+  xd3_stream stream;
+  xd3_source source;
+
+  xd3_init_config (& config, 0);
+  use (xd3_config_stream (&stream, &config));
+  use (xd3_close_stream (&stream));
+  xd3_abort_stream (&stream);
+  xd3_free_stream (&stream);
+  
+  xd3_avail_input (& stream, NULL, 0);
+  xd3_consume_output (& stream);
+  
+  use (xd3_bytes_on_srcblk (& source, 0));
+  use (xd3_set_source (& stream, & source));
+  xd3_set_flags (& stream, 0);
+  
+  use (xd3_decode_stream (& stream, NULL, 0, NULL, NULL, 0));
+  use (xd3_decode_input (&stream));
+  use (xd3_decoder_needs_source (& stream));
+  use (xd3_get_appheader (& stream, NULL, NULL));
+  
+  use ((int) xd3_errstring (& stream));
+  use ((int) xd3_strerror (0));
+			     
+#if XD3_ENCODER
+  use (xd3_encode_input (&stream));
+  use (xd3_encode_stream (& stream, NULL, 0, NULL, NULL, 0));
+  use (xd3_set_appheader (& stream));
+  use (xd3_encoder_used_source (& stream));
+  use (xd3_encoder_srcbase (& stream));
+  use (xd3_encoder_srclen (& stream));
+#endif
+  return 0;
+}
Index: /nikanabo/current/xdelta/diy/setup.py
===================================================================
--- /nikanabo/current/xdelta/diy/setup.py	(revision 185)
+++ /nikanabo/current/xdelta/diy/setup.py	(revision 185)
@@ -0,0 +1,58 @@
+# xdelta 3 - delta compression tools and library
+# Copyright (C) 2004, 2007.  Joshua P. MacDonald
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+#
+from distutils.core import setup, Extension
+from distutils.util import get_platform
+
+# External compression support works on Windows/Cygwin, but not from
+# within the Python module. It's something to do with fork() and
+# exec() support.
+#platform  = get_platform()
+#is_cygwin = platform.startswith('cygwin')
+
+xdelta3_ext = Extension('xdelta3main',
+                        ['xdelta3.c'],
+                        define_macros = [
+                                         ('PYTHON_MODULE',1),
+                                         ('SECONDARY_DJW',1),
+                                         ('VCDIFF_TOOLS',1),
+                                         ('GENERIC_ENCODE_TABLES',1),
+                                         ('XD3_POSIX',1),
+                                         ('XD3_USE_LARGEFILE64',1),
+
+                                         # the fork/exec stuff doesn't
+                                         # work inside python.
+                                         ('EXTERNAL_COMPRESSION',0),
+
+                                         ('REGRESSION_TEST',0),
+                                         ('SECONDARY_FGK',0),
+                                         ('XD3_DEBUG',0),
+                                         ],
+                        extra_compile_args = [ '-O3',
+                                               '-g',
+                                               '-funroll-loops',
+                                               ])
+
+# $Format: "REL='$Xdelta3Version$'" $
+REL='0q'
+
+# This provides xdelta3.main(), which calls the xdelta3 command-line main()
+# from python.
+setup(name='xdelta3main',
+      version=REL,
+      ext_modules=[xdelta3_ext])
Index: /nikanabo/current/xdelta/diy/xdelta3-cfgs.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-cfgs.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-cfgs.h	(revision 185)
@@ -0,0 +1,148 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007. Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/******************************************************************************************
+ SOFT string matcher
+ ******************************************************************************************/
+
+#if XD3_BUILD_SOFT
+
+#define TEMPLATE      soft
+#define LLOOK         stream->smatcher.large_look
+#define LSTEP         stream->smatcher.large_step
+#define SLOOK         stream->smatcher.small_look
+#define SCHAIN        stream->smatcher.small_chain
+#define SLCHAIN       stream->smatcher.small_lchain
+#define MAXLAZY       stream->smatcher.max_lazy
+#define LONGENOUGH    stream->smatcher.long_enough
+
+#define SOFTCFG 1
+#include "xdelta3.c"
+#undef  SOFTCFG
+
+#undef  TEMPLATE
+#undef  LLOOK
+#undef  SLOOK
+#undef  LSTEP
+#undef  SCHAIN
+#undef  SLCHAIN
+#undef  MAXLAZY
+#undef  LONGENOUGH
+#endif
+
+#define SOFTCFG 0
+
+/******************************************************************************************
+ FASTEST string matcher
+ ******************************************************************************************/
+#if XD3_BUILD_FASTEST
+#define TEMPLATE      fastest
+#define LLOOK         9
+#define LSTEP         15
+#define SLOOK         4
+#define SCHAIN        1
+#define SLCHAIN       1
+#define MAXLAZY       18
+#define LONGENOUGH    18
+
+#include "xdelta3.c"
+
+#undef  TEMPLATE
+#undef  LLOOK
+#undef  SLOOK
+#undef  LSTEP
+#undef  SCHAIN
+#undef  SLCHAIN
+#undef  MAXLAZY
+#undef  LONGENOUGH
+#endif
+
+/******************************************************************************************
+ FAST string matcher
+ ******************************************************************************************/
+#if XD3_BUILD_FAST
+#define TEMPLATE      fast
+#define LLOOK         9
+#define LSTEP         8
+#define SLOOK         4
+#define SCHAIN        4
+#define SLCHAIN       1
+#define MAXLAZY       18
+#define LONGENOUGH    35
+
+#include "xdelta3.c"
+
+#undef  TEMPLATE
+#undef  LLOOK
+#undef  SLOOK
+#undef  LSTEP
+#undef  SCHAIN
+#undef  SLCHAIN
+#undef  MAXLAZY
+#undef  LONGENOUGH
+#endif
+
+/******************************************************************************************
+ SLOW string matcher
+ ******************************************************************************************/
+#if XD3_BUILD_SLOW
+#define TEMPLATE      slow
+#define LLOOK         9
+#define LSTEP         2
+#define SLOOK         4
+#define SCHAIN        44
+#define SLCHAIN       13
+#define MAXLAZY       90
+#define LONGENOUGH    70
+
+#include "xdelta3.c"
+
+#undef  TEMPLATE
+#undef  LLOOK
+#undef  SLOOK
+#undef  LSTEP
+#undef  SCHAIN
+#undef  SLCHAIN
+#undef  MAXLAZY
+#undef  LONGENOUGH
+#endif
+
+/******************************************************************************************
+ DEFAULT string matcher
+ ******************************************************************************************/
+#if XD3_BUILD_DEFAULT
+#define TEMPLATE      default
+#define LLOOK         9
+#define LSTEP         3
+#define SLOOK         4
+#define SCHAIN        8
+#define SLCHAIN       2
+#define MAXLAZY       36
+#define LONGENOUGH    70
+
+#include "xdelta3.c"
+
+#undef  TEMPLATE
+#undef  LLOOK
+#undef  SLOOK
+#undef  LSTEP
+#undef  SCHAIN
+#undef  SLCHAIN
+#undef  MAXLAZY
+#undef  LONGENOUGH
+#endif
Index: /nikanabo/current/xdelta/diy/xdelta3-decode.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-decode.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-decode.h	(revision 185)
@@ -0,0 +1,1030 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _XDELTA3_DECODE_H_
+#define _XDELTA3_DECODE_H_
+
+
+/* Return true if the caller must provide a source.  Theoretically, this has to be checked
+ * after every window.  It could be that the first window requires no source, but the
+ * second window does.  In practice? */
+int xd3_decoder_needs_source (xd3_stream *stream)
+{
+  return stream->dec_win_ind & VCD_SOURCE;
+}
+
+/* Initialize the decoder for a new window.  The dec_tgtlen value is preserved across
+ * successive window decodings, and the update to dec_winstart is delayed until a new
+ * window actually starts.  This is to avoid throwing an error due to overflow until the
+ * last possible moment.  This makes it possible to encode exactly 4GB through a 32-bit
+ * encoder. */
+static int
+xd3_decode_init_window (xd3_stream *stream)
+{
+  stream->dec_cpylen = 0;
+  stream->dec_cpyoff = 0;
+  stream->dec_cksumbytes = 0;
+
+  xd3_init_cache (& stream->acache);
+
+  return 0;
+}
+
+/* Allocates buffer space for the target window and possibly the VCD_TARGET copy-window.
+ * Also sets the base of the two copy segments. */
+static int
+xd3_decode_setup_buffers (xd3_stream *stream)
+{
+  /* If VCD_TARGET is set then the previous buffer may be reused. */
+  if (stream->dec_win_ind & VCD_TARGET)
+    {
+      /* But this implementation only supports copying from the last target window.  If the
+       * offset is outside that range, it can't be done. */
+      if (stream->dec_cpyoff < stream->dec_laststart)
+	{
+	  stream->msg = "unsupported VCD_TARGET offset";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* See if the two windows are the same.  This indicates the first time VCD_TARGET is
+       * used.  This causes a second buffer to be allocated, after that the two are
+       * swapped in the DEC_FINISH case. */
+      if (stream->dec_lastwin == stream->next_out)
+	{
+	  stream->next_out  = NULL;
+	  stream->space_out = 0;
+	}
+
+      stream->dec_cpyaddrbase = stream->dec_lastwin + (usize_t) (stream->dec_cpyoff - stream->dec_laststart);
+    }
+
+  /* See if the current output window is large enough. */
+  if (stream->space_out < stream->dec_tgtlen)
+    {
+      xd3_free (stream, stream->dec_buffer);
+
+      stream->space_out = xd3_round_blksize (stream->dec_tgtlen, XD3_ALLOCSIZE);
+
+      if ((stream->dec_buffer = xd3_alloc (stream, stream->space_out, 1)) == NULL)
+	{
+	  return ENOMEM;
+	}
+
+      stream->next_out = stream->dec_buffer;
+    }
+
+  /* dec_tgtaddrbase refers to an invalid base address, but it is always used with a
+   * sufficiently large instruction offset (i.e., beyond the copy window).  This condition
+   * is enforced by xd3_decode_output_halfinst. */
+  stream->dec_tgtaddrbase = stream->next_out - stream->dec_cpylen;
+
+  return 0;
+}
+
+static int
+xd3_decode_allocate (xd3_stream  *stream,
+		     usize_t       size,
+		     uint8_t    **copied1,
+		     usize_t      *alloc1,
+		     uint8_t    **copied2,
+		     usize_t      *alloc2)
+{
+  if (*copied1 != NULL && *alloc1 < size)
+    {
+      xd3_free (stream, *copied1);
+      *copied1 = NULL;
+    }
+
+  if (*copied1 == NULL)
+    {
+      *alloc1 = xd3_round_blksize (size, XD3_ALLOCSIZE);
+
+      if ((*copied1 = xd3_alloc (stream, *alloc1, 1)) == NULL)
+	{
+	  return ENOMEM;
+	}
+    }
+
+  return 0;
+}
+
+static int
+xd3_decode_section (xd3_stream *stream,
+		    xd3_desect *section,
+		    xd3_decode_state nstate,
+		    int copy)
+{
+  XD3_ASSERT (section->pos <= section->size);
+  XD3_ASSERT (stream->dec_state != nstate);
+
+  if (section->pos < section->size)
+    {
+      usize_t sect_take;
+
+      if (stream->avail_in == 0)
+	{
+	  return XD3_INPUT;
+	}
+
+      if ((copy == 0) && (section->pos == 0))
+	{
+	  /* No allocation/copy needed */
+	  section->buf = stream->next_in;
+	  sect_take    = section->size;
+	}
+      else
+	{
+	  usize_t sect_need = section->size - section->pos;
+
+	  /* Allocate and copy */
+	  sect_take = min (sect_need, stream->avail_in);
+
+	  if (section->pos == 0)
+	    {
+	      int ret;
+
+	      if ((ret = xd3_decode_allocate (stream,
+					      section->size,
+					      & section->copied1,
+					      & section->alloc1,
+					      & section->copied2,
+					      & section->alloc2))) { return ret; }
+
+	      section->buf = section->copied1;
+	    }
+
+	  memcpy (section->copied1 + section->pos,
+		  stream->next_in,
+		  sect_take);
+	}
+
+      section->pos += sect_take;
+
+      stream->dec_winbytes += sect_take;
+
+      DECODE_INPUT (sect_take);
+    }
+
+  if (section->pos < section->size)
+    {
+      stream->msg = "further input required";
+      return XD3_INPUT;
+    }
+
+  XD3_ASSERT (section->pos == section->size);
+
+  stream->dec_state = nstate;
+  section->buf_max  = section->buf + section->size;
+  section->pos      = 0;
+  return 0;
+}
+
+/* Decode the size and address for half of an instruction (i.e., a single opcode).  This
+ * updates the stream->dec_position, which are bytes already output prior to processing
+ * this instruction.  Perform bounds checking for sizes and copy addresses, which uses the
+ * dec_position (which is why these checks are done here). */
+static int
+xd3_decode_parse_halfinst (xd3_stream *stream, xd3_hinst *inst)
+{
+  int ret;
+
+  /* If the size from the instruction table is zero then read a size value. */
+  if ((inst->size == 0) &&
+      (ret = xd3_read_size (stream,
+ 			    & stream->inst_sect.buf,
+			      stream->inst_sect.buf_max,
+			    & inst->size)))
+    {
+      return XD3_INVALID_INPUT;
+    }
+
+  /* For copy instructions, read address. */
+  if (inst->type >= XD3_CPY)
+    {
+      IF_DEBUG1 ({
+	static int cnt = 0;
+	DP(RINT "DECODE:%u: COPY at %"Q"u (winoffset %u) size %u winaddr %u\n",
+		 cnt++,
+		 stream->total_out + (stream->dec_position - stream->dec_cpylen),
+		 (stream->dec_position - stream->dec_cpylen),
+		 inst->size,
+		 inst->addr);
+      });
+
+      if ((ret = xd3_decode_address (stream,
+				     stream->dec_position,
+				     inst->type - XD3_CPY,
+				     & stream->addr_sect.buf,
+				     stream->addr_sect.buf_max,
+				     & inst->addr)))
+	{
+	  return ret;
+	}
+
+      /* Cannot copy an address before it is filled-in. */
+      if (inst->addr >= stream->dec_position)
+	{
+	  stream->msg = "address too large";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* Check: a VCD_TARGET or VCD_SOURCE copy cannot exceed the remaining buffer space
+       * in its own segment. */
+      if (inst->addr < stream->dec_cpylen && inst->addr + inst->size > stream->dec_cpylen)
+	{
+	  stream->msg = "size too large";
+	  return XD3_INVALID_INPUT;
+	}
+    }
+  else
+    {
+      IF_DEBUG1 ({
+	if (inst->type == XD3_ADD)
+	  {
+	    static int cnt;
+	    DP(RINT "DECODE:%d: ADD at %"Q"u (winoffset %u) size %u\n",
+		     cnt++,
+		     stream->total_out + stream->dec_position - stream->dec_cpylen,
+		     stream->dec_position - stream->dec_cpylen,
+		     inst->size);
+	  }
+	else
+	  {
+	    static int cnt;
+	    XD3_ASSERT (inst->type == XD3_RUN);
+	    DP(RINT "DECODE:%d: RUN at %"Q"u (winoffset %u) size %u\n",
+		     cnt++,
+		     stream->total_out + stream->dec_position - stream->dec_cpylen,
+		     stream->dec_position - stream->dec_cpylen,
+		     inst->size);
+	  }
+      });
+    }
+
+  /* Check: The instruction will not overflow the output buffer. */
+  if (stream->dec_position + inst->size > stream->dec_maxpos)
+    {
+      stream->msg = "size too large";
+      return XD3_INVALID_INPUT;
+    }
+
+  stream->dec_position += inst->size;
+  return 0;
+}
+
+/* Decode a single opcode and then decode the two half-instructions. */
+static int
+xd3_decode_instruction (xd3_stream *stream)
+{
+  int ret;
+  const xd3_dinst *inst;
+
+  if (stream->inst_sect.buf == stream->inst_sect.buf_max)
+    {
+      stream->msg = "instruction underflow";
+      return XD3_INVALID_INPUT;
+    }
+
+  inst = &stream->code_table[*stream->inst_sect.buf++];
+
+  stream->dec_current1.type = inst->type1;
+  stream->dec_current2.type = inst->type2;
+  stream->dec_current1.size = inst->size1;
+  stream->dec_current2.size = inst->size2;
+
+  /* For each instruction with a real operation, decode the corresponding size and
+   * addresses if necessary.  Assume a code-table may have NOOP in either position,
+   * although this is unlikely. */
+  if (inst->type1 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current1)))
+    {
+      return ret;
+    }
+  if (inst->type2 != XD3_NOOP && (ret = xd3_decode_parse_halfinst (stream, & stream->dec_current2)))
+    {
+      return ret;
+    }
+  return 0;
+}
+
+/* Output the result of a single half-instruction. OPT: This the decoder hotspot. */
+static int
+xd3_decode_output_halfinst (xd3_stream *stream, xd3_hinst *inst)
+{
+  /* To make this reentrant, set take = min (inst->size, available space)... */
+  usize_t take = inst->size;
+
+  XD3_ASSERT (inst->type != XD3_NOOP);
+
+  switch (inst->type)
+    {
+    case XD3_RUN:
+      {
+	/* Only require a single data byte. */
+	if (stream->data_sect.buf == stream->data_sect.buf_max)
+	  {
+	    stream->msg = "data underflow";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	/* TUNE: Probably want to eliminate memset/memcpy here */
+	memset (stream->next_out + stream->avail_out,
+		stream->data_sect.buf[0],
+		take);
+
+	stream->data_sect.buf += 1;
+	stream->avail_out += take;
+	inst->type = XD3_NOOP;
+	break;
+      }
+    case XD3_ADD:
+      {
+	/* Require at least TAKE data bytes. */
+	if (stream->data_sect.buf + take > stream->data_sect.buf_max)
+	  {
+	    stream->msg = "data underflow";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	memcpy (stream->next_out + stream->avail_out,
+		stream->data_sect.buf,
+		take);
+
+	stream->data_sect.buf += take;
+	stream->avail_out += take;
+	inst->type = XD3_NOOP;
+	break;
+      }
+    default:
+      {
+	usize_t i;
+	const uint8_t *src;
+	uint8_t *dst;
+
+	/* See if it copies from the VCD_TARGET/VCD_SOURCE window or the target window.
+	 * Out-of-bounds checks for the addresses and sizes are performed in
+	 * xd3_decode_parse_halfinst. */
+	if (inst->addr < stream->dec_cpylen)
+	  {
+	    if (stream->dec_win_ind & VCD_TARGET)
+	      {
+		/* For VCD_TARGET we know the entire range is in-memory, as established by
+		 * decode_setup_buffers. */
+		src = stream->dec_cpyaddrbase + inst->addr;
+		inst->type = XD3_NOOP;
+		inst->size = 0;
+	      }
+	    else
+	      {
+		/* In this case we have to read a source block, which could return control
+		 * to the caller.  We need to know the first block number needed for this
+		 * copy. */
+		xd3_source *source;
+		xoff_t block;
+		usize_t blkoff;
+		usize_t blksize;
+		int ret;
+
+	      more:
+
+		source  = stream->src;
+		block   = source->cpyoff_blocks;
+		blkoff  = source->cpyoff_blkoff + inst->addr;
+		blksize = source->blksize;
+
+ 		while (blkoff >= blksize)
+		  {
+		    block  += 1;
+		    blkoff -= blksize;
+		  }
+
+		if ((ret = xd3_getblk (stream, block)))
+		  {
+		    /* could be a XD3_GETSRCBLK failure. */
+		    XD3_ASSERT(ret != XD3_TOOFARBACK);
+		    return ret;
+		  }
+
+		src = source->curblk + blkoff;
+
+		/* This block either contains enough data or the source file is
+		 * short. */
+		if ((source->onblk != blksize) && (blkoff + take > source->onblk))
+		  {
+		    stream->msg = "source file too short";
+		    return XD3_INVALID_INPUT;
+
+		  }
+
+		XD3_ASSERT (blkoff != blksize);
+
+		if (blkoff + take <= blksize)
+		  {
+		    inst->type = XD3_NOOP;
+		    inst->size = 0;
+		  }
+		else
+		  {
+		    /* This block doesn't contain all the data, modify the instruction, do
+		     * not set to XD3_NOOP. */
+		    take = blksize - blkoff;
+		    inst->size -= take;
+		    inst->addr += take;
+		  }
+	      }
+	  }
+	else
+	  {
+	    /* For a target-window copy, we know the entire range is in-memory.  The
+	     * dec_tgtaddrbase is negatively offset by dec_cpylen because the addresses
+	     * start beyond that point. */
+	    src = stream->dec_tgtaddrbase + inst->addr;
+	    inst->type = XD3_NOOP;
+	    inst->size = 0;
+	  }
+
+ 	dst = stream->next_out + stream->avail_out;
+
+	stream->avail_out += take;
+
+	/* Can't just memcpy here due to possible overlap. */
+	for (i = take; i != 0; i -= 1)
+	  {
+	    *dst++ = *src++;
+	  }
+
+	take = inst->size;
+
+	/* If there is more to copy, call getblk again. */
+	if (inst->type != XD3_NOOP)
+	  {
+	    XD3_ASSERT (take > 0);
+	    goto more;
+	  }
+	else
+	  {
+	    XD3_ASSERT (take == 0);
+	  }
+      }
+    }
+
+  return 0;
+}
+
+static int
+xd3_decode_finish_window (xd3_stream *stream)
+{
+  stream->dec_winbytes  = 0;
+  stream->dec_state     = DEC_FINISH;
+
+  stream->data_sect.pos = 0;
+  stream->inst_sect.pos = 0;
+  stream->addr_sect.pos = 0;
+
+  return XD3_OUTPUT;
+}
+
+static int
+xd3_decode_sections (xd3_stream *stream)
+{
+  usize_t need, more, take;
+  int copy, ret;
+
+  if ((stream->flags & XD3_JUST_HDR) != 0)
+    {
+      /* Nothing left to do. */
+      return xd3_decode_finish_window (stream);
+    }
+
+  /* To avoid copying, need this much data available */
+  need = (stream->inst_sect.size +
+	  stream->addr_sect.size +
+	  stream->data_sect.size);
+
+  /* The window may be entirely processed. */
+  XD3_ASSERT (stream->dec_winbytes <= need);
+
+  /* Compute how much more input is needed. */
+  more = (need - stream->dec_winbytes);
+
+  /* How much to consume. */
+  take = min (more, stream->avail_in);
+
+  /* See if the input is completely available, to avoid copy. */
+  copy = (take != more);
+
+  /* If the window is skipped... */
+  if ((stream->flags & XD3_SKIP_WINDOW) != 0)
+    {
+      /* Skip the available input. */
+      DECODE_INPUT (take);
+
+      stream->dec_winbytes += take;
+
+      if (copy)
+	{
+	  stream->msg = "further input required";
+	  return XD3_INPUT;
+	}
+
+      return xd3_decode_finish_window (stream);
+    }
+
+  /* Process all but the DATA section. */
+  switch (stream->dec_state)
+    {
+    default:
+      stream->msg = "internal error";
+      return XD3_INVALID_INPUT;
+
+    case DEC_DATA:
+      if ((ret = xd3_decode_section (stream, & stream->data_sect, DEC_INST, copy))) { return ret; }
+    case DEC_INST:
+      if ((ret = xd3_decode_section (stream, & stream->inst_sect, DEC_ADDR, copy))) { return ret; }
+    case DEC_ADDR:
+      if ((ret = xd3_decode_section (stream, & stream->addr_sect, DEC_EMIT, copy))) { return ret; }
+    }
+
+  XD3_ASSERT (stream->dec_winbytes == need);
+
+#if SECONDARY_ANY
+#define DECODE_SECONDARY_SECTION(UPPER,LOWER) \
+  ((stream->dec_del_ind & VCD_ ## UPPER ## COMP) && \
+   (ret = xd3_decode_secondary (stream, & stream-> LOWER ## _sect, \
+					& xd3_sec_ ## LOWER (stream))))
+
+  if (DECODE_SECONDARY_SECTION (DATA, data) ||
+      DECODE_SECONDARY_SECTION (INST, inst) ||
+      DECODE_SECONDARY_SECTION (ADDR, addr))
+    {
+      return ret;
+    }
+#endif
+
+  if (stream->flags & XD3_SKIP_EMIT)
+    {
+      return xd3_decode_finish_window (stream);
+    }
+
+  /* OPT: A possible optimization is to avoid allocating memory in decode_setup_buffers
+   * and to avoid a large memcpy when the window consists of a single VCD_SOURCE copy
+   * instruction.  The only potential problem is if the following window is a VCD_TARGET,
+   * then you need to remember... */
+  if ((ret = xd3_decode_setup_buffers (stream))) { return ret; }
+
+  return 0;
+}
+
+static int
+xd3_decode_emit (xd3_stream *stream)
+{
+  int ret;
+
+  /* Produce output: originally structured to allow reentrant code that fills as much of
+   * the output buffer as possible, but VCDIFF semantics allows to copy from anywhere from
+   * the target window, so instead allocate a sufficiently sized buffer after the target
+   * window length is decoded.
+   *
+   * This code still needs to be reentrant to allow XD3_GETSRCBLK to return control.  This
+   * is handled by setting the stream->dec_currentN instruction types to XD3_NOOP after
+   * they have been processed. */
+  XD3_ASSERT (! (stream->flags & XD3_SKIP_EMIT));
+  XD3_ASSERT (stream->avail_out == 0);
+  XD3_ASSERT (stream->dec_tgtlen <= stream->space_out);
+
+  while (stream->inst_sect.buf != stream->inst_sect.buf_max)
+    {
+      /* Decode next instruction pair. */
+      if ((stream->dec_current1.type == XD3_NOOP) &&
+	  (stream->dec_current2.type == XD3_NOOP) &&
+	  (ret = xd3_decode_instruction (stream))) { return ret; }
+
+      /* Output for each instruction. */
+      if ((stream->dec_current1.type != XD3_NOOP) &&
+	  (ret = xd3_decode_output_halfinst (stream, & stream->dec_current1))) { return ret; }
+
+      if ((stream->dec_current2.type != XD3_NOOP) &&
+	  (ret = xd3_decode_output_halfinst (stream, & stream->dec_current2))) { return ret; }
+    }
+
+  if (stream->avail_out != stream->dec_tgtlen)
+    {
+      IF_DEBUG1 (DP(RINT "AVAIL_OUT(%d) != DEC_TGTLEN(%d)\n", stream->avail_out, stream->dec_tgtlen));
+      stream->msg = "wrong window length";
+      return XD3_INVALID_INPUT;
+    }
+
+  if (stream->data_sect.buf != stream->data_sect.buf_max)
+    {
+      stream->msg = "extra data section";
+      return XD3_INVALID_INPUT;
+    }
+
+  if (stream->addr_sect.buf != stream->addr_sect.buf_max)
+    {
+      stream->msg = "extra address section";
+      return XD3_INVALID_INPUT;
+    }
+
+  /* OPT: Should cksum computation be combined with the above loop? */
+  if ((stream->dec_win_ind & VCD_ADLER32) != 0 &&
+      (stream->flags & XD3_ADLER32_NOVER) == 0)
+    {
+      uint32_t a32 = adler32 (1L, stream->next_out, stream->avail_out);
+
+      if (a32 != stream->dec_adler32)
+	{
+	  stream->msg = "target window checksum mismatch";
+	  return XD3_INVALID_INPUT;
+	}
+    }
+
+  /* Finished with a window. */
+  return xd3_decode_finish_window (stream);
+}
+
+int
+xd3_decode_input (xd3_stream *stream)
+{
+  int ret;
+
+  if (stream->enc_state != 0)
+    {
+      stream->msg = "encoder/decoder transition";
+      return XD3_INVALID_INPUT;
+    }
+
+#define BYTE_CASE(expr,x,nstate)                                               \
+      do {                                                                     \
+      if ( (expr) &&                                                           \
+           ((ret = xd3_decode_byte (stream, & (x))) != 0) ) { return ret; }    \
+      stream->dec_state = (nstate);                                            \
+      } while (0)
+
+#define OFFSET_CASE(expr,x,nstate)                                             \
+      do {                                                                     \
+      if ( (expr) &&                                                           \
+           ((ret = xd3_decode_offset (stream, & (x))) != 0) ) { return ret; }  \
+      stream->dec_state = (nstate);                                            \
+      } while (0)
+
+#define SIZE_CASE(expr,x,nstate)                                               \
+      do {                                                                     \
+      if ( (expr) &&                                                           \
+           ((ret = xd3_decode_size (stream, & (x))) != 0) ) { return ret; }    \
+      stream->dec_state = (nstate);                                            \
+      } while (0)
+
+#define SRCORTGT(x) (((x) & VCD_SRCORTGT) == VCD_SOURCE ||                     \
+		     ((x) & VCD_SRCORTGT) == VCD_TARGET)
+
+  switch (stream->dec_state)
+    {
+    case DEC_VCHEAD:
+      {
+	if ((ret = xd3_decode_bytes (stream, stream->dec_magic, & stream->dec_magicbytes, 4))) { return ret; }
+
+	if (stream->dec_magic[0] != VCDIFF_MAGIC1 ||
+	    stream->dec_magic[1] != VCDIFF_MAGIC2 ||
+	    stream->dec_magic[2] != VCDIFF_MAGIC3)
+	  {
+	    stream->msg = "not a VCDIFF input";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	if (stream->dec_magic[3] != 0)
+	  {
+	    stream->msg = "VCDIFF input version > 0 is not supported";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	stream->dec_state = DEC_HDRIND;
+      }
+    case DEC_HDRIND:
+      {
+	if ((ret = xd3_decode_byte (stream, & stream->dec_hdr_ind))) { return ret; }
+
+	if ((stream->dec_hdr_ind & VCD_INVHDR) != 0)
+	  {
+	    stream->msg = "unrecognized header indicator bits set";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	stream->dec_state = DEC_SECONDID;
+      }
+
+    case DEC_SECONDID:
+      /* Secondary compressor ID: only if VCD_SECONDARY is set */
+      if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0)
+	{
+	  BYTE_CASE (1, stream->dec_secondid, DEC_TABLEN);
+
+	  switch (stream->dec_secondid)
+	    {
+	    case VCD_FGK_ID:
+	      FGK_CASE (stream);
+	    case VCD_DJW_ID:
+	      DJW_CASE (stream);
+	    default:
+	      stream->msg = "unknown secondary compressor ID";
+	      return XD3_INVALID_INPUT;
+	    }
+	}
+
+    case DEC_TABLEN:
+      /* Length of code table data: only if VCD_CODETABLE is set */
+      SIZE_CASE ((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->dec_codetblsz, DEC_NEAR);
+
+      /* The codetblsz counts the two NEAR/SAME bytes */
+      if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) {
+	if (stream->dec_codetblsz <= 2) {
+	  stream->msg = "invalid code table size";
+	  return ENOMEM;
+	}
+	stream->dec_codetblsz -= 2;
+      }
+    case DEC_NEAR:
+      /* Near modes: only if VCD_CODETABLE is set */
+      BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_near, DEC_SAME);
+    case DEC_SAME:
+      /* Same modes: only if VCD_CODETABLE is set */
+      BYTE_CASE((stream->dec_hdr_ind & VCD_CODETABLE) != 0, stream->acache.s_same, DEC_TABDAT);
+    case DEC_TABDAT:
+      /* Compressed code table data */
+
+      if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0)
+	{
+	  /* Get the code table data. */
+	  if ((stream->dec_codetbl == NULL) &&
+	      (stream->dec_codetbl = xd3_alloc (stream, stream->dec_codetblsz, 1)) == NULL) { return ENOMEM; }
+
+	  if ((ret = xd3_decode_bytes (stream, stream->dec_codetbl, & stream->dec_codetblbytes, stream->dec_codetblsz)))
+	    {
+	      return ret;
+	    }
+
+	  if ((ret = xd3_apply_table_encoding (stream, stream->dec_codetbl, stream->dec_codetblbytes)))
+	    {
+	      return ret;
+	    }
+	}
+      else
+	{
+	  /* Use the default table. */
+	  stream->acache.s_near = __rfc3284_code_table_desc.near_modes;
+	  stream->acache.s_same = __rfc3284_code_table_desc.same_modes;
+	  stream->code_table    = xd3_rfc3284_code_table ();
+	}
+
+      if ((ret = xd3_alloc_cache (stream))) { return ret; }
+
+      stream->dec_state = DEC_APPLEN;
+
+    case DEC_APPLEN:
+      /* Length of application data */
+      SIZE_CASE((stream->dec_hdr_ind & VCD_APPHEADER) != 0, stream->dec_appheadsz, DEC_APPDAT);
+
+    case DEC_APPDAT:
+      /* Application data */
+      if (stream->dec_hdr_ind & VCD_APPHEADER)
+	{
+	  /* Note: we add an additional byte for padding, to allow 0-termination. */
+	  if ((stream->dec_appheader == NULL) &&
+	      (stream->dec_appheader = xd3_alloc (stream, stream->dec_appheadsz+1, 1)) == NULL) { return ENOMEM; }
+
+	  stream->dec_appheader[stream->dec_appheadsz] = 0;
+
+	  if ((ret = xd3_decode_bytes (stream, stream->dec_appheader, & stream->dec_appheadbytes, stream->dec_appheadsz)))
+	    {
+	      return ret;
+	    }
+	}
+
+      stream->dec_hdrsize = stream->total_in;
+      stream->dec_state = DEC_WININD;
+
+    case DEC_WININD:
+      {
+	/* Start of a window: the window indicator */
+
+	if ((ret = xd3_decode_byte (stream, & stream->dec_win_ind))) { return ret; }
+
+	stream->current_window = stream->dec_window_count;
+
+	if (XOFF_T_OVERFLOW (stream->dec_winstart, stream->dec_tgtlen))
+	  {
+	    stream->msg = "decoder file offset overflow";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	stream->dec_winstart += stream->dec_tgtlen;
+
+	if ((stream->dec_win_ind & VCD_INVWIN) != 0)
+	  {
+	    stream->msg = "unrecognized window indicator bits set";
+	    return XD3_INVALID_INPUT;
+	  }
+
+	if ((ret = xd3_decode_init_window (stream))) { return ret; }
+
+	stream->dec_state = DEC_CPYLEN;
+
+	IF_DEBUG1 (DP(RINT "--------- TARGET WINDOW %"Q"u ------------------\n", stream->current_window));
+      }
+
+    case DEC_CPYLEN:
+      /* Copy window length: only if VCD_SOURCE or VCD_TARGET is set */
+      SIZE_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpylen, DEC_CPYOFF);
+
+      /* Set the initial, logical decoder position (HERE address) in dec_position.  This
+       * is set to just after the source/copy window, as we are just about to output the
+       * first byte of target window. */
+      stream->dec_position = stream->dec_cpylen;
+
+    case DEC_CPYOFF:
+      /* Copy window offset: only if VCD_SOURCE or VCD_TARGET is set */
+      OFFSET_CASE(SRCORTGT (stream->dec_win_ind), stream->dec_cpyoff, DEC_ENCLEN);
+
+      /* Copy offset and copy length may not overflow. */
+      if (XOFF_T_OVERFLOW (stream->dec_cpyoff, stream->dec_cpylen))
+	{
+	  stream->msg = "decoder copy window overflows a file offset";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* Check copy window bounds: VCD_TARGET window may not exceed current position. */
+      if ((stream->dec_win_ind & VCD_TARGET) &&
+	  (stream->dec_cpyoff + (xoff_t) stream->dec_cpylen > stream->dec_winstart))
+	{
+	  stream->msg = "VCD_TARGET window out of bounds";
+	  return XD3_INVALID_INPUT;
+	}
+
+    case DEC_ENCLEN:
+      /* Length of the delta encoding */
+      SIZE_CASE(1, stream->dec_enclen, DEC_TGTLEN);
+    case DEC_TGTLEN:
+      /* Length of target window */
+      SIZE_CASE(1, stream->dec_tgtlen, DEC_DELIND);
+
+      /* Set the maximum decoder position, beyond which we should not decode any data.
+       * This is the maximum value for dec_position.  This may not exceed the size of a
+       * usize_t. */
+      if (USIZE_T_OVERFLOW (stream->dec_cpylen, stream->dec_tgtlen))
+	{
+	  stream->msg = "decoder target window overflows a usize_t";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* Check for malicious files. */
+      if (stream->dec_tgtlen > XD3_HARDMAXWINSIZE)
+	{
+	  stream->msg = "hard window size exceeded";
+	  return XD3_INVALID_INPUT;
+	}
+
+      stream->dec_maxpos = stream->dec_cpylen + stream->dec_tgtlen;
+
+    case DEC_DELIND:
+      /* Delta indicator */
+      BYTE_CASE(1, stream->dec_del_ind, DEC_DATALEN);
+
+      if ((stream->dec_del_ind & VCD_INVDEL) != 0)
+	{
+	  stream->msg = "unrecognized delta indicator bits set";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* Delta indicator is only used with secondary compression. */
+      if ((stream->dec_del_ind != 0) && (stream->sec_type == NULL))
+	{
+	  stream->msg = "invalid delta indicator bits set";
+	  return XD3_INVALID_INPUT;
+	}
+
+      /* Section lengths */
+    case DEC_DATALEN:
+      SIZE_CASE(1, stream->data_sect.size, DEC_INSTLEN);
+    case DEC_INSTLEN:
+      SIZE_CASE(1, stream->inst_sect.size, DEC_ADDRLEN);
+    case DEC_ADDRLEN:
+      SIZE_CASE(1, stream->addr_sect.size, DEC_CKSUM);
+
+    case DEC_CKSUM:
+      /* Window checksum. */
+      if ((stream->dec_win_ind & VCD_ADLER32) != 0)
+	{
+	  int i;
+
+	  if ((ret = xd3_decode_bytes (stream, stream->dec_cksum, & stream->dec_cksumbytes, 4))) { return ret; }
+
+	  for (i = 0; i < 4; i += 1)
+	    {
+	      stream->dec_adler32 = (stream->dec_adler32 << 8) | stream->dec_cksum[i];
+	    }
+	}
+
+      stream->dec_state = DEC_DATA;
+
+      /* Check dec_enclen for redundency, otherwise it is not really used. */
+      {
+	usize_t enclen_check = (1 + (xd3_sizeof_size (stream->dec_tgtlen) +
+				    xd3_sizeof_size (stream->data_sect.size) +
+				    xd3_sizeof_size (stream->inst_sect.size) +
+				    xd3_sizeof_size (stream->addr_sect.size)) +
+			       stream->data_sect.size +
+			       stream->inst_sect.size +
+			       stream->addr_sect.size +
+			       ((stream->dec_win_ind & VCD_ADLER32) ? 4 : 0));
+
+	if (stream->dec_enclen != enclen_check)
+	  {
+	    stream->msg = "incorrect encoding length (redundent)";
+	    return XD3_INVALID_INPUT;
+	  }
+      }
+
+      /* Returning here gives the application a chance to inspect the header, skip the
+       * window, etc. */
+      if (stream->current_window == 0) { return XD3_GOTHEADER; }
+      else                             { return XD3_WINSTART; }
+
+    case DEC_DATA:
+    case DEC_INST:
+    case DEC_ADDR:
+      /* Next read the three sections. */
+     if ((ret = xd3_decode_sections (stream))) { return ret; }
+
+    case DEC_EMIT:
+
+      /* To speed VCD_SOURCE block-address calculations, the source cpyoff_blocks and
+       * cpyoff_blkoff are pre-computed. */
+      if (stream->dec_win_ind & VCD_SOURCE)
+	{
+	  xd3_source *src = stream->src;
+
+	  if (src == NULL)
+	    {
+	      stream->msg = "source input required";
+	      return XD3_INVALID_INPUT;
+	    }
+
+	  src->cpyoff_blocks = stream->dec_cpyoff / src->blksize;
+	  src->cpyoff_blkoff = stream->dec_cpyoff % src->blksize;
+	}
+
+      /* xd3_decode_emit returns XD3_OUTPUT on every success. */
+      if ((ret = xd3_decode_emit (stream)) == XD3_OUTPUT)
+	{
+	  stream->total_out += (xoff_t) stream->avail_out;
+	}
+
+      return ret;
+
+    case DEC_FINISH:
+      {
+	if (stream->dec_win_ind & VCD_TARGET)
+	  {
+	    if (stream->dec_lastwin == NULL)
+	      {
+		stream->dec_lastwin   = stream->next_out;
+		stream->dec_lastspace = stream->space_out;
+	      }
+	    else
+	      {
+		xd3_swap_uint8p (& stream->dec_lastwin,   & stream->next_out);
+		xd3_swap_usize_t (& stream->dec_lastspace, & stream->space_out);
+	      }
+	  }
+
+	stream->dec_lastlen   = stream->dec_tgtlen;
+	stream->dec_laststart = stream->dec_winstart;
+	stream->dec_window_count += 1;
+
+	/* Note: the updates to dec_winstart & current_window are deferred until after the
+	 * next DEC_WININD byte is read. */
+	stream->dec_state = DEC_WININD;
+	return XD3_WINFINISH;
+      }
+
+    default:
+      stream->msg = "invalid state";
+      return XD3_INVALID_INPUT;
+    }
+}
+
+#endif // _XDELTA3_DECODE_H_
Index: /nikanabo/current/xdelta/diy/xdelta3-djw.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-djw.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-djw.h	(revision 185)
@@ -0,0 +1,1923 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2002, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _XDELTA3_DJW_H_
+#define _XDELTA3_DJW_H_
+
+/* The following people deserve much credit for the algorithms and techniques contained in
+ * this file:
+
+ Julian Seward
+ Bzip2 sources, implementation of the multi-table Huffman technique.
+
+ Jean-loup Gailly and Mark Adler and L. Peter Deutsch
+ Zlib source code, RFC 1951
+
+ Daniel S. Hirschberg and Debra A. LeLewer
+ "Efficient Decoding of Prefix Codes"
+ Communications of the ACM, April 1990 33(4).
+
+ David J. Wheeler
+ Program bred3.c, bexp3 and accompanying documents bred3.ps, huff.ps.
+ This contains the idea behind the multi-table Huffman and 1-2 coding techniques.
+ ftp://ftp.cl.cam.ac.uk/users/djw3/
+
+*/
+
+/* OPT: during the multi-table iteration, pick the worst-overall performing table and
+ * replace it with exactly the frequencies of the worst-overall performing sector or
+ * N-worst performing sectors. */
+
+/* REF: See xdfs-0.222 and xdfs-0.226 for some old experiments with the Bzip prefix coding
+ * strategy.  xdfs-0.256 contains the last of the other-format tests, including RFC1950
+ * and the RFC1950+MTF tests. */
+
+#define DJW_MAX_CODELEN      32 /* Maximum length of an alphabet code. */
+
+#define DJW_TOTAL_CODES      (DJW_MAX_CODELEN+2) /* [RUN_0, RUN_1, 1-DJW_MAX_CODELEN] */
+
+#define RUN_0                0 /* Symbols used in MTF+1/2 coding. */
+#define RUN_1                1
+
+#define DJW_BASIC_CODES      5  /* Number of code lengths always encoded (djw_encode_basic array) */
+#define DJW_RUN_CODES        2  /* Number of run codes */
+#define DJW_EXTRA_12OFFSET   7  /* Offset of extra codes */
+#define DJW_EXTRA_CODES      15 /* Number of optionally encoded code lengths (djw_encode_extra array) */
+#define DJW_EXTRA_CODE_BITS  4  /* Number of bits to code [0-DJW_EXTRA_CODES] */
+
+#define DJW_MAX_GROUPS       8  /* Max number of group coding tables */
+#define DJW_GROUP_BITS       3  /* Number of bits to code [1-DJW_MAX_GROUPS] */
+
+#define DJW_SECTORSZ_MULT     5  /* Multiplier for encoded sectorsz */
+#define DJW_SECTORSZ_BITS     5  /* Number of bits to code group size */
+#define DJW_SECTORSZ_MAX      ((1 << DJW_SECTORSZ_BITS) * DJW_SECTORSZ_MULT)
+
+#define DJW_MAX_ITER         6  /* Maximum number of iterations to find group tables. */
+#define DJW_MIN_IMPROVEMENT  20 /* Minimum number of bits an iteration must reduce coding by. */
+
+#define DJW_MAX_CLCLEN       15 /* Maximum code length of a prefix code length */
+#define DJW_CLCLEN_BITS      4  /* Number of bits to code [0-DJW_MAX_CLCLEN] */
+
+#define DJW_MAX_GBCLEN       7  /* Maximum code length of a group selector */
+#define DJW_GBCLEN_BITS      3  /* Number of bits to code [0-DJW_MAX_GBCLEN]
+				 * @!@ Actually, should never have zero code lengths here, or
+				 * else a group went unused.  Write a test for this: if a group
+				 * goes unused, eliminate it? */
+
+#define EFFICIENCY_BITS      16 /* It has to save at least this many bits... */
+
+typedef struct _djw_stream   djw_stream;
+typedef struct _djw_heapen   djw_heapen;
+typedef struct _djw_prefix   djw_prefix;
+typedef uint32_t             djw_weight;
+
+/* To enable Huffman tuning code... */
+#ifndef TUNE_HUFFMAN
+#define TUNE_HUFFMAN 0
+#endif
+
+#if TUNE_HUFFMAN == 0
+#define xd3_real_encode_huff xd3_encode_huff
+#define IF_TUNE(x)
+#define IF_NTUNE(x) x
+#else
+static uint xd3_bitsof_output (xd3_output *output, bit_state *bstate);
+#define IF_TUNE(x) x
+#define IF_NTUNE(x)
+static djw_weight tune_freq[DJW_TOTAL_CODES];
+static uint8_t tune_clen[DJW_MAX_GROUPS][ALPHABET_SIZE];
+static usize_t  tune_prefix_bits;
+static usize_t  tune_select_bits;
+static usize_t  tune_encode_bits;
+#endif
+struct _djw_heapen
+{
+  uint32_t depth;
+  uint32_t freq;
+  uint32_t parent;
+};
+
+struct _djw_prefix
+{
+  usize_t   scount;
+  uint8_t *symbol;
+  usize_t   mcount;
+  uint8_t *mtfsym;
+  uint8_t *repcnt;
+};
+
+struct _djw_stream
+{
+  int unused;
+};
+
+/* Each Huffman table consists of 256 "code length" (CLEN) codes, which are themselves
+ * Huffman coded after eliminating repeats and move-to-front coding.  The prefix consists
+ * of all the CLEN codes in djw_encode_basic plus a 4-bit value stating how many of the
+ * djw_encode_extra codes are actually coded (the rest are presumed zero, or unused CLEN
+ * codes).
+ *
+ * These values of these two arrays were arrived at by studying the distribution of min
+ * and max clen over a collection of DATA, INST, and ADDR inputs.  The goal is to specify
+ * the order of djw_extra_codes that is most likely to minimize the number of extra codes
+ * that must be encoded.
+ *
+ * Results: 158896 sections were counted by compressing files (window size 512K) listed
+ * with: `find / -type f ( -user jmacd -o -perm +444 )`
+ *
+ * The distribution of CLEN codes for each efficient invocation of the secondary
+ * compressor (taking the best number of groups/sector size) was recorded.  Then we look at
+ * the distribution of min and max clen values, counting the number of times the value
+ * C_low is less than the min and C_high is greater than the max.  Values >= C_high and <=
+ * C_low will not have their lengths coded.  The results are sorted and the least likely
+ * 15 are placed into the djw_encode_extra[] array in order.  These values are used as
+ * the initial MTF ordering.
+
+ clow[1] = 155119
+ clow[2] = 140325
+ clow[3] = 84072
+ ---
+ clow[4] = 7225
+ clow[5] = 1093
+ clow[6] = 215
+ ---
+ chigh[4] = 1
+ chigh[5] = 30
+ chigh[6] = 218
+ chigh[7] = 2060
+ chigh[8] = 13271
+ ---
+ chigh[9] = 39463
+ chigh[10] = 77360
+ chigh[11] = 118298
+ chigh[12] = 141360
+ chigh[13] = 154086
+ chigh[14] = 157967
+ chigh[15] = 158603
+ chigh[16] = 158864
+ chigh[17] = 158893
+ chigh[18] = 158895
+ chigh[19] = 158896
+ chigh[20] = 158896
+
+*/
+
+static const uint8_t djw_encode_12extra[DJW_EXTRA_CODES] =
+  {
+    9, 10, 3, 11, 2, 12, 13, 1, 14, 15, 16, 17, 18, 19, 20
+  };
+
+static const uint8_t djw_encode_12basic[DJW_BASIC_CODES] =
+  {
+    4, 5, 6, 7, 8,
+  };
+
+/*********************************************************************/
+/*                              DECLS                                */
+/*********************************************************************/
+
+static djw_stream*     djw_alloc           (xd3_stream *stream /*, int alphabet_size */);
+static void            djw_init            (djw_stream *h);
+static void            djw_destroy         (xd3_stream *stream,
+					    djw_stream *h);
+
+#if XD3_ENCODER
+static int             xd3_encode_huff     (xd3_stream   *stream,
+					    djw_stream  *sec_stream,
+					    xd3_output   *input,
+					    xd3_output   *output,
+					    xd3_sec_cfg  *cfg);
+#endif
+
+static int             xd3_decode_huff     (xd3_stream     *stream,
+					    djw_stream    *sec_stream,
+					    const uint8_t **input,
+					    const uint8_t  *const input_end,
+					    uint8_t       **output,
+					    const uint8_t  *const output_end);
+
+/*********************************************************************/
+/*                             HUFFMAN                               */
+/*********************************************************************/
+
+static djw_stream*
+djw_alloc (xd3_stream *stream)
+{
+  return xd3_alloc (stream, sizeof (djw_stream), 1);
+}
+
+static void
+djw_init (djw_stream *h)
+{
+  /* Fields are initialized prior to use. */
+}
+
+static void
+djw_destroy (xd3_stream *stream,
+	     djw_stream *h)
+{
+  xd3_free (stream, h);
+}
+
+
+/*********************************************************************/
+/*                               HEAP                                */
+/*********************************************************************/
+
+static INLINE int
+heap_less (const djw_heapen *a, const djw_heapen *b)
+{
+  return a->freq   < b->freq ||
+    (a->freq  == b->freq &&
+     a->depth  < b->depth);
+}
+
+static INLINE void
+heap_insert (uint *heap, const djw_heapen *ents, uint p, const uint e)
+{
+  /* Insert ents[e] into next slot heap[p] */
+  uint pp = p/2; /* P's parent */
+
+  while (heap_less (& ents[e], & ents[heap[pp]]))
+    {
+      heap[p] = heap[pp];
+      p  = pp;
+      pp = p/2;
+    }
+
+  heap[p] = e;
+}
+
+static INLINE djw_heapen*
+heap_extract (uint *heap, const djw_heapen *ents, uint heap_last)
+{
+  uint smallest = heap[1];
+  uint p, pc, t;
+
+  /* Caller decrements heap_last, so heap_last+1 is the replacement elt. */
+  heap[1] = heap[heap_last+1];
+
+  /* Re-heapify */
+  for (p = 1; ; p = pc)
+    {
+      pc = p*2;
+
+      /* Reached bottom of heap */
+      if (pc > heap_last) { break; }
+
+      /* See if second child is smaller. */
+      if (pc < heap_last && heap_less (& ents[heap[pc+1]], & ents[heap[pc]])) { pc += 1; }
+
+      /* If pc is not smaller than p, heap property re-established. */
+      if (! heap_less (& ents[heap[pc]], & ents[heap[p]])) { break; }
+
+      t = heap[pc];
+      heap[pc] = heap[p];
+      heap[p] = t;
+    }
+
+  return (djw_heapen*) & ents[smallest];
+}
+
+#if XD3_DEBUG
+static void
+heap_check (uint *heap, djw_heapen *ents, uint heap_last)
+{
+  uint i;
+  for (i = 1; i <= heap_last; i += 1)
+    {
+      /* Heap property: child not less than parent */
+      XD3_ASSERT (! heap_less (& ents[heap[i]], & ents[heap[i/2]]));
+    }
+}
+#endif
+
+/*********************************************************************/
+/*                             MTF, 1/2                              */
+/*********************************************************************/
+
+static INLINE usize_t
+djw_update_mtf (uint8_t *mtf, usize_t mtf_i)
+{
+  int k;
+  usize_t sym = mtf[mtf_i];
+
+  for (k = mtf_i; k != 0; k -= 1) { mtf[k] = mtf[k-1]; }
+
+  mtf[0] = sym;
+  return sym;
+}
+
+static INLINE void
+djw_update_1_2 (int *mtf_run, usize_t *mtf_i, uint8_t *mtfsym, djw_weight *freq)
+{
+  int code;
+  
+  do
+    {
+      /* Offset by 1, since any number of RUN_ symbols implies run>0... */
+      *mtf_run -= 1;
+
+      code = (*mtf_run & 1) ? RUN_1 : RUN_0;
+
+      mtfsym[(*mtf_i)++] = code;
+      freq[code] += 1;
+      *mtf_run >>= 1;
+    }
+  while (*mtf_run >= 1);
+
+  *mtf_run = 0;
+}
+
+static void
+djw_init_clen_mtf_1_2 (uint8_t *clmtf)
+{
+  int i, cl_i = 0;
+
+  clmtf[cl_i++] = 0;
+  for (i = 0; i < DJW_BASIC_CODES; i += 1) { clmtf[cl_i++] = djw_encode_12basic[i]; }
+  for (i = 0; i < DJW_EXTRA_CODES; i += 1) { clmtf[cl_i++] = djw_encode_12extra[i]; }
+}
+
+/*********************************************************************/
+/*                           PREFIX CODES                            */
+/*********************************************************************/
+#if XD3_ENCODER
+static usize_t
+djw_build_prefix (const djw_weight *freq, uint8_t *clen, int asize, int maxlen)
+{
+  /* Heap with 0th entry unused, prefix tree with up to ALPHABET_SIZE-1 internal nodes,
+   * never more than ALPHABET_SIZE entries actually in the heap (minimum weight subtrees
+   * during prefix construction).  First ALPHABET_SIZE entries are the actual symbols,
+   * next ALPHABET_SIZE-1 are internal nodes. */
+  djw_heapen ents[ALPHABET_SIZE * 2];
+  uint        heap[ALPHABET_SIZE + 1];
+
+  uint heap_last; /* Index of the last _valid_ heap entry. */
+  uint ents_size; /* Number of entries, including 0th fake entry */
+  int  overflow;  /* Number of code lengths that overflow */
+  uint32_t total_bits;
+  int i;
+
+  IF_DEBUG (uint32_t first_bits = 0);
+
+  /* Insert real symbol frequences. */
+  for (i = 0; i < asize; i += 1)
+    {
+      ents[i+1].freq = freq[i];
+    }
+
+ again:
+
+  /* The loop is re-entered each time an overflow occurs.  Re-initialize... */
+  heap_last = 0;
+  ents_size = 1;
+  overflow  = 0;
+  total_bits = 0;
+
+  /* 0th entry terminates the while loop in heap_insert (its the parent of the smallest
+   * element, always less-than) */
+  heap[0] = 0;
+  ents[0].depth = 0;
+  ents[0].freq  = 0;
+
+  /* Initial heap. */
+  for (i = 0; i < asize; i += 1, ents_size += 1)
+    {
+      ents[ents_size].depth  = 0;
+      ents[ents_size].parent = 0;
+
+      if (ents[ents_size].freq != 0)
+	{
+	  heap_insert (heap, ents, ++heap_last, ents_size);
+	}
+    }
+
+  IF_DEBUG (heap_check (heap, ents, heap_last));
+
+  /* Must be at least one symbol, or else we can't get here. */
+  XD3_ASSERT (heap_last != 0);
+
+  /* If there is only one symbol, fake a second to prevent zero-length codes. */
+  if (unlikely (heap_last == 1))
+    {
+      /* Pick either the first or last symbol. */
+      int s = freq[0] ? asize-1 : 0;
+      ents[s+1].freq = 1;
+      goto again;
+    }
+
+  /* Build prefix tree. */
+  while (heap_last > 1)
+    {
+      djw_heapen *h1 = heap_extract (heap, ents, --heap_last);
+      djw_heapen *h2 = heap_extract (heap, ents, --heap_last);
+
+      ents[ents_size].freq   = h1->freq + h2->freq;
+      ents[ents_size].depth  = 1 + max (h1->depth, h2->depth);
+      ents[ents_size].parent = 0;
+
+      h1->parent = h2->parent = ents_size;
+
+      heap_insert (heap, ents, ++heap_last, ents_size++);
+
+      IF_DEBUG (heap_check (heap, ents, heap_last));
+    }
+
+  /* Now compute prefix code lengths, counting parents. */
+  for (i = 1; i < asize+1; i += 1)
+    {
+      int b = 0;
+
+      if (ents[i].freq != 0)
+	{
+	  int p = i;
+
+	  while ((p = ents[p].parent) != 0) { b += 1; }
+
+	  if (b > maxlen) { overflow = 1; }
+
+	  total_bits += b * freq[i-1];
+	}
+
+      /* clen is 0-origin, unlike ents. */
+      clen[i-1] = b;
+    }
+
+  IF_DEBUG (if (first_bits == 0) first_bits = total_bits);
+
+  if (! overflow)
+    {
+      IF_DEBUG (if (first_bits != total_bits)
+      {
+	DP(RINT "code length overflow changed %u bits\n", (usize_t)(total_bits - first_bits));
+      });
+      return total_bits;
+    }
+
+  /* OPT: There is a non-looping way to fix overflow shown in zlib, but this is easier
+   * (for now), as done in bzip2. */
+  for (i = 1; i < asize+1; i += 1)
+    {
+      ents[i].freq = ents[i].freq / 2 + 1;
+    }
+
+  goto again;
+}
+
+static void
+djw_build_codes (uint *codes, const uint8_t *clen, int asize DEBUG_ARG (int abs_max))
+{
+  int i, l;
+  int min_clen = DJW_MAX_CODELEN;
+  int max_clen = 0;
+  uint code = 0;
+
+  for (i = 0; i < asize; i += 1)
+    {
+      if (clen[i] > 0 && clen[i] < min_clen)
+	{
+	  min_clen = clen[i];
+	}
+
+      max_clen = max (max_clen, (int) clen[i]);
+    }
+
+  XD3_ASSERT (max_clen <= abs_max);
+
+  for (l = min_clen; l <= max_clen; l += 1)
+    {
+      for (i = 0; i < asize; i += 1)
+	{
+	  if (clen[i] == l) { codes[i] = code++; }
+	}
+
+      code <<= 1;
+    }
+}
+
+/*********************************************************************/
+/*			      MOVE-TO-FRONT                          */
+/*********************************************************************/
+static void
+djw_compute_mtf_1_2 (djw_prefix *prefix,
+		     uint8_t     *mtf,
+		     djw_weight *freq_out,   /* freak out! */
+		     usize_t       nsym)
+{
+  int i, j, k;
+  usize_t sym;
+  usize_t size = prefix->scount;
+  usize_t mtf_i = 0;
+  int mtf_run = 0;
+
+  memset (freq_out, 0, sizeof (freq_out[0]) * (nsym+1));
+
+  for (i = 0; i < size; )
+    {
+      /* OPT: Bzip optimizes this algorithm a little by effectively checking j==0 before
+       * the MTF update. */
+      sym = prefix->symbol[i++];
+
+      for (j = 0; mtf[j] != sym; j += 1) { }
+
+      XD3_ASSERT (j < nsym);
+
+      for (k = j; k >= 1; k -= 1) { mtf[k] = mtf[k-1]; }
+
+      mtf[0] = sym;
+
+      if (j == 0)
+	{
+	  mtf_run += 1;
+	  continue;
+	}
+
+      if (mtf_run > 0)
+	{
+	  djw_update_1_2 (& mtf_run, & mtf_i, prefix->mtfsym, freq_out);
+	}
+
+      /* Non-zero symbols are offset by RUN_1 */
+      prefix->mtfsym[mtf_i++] = j+RUN_1;
+      freq_out[j+RUN_1] += 1;
+    }
+
+  if (mtf_run > 0)
+    {
+      djw_update_1_2 (& mtf_run, & mtf_i, prefix->mtfsym, freq_out);
+    }
+
+  prefix->mcount = mtf_i;
+}
+
+static usize_t
+djw_count_freqs (djw_weight *freq, xd3_output *input)
+{
+  xd3_output  *in;
+  usize_t       size = 0;
+
+  memset (freq, 0, sizeof (freq[0]) * ALPHABET_SIZE);
+
+  /* Freqency counting. OPT: can be accomplished beforehand. */
+  for (in = input; in; in = in->next_page)
+    {
+      const uint8_t *p     = in->base;
+      const uint8_t *p_max = p + in->next;
+
+      size += in->next;
+
+      do { freq[*p++] += 1; } while (p < p_max);
+    }
+
+  IF_DEBUG1 ({int i;
+  DP(RINT "freqs: ");
+  for (i = 0; i < ALPHABET_SIZE; i += 1) { DP(RINT "%u ", freq[i]); }
+  DP(RINT "\n");});
+
+  return size;
+}
+
+static void
+djw_compute_multi_prefix (int          groups,
+			  uint8_t      clen[DJW_MAX_GROUPS][ALPHABET_SIZE],
+			  djw_prefix *prefix)
+{
+  int gp, i;
+      
+  prefix->scount = ALPHABET_SIZE;
+  memcpy (prefix->symbol, clen[0], ALPHABET_SIZE);
+
+  for (gp = 1; gp < groups; gp += 1)
+    {
+      for (i = 0; i < ALPHABET_SIZE; i += 1)
+	{
+	  if (clen[gp][i] == 0)
+	    {
+	      continue;
+	    }
+
+	  prefix->symbol[prefix->scount++] = clen[gp][i];
+	}
+    }
+}
+
+static void
+djw_compute_prefix_1_2 (djw_prefix *prefix, djw_weight *freq)
+{
+  uint8_t clmtf[DJW_MAX_CODELEN+1];
+
+  djw_init_clen_mtf_1_2 (clmtf);
+
+  djw_compute_mtf_1_2 (prefix, clmtf, freq, DJW_MAX_CODELEN+1);
+}
+
+static int
+djw_encode_prefix (xd3_stream    *stream,
+		   xd3_output   **output,
+		   bit_state     *bstate,
+		   djw_prefix   *prefix)
+{
+  int ret, i;
+  uint num_to_encode;
+  djw_weight clfreq[DJW_TOTAL_CODES];
+  uint8_t    clclen[DJW_TOTAL_CODES];
+  uint       clcode[DJW_TOTAL_CODES];
+
+  IF_TUNE (memset (clfreq, 0, sizeof (clfreq)));
+
+  /* Move-to-front encode prefix symbols, count frequencies */
+  djw_compute_prefix_1_2 (prefix, clfreq);
+
+  /* Compute codes */
+  djw_build_prefix (clfreq, clclen, DJW_TOTAL_CODES, DJW_MAX_CLCLEN);
+  djw_build_codes  (clcode, clclen, DJW_TOTAL_CODES DEBUG_ARG (DJW_MAX_CLCLEN));
+
+  /* Compute number of extra codes beyond basic ones for this template. */
+  num_to_encode = DJW_TOTAL_CODES;
+  while (num_to_encode > DJW_EXTRA_12OFFSET && clclen[num_to_encode-1] == 0) { num_to_encode -= 1; }
+  XD3_ASSERT (num_to_encode - DJW_EXTRA_12OFFSET < (1 << DJW_EXTRA_CODE_BITS));
+
+  /* Encode: # of extra codes */
+  if ((ret = xd3_encode_bits (stream, output, bstate, DJW_EXTRA_CODE_BITS,
+			      num_to_encode - DJW_EXTRA_12OFFSET))) { return ret; }
+
+  /* Encode: MTF code lengths */
+  for (i = 0; i < num_to_encode; i += 1)
+    {
+      if ((ret = xd3_encode_bits (stream, output, bstate, DJW_CLCLEN_BITS, clclen[i]))) { return ret; }
+    }
+
+  /* Encode: CLEN code lengths */
+  for (i = 0; i < prefix->mcount; i += 1)
+    {
+      usize_t mtf_sym = prefix->mtfsym[i];
+      usize_t bits    = clclen[mtf_sym];
+      usize_t code    = clcode[mtf_sym];
+
+      if ((ret = xd3_encode_bits (stream, output, bstate, bits, code))) { return ret; }
+    }
+
+  IF_TUNE (memcpy (tune_freq, clfreq, sizeof (clfreq)));
+
+  return 0;
+}
+
+static void
+djw_compute_selector_1_2 (djw_prefix *prefix,
+			  usize_t       groups,
+			  djw_weight *gbest_freq)
+{
+  uint8_t grmtf[DJW_MAX_GROUPS];
+  usize_t i;
+
+  for (i = 0; i < groups; i += 1) { grmtf[i] = i; }
+
+  djw_compute_mtf_1_2 (prefix, grmtf, gbest_freq, groups);
+}
+
+static int
+xd3_encode_howmany_groups (xd3_stream *stream,
+			   xd3_sec_cfg *cfg,
+			   usize_t input_size,
+			   usize_t *ret_groups,
+			   usize_t *ret_sector_size)
+{
+  usize_t cfg_groups = 0;
+  usize_t cfg_sector_size = 0;
+  usize_t sugg_groups = 0;
+  usize_t sugg_sector_size = 0;
+
+  if (cfg->ngroups != 0)
+    {
+      if (cfg->ngroups < 0 || cfg->ngroups > DJW_MAX_GROUPS)
+	{
+	  stream->msg = "invalid secondary encoder group number";
+	  return XD3_INTERNAL;
+	}
+
+      cfg_groups = cfg->ngroups;
+    }
+
+  if (cfg->sector_size != 0)
+    {
+      if (cfg->sector_size < DJW_SECTORSZ_MULT || cfg->sector_size > DJW_SECTORSZ_MAX || (cfg->sector_size % DJW_SECTORSZ_MULT) != 0)
+	{
+	  stream->msg = "invalid secondary encoder sector size";
+	  return XD3_INTERNAL;
+	}
+
+      cfg_sector_size = cfg->sector_size;
+    }
+
+  if (cfg_groups == 0 || cfg_sector_size == 0)
+    {
+      /* These values were found empirically using xdelta3-tune around version
+       * xdfs-0.256. */
+      switch (cfg->data_type)
+	{
+	case DATA_SECTION:
+	  if      (input_size < 1000)   { sugg_groups = 1; sugg_sector_size = 0; }
+	  else if (input_size < 4000)   { sugg_groups = 2; sugg_sector_size = 10; }
+	  else if (input_size < 7000)   { sugg_groups = 3; sugg_sector_size = 10; }
+	  else if (input_size < 10000)  { sugg_groups = 4; sugg_sector_size = 10; }
+	  else if (input_size < 25000)  { sugg_groups = 5; sugg_sector_size = 10; }
+	  else if (input_size < 50000)  { sugg_groups = 7; sugg_sector_size = 20; }
+	  else if (input_size < 100000) { sugg_groups = 8; sugg_sector_size = 30; }
+	  else                          { sugg_groups = 8; sugg_sector_size = 70; }
+	  break;
+	case INST_SECTION:
+	  if      (input_size < 7000)   { sugg_groups = 1; sugg_sector_size = 0; }
+	  else if (input_size < 10000)  { sugg_groups = 2; sugg_sector_size = 50; }
+	  else if (input_size < 25000)  { sugg_groups = 3; sugg_sector_size = 50; }
+	  else if (input_size < 50000)  { sugg_groups = 6; sugg_sector_size = 40; }
+	  else if (input_size < 100000) { sugg_groups = 8; sugg_sector_size = 40; }
+	  else                          { sugg_groups = 8; sugg_sector_size = 40; }
+	  break;
+	case ADDR_SECTION:
+	  if      (input_size < 9000)   { sugg_groups = 1; sugg_sector_size = 0; }
+	  else if (input_size < 25000)  { sugg_groups = 2; sugg_sector_size = 130; }
+	  else if (input_size < 50000)  { sugg_groups = 3; sugg_sector_size = 130; }
+	  else if (input_size < 100000) { sugg_groups = 5; sugg_sector_size = 130; }
+	  else                          { sugg_groups = 7; sugg_sector_size = 130; }
+	  break;
+	}
+
+      if (cfg_groups == 0)
+	{
+	  cfg_groups = sugg_groups;
+	}
+
+      if (cfg_sector_size == 0)
+	{
+	  cfg_sector_size = sugg_sector_size;
+	}
+    }
+
+  if (cfg_groups != 1 && cfg_sector_size == 0)
+    {
+      switch (cfg->data_type)
+	{
+	case DATA_SECTION:
+	  cfg_sector_size = 20;
+	  break;
+	case INST_SECTION:
+	  cfg_sector_size = 50;
+	  break;
+	case ADDR_SECTION:
+	  cfg_sector_size = 130;
+	  break;
+	}
+    }
+
+  (*ret_groups)     = cfg_groups;
+  (*ret_sector_size) = cfg_sector_size;
+
+  XD3_ASSERT (cfg_groups > 0 && cfg_groups <= DJW_MAX_GROUPS);
+  XD3_ASSERT (cfg_groups == 1 || (cfg_sector_size >= DJW_SECTORSZ_MULT && cfg_sector_size <= DJW_SECTORSZ_MAX));
+
+  return 0;
+}
+
+static int
+xd3_real_encode_huff (xd3_stream   *stream,
+		      djw_stream  *h,
+		      xd3_output   *input,
+		      xd3_output   *output,
+		      xd3_sec_cfg  *cfg)
+{
+  int         ret;
+  usize_t      groups, sector_size;
+  bit_state   bstate = BIT_STATE_ENCODE_INIT;
+  xd3_output *in;
+  int         encode_bits;
+  usize_t      input_bits;
+  usize_t      input_bytes;
+  usize_t      initial_offset = output->next;
+  djw_weight real_freq[ALPHABET_SIZE];
+  uint8_t    *gbest = NULL; /* Dynamic allocations: could put these in djw_stream. */
+  uint8_t    *gbest_mtf = NULL;
+
+  input_bytes = djw_count_freqs (real_freq, input);
+  input_bits  = input_bytes * 8;
+
+  XD3_ASSERT (input_bytes > 0);
+
+  if ((ret = xd3_encode_howmany_groups (stream, cfg, input_bytes, & groups, & sector_size)))
+    {
+      return ret;
+    }
+
+  if (0)
+    {
+    regroup:
+      /* Sometimes we dynamically decide there are too many groups.  Arrive here. */
+      output->next = initial_offset;
+      xd3_bit_state_encode_init (& bstate);
+    }
+
+  /* Encode: # of groups (3 bits) */
+  if ((ret = xd3_encode_bits (stream, & output, & bstate, DJW_GROUP_BITS, groups-1))) { goto failure; }
+
+  if (groups == 1)
+    {
+      /* Single Huffman group. */
+      uint        code[ALPHABET_SIZE]; /* Codes */
+      IF_TUNE  (uint8_t    *clen = tune_clen[0];)
+      IF_NTUNE (uint8_t     clen[ALPHABET_SIZE];)
+      uint8_t    prefix_mtfsym[ALPHABET_SIZE];
+      djw_prefix prefix;
+
+      encode_bits =
+	djw_build_prefix (real_freq, clen, ALPHABET_SIZE, DJW_MAX_CODELEN);
+      djw_build_codes  (code, clen, ALPHABET_SIZE DEBUG_ARG (DJW_MAX_CODELEN));
+
+      if (encode_bits + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; }
+
+      /* Encode: prefix */
+      prefix.mtfsym = prefix_mtfsym;
+      prefix.symbol = clen;
+      prefix.scount = ALPHABET_SIZE;
+
+      if ((ret = djw_encode_prefix (stream, & output, & bstate, & prefix))) { goto failure; }
+
+      if (encode_bits + (8 * output->next) + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; }
+
+      IF_TUNE (tune_prefix_bits = xd3_bitsof_output (output, & bstate));
+      IF_TUNE (tune_select_bits = 0);
+      IF_TUNE (tune_encode_bits = encode_bits);
+
+      /* Encode: data */
+      for (in = input; in; in = in->next_page)
+	{
+	  const uint8_t *p     = in->base;
+	  const uint8_t *p_max = p + in->next;
+
+	  do
+	    {
+	      usize_t sym  = *p++;
+	      usize_t bits = clen[sym];
+
+	      IF_DEBUG (encode_bits -= bits);
+
+	      if ((ret = xd3_encode_bits (stream, & output, & bstate, bits, code[sym]))) { goto failure; }
+	    }
+	  while (p < p_max);
+	}
+
+      XD3_ASSERT (encode_bits == 0);
+    }
+  else
+    {
+      /* DJW Huffman */
+      djw_weight evolve_freq[DJW_MAX_GROUPS][ALPHABET_SIZE];
+#if TUNE_HUFFMAN == 0
+      uint8_t evolve_clen[DJW_MAX_GROUPS][ALPHABET_SIZE];
+#else
+#define evolve_clen tune_clen
+#endif
+      djw_weight left = input_bytes;
+      int gp;
+      int niter = 0;
+      usize_t select_bits;
+      usize_t sym1 = 0, sym2 = 0, s;
+      usize_t   gcost[DJW_MAX_GROUPS];
+      uint     gbest_code[DJW_MAX_GROUPS+2];
+      uint8_t  gbest_clen[DJW_MAX_GROUPS+2];
+      usize_t   gbest_max = 1 + (input_bytes - 1) / sector_size;
+      int      best_bits = 0;
+      usize_t   gbest_no;
+      usize_t   gpcnt;
+      const uint8_t *p;
+      IF_DEBUG1 (usize_t gcount[DJW_MAX_GROUPS]);
+
+      /* Encode: sector size (5 bits) */
+      if ((ret = xd3_encode_bits (stream, & output, & bstate,
+				  DJW_SECTORSZ_BITS, (sector_size/DJW_SECTORSZ_MULT)-1))) { goto failure; }
+
+      /* Dynamic allocation. */
+      if (gbest == NULL)
+	{
+	  if ((gbest = xd3_alloc (stream, gbest_max, 1)) == NULL) { ret = ENOMEM; goto failure; }
+	}
+
+      if (gbest_mtf == NULL)
+	{
+	  if ((gbest_mtf = xd3_alloc (stream, gbest_max, 1)) == NULL) { ret = ENOMEM; goto failure; }
+	}
+
+      /* OPT: Some of the inner loops can be optimized, as shown in bzip2 */
+
+      /* Generate initial code length tables. */
+      for (gp = 0; gp < groups; gp += 1)
+	{
+	  djw_weight sum  = 0;
+	  djw_weight goal = left / (groups - gp);
+
+	  IF_DEBUG1 (usize_t nz = 0);
+
+	  /* Due to the single-code granularity of this distribution, it may be that we
+	   * can't generate a distribution for each group.  In that case subtract one
+	   * group and try again.  If (inefficient), we're testing group behavior, so
+	   * don't mess things up. */
+	  if (goal == 0 && !cfg->inefficient)
+	    {
+	      IF_DEBUG1 (DP(RINT "too many groups (%u), dropping one\n", groups));
+	      groups -= 1;
+	      goto regroup;
+	    }
+
+	  /* Sum == goal is possible when (cfg->inefficient)... */
+	  while (sum < goal)
+	    {
+	      XD3_ASSERT (sym2 < ALPHABET_SIZE);
+	      IF_DEBUG1 (nz += real_freq[sym2] != 0);
+	      sum += real_freq[sym2++];
+	    }
+
+	  IF_DEBUG1(DP(RINT "group %u has symbols %u..%u (%u non-zero) (%u/%u = %.3f)\n",
+			     gp, sym1, sym2, nz, sum, input_bytes, sum / (double)input_bytes););
+
+	  for (s = 0; s < ALPHABET_SIZE; s += 1)
+	    {
+	      evolve_clen[gp][s] = (s >= sym1 && s <= sym2) ? 1 : 16;
+	    }
+
+	  left -= sum;
+	  sym1  = sym2+1;
+	}
+
+    repeat:
+
+      niter += 1;
+      gbest_no = 0;
+      memset (evolve_freq, 0, sizeof (evolve_freq[0]) * groups);
+      IF_DEBUG1 (memset (gcount, 0, sizeof (gcount[0]) * groups));
+
+      /* For each input page (loop is irregular to allow non-pow2-size group size. */
+      in = input;
+      p  = in->base;
+
+      /* For each group-size sector. */
+      do
+	{
+	  const uint8_t *p0  = p;
+	  xd3_output    *in0 = in;
+	  usize_t best   = 0;
+	  usize_t winner = 0;
+
+	  /* Select best group for each sector, update evolve_freq. */
+	  memset (gcost, 0, sizeof (gcost[0]) * groups);
+
+	  /* For each byte in sector. */
+	  for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1)
+	    {
+	      /* For each group. */
+	      for (gp = 0; gp < groups; gp += 1)
+		{
+		  gcost[gp] += evolve_clen[gp][*p];
+		}
+
+	      /* Check end-of-input-page. */
+#             define GP_PAGE()                \
+	      if (++p - in->base == in->next) \
+		{                             \
+		  in = in->next_page;         \
+		  if (in == NULL) { break; }  \
+		  p  = in->base;              \
+		}
+
+	      GP_PAGE ();
+	    }
+
+	  /* Find min cost group for this sector */
+	  best = -1U;
+	  for (gp = 0; gp < groups; gp += 1)
+	    {
+	      if (gcost[gp] < best) { best = gcost[gp]; winner = gp; }
+	    }
+
+	  XD3_ASSERT(gbest_no < gbest_max);
+	  gbest[gbest_no++] = winner;
+	  IF_DEBUG1 (gcount[winner] += 1);
+
+	  p  = p0;
+	  in = in0;
+
+	  /* Update group frequencies. */
+	  for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1)
+	    {
+	      evolve_freq[winner][*p] += 1;
+
+	      GP_PAGE ();
+	    }
+	}
+      while (in != NULL);
+
+      XD3_ASSERT (gbest_no == gbest_max);
+
+      /* Recompute code lengths. */
+      encode_bits = 0;
+      for (gp = 0; gp < groups; gp += 1)
+	{
+	  int i;
+	  uint8_t evolve_zero[ALPHABET_SIZE];
+	  int any_zeros = 0;
+
+	  memset (evolve_zero, 0, sizeof (evolve_zero));
+
+	  /* Cannot allow a zero clen when the real frequency is non-zero.  Note: this
+	   * means we are going to encode a fairly long code for these unused entries.  An
+	   * improvement would be to implement a NOTUSED code for when these are actually
+	   * zero, but this requires another data structure (evolve_zero) since we don't
+	   * know when evolve_freq[i] == 0...  Briefly tested, looked worse. */
+	  for (i = 0; i < ALPHABET_SIZE; i += 1)
+	    {
+	      if (evolve_freq[gp][i] == 0 && real_freq[i] != 0)
+		{
+		  evolve_freq[gp][i] = 1;
+		  evolve_zero[i] = 1;
+		  any_zeros = 1;
+		}
+	    }
+
+	  encode_bits += djw_build_prefix (evolve_freq[gp], evolve_clen[gp], ALPHABET_SIZE, DJW_MAX_CODELEN);
+
+	  /* The above faking of frequencies does not matter for the last iteration, but
+	   * we don't know when that is yet.  However, it also breaks the encode_bits
+	   * computation.  Necessary for accuracy, and for the (encode_bits==0) assert
+	   * after all bits are output. */
+	  if (any_zeros)
+	    {
+	      IF_DEBUG1 (usize_t save_total = encode_bits);
+
+	      for (i = 0; i < ALPHABET_SIZE; i += 1)
+		{
+		  if (evolve_zero[i]) { encode_bits -= evolve_clen[gp][i]; }
+		}
+
+	      IF_DEBUG1 (DP(RINT "evolve_zero reduced %u bits in group %u\n", save_total - encode_bits, gp));
+	    }
+	}
+
+      IF_DEBUG1(
+		DP(RINT "pass %u total bits: %u group uses: ", niter, encode_bits);
+		for (gp = 0; gp < groups; gp += 1) { DP(RINT "%u ", gcount[gp]); }
+		DP(RINT "\n"););
+
+      /* End iteration.  (The following assertion proved invalid.) */
+      /*XD3_ASSERT (niter == 1 || best_bits >= encode_bits);*/
+
+      IF_DEBUG1 (if (niter > 1 && best_bits < encode_bits) {
+	DP(RINT "iteration lost %u bits\n", encode_bits - best_bits); });
+
+      if (niter == 1 || (niter < DJW_MAX_ITER && (best_bits - encode_bits) >= DJW_MIN_IMPROVEMENT))
+	{
+	  best_bits = encode_bits;
+	  goto repeat;
+	}
+
+      /* Efficiency check. */
+      if (encode_bits + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; }
+
+      IF_DEBUG1 (DP(RINT "djw compression: %u -> %0.3f\n", input_bytes, encode_bits / 8.0));
+
+      /* Encode: prefix */
+      {
+	uint8_t     prefix_symbol[DJW_MAX_GROUPS * ALPHABET_SIZE];
+	uint8_t     prefix_mtfsym[DJW_MAX_GROUPS * ALPHABET_SIZE];
+	uint8_t     prefix_repcnt[DJW_MAX_GROUPS * ALPHABET_SIZE];
+	djw_prefix prefix;
+
+	prefix.symbol = prefix_symbol;
+	prefix.mtfsym = prefix_mtfsym;
+	prefix.repcnt = prefix_repcnt;
+
+	djw_compute_multi_prefix (groups, evolve_clen, & prefix);
+	if ((ret = djw_encode_prefix (stream, & output, & bstate, & prefix))) { goto failure; }
+      }
+
+      /* Encode: selector frequencies */
+      {
+	djw_weight gbest_freq[DJW_MAX_GROUPS+1];
+	djw_prefix gbest_prefix;
+	usize_t i;
+
+	gbest_prefix.scount = gbest_no;
+	gbest_prefix.symbol = gbest;
+	gbest_prefix.mtfsym = gbest_mtf;
+
+	djw_compute_selector_1_2 (& gbest_prefix, groups, gbest_freq);
+
+	select_bits =
+	  djw_build_prefix (gbest_freq, gbest_clen, groups+1, DJW_MAX_GBCLEN);
+	djw_build_codes  (gbest_code, gbest_clen, groups+1  DEBUG_ARG (DJW_MAX_GBCLEN));
+
+	IF_TUNE (tune_prefix_bits = xd3_bitsof_output (output, & bstate));
+	IF_TUNE (tune_select_bits = select_bits);
+	IF_TUNE (tune_encode_bits = encode_bits);
+
+	for (i = 0; i < groups+1; i += 1)
+	  {
+	    if ((ret = xd3_encode_bits (stream, & output, & bstate, DJW_GBCLEN_BITS, gbest_clen[i]))) { goto failure; }
+	  }
+
+	for (i = 0; i < gbest_prefix.mcount; i += 1)
+	  {
+	    usize_t gp_mtf      = gbest_mtf[i];
+	    usize_t gp_sel_bits = gbest_clen[gp_mtf];
+	    usize_t gp_sel_code = gbest_code[gp_mtf];
+
+	    XD3_ASSERT (gp_mtf < groups+1);
+
+	    if ((ret = xd3_encode_bits (stream, & output, & bstate, gp_sel_bits, gp_sel_code))) { goto failure; }
+
+	    IF_DEBUG (select_bits -= gp_sel_bits);
+	  }
+
+	XD3_ASSERT (select_bits == 0);
+      }
+
+      /* Efficiency check. */
+      if (encode_bits + select_bits + (8 * output->next) + EFFICIENCY_BITS >= input_bits && ! cfg->inefficient) { goto nosecond; }
+
+      /* Encode: data */
+      {
+	uint evolve_code[DJW_MAX_GROUPS][ALPHABET_SIZE];
+	usize_t sector = 0;
+
+	/* Build code tables for each group. */
+	for (gp = 0; gp < groups; gp += 1)
+	  {
+	    djw_build_codes (evolve_code[gp], evolve_clen[gp], ALPHABET_SIZE DEBUG_ARG (DJW_MAX_CODELEN));
+	  }
+
+	/* Now loop over the input. */
+	in = input;
+	p  = in->base;
+
+	do
+	  {
+	    /* For each sector. */
+	    usize_t   gp_best  = gbest[sector];
+	    uint    *gp_codes = evolve_code[gp_best];
+	    uint8_t *gp_clens = evolve_clen[gp_best];
+
+	    XD3_ASSERT (sector < gbest_no);
+
+	    sector += 1;
+
+	    /* Encode the sector data. */
+	    for (gpcnt = 0; gpcnt < sector_size; gpcnt += 1)
+	      {
+		usize_t sym  = *p;
+		usize_t bits = gp_clens[sym];
+		usize_t code = gp_codes[sym];
+
+		IF_DEBUG (encode_bits -= bits);
+
+		if ((ret = xd3_encode_bits (stream, & output, & bstate, bits, code))) { goto failure; }
+
+		GP_PAGE ();
+	      }
+	  }
+	while (in != NULL);
+
+	XD3_ASSERT (select_bits == 0);
+	XD3_ASSERT (encode_bits == 0);
+
+#undef evolve_clen
+      }
+    }
+
+  ret = xd3_flush_bits (stream, & output, & bstate);
+
+  if (0)
+    {
+    nosecond:
+      stream->msg = "secondary compression was inefficient";
+      ret = XD3_NOSECOND;
+    }
+
+ failure:
+
+  xd3_free (stream, gbest);
+  xd3_free (stream, gbest_mtf);
+  return ret;
+}
+#endif /* XD3_ENCODER */
+
+/*********************************************************************/
+/*                              DECODE                               */
+/*********************************************************************/
+
+static void
+djw_build_decoder (xd3_stream    *stream,
+		   usize_t         asize,
+		   usize_t         abs_max,
+		   const uint8_t *clen,
+		   uint8_t       *inorder,
+		   uint          *base,
+		   uint          *limit,
+		   uint          *min_clenp,
+		   uint          *max_clenp)
+{
+  int i, l;
+  const uint8_t *ci;
+  uint nr_clen [DJW_MAX_CODELEN+2];
+  uint tmp_base[DJW_MAX_CODELEN+2];
+  int min_clen;
+  int max_clen;
+
+  /* Assumption: the two temporary arrays are large enough to hold abs_max. */
+  XD3_ASSERT (abs_max <= DJW_MAX_CODELEN);
+
+  /* This looks something like the start of zlib's inftrees.c */
+  memset (nr_clen, 0, sizeof (nr_clen[0]) * (abs_max+1));
+
+  /* Count number of each code length */
+  i  = asize;
+  ci = clen;
+  do
+    {
+      /* Caller _must_ check that values are in-range.  Most of the time
+       * the caller decodes a specific number of bits, which imply the max value, and the
+       * other time the caller decodes a huffman value, which must be in-range.  Therefore,
+       * its an assertion and this function cannot otherwise fail. */
+      XD3_ASSERT (*ci <= abs_max);
+
+      nr_clen[*ci++]++;
+    }
+  while (--i != 0);
+
+  /* Compute min, max. */
+  for (i = 1; i <= abs_max; i += 1) { if (nr_clen[i]) { break; } }
+  min_clen = i;
+  for (i = abs_max; i != 0; i -= 1) { if (nr_clen[i]) { break; } }
+  max_clen = i;
+
+  /* Fill the BASE, LIMIT table. */
+  tmp_base[min_clen] = 0;
+  base[min_clen]     = 0;
+  limit[min_clen]    = nr_clen[min_clen] - 1;
+  for (i = min_clen + 1; i <= max_clen; i += 1)
+    {
+      uint last_limit = ((limit[i-1] + 1) << 1);
+      tmp_base[i] = tmp_base[i-1] + nr_clen[i-1];
+      limit[i]    = last_limit + nr_clen[i] - 1;
+      base[i]     = last_limit - tmp_base[i];
+    }
+
+  /* Fill the inorder array, canonically ordered codes. */
+  ci = clen;
+  for (i = 0; i < asize; i += 1)
+    {
+      if ((l = *ci++) != 0)
+	{
+	  inorder[tmp_base[l]++] = i;
+	}
+    }
+
+  *min_clenp = min_clen;
+  *max_clenp = max_clen;
+}
+
+static INLINE int
+djw_decode_symbol (xd3_stream     *stream,
+		   bit_state      *bstate,
+		   const uint8_t **input,
+		   const uint8_t  *input_end,
+		   const uint8_t  *inorder,
+		   const uint     *base,
+		   const uint     *limit,
+		   uint            min_clen,
+		   uint            max_clen,
+		   usize_t         *sym,
+		   usize_t          max_sym)
+{
+  usize_t code = 0;
+  usize_t bits = 0;
+
+  /* OPT: Supposedly a small lookup table improves speed here... */
+
+  /* Code outline is similar to xd3_decode_bits... */
+  if (bstate->cur_mask == 0x100) { goto next_byte; }
+
+  for (;;)
+    {
+      do
+	{
+	  if (bits == max_clen) { goto corrupt; }
+
+	  bits += 1;
+	  code  = (code << 1);
+
+	  if (bstate->cur_byte & bstate->cur_mask) { code |= 1; }
+
+	  bstate->cur_mask <<= 1;
+
+	  if (bits >= min_clen && code <= limit[bits]) { goto done; }
+	}
+      while (bstate->cur_mask != 0x100);
+
+    next_byte:
+
+      if (*input == input_end)
+	{
+	  stream->msg = "secondary decoder end of input";
+	  return XD3_INTERNAL;
+	}
+
+      bstate->cur_byte = *(*input)++;
+      bstate->cur_mask = 1;
+    }
+
+ done:
+
+  if (base[bits] <= code)
+    {
+      usize_t offset = code - base[bits];
+
+      if (offset <= max_sym)
+	{
+	  IF_DEBUG2 (DP(RINT "(j) %u ", code));
+	  *sym = inorder[offset];
+	  return 0;
+	}
+    }
+
+ corrupt:
+  stream->msg = "secondary decoder invalid code";
+  return XD3_INTERNAL;
+}
+
+static int
+djw_decode_clclen (xd3_stream     *stream,
+		   bit_state      *bstate,
+		   const uint8_t **input,
+		   const uint8_t  *input_end,
+		   uint8_t        *cl_inorder,
+		   uint           *cl_base,
+		   uint           *cl_limit,
+		   uint           *cl_minlen,
+		   uint           *cl_maxlen,
+		   uint8_t        *cl_mtf)
+{
+  int ret;
+  uint8_t cl_clen[DJW_TOTAL_CODES];
+  usize_t num_codes, value;
+  int i;
+
+  /* How many extra code lengths to encode. */
+  if ((ret = xd3_decode_bits (stream, bstate, input, input_end, DJW_EXTRA_CODE_BITS, & num_codes))) { return ret; }
+
+  num_codes += DJW_EXTRA_12OFFSET;
+
+  /* Read num_codes. */
+  for (i = 0; i < num_codes; i += 1)
+    {
+      if ((ret = xd3_decode_bits (stream, bstate, input, input_end, DJW_CLCLEN_BITS, & value))) { return ret; }
+
+      cl_clen[i] = value;
+    }
+
+  /* Set the rest to zero. */
+  for (; i < DJW_TOTAL_CODES; i += 1) { cl_clen[i] = 0; }
+
+  /* No need to check for in-range clen values, because: */
+  XD3_ASSERT (1 << DJW_CLCLEN_BITS == DJW_MAX_CLCLEN + 1);
+
+  /* Build the code-length decoder. */
+  djw_build_decoder (stream, DJW_TOTAL_CODES, DJW_MAX_CLCLEN,
+		     cl_clen, cl_inorder, cl_base, cl_limit, cl_minlen, cl_maxlen);
+
+  /* Initialize the MTF state. */
+  djw_init_clen_mtf_1_2 (cl_mtf);
+
+  return 0;
+}
+
+static INLINE int
+djw_decode_1_2 (xd3_stream     *stream,
+		bit_state      *bstate,
+		const uint8_t **input,
+		const uint8_t  *input_end,
+		const uint8_t  *inorder,
+		const uint     *base,
+		const uint     *limit,
+		const uint     *minlen,
+		const uint     *maxlen,
+		uint8_t        *mtfvals,
+		usize_t          elts,
+		usize_t          skip_offset,
+		uint8_t        *values)
+{
+  usize_t n = 0, rep = 0, mtf = 0, s = 0;
+  int ret;
+  
+  while (n < elts)
+    {
+      /* Special case inside generic code: CLEN only: If not the first group, we already
+       * know the zero frequencies. */
+      if (skip_offset != 0 && n >= skip_offset && values[n-skip_offset] == 0)
+	{
+	  values[n++] = 0;
+	  continue;
+	}
+
+      /* Repeat last symbol. */
+      if (rep != 0)
+	{
+	  values[n++] = mtfvals[0];
+	  rep -= 1;
+	  continue;
+	}
+
+      /* Symbol following last repeat code. */
+      if (mtf != 0)
+	{
+	  usize_t sym = djw_update_mtf (mtfvals, mtf);
+	  values[n++] = sym;
+	  mtf = 0;
+	  continue;
+	}
+
+      /* Decode next symbol/repeat code. */
+      if ((ret = djw_decode_symbol (stream, bstate, input, input_end,
+				    inorder, base, limit, *minlen, *maxlen,
+				    & mtf, DJW_TOTAL_CODES))) { return ret; }
+
+      if (mtf <= RUN_1)
+	{
+	  /* Repetition. */
+	  rep = ((mtf + 1) << s);
+	  mtf = 0;
+	  s += 1;
+	}
+      else
+	{
+	  /* Remove the RUN_1 MTF offset. */
+	  mtf -= 1;
+	  s = 0;
+	}
+    }
+
+  /* If (rep != 0) there were too many codes received. */
+  if (rep != 0)
+    {
+      stream->msg = "secondary decoder invalid repeat code";
+      return XD3_INTERNAL;
+    }
+  
+  return 0;
+}
+
+static INLINE int
+djw_decode_prefix (xd3_stream     *stream,
+		   bit_state      *bstate,
+		   const uint8_t **input,
+		   const uint8_t  *input_end,
+		   const uint8_t  *cl_inorder,
+		   const uint     *cl_base,
+		   const uint     *cl_limit,
+		   const uint     *cl_minlen,
+		   const uint     *cl_maxlen,
+		   uint8_t        *cl_mtf,
+		   usize_t          groups,
+		   uint8_t        *clen)
+{
+  return djw_decode_1_2 (stream, bstate, input, input_end,
+			 cl_inorder, cl_base, cl_limit, cl_minlen, cl_maxlen, cl_mtf,
+			 ALPHABET_SIZE * groups, ALPHABET_SIZE, clen);
+}
+
+static int
+xd3_decode_huff (xd3_stream     *stream,
+		 djw_stream    *h,
+		 const uint8_t **input_pos,
+		 const uint8_t  *const input_end,
+		 uint8_t       **output_pos,
+		 const uint8_t  *const output_end)
+{
+  const uint8_t *input = *input_pos;
+  uint8_t  *output = *output_pos;
+  bit_state bstate = BIT_STATE_DECODE_INIT;
+  uint8_t  *sel_group = NULL;
+  usize_t    groups, gp;
+  usize_t    output_bytes = (output_end - output);
+  usize_t    sector_size;
+  usize_t    sectors;
+  int ret;
+
+  /* Invalid input. */
+  if (output_bytes == 0)
+    {
+      stream->msg = "secondary decoder invalid input";
+      return XD3_INTERNAL;
+    }
+
+  /* Decode: number of groups */
+  if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_GROUP_BITS, & groups))) { goto fail; }
+
+  groups += 1;
+
+  if (groups > 1)
+    {
+      /* Decode: group size */
+      if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_SECTORSZ_BITS, & sector_size))) { goto fail; }
+      
+      sector_size = (sector_size + 1) * DJW_SECTORSZ_MULT;
+    }
+  else
+    {
+      /* Default for groups == 1 */
+      sector_size = output_bytes;
+    }
+
+  sectors = 1 + (output_bytes - 1) / sector_size;
+
+  /* @!@ In the case of groups==1, lots of extra stack space gets used here.  Could
+   * dynamically allocate this memory, which would help with excess parameter passing,
+   * too.  Passing too many parameters in this file, simplify it! */
+
+  /* Outer scope: per-group symbol decoder tables. */
+  {
+    uint8_t inorder[DJW_MAX_GROUPS][ALPHABET_SIZE];
+    uint    base   [DJW_MAX_GROUPS][DJW_MAX_CODELEN+2];
+    uint    limit  [DJW_MAX_GROUPS][DJW_MAX_CODELEN+2];
+    uint    minlen [DJW_MAX_GROUPS];
+    uint    maxlen [DJW_MAX_GROUPS];
+
+    /* Nested scope: code length decoder tables. */
+    {
+      uint8_t clen      [DJW_MAX_GROUPS][ALPHABET_SIZE];
+      uint8_t cl_inorder[DJW_TOTAL_CODES];
+      uint    cl_base   [DJW_MAX_CLCLEN+2];
+      uint    cl_limit  [DJW_MAX_CLCLEN+2];
+      uint8_t cl_mtf    [DJW_TOTAL_CODES];
+      uint    cl_minlen;
+      uint    cl_maxlen;
+
+      /* Compute the code length decoder. */
+      if ((ret = djw_decode_clclen (stream, & bstate, & input, input_end,
+				    cl_inorder, cl_base, cl_limit, & cl_minlen,
+				    & cl_maxlen, cl_mtf))) { goto fail; }
+
+      /* Now decode each group decoder. */
+      if ((ret = djw_decode_prefix (stream, & bstate, & input, input_end,
+				    cl_inorder, cl_base, cl_limit,
+				    & cl_minlen, & cl_maxlen, cl_mtf,
+				    groups, clen[0]))) { goto fail; }
+
+      /* Prepare the actual decoding tables. */
+      for (gp = 0; gp < groups; gp += 1)
+	{
+	  djw_build_decoder (stream, ALPHABET_SIZE, DJW_MAX_CODELEN,
+			     clen[gp], inorder[gp], base[gp], limit[gp],
+			     & minlen[gp], & maxlen[gp]);
+	}
+    }
+
+    /* Decode: selector clens. */
+    {
+      uint8_t sel_inorder[DJW_MAX_GROUPS+2];
+      uint    sel_base   [DJW_MAX_GBCLEN+2];
+      uint    sel_limit  [DJW_MAX_GBCLEN+2];
+      uint8_t sel_mtf    [DJW_MAX_GROUPS+2];
+      uint    sel_minlen;
+      uint    sel_maxlen;
+
+      /* Setup group selection. */
+      if (groups > 1)
+	{
+	  uint8_t sel_clen[DJW_MAX_GROUPS+1];
+
+	  for (gp = 0; gp < groups+1; gp += 1)
+	    {
+	      usize_t value;
+
+	      if ((ret = xd3_decode_bits (stream, & bstate, & input, input_end, DJW_GBCLEN_BITS, & value))) { goto fail; }
+
+	      sel_clen[gp] = value;
+	      sel_mtf[gp]  = gp;
+	    }
+
+	  if ((sel_group = xd3_alloc (stream, sectors, 1)) == NULL) { ret = ENOMEM; goto fail; }
+
+	  djw_build_decoder (stream, groups+1, DJW_MAX_GBCLEN, sel_clen,
+			     sel_inorder, sel_base, sel_limit, & sel_minlen, & sel_maxlen);
+
+	  if ((ret = djw_decode_1_2 (stream, & bstate, & input, input_end,
+				     sel_inorder, sel_base, sel_limit, & sel_minlen, & sel_maxlen, sel_mtf,
+				     sectors, 0, sel_group))) { goto fail; }
+	}
+
+      /* Now decode each sector. */
+      {
+	uint8_t *gp_inorder = inorder[0]; /* Initialize for (groups==1) case. */
+	uint    *gp_base    = base[0];
+	uint    *gp_limit   = limit[0];
+	uint     gp_minlen  = minlen[0];
+	uint     gp_maxlen  = maxlen[0];
+	usize_t c;
+
+	for (c = 0; c < sectors; c += 1)
+	  {
+	    usize_t n;
+
+	    if (groups >= 2)
+	      {
+		gp = sel_group[c];
+
+		XD3_ASSERT (gp < groups);
+
+		gp_inorder = inorder[gp];
+		gp_base    = base[gp];
+		gp_limit   = limit[gp];
+		gp_minlen  = minlen[gp];
+		gp_maxlen  = maxlen[gp];
+	      }
+
+	    XD3_ASSERT (output_end - output > 0);
+	    
+	    /* Decode next sector. */
+	    n = min (sector_size, (usize_t) (output_end - output));
+
+	    do
+	      {
+		usize_t sym;
+
+		if ((ret = djw_decode_symbol (stream, & bstate, & input, input_end,
+					      gp_inorder, gp_base, gp_limit, gp_minlen, gp_maxlen,
+					      & sym, ALPHABET_SIZE))) { goto fail; }
+
+		*output++ = sym;
+	      }
+	    while (--n);
+	  }
+      }
+    }
+  }
+
+  IF_REGRESSION (if ((ret = xd3_test_clean_bits (stream, & bstate))) { goto fail; });
+  XD3_ASSERT (ret == 0);
+
+ fail:
+  xd3_free (stream, sel_group);
+
+  (*input_pos) = input;
+  (*output_pos) = output;
+  return ret;
+}
+
+/*********************************************************************/
+/*                              TUNING                               */
+/*********************************************************************/
+
+#if TUNE_HUFFMAN && XD3_ENCODER
+#include <stdio.h>
+#include "xdelta3-fgk.h"
+
+static uint
+xd3_bitsof_output (xd3_output *output, bit_state *bstate)
+{
+  uint x = 0;
+  uint m = bstate->cur_mask;
+
+  while (m != 1)
+    {
+      x += 1;
+      m >>= 1;
+    }
+
+  return x + 8 * xd3_sizeof_output (output);
+}
+
+static const char* xd3_sect_type (xd3_section_type type)
+{
+  switch (type)
+    {
+    case DATA_SECTION: return "DATA";
+    case INST_SECTION: return "INST";
+    case ADDR_SECTION: return "ADDR";
+    }
+  abort ();
+}
+
+static int
+xd3_encode_huff (xd3_stream   *stream,
+		 djw_stream  *h,
+		 xd3_output   *input,
+		 xd3_output   *unused_output,
+		 xd3_sec_cfg  *cfg)
+{
+  int ret = 0;
+  int input_size = xd3_sizeof_output (input);
+  static int hdr = 0;
+  const char *sect_type = xd3_sect_type (cfg->data_type);
+  xd3_output *output;
+  usize_t output_size;
+
+  if (hdr == 0) { hdr = 1; DP(RINT "____ SECT INSZ SECTORSZ GPNO OUTSZ PREFIX SELECT ENCODE\n"); }
+
+  DP(RINT "SECTION %s %u\n", sect_type, input_size);
+
+    {
+      int gp, i;
+      int best_size = 99999999;
+      usize_t best_prefix = 0, best_select = 0, best_encode = 0, best_sector_size = 0;
+      int best_gpno = -1;
+      const char *t12 = "12";
+      usize_t clen_count[DJW_MAX_CODELEN+1];
+      djw_weight best_freq[DJW_TOTAL_CODES];
+
+      for (cfg->ngroups = 1; cfg->ngroups <= /*1*/ DJW_MAX_GROUPS; cfg->ngroups += 1)
+	{
+	  for (cfg->sector_size = 10; cfg->sector_size <= DJW_SECTORSZ_MAX; cfg->sector_size += 10)
+	    {
+	      output = xd3_alloc_output (stream, NULL);
+
+	      if ((ret = xd3_real_encode_huff (stream, h, input, output, cfg))) { goto fail; }
+
+	      output_size = xd3_sizeof_output (output);
+
+	      if (output_size < best_size)
+		{
+		  best_size = output_size;
+		  best_gpno = cfg->ngroups;
+		  best_prefix = tune_prefix_bits;
+		  best_select = tune_select_bits;
+		  best_encode = tune_encode_bits;
+		  best_sector_size = cfg->sector_size;
+		  memset (clen_count, 0, sizeof (clen_count));
+
+		  for (gp = 0; gp < cfg->ngroups; gp += 1)
+		    {
+		      for (i = 0; i < ALPHABET_SIZE; i += 1)
+			{
+			  clen_count[tune_clen[gp][i]] += 1;
+			}
+		    }
+
+		  memcpy (best_freq, tune_freq, sizeof (tune_freq));
+
+		  XD3_ASSERT (sizeof (tune_freq) == sizeof (mtf_freq));
+		}
+
+	      if (1)
+		{
+		  DP(RINT "COMP%s %u %u %u %u %u %u\n",
+			   t12, cfg->ngroups, cfg->sector_size,
+			   output_size, tune_prefix_bits, tune_select_bits, tune_encode_bits);
+		}
+	      else
+		{
+		fail:
+		  DP(RINT "COMP%s %u %u %u %u %u %u\n",
+			   t12, cfg->ngroups, cfg->sector_size,
+			   input_size, 0, 0, 0);
+		}
+
+	      xd3_free_output (stream, output);
+
+	      XD3_ASSERT (ret == 0 || ret == XD3_NOSECOND);
+
+	      if (cfg->ngroups == 1) { break; }
+	    }
+	}
+
+      if (best_gpno > 0)
+	{
+	  DP(RINT "BEST%s %u %u %u %u %u %u\n",
+		   t12, best_gpno, best_sector_size,
+		   best_size, best_prefix, best_select, best_encode);
+
+#if 0
+	  DP(RINT "CLEN%s ", t12);
+	  for (i = 1; i <= DJW_MAX_CODELEN; i += 1)
+	    {
+	      DP(RINT "%u ", clen_count[i]);
+	    }
+	  DP(RINT "\n");
+
+	  DP(RINT "FREQ%s ", t12);
+	  for (i = 0; i < DJW_TOTAL_CODES; i += 1)
+	    {
+	      DP(RINT "%u ", tune_freq[i]);
+	    }
+	  DP(RINT "\n");
+#endif
+	}
+    }
+
+  /* Compare to split single-table windows. */
+  {
+    int parts, i;
+
+    cfg->ngroups = 1;
+
+    for (parts = 2; parts <= DJW_MAX_GROUPS; parts += 1)
+      {
+	usize_t part_size = input_size / parts;
+	xd3_output *inp = input, *partin, *partin_head;
+	usize_t      off = 0;
+	usize_t      part_total = 0;
+	
+	if (part_size < 1000) { break; } 
+
+	for (i = 0; i < parts; i += 1)
+	  {
+	    usize_t inc;
+
+	    partin = partin_head = xd3_alloc_output (stream, NULL);
+	    output = xd3_alloc_output (stream, NULL);
+
+	    for (inc = 0; ((i < parts-1) && inc < part_size) ||
+		   ((i == parts-1) && inp != NULL); )
+	      {
+		usize_t take;
+
+		if (i < parts-1)
+		  {
+		    take = min (part_size - inc, inp->next - off);
+		  }
+		else
+		  {
+		    take = inp->next - off;
+		  }
+
+		ret = xd3_emit_bytes (stream, & partin, inp->base + off, take);
+
+		off += take;
+		inc += take;
+
+		if (off == inp->next)
+		  {
+		    inp = inp->next_page;
+		    off = 0;
+		  }
+	      }
+
+	    ret = xd3_real_encode_huff (stream, h, partin_head, output, cfg);
+
+	    part_total += xd3_sizeof_output (output);
+
+	    xd3_free_output (stream, partin_head);
+	    xd3_free_output (stream, output);
+
+	    XD3_ASSERT (ret == 0 || ret == XD3_NOSECOND);
+
+	    if (ret == XD3_NOSECOND)
+	      {
+		break;
+	      }
+	  }
+
+	if (ret != XD3_NOSECOND)
+	  {
+	    DP(RINT "PART %u %u\n", parts, part_total);
+	  }
+      }
+  }
+
+  /* Compare to FGK */
+  {
+    fgk_stream *fgk = fgk_alloc (stream);
+    
+    fgk_init (fgk);
+    
+    output = xd3_alloc_output (stream, NULL);
+    
+    ret = xd3_encode_fgk (stream, fgk, input, output, NULL);
+    
+    output_size = xd3_sizeof_output (output);
+    xd3_free_output (stream, output);
+    fgk_destroy (stream, fgk);
+
+    XD3_ASSERT (ret == 0);
+    
+    DP(RINT "FGK %u\n", output_size);
+  }
+
+  DP(RINT "END_SECTION %s %u\n", sect_type, input_size);
+
+  return 0;
+}
+#endif
+
+#endif
Index: /nikanabo/current/xdelta/diy/xdelta3-fgk.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-fgk.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-fgk.h	(revision 185)
@@ -0,0 +1,843 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2002, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* For demonstration purposes only.
+ */
+
+#ifndef _XDELTA3_FGK_h_
+#define _XDELTA3_FGK_h_
+
+/* An implementation of the FGK algorithm described by D.E. Knuth in "Dynamic Huffman
+ * Coding" in Journal of Algorithms 6. */
+
+/* A 32bit counter (fgk_weight) is used as the frequency counter for nodes in the huffman
+ * tree.  @!@ Need to test for overflow and/or reset stats. */
+
+typedef struct _fgk_stream fgk_stream;
+typedef struct _fgk_node   fgk_node;
+typedef struct _fgk_block  fgk_block;
+typedef unsigned int       fgk_bit;
+typedef uint32_t           fgk_weight;
+
+struct _fgk_block {
+  union {
+    fgk_node  *un_leader;
+    fgk_block *un_freeptr;
+  } un;
+};
+
+#define block_leader  un.un_leader
+#define block_freeptr un.un_freeptr
+
+/* The code can also support fixed huffman encoding/decoding. */
+#define IS_ADAPTIVE 1
+
+/* weight is a count of the number of times this element has been seen in the current
+ * encoding/decoding.  parent, right_child, and left_child are pointers defining the tree
+ * structure.  right and left point to neighbors in an ordered sequence of
+ * weights.  The left child of a node is always guaranteed to have weight not greater than
+ * its sibling.  fgk_blockLeader points to the element with the same weight as itself which is
+ * closest to the next increasing weight block.  */
+struct _fgk_node
+{
+  fgk_weight  weight;
+  fgk_node   *parent;
+  fgk_node   *left_child;
+  fgk_node   *right_child;
+  fgk_node   *left;
+  fgk_node   *right;
+  fgk_block  *my_block;
+};
+
+/* alphabet_size is the a count of the number of possible leaves in the huffman tree.  The
+ * number of total nodes counting internal nodes is ((2 * alphabet_size) - 1).
+ * zero_freq_count is the number of elements remaining which have zero frequency.
+ * zero_freq_exp and zero_freq_rem satisfy the equation zero_freq_count = 2^zero_freq_exp +
+ * zero_freq_rem.  root_node is the root of the tree, which is initialized to a node with
+ * zero frequency and contains the 0th such element.  free_node contains a pointer to the
+ * next available fgk_node space.  alphabet contains all the elements and is indexed by N.
+ * remaining_zeros points to the head of the list of zeros.  */
+struct _fgk_stream
+{
+  int alphabet_size;
+  int zero_freq_count;
+  int zero_freq_exp;
+  int zero_freq_rem;
+  int coded_depth;
+
+  int total_nodes;
+  int total_blocks;
+
+  fgk_bit *coded_bits;
+
+  fgk_block *block_array;
+  fgk_block *free_block;
+
+  fgk_node *decode_ptr;
+  fgk_node *remaining_zeros;
+  fgk_node *alphabet;
+  fgk_node *root_node;
+  fgk_node *free_node;
+};
+
+/*********************************************************************/
+/*                             Encoder                               */
+/*********************************************************************/
+
+static fgk_stream*     fgk_alloc           (xd3_stream *stream /*, int alphabet_size */);
+static void            fgk_init            (fgk_stream *h);
+static int             fgk_encode_data     (fgk_stream *h,
+					    int         n);
+static INLINE fgk_bit  fgk_get_encoded_bit (fgk_stream *h);
+
+static int             xd3_encode_fgk      (xd3_stream  *stream,
+					    fgk_stream  *sec_stream,
+					    xd3_output  *input,
+					    xd3_output  *output,
+					    xd3_sec_cfg *cfg);
+
+/*********************************************************************/
+/* 			       Decoder                               */
+/*********************************************************************/
+
+static INLINE int      fgk_decode_bit      (fgk_stream *h,
+					    fgk_bit     b);
+static int             fgk_decode_data     (fgk_stream *h);
+static void            fgk_destroy         (xd3_stream *stream,
+					    fgk_stream *h);
+
+static int             xd3_decode_fgk      (xd3_stream     *stream,
+					    fgk_stream     *sec_stream,
+					    const uint8_t **input,
+					    const uint8_t  *const input_end,
+					    uint8_t       **output,
+					    const uint8_t  *const output_end);
+
+/*********************************************************************/
+/* 			       Private                               */
+/*********************************************************************/
+
+static unsigned int fgk_find_nth_zero        (fgk_stream *h, int n);
+static int          fgk_nth_zero             (fgk_stream *h, int n);
+static void         fgk_update_tree          (fgk_stream *h, int n);
+static fgk_node*    fgk_increase_zero_weight (fgk_stream *h, int n);
+static void         fgk_eliminate_zero       (fgk_stream* h, fgk_node *node);
+static void         fgk_move_right           (fgk_stream *h, fgk_node *node);
+static void         fgk_promote              (fgk_stream *h, fgk_node *node);
+static void         fgk_init_node            (fgk_node *node, int i, int size);
+static fgk_block*   fgk_make_block           (fgk_stream *h, fgk_node *l);
+static void         fgk_free_block           (fgk_stream *h, fgk_block *b);
+static void         fgk_factor_remaining     (fgk_stream *h);
+static INLINE void  fgk_swap_ptrs            (fgk_node **one, fgk_node **two);
+
+/*********************************************************************/
+/* 			    Basic Routines                           */
+/*********************************************************************/
+
+/* returns an initialized huffman encoder for an alphabet with the
+ * given size.  returns NULL if enough memory cannot be allocated */
+static fgk_stream* fgk_alloc (xd3_stream *stream /*, int alphabet_size0 */)
+{
+  int alphabet_size0 = ALPHABET_SIZE;
+  fgk_stream *h;
+
+  if ((h = (fgk_stream*) xd3_alloc (stream, 1, sizeof (fgk_stream))) == NULL)
+    {
+      return NULL;
+    }
+
+  h->total_nodes  = (2 * alphabet_size0) - 1;
+  h->total_blocks = (2 * h->total_nodes);
+  h->alphabet     = (fgk_node*)  xd3_alloc (stream, h->total_nodes,    sizeof (fgk_node));
+  h->block_array  = (fgk_block*) xd3_alloc (stream, h->total_blocks,   sizeof (fgk_block));
+  h->coded_bits   = (fgk_bit*)   xd3_alloc (stream, alphabet_size0, sizeof (fgk_bit));
+
+  if (h->coded_bits  == NULL ||
+      h->alphabet    == NULL ||
+      h->block_array == NULL)
+    {
+      fgk_destroy (stream, h);
+      return NULL;
+    }
+
+  h->alphabet_size   = alphabet_size0;
+
+  return h;
+}
+
+static void fgk_init (fgk_stream *h)
+{
+  int i;
+
+  h->root_node       = h->alphabet;
+  h->decode_ptr      = h->root_node;
+  h->free_node       = h->alphabet + h->alphabet_size;
+  h->remaining_zeros = h->alphabet;
+  h->coded_depth     = 0;
+  h->zero_freq_count = h->alphabet_size + 2;
+
+  /* after two calls to factor_remaining, zero_freq_count == alphabet_size */
+  fgk_factor_remaining(h); /* set ZFE and ZFR */
+  fgk_factor_remaining(h); /* set ZFDB according to prev state */
+
+  IF_DEBUG (memset (h->alphabet, 0, sizeof (h->alphabet[0]) * h->total_nodes));
+
+  for (i = 0; i < h->total_blocks-1; i += 1)
+    {
+      h->block_array[i].block_freeptr = &h->block_array[i + 1];
+    }
+
+  h->block_array[h->total_blocks - 1].block_freeptr = NULL;
+  h->free_block = h->block_array;
+
+  /* Zero frequency nodes are inserted in the first alphabet_size
+   * positions, with Value, weight, and a pointer to the next zero
+   * frequency node.  */
+  for (i = h->alphabet_size - 1; i >= 0; i -= 1)
+    {
+      fgk_init_node (h->alphabet + i, i, h->alphabet_size);
+    }
+}
+
+static void fgk_swap_ptrs(fgk_node **one, fgk_node **two)
+{
+  fgk_node *tmp = *one;
+  *one = *two;
+  *two = tmp;
+}
+
+/* Takes huffman transmitter h and n, the nth elt in the alphabet, and
+ * returns the number of required to encode n. */
+static int fgk_encode_data (fgk_stream* h, int n)
+{
+  fgk_node *target_ptr = h->alphabet + n;
+
+  XD3_ASSERT (n < h->alphabet_size);
+
+  h->coded_depth = 0;
+
+  /* First encode the binary representation of the nth remaining
+   * zero frequency element in reverse such that bit, which will be
+   * encoded from h->coded_depth down to 0 will arrive in increasing
+   * order following the tree path.  If there is only one left, it
+   * is not neccesary to encode these bits. */
+  if (IS_ADAPTIVE && target_ptr->weight == 0)
+    {
+      unsigned int where, shift;
+      int bits;
+
+      where = fgk_find_nth_zero(h, n);
+      shift = 1;
+
+      if (h->zero_freq_rem == 0)
+	{
+	  bits = h->zero_freq_exp;
+	}
+      else
+	{
+	  bits = h->zero_freq_exp + 1;
+	}
+
+      while (bits > 0)
+	{
+	  h->coded_bits[h->coded_depth++] = (shift & where) && 1;
+
+	  bits   -= 1;
+	  shift <<= 1;
+	};
+
+      target_ptr = h->remaining_zeros;
+    }
+
+  /* The path from root to node is filled into coded_bits in reverse so
+   * that it is encoded in the right order */
+  while (target_ptr != h->root_node)
+    {
+      h->coded_bits[h->coded_depth++] = (target_ptr->parent->right_child == target_ptr);
+
+      target_ptr = target_ptr->parent;
+    }
+
+  if (IS_ADAPTIVE)
+    {
+      fgk_update_tree(h, n);
+    }
+
+  return h->coded_depth;
+}
+
+/* Should be called as many times as fgk_encode_data returns.
+ */
+static INLINE fgk_bit fgk_get_encoded_bit (fgk_stream *h)
+{
+  XD3_ASSERT (h->coded_depth > 0);
+
+  return h->coded_bits[--h->coded_depth];
+}
+
+/* This procedure updates the tree after alphabet[n] has been encoded
+ * or decoded.
+ */
+static void fgk_update_tree (fgk_stream *h, int n)
+{
+  fgk_node *incr_node;
+
+  if (h->alphabet[n].weight == 0)
+    {
+      incr_node = fgk_increase_zero_weight (h, n);
+    }
+  else
+    {
+      incr_node = h->alphabet + n;
+    }
+
+  while (incr_node != h->root_node)
+    {
+      fgk_move_right (h, incr_node);
+      fgk_promote    (h, incr_node);
+      incr_node->weight += 1;   /* incr the parent */
+      incr_node = incr_node->parent; /* repeat */
+    }
+
+  h->root_node->weight += 1;
+}
+
+static void fgk_move_right (fgk_stream *h, fgk_node *move_fwd)
+{
+  fgk_node **fwd_par_ptr, **back_par_ptr;
+  fgk_node *move_back, *tmp;
+
+  move_back = move_fwd->my_block->block_leader;
+
+  if (move_fwd         == move_back ||
+      move_fwd->parent == move_back ||
+      move_fwd->weight == 0)
+    {
+      return;
+    }
+
+  move_back->right->left = move_fwd;
+
+  if (move_fwd->left)
+    {
+      move_fwd->left->right = move_back;
+    }
+
+  tmp = move_fwd->right;
+  move_fwd->right = move_back->right;
+
+  if (tmp == move_back)
+    {
+      move_back->right = move_fwd;
+    }
+  else
+    {
+      tmp->left = move_back;
+      move_back->right = tmp;
+    }
+
+  tmp = move_back->left;
+  move_back->left = move_fwd->left;
+
+  if (tmp == move_fwd)
+    {
+      move_fwd->left = move_back;
+    }
+  else
+    {
+      tmp->right = move_fwd;
+      move_fwd->left = tmp;
+    }
+
+  if (move_fwd->parent->right_child == move_fwd)
+    {
+      fwd_par_ptr = &move_fwd->parent->right_child;
+    }
+  else
+    {
+      fwd_par_ptr = &move_fwd->parent->left_child;
+    }
+
+  if (move_back->parent->right_child == move_back)
+    {
+      back_par_ptr = &move_back->parent->right_child;
+    }
+  else
+    {
+      back_par_ptr = &move_back->parent->left_child;
+    }
+
+  fgk_swap_ptrs (&move_fwd->parent, &move_back->parent);
+  fgk_swap_ptrs (fwd_par_ptr, back_par_ptr);
+
+  move_fwd->my_block->block_leader = move_fwd;
+}
+
+/* Shifts node, the leader of its block, into the next block. */
+static void fgk_promote (fgk_stream *h, fgk_node *node)
+{
+  fgk_node *my_left, *my_right;
+  fgk_block *cur_block;
+
+  my_right  = node->right;
+  my_left   = node->left;
+  cur_block = node->my_block;
+
+  if (node->weight == 0)
+    {
+      return;
+    }
+
+  /* if left is right child, parent of remaining zeros case (?), means parent
+   * has same weight as right child. */
+  if (my_left == node->right_child &&
+      node->left_child &&
+      node->left_child->weight == 0)
+    {
+      XD3_ASSERT (node->left_child == h->remaining_zeros);
+      XD3_ASSERT (node->right_child->weight == (node->weight+1)); /* child weight was already incremented */
+      
+      if (node->weight == (my_right->weight - 1) && my_right != h->root_node)
+	{
+	  fgk_free_block (h, cur_block);
+	  node->my_block    = my_right->my_block;
+	  my_left->my_block = my_right->my_block;
+	}
+
+      return;
+    }
+
+  if (my_left == h->remaining_zeros)
+    {
+      return;
+    }
+
+  /* true if not the leftmost node */
+  if (my_left->my_block == cur_block)
+    {
+      my_left->my_block->block_leader = my_left;
+    }
+  else
+    {
+      fgk_free_block (h, cur_block);
+    }
+
+  /* node->parent != my_right */
+  if ((node->weight == (my_right->weight - 1)) && (my_right != h->root_node))
+    {
+      node->my_block = my_right->my_block;
+    }
+  else
+    {
+      node->my_block = fgk_make_block (h, node);
+    }
+}
+
+/* When an element is seen the first time this is called to remove it from the list of
+ * zero weight elements and introduce a new internal node to the tree.  */
+static fgk_node* fgk_increase_zero_weight (fgk_stream *h, int n)
+{
+  fgk_node *this_zero, *new_internal, *zero_ptr;
+
+  this_zero = h->alphabet + n;
+
+  if (h->zero_freq_count == 1)
+    {
+      /* this is the last one */
+      this_zero->right_child = NULL;
+
+      if (this_zero->right->weight == 1)
+	{
+	  this_zero->my_block = this_zero->right->my_block;
+	}
+      else
+	{
+	  this_zero->my_block = fgk_make_block (h, this_zero);
+	}
+
+      h->remaining_zeros = NULL;
+
+      return this_zero;
+    }
+
+  zero_ptr = h->remaining_zeros;
+
+  new_internal = h->free_node++;
+
+  new_internal->parent      = zero_ptr->parent;
+  new_internal->right       = zero_ptr->right;
+  new_internal->weight      = 0;
+  new_internal->right_child = this_zero;
+  new_internal->left        = this_zero;
+
+  if (h->remaining_zeros == h->root_node)
+    {
+      /* This is the first element to be coded */
+      h->root_node           = new_internal;
+      this_zero->my_block    = fgk_make_block (h, this_zero);
+      new_internal->my_block = fgk_make_block (h, new_internal);
+    }
+  else
+    {
+      new_internal->right->left = new_internal;
+
+      if (zero_ptr->parent->right_child == zero_ptr)
+	{
+	  zero_ptr->parent->right_child = new_internal;
+	}
+      else
+	{
+	  zero_ptr->parent->left_child = new_internal;
+	}
+
+      if (new_internal->right->weight == 1)
+	{
+	  new_internal->my_block = new_internal->right->my_block;
+	}
+      else
+	{
+	  new_internal->my_block = fgk_make_block (h, new_internal);
+	}
+
+      this_zero->my_block = new_internal->my_block;
+    }
+
+  fgk_eliminate_zero (h, this_zero);
+
+  new_internal->left_child = h->remaining_zeros;
+
+  this_zero->right       = new_internal;
+  this_zero->left        = h->remaining_zeros;
+  this_zero->parent      = new_internal;
+  this_zero->left_child  = NULL;
+  this_zero->right_child = NULL;
+
+  h->remaining_zeros->parent = new_internal;
+  h->remaining_zeros->right  = this_zero;
+
+  return this_zero;
+}
+
+/* When a zero frequency element is encoded, it is followed by the binary representation
+ * of the index into the remaining elements.  Sets a cache to the element before it so
+ * that it can be removed without calling this procedure again.  */
+static unsigned int fgk_find_nth_zero (fgk_stream* h, int n)
+{
+  fgk_node *target_ptr = h->alphabet + n;
+  fgk_node *head_ptr = h->remaining_zeros;
+  unsigned int idx = 0;
+
+  while (target_ptr != head_ptr)
+    {
+      head_ptr = head_ptr->right_child;
+      idx += 1;
+    }
+
+  return idx;
+}
+
+/* Splices node out of the list of zeros. */
+static void fgk_eliminate_zero (fgk_stream* h, fgk_node *node)
+{
+  if (h->zero_freq_count == 1)
+    {
+      return;
+    }
+
+  fgk_factor_remaining(h);
+
+  if (node->left_child == NULL)
+    {
+      h->remaining_zeros = h->remaining_zeros->right_child;
+      h->remaining_zeros->left_child = NULL;
+    }
+  else if (node->right_child == NULL)
+    {
+      node->left_child->right_child = NULL;
+    }
+  else
+    {
+      node->right_child->left_child = node->left_child;
+      node->left_child->right_child = node->right_child;
+    }
+}
+
+static void fgk_init_node (fgk_node *node, int i, int size)
+{
+  if (i < size - 1)
+    {
+      node->right_child = node + 1;
+    }
+  else
+    {
+      node->right_child = NULL;
+    }
+
+  if (i >= 1)
+    {
+      node->left_child = node - 1;
+    }
+  else
+    {
+      node->left_child = NULL;
+    }
+
+  node->weight      = 0;
+  node->parent      = NULL;
+  node->right = NULL;
+  node->left  = NULL;
+  node->my_block    = NULL;
+}
+
+/* The data structure used is an array of blocks, which are unions of free pointers and
+ * huffnode pointers.  free blocks are a linked list of free blocks, the front of which is
+ * h->free_block.  The used blocks are pointers to the head of each block.  */
+static fgk_block* fgk_make_block (fgk_stream *h, fgk_node* lead)
+{
+  fgk_block *ret = h->free_block;
+
+  XD3_ASSERT (h->free_block != NULL);
+
+  h->free_block = h->free_block->block_freeptr;
+
+  ret->block_leader = lead;
+
+  return ret;
+}
+
+/* Restores the block to the front of the free list. */
+static void fgk_free_block (fgk_stream *h, fgk_block *b)
+{
+  b->block_freeptr = h->free_block;
+  h->free_block = b;
+}
+
+/* sets zero_freq_count, zero_freq_rem, and zero_freq_exp to satsity the equation given
+ * above.  */
+static void fgk_factor_remaining (fgk_stream *h)
+{
+  unsigned int i;
+
+  i = (--h->zero_freq_count);
+  h->zero_freq_exp = 0;
+
+  while (i > 1)
+    {
+      h->zero_freq_exp += 1;
+      i >>= 1;
+    }
+
+  i = 1 << h->zero_freq_exp;
+
+  h->zero_freq_rem = h->zero_freq_count - i;
+}
+
+/* receives a bit at a time and returns true when a complete code has
+ * been received.
+ */
+static int INLINE fgk_decode_bit (fgk_stream* h, fgk_bit b)
+{
+  XD3_ASSERT (b == 1 || b == 0);
+
+  if (IS_ADAPTIVE && h->decode_ptr->weight == 0)
+    {
+      int bitsreq;
+
+      if (h->zero_freq_rem == 0)
+	{
+	  bitsreq = h->zero_freq_exp;
+	}
+      else
+	{
+	  bitsreq = h->zero_freq_exp + 1;
+	}
+
+      h->coded_bits[h->coded_depth] = b;
+      h->coded_depth += 1;
+
+      return h->coded_depth >= bitsreq;
+    }
+  else
+    {
+      if (b)
+	{
+	  h->decode_ptr = h->decode_ptr->right_child;
+	}
+      else
+	{
+	  h->decode_ptr = h->decode_ptr->left_child;
+	}
+
+      if (h->decode_ptr->left_child == NULL)
+	{
+	  /* If the weight is non-zero, finished. */
+	  if (h->decode_ptr->weight != 0)
+	    {
+	      return 1;
+	    }
+
+	  /* zero_freq_count is dropping to 0, finished. */
+	  return h->zero_freq_count == 1;
+	}
+      else
+	{
+	  return 0;
+	}
+    }
+}
+
+static int fgk_nth_zero (fgk_stream* h, int n)
+{
+  fgk_node *ret = h->remaining_zeros;
+
+  /* ERROR: if during this loop (ret->right_child == NULL) then the encoder's zero count
+   * is too high.  Could return an error code now, but is probably unnecessary overhead,
+   * since the caller should check integrity anyway. */
+  for (; n != 0 && ret->right_child != NULL; n -= 1)
+    {
+      ret = ret->right_child;
+    }
+
+  return ret - h->alphabet;
+}
+
+/* once fgk_decode_bit returns 1, this retrieves an index into the
+ * alphabet otherwise this returns 0, indicating more bits are
+ * required.
+ */
+static int fgk_decode_data (fgk_stream* h)
+{
+  unsigned int elt = h->decode_ptr - h->alphabet;
+
+  if (IS_ADAPTIVE && h->decode_ptr->weight == 0) {
+    int i;
+    unsigned int n = 0;
+
+    for (i = 0; i < h->coded_depth - 1; i += 1)
+      {
+	n |= h->coded_bits[i];
+	n <<= 1;
+      }
+
+    n |= h->coded_bits[i];
+    elt = fgk_nth_zero(h, n);
+  }
+
+  h->coded_depth = 0;
+
+  if (IS_ADAPTIVE)
+    {
+      fgk_update_tree(h, elt);
+    }
+
+  h->decode_ptr = h->root_node;
+
+  return elt;
+}
+
+static void fgk_destroy (xd3_stream *stream,
+			 fgk_stream *h)
+{
+  if (h != NULL)
+    {
+      xd3_free (stream, h->alphabet);
+      xd3_free (stream, h->coded_bits);
+      xd3_free (stream, h->block_array);
+      xd3_free (stream, h);
+    }
+}
+
+/*********************************************************************/
+/* 			       Xdelta                                */
+/*********************************************************************/
+
+static int
+xd3_encode_fgk (xd3_stream *stream, fgk_stream *sec_stream, xd3_output *input, xd3_output *output, xd3_sec_cfg *cfg)
+{
+  bit_state   bstate = BIT_STATE_ENCODE_INIT;
+  xd3_output *cur_page;
+  int ret;
+
+  /* OPT: quit compression early if it looks bad */
+  for (cur_page = input; cur_page; cur_page = cur_page->next_page)
+    {
+      const uint8_t *inp     = cur_page->base;
+      const uint8_t *inp_max = inp + cur_page->next;
+
+      while (inp < inp_max)
+	{
+	  usize_t bits = fgk_encode_data (sec_stream, *inp++);
+
+	  while (bits--)
+	    {
+	      if ((ret = xd3_encode_bit (stream, & output, & bstate, fgk_get_encoded_bit (sec_stream)))) { return ret; }
+	    }
+	}
+    }
+
+  return xd3_flush_bits (stream, & output, & bstate);
+}
+
+static int
+xd3_decode_fgk (xd3_stream     *stream,
+		fgk_stream     *sec_stream,
+		const uint8_t **input_pos,
+		const uint8_t  *const input_max,
+		uint8_t       **output_pos,
+		const uint8_t  *const output_max)
+{
+  bit_state bstate;
+  uint8_t *output = *output_pos;
+  const uint8_t *input = *input_pos;
+
+  for (;;)
+    {
+      if (input == input_max)
+	{
+	  stream->msg = "secondary decoder end of input";
+	  return XD3_INTERNAL;
+	}
+
+      bstate.cur_byte = *input++;
+
+      for (bstate.cur_mask = 1; bstate.cur_mask != 0x100; bstate.cur_mask <<= 1)
+	{
+	  int done = fgk_decode_bit (sec_stream, (bstate.cur_byte & bstate.cur_mask) && 1);
+
+	  if (! done) { continue; }
+
+	  *output++ = fgk_decode_data (sec_stream);
+
+	  if (unlikely (output == output_max))
+	    {
+	      /* During regression testing: */
+	      IF_REGRESSION ({
+		int ret;
+		bstate.cur_mask <<= 1;
+		if ((ret = xd3_test_clean_bits (stream, & bstate))) { return ret; }
+	      });
+
+	      (*output_pos) = output;
+	      (*input_pos) = input;
+	      return 0;
+	    }
+	}
+    }
+}
+
+#endif /* _XDELTA3_FGK_ */
Index: /nikanabo/current/xdelta/diy/xdelta3-list.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-list.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-list.h	(revision 185)
@@ -0,0 +1,130 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2002, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __XDELTA3_LIST__
+#define __XDELTA3_LIST__
+
+#define XD3_MAKELIST(LTYPE,ETYPE,LNAME)                                                   \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _entry (LTYPE* l)                                                                \
+{                                                                                         \
+  return (ETYPE*) ((char*) l - (unsigned long) &((ETYPE*) 0)->LNAME);                     \
+}                                                                                         \
+                                                                                          \
+static inline void                                                                        \
+LTYPE ## _init (LTYPE *l)                                                                 \
+{                                                                                         \
+  l->next = l;                                                                            \
+  l->prev = l;                                                                            \
+}                                                                                         \
+                                                                                          \
+static inline void                                                                        \
+LTYPE ## _add (LTYPE *prev, LTYPE *next, LTYPE *ins)                                      \
+{                                                                                         \
+  next->prev = ins;                                                                       \
+  prev->next = ins;                                                                       \
+  ins->next  = next;                                                                      \
+  ins->prev  = prev;                                                                      \
+}                                                                                         \
+                                                                                          \
+static inline void                                                                        \
+LTYPE ## _push_back (LTYPE *l, ETYPE *i)                                                  \
+{                                                                                         \
+  LTYPE ## _add (l->prev, l, & i->LNAME);                                                 \
+}                                                                                         \
+                                                                                          \
+static inline void                                                                        \
+LTYPE ## _del (LTYPE *next,                                                               \
+	       LTYPE *prev)                                                               \
+{                                                                                         \
+  next->prev = prev;                                                                      \
+  prev->next = next;                                                                      \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _remove (ETYPE *f)                                                               \
+{                                                                                         \
+  LTYPE *i = f->LNAME.next;                                                               \
+  LTYPE ## _del (f->LNAME.next, f->LNAME.prev);                                           \
+  return LTYPE ## _entry (i);                                                             \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _pop_back (LTYPE *l)                                                             \
+{                                                                                         \
+  LTYPE *i = l->prev;                                                                     \
+  LTYPE ## _del (i->next, i->prev);                                                       \
+  return LTYPE ## _entry (i);                                                             \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _pop_front (LTYPE *l)                                                            \
+{                                                                                         \
+  LTYPE *i = l->next;                                                                     \
+  LTYPE ## _del (i->next, i->prev);                                                       \
+  return LTYPE ## _entry (i);                                                             \
+}                                                                                         \
+                                                                                          \
+static inline int                                                                         \
+LTYPE ## _empty (LTYPE *l)                                                                \
+{                                                                                         \
+  return l == l->next;                                                                    \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _front (LTYPE *f)                                                                \
+{                                                                                         \
+  return LTYPE ## _entry (f->next);                                                       \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _back (LTYPE *f)                                                                 \
+{                                                                                         \
+  return LTYPE ## _entry (f->prev);                                                       \
+}                                                                                         \
+                                                                                          \
+static inline int                                                                         \
+LTYPE ## _end (LTYPE *f, ETYPE *i)                                                        \
+{                                                                                         \
+  return f == & i->LNAME;                                                                 \
+}                                                                                         \
+                                                                                          \
+static inline ETYPE*                                                                      \
+LTYPE ## _next (ETYPE *f)                                                                 \
+{                                                                                         \
+  return LTYPE ## _entry (f->LNAME.next);                                                 \
+}                                                                                         \
+                                                                                          \
+static inline int                                                                         \
+LTYPE ## _length (LTYPE *l)                                                               \
+{                                                                                         \
+  LTYPE *p;                                                                               \
+  int c = 0;                                                                              \
+                                                                                          \
+  for (p = l->next; p != l; p = p->next)                                                  \
+    {                                                                                     \
+      c += 1;                                                                             \
+    }                                                                                     \
+                                                                                          \
+  return c;                                                                               \
+}                                                                                         \
+                                                                                          \
+typedef int unused_ ## LTYPE
+
+#endif
Index: /nikanabo/current/xdelta/diy/xdelta3-main.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-main.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-main.h	(revision 185)
@@ -0,0 +1,3327 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ * Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* This is all the extra stuff you need for convenience to users in a command line
+ * application.  It contains these major components:
+ *
+ * 1. VCDIFF tools
+ * 2. external compression support (this is POSIX-specific).
+ * 3. a general read/write loop that handles all of the Xdelta decode/encode/VCDIFF-print
+ *    functions
+ * 4. command-line interpreter
+ * 5. an Xdelta application header which stores default filename, external compression settings
+ * 6. output/error printing
+ * 7. basic file support and OS interface
+ */
+
+/* TODO list:
+ * 1. do exact gzip-like filename, stdout handling.  make a .vcdiff extension, refuse
+ *    to encode to stdout without -cf, etc.
+ * 2. Allow the user to add a comment string to the app header without disturbing the default
+ *    behavior.
+ * 3. "Source file must be seekable" is not actually true for encoding, given current
+ *    behavior.  Allow non-seekable sources?  It would in theory let you use a fifo for
+ *    the source.
+ */
+
+/* On error handling and printing:
+ *
+ * The xdelta library sets stream->msg to indicate what condition caused an internal
+ * failure, but many failures originate here and are printed here.  The return convention
+ * is 0 for success, as throughout Xdelta code, but special attention is required here for
+ * the operating system calls with different error handling.  See the main_file_* routines.
+ * All errors in this file have a message printed at the time of occurance.  Since some of
+ * these calls occur within calls to the library, the error may end up being printed again
+ * with a more general error message.
+ */
+
+/******************************************************************************************/
+
+#ifndef XD3_POSIX
+#define XD3_POSIX 0
+#endif
+#ifndef XD3_STDIO
+#define XD3_STDIO 0
+#endif
+#ifndef XD3_WIN32
+#define XD3_WIN32 0
+#endif
+
+/* Combines xd3_strerror() and strerror() */
+const char* xd3_mainerror(int err_num);
+
+/* XPRINTX (used by main) prefixes an "xdelta3: " to the output. */
+#define XPR fprintf
+#define NT stderr, "xdelta3: "
+
+/* If none are set, default to posix. */
+#if (XD3_POSIX + XD3_STDIO + XD3_WIN32) == 0
+#undef XD3_POSIX
+#define XD3_POSIX 1
+#endif
+
+/* Handle externally-compressed inputs. */
+#ifndef EXTERNAL_COMPRESSION
+#define EXTERNAL_COMPRESSION 1
+#endif
+
+#define PRINTHDR_SPECIAL -4378291
+
+/* The number of soft-config variables.  */
+#define XD3_SOFTCFG_VARCNT 7
+
+/* this is used as in XPR(NT XD3_LIB_ERRMSG (stream, ret)) to print an error message
+ * from the library. */
+#define XD3_LIB_ERRMSG(stream, ret) "%s: %s\n", xd3_errstring (stream), xd3_mainerror (ret)
+
+#include <stdio.h>  /* fprintf */
+
+#if XD3_POSIX
+#include <unistd.h> /* close, read, write... */
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h> /* lots */
+#include <sys/time.h> /* gettimeofday() */
+#include <sys/stat.h> /* stat() and fstat() */
+#else
+#define strtoll _strtoi64
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef WIFEXITED
+#   define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0)
+#endif
+#ifndef WEXITSTATUS
+#   define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
+#endif
+#ifndef S_ISREG
+//#   ifdef S_IFREG
+//#       define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+//#   else
+#       define S_ISREG(m) 1
+//#   endif
+#endif /* !S_ISREG */
+
+// For standard input/output handles
+static STARTUPINFO winStartupInfo;
+#endif
+
+/******************************************************************************************
+ ENUMS and TYPES
+ ******************************************************************************************/
+
+/* These flags (mainly pertaining to main_read() operations) are set in the
+ * main_file->flags variable.  All are related to with external decompression support.
+ *
+ * RD_FIRST causes the external decompression check when the input is first read.
+ *
+ * RD_NONEXTERNAL disables external decompression for reading a compressed input, in the
+ * case of Xdelta inputs.  Note: Xdelta is supported as an external compression type,
+ * which makes is the reason for this flag.  An example to justify this is: to create a
+ * delta between two files that are VCDIFF-compressed.  Two external Xdelta decoders are
+ * run to supply decompressed source and target inputs to the Xdelta encoder. */
+typedef enum
+{
+  RD_FIRST        = (1 << 0),
+  RD_NONEXTERNAL  = (1 << 1),
+  RD_EXTERNAL_V1  = (1 << 2),
+} xd3_read_flags;
+
+/* main_file->mode values */
+typedef enum
+{
+  XO_READ  = 0,
+  XO_WRITE = 1,
+} main_file_modes;
+
+/* Main commands.  For example, CMD_PRINTHDR is the "xdelta printhdr" command. */
+typedef enum
+{
+  CMD_NONE = 0,
+  CMD_PRINTHDR,
+  CMD_PRINTHDRS,
+  CMD_PRINTDELTA,
+#if XD3_ENCODER
+  CMD_ENCODE,
+#endif
+  CMD_DECODE,
+  CMD_TEST,
+  CMD_CONFIG,
+} xd3_cmd;
+
+#if XD3_ENCODER
+#define CMD_DEFAULT CMD_ENCODE
+#define IS_ENCODE(cmd) (cmd == CMD_ENCODE)
+#else
+#define CMD_DEFAULT CMD_DECODE
+#define IS_ENCODE(cmd) (0)
+#endif
+
+typedef struct _main_file        main_file;
+typedef struct _main_extcomp     main_extcomp;
+typedef struct _main_blklru      main_blklru;
+typedef struct _main_blklru_list main_blklru_list;
+
+/* The main_file object supports abstract system calls like open, close, read, write, seek,
+ * stat.  The program uses these to represent both seekable files and non-seekable files.
+ * Source files must be seekable, but the target input and any output file do not require
+ * seekability.
+ */
+struct _main_file
+{
+#if XD3_STDIO
+  FILE               *file;
+#elif XD3_POSIX
+  int                 file;
+#elif XD3_WIN32
+  HANDLE              file;
+#endif
+
+  int                 mode;          /* XO_READ and XO_WRITE */
+  const char         *filename;      /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */
+  char               *filename_copy; /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */
+  const char         *realname;      /* File name or /dev/stdin, /dev/stdout, /dev/stderr. */
+  const main_extcomp *compressor;    /* External compression struct. */
+  int                 flags;         /* RD_FIRST, RD_NONEXTERNAL, ... */
+  xoff_t              nread;         /* for input position */
+  xoff_t              nwrite;        /* for output position */
+  uint8_t            *snprintf_buf;  /* internal snprintf() use */
+};
+
+/* Various strings and magic values used to detect and call external compression.  See
+ * below for examples. */
+struct _main_extcomp
+{
+  const char    *recomp_cmdname;
+  const char    *recomp_options;
+
+  const char    *decomp_cmdname;
+  const char    *decomp_options;
+
+  const char    *ident;
+  const char    *magic;
+  int            magic_size;
+  int            flags;
+};
+
+/* This file implements a small LRU of source blocks.  For encoding purposes,
+ * we prevent paging in blocks we've already scanned in the source (return
+ * XD3_NOTAVAIL). */
+struct _main_blklru_list
+{
+  main_blklru_list  *next;
+  main_blklru_list  *prev;
+};
+
+struct _main_blklru
+{
+  uint8_t         *blk;
+  xoff_t           blkno;
+  main_blklru_list  link;
+};
+
+#define LRU_SIZE 32U
+#define XD3_MINSRCWINSZ XD3_ALLOCSIZE
+
+/* ... represented as a list (no cache index). */
+XD3_MAKELIST(main_blklru_list,main_blklru,link);
+
+// TODO:
+// struct _main_state
+// {
+
+/* Program options: various command line flags and options. */
+static int         option_stdout             = 0;
+static int         option_force              = 0;
+static int         option_verbose            = 0;
+static int         option_quiet              = 0;
+static int         option_use_appheader      = 1;
+static uint8_t*    option_appheader          = NULL;
+static int         option_use_secondary      = 0;
+static char*       option_secondary          = NULL;
+static int         option_use_checksum       = 1;
+static int         option_use_altcodetable   = 0;
+static char*       option_smatch_config      = NULL;
+static int         option_no_compress        = 0;
+static int         option_no_output          = 0; /* do not open or write output */
+static const char *option_source_filename    = NULL;
+
+static int         option_level              = XD3_DEFAULT_LEVEL;
+static usize_t     option_iopt_size          = XD3_DEFAULT_IOPT_SIZE;
+static usize_t     option_winsize            = XD3_DEFAULT_WINSIZE;
+static usize_t     option_srcwinsz           = XD3_DEFAULT_SRCWINSZ;
+static usize_t     option_sprevsz            = XD3_DEFAULT_SPREVSZ;
+
+/* These variables are supressed to avoid their use w/o support.  main() warns
+ * appropriately. */
+#if EXTERNAL_COMPRESSION
+static int         option_decompress_inputs  = 1;
+static int         option_recompress_outputs = 1;
+#endif
+
+/* This is for comparing "printdelta" output without attention to
+ * copy-instruction modes. */
+#if VCDIFF_TOOLS
+static int         option_print_cpymode = 1;
+#endif
+
+/* Static variables */
+IF_DEBUG(static int main_mallocs = 0;)
+
+static char*          program_name = NULL;
+static uint8_t*       appheader_used = NULL;
+static uint8_t*       main_bdata = NULL;
+
+/* The LRU: obviously this is shared by all callers. */
+static int               lru_size = 0;
+static main_blklru      *lru = NULL;  /* array of lru_size elts */
+static main_blklru_list  lru_list;
+static main_blklru_list  lru_free;
+static int               do_not_lru = 0;  /* set to avoid lru, instead discard oldest */
+
+static int lru_hits   = 0;
+static int lru_misses = 0;
+static int lru_filled = 0;
+
+/* Hacks for VCDIFF tools */
+static int allow_fake_source = 0;
+
+/* This array of compressor types is compiled even if EXTERNAL_COMPRESSION is false just so
+ * the program knows the mapping of IDENT->NAME. */
+static main_extcomp extcomp_types[] =
+{
+  /* The entry for xdelta3 must be 0 because the program_name is set there. */
+  { "xdelta3",  "-cfq",  "xdelta3",    "-dcfq",  "X", "\xd6\xc3\xc4", 3, RD_NONEXTERNAL },
+  { "bzip2",    "-cf",   "bzip2",      "-dcf",   "B", "BZh",          3, 0 },
+  { "gzip",     "-cf",   "gzip",       "-dcf",   "G", "\037\213",     2, 0 },
+  { "compress", "-cf",   "uncompress", "-cf",    "Z", "\037\235",     2, 0 },
+
+  /* TODO: add commandline support for magic-less formats */
+  /*{ "lzma",     "-cf",   "lzma",       "-dcf",   "M", "]\000",        2, 0 },*/
+};
+
+// };
+
+static void main_get_appheader (xd3_stream *stream, main_file *ifile,
+				main_file *output, main_file *sfile);
+
+static int main_help (void);
+
+static int
+main_version (void)
+{
+  /* $Format: "  DP(RINT \"VERSION=3.$Xdelta3Version$\\n\");" $ */
+  DP(RINT "VERSION=3.0q\n");
+  return EXIT_SUCCESS;
+}
+
+static int
+main_config (void)
+{
+  main_version ();
+
+  DP(RINT "EXTERNAL_COMPRESSION=%d\n", EXTERNAL_COMPRESSION);
+  DP(RINT "GENERIC_ENCODE_TABLES=%d\n", GENERIC_ENCODE_TABLES);
+  DP(RINT "GENERIC_ENCODE_TABLES_COMPUTE=%d\n", GENERIC_ENCODE_TABLES_COMPUTE);
+  DP(RINT "REGRESSION_TEST=%d\n", REGRESSION_TEST);
+  DP(RINT "SECONDARY_DJW=%d\n", SECONDARY_DJW);
+  DP(RINT "SECONDARY_FGK=%d\n", SECONDARY_FGK);
+  DP(RINT "VCDIFF_TOOLS=%d\n", VCDIFF_TOOLS);
+  DP(RINT "XD3_ALLOCSIZE=%d\n", XD3_ALLOCSIZE);
+  DP(RINT "XD3_DEBUG=%d\n", XD3_DEBUG);
+  DP(RINT "XD3_ENCODER=%d\n", XD3_ENCODER);
+  DP(RINT "XD3_POSIX=%d\n", XD3_POSIX);
+  DP(RINT "XD3_STDIO=%d\n", XD3_STDIO);
+  DP(RINT "XD3_WIN32=%d\n", XD3_WIN32);
+  DP(RINT "XD3_USE_LARGEFILE64=%d\n", XD3_USE_LARGEFILE64);
+  DP(RINT "XD3_DEFAULT_LEVEL=%d\n", XD3_DEFAULT_LEVEL);
+  DP(RINT "XD3_DEFAULT_IOPT_SIZE=%d\n", XD3_DEFAULT_IOPT_SIZE);
+  DP(RINT "XD3_DEFAULT_SPREVSZ=%d\n", XD3_DEFAULT_SPREVSZ);
+  DP(RINT "XD3_DEFAULT_SRCWINSZ=%d\n", XD3_DEFAULT_SRCWINSZ);
+  DP(RINT "XD3_DEFAULT_WINSIZE=%d\n", XD3_DEFAULT_WINSIZE);
+  DP(RINT "XD3_HARDMAXWINSIZE=%d\n", XD3_HARDMAXWINSIZE);
+  DP(RINT "XD3_NODECOMPRESSSIZE=%d\n", XD3_NODECOMPRESSSIZE);
+
+  return EXIT_SUCCESS;
+}
+
+static void
+reset_defaults(void)
+{
+  option_stdout = 0;
+  option_force = 0;
+  option_verbose = 0;
+  option_quiet = 0;
+  option_appheader = NULL;
+  option_use_secondary = 0;
+  option_secondary = NULL;
+  option_use_altcodetable = 0;
+  option_smatch_config = NULL;
+  option_no_compress = 0;
+  option_no_output = 0;
+  option_source_filename = NULL;
+  program_name = NULL;
+  appheader_used = NULL;
+  main_bdata = NULL;
+  lru_size = 0;
+  lru = NULL;
+  do_not_lru = 0;
+  lru_hits   = 0;
+  lru_misses = 0;
+  lru_filled = 0;
+  allow_fake_source = 0;
+  option_smatch_config = NULL;
+
+  option_use_appheader = 1;
+  option_use_checksum = 1;
+#if EXTERNAL_COMPRESSION
+  option_decompress_inputs  = 1;
+  option_recompress_outputs = 1;
+#endif
+#if VCDIFF_TOOLS
+  option_print_cpymode = 1;
+#endif
+  option_level = XD3_DEFAULT_LEVEL;
+  option_iopt_size = XD3_DEFAULT_IOPT_SIZE;
+  option_winsize = XD3_DEFAULT_WINSIZE;
+  option_srcwinsz = XD3_DEFAULT_SRCWINSZ;
+  option_sprevsz = XD3_DEFAULT_SPREVSZ;
+}
+
+static void*
+main_malloc1 (usize_t size)
+{
+  void* r = malloc (size);
+  if (r == NULL) { XPR(NT "malloc: %s\n", xd3_mainerror (ENOMEM)); }
+  else if (option_verbose > 3) { XPR(NT "malloc: %u: %p\n", size, r); }
+  return r;
+}
+
+static void*
+main_malloc (usize_t size)
+{
+  void *r = main_malloc1 (size);
+   if (r) { IF_DEBUG (main_mallocs += 1); }
+  return r;
+}
+
+static void*
+main_alloc (void   *opaque,
+	    usize_t  items,
+	    usize_t  size)
+{
+  return main_malloc1 (items * size);
+}
+
+static void
+main_free1 (void *opaque, void *ptr)
+{
+  if (option_verbose > 3) { XPR(NT "free: %p\n", ptr); }
+  free (ptr);
+}
+
+static void
+main_free (void *ptr)
+{
+  if (ptr)
+    {
+      IF_DEBUG (main_mallocs -= 1);
+      main_free1 (NULL, ptr);
+      IF_DEBUG (XD3_ASSERT(main_mallocs >= 0));
+    }
+}
+
+/* This ensures that (ret = errno) always indicates failure, in case errno was
+ * accidentally not set.  If this prints there's a bug somewhere. */
+static int
+get_errno (void)
+{
+#ifndef _WIN32
+  if (errno == 0)
+    {
+      XPR(NT "you found a bug: expected errno != 0\n");
+      errno = XD3_INTERNAL;
+    }
+  return errno;
+#else
+  DWORD errNum = GetLastError();
+  if (errNum == NO_ERROR) {
+	  errNum = XD3_INTERNAL;
+  }
+  return errNum;
+#endif
+}
+
+const char*
+xd3_mainerror(int err_num) {
+#ifndef _WIN32
+	const char* x = xd3_strerror (err_num);
+	if (x != NULL) {
+		return x;
+	}
+	return strerror(err_num);
+#else
+	static char err_buf[256];
+	const char* x = xd3_strerror (err_num);
+	if (x != NULL) {
+		return x;
+	}
+	memset (err_buf, 0, 256);
+	FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+		NULL, err_num,
+		MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+		err_buf, 256, NULL);
+	return err_buf;
+#endif
+}
+
+static long
+get_millisecs_now (void)
+{
+#ifndef _WIN32
+  struct timeval tv;
+
+  gettimeofday (& tv, NULL);
+
+  return (tv.tv_sec) * 1000L + (tv.tv_usec) / 1000;
+#else
+  // Found this in an example on www.codeproject.com
+  // It doesn't matter that the offset is Jan 1, 1601
+  // Result is the numbre of 100 nanosecond units
+  // 100ns * 10,000 = 1ms
+  SYSTEMTIME st;
+  FILETIME ft;
+  __int64 *pi = (__int64*)&ft;
+  GetLocalTime(&st);
+  SystemTimeToFileTime(&st, &ft);
+  return (long)((*pi) / 10000);
+#endif
+}
+
+/* Always >= 1 millisec, right? */
+static long
+get_millisecs_since (void)
+{
+  static long last = 0;
+  long now = get_millisecs_now();
+  long diff = now - last;
+  last = now;
+  return diff;
+}
+
+static char*
+main_format_bcnt (xoff_t r, char *buf)
+{
+  static const char* fmts[] = { "B", "KB", "MB", "GB" };
+  int i;
+
+  for (i = 0; i < SIZEOF_ARRAY(fmts); i += 1)
+    {
+      if (r <= (10 * 1024) || i == (-1 + (int)SIZEOF_ARRAY(fmts)))
+  	    {
+	      sprintf (buf, "%"Q"u %s", r, fmts[i]);
+	      break;
+	    }
+      r /= 1024;
+    }
+  return buf;
+}
+
+static char*
+main_format_rate (xoff_t bytes, long millis, char *buf)
+{
+  xoff_t r = (xoff_t)(1.0 * bytes / (1.0 * millis / 1000.0));
+  static char lbuf[32];
+
+  main_format_bcnt (r, lbuf);
+  sprintf (buf, "%s/sec", lbuf);
+  return buf;
+}
+
+static char*
+main_format_millis (long millis, char *buf)
+{
+  if (millis < 1000)       { sprintf (buf, "%lu ms", millis); }
+  else if (millis < 10000) { sprintf (buf, "%.1f sec", millis / 1000.0); }
+  else                     { sprintf (buf, "%lu sec", millis / 1000L); }
+  return buf;
+}
+
+/* A safe version of strtol for xoff_t. */
+static int
+main_strtoxoff (const char* s, xoff_t *xo, char which)
+{
+  char *e;
+  xoff_t x;
+
+  XD3_ASSERT(s && *s != 0);
+
+  {
+    /* Should check LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX? */
+#if SIZEOF_XOFF_T == 4
+    long xx = strtol (s, &e, 0);
+#else
+    long long xx = strtoll (s, &e, 0);
+#endif
+
+    if (xx < 0)
+      {
+	XPR(NT "-%c: negative integer: %s\n", which, s);
+	return EXIT_FAILURE;
+      }
+
+    x = xx;
+  }
+
+  if (*e != 0)
+    {
+      XPR(NT "-%c: invalid integer: %s\n", which, s);
+      return EXIT_FAILURE;
+    }
+
+  (*xo) = x;
+  return 0;
+}
+
+static int
+main_atou (const char* arg, usize_t *xo, usize_t low, usize_t high, char which)
+{
+  xoff_t x;
+  int ret;
+
+  if ((ret = main_strtoxoff (arg, & x, which))) { return ret; }
+
+  if (x < low)
+    {
+      XPR(NT "-%c: minimum value: %u\n", which, low);
+      return EXIT_FAILURE;
+    }
+  if (high == 0)
+    {
+      high = USIZE_T_MAX;
+    }
+  if (x > high)
+    {
+      XPR(NT "-%c: maximum value: %u\n", which, high);
+      return EXIT_FAILURE;
+    }
+  (*xo) = (usize_t)x;
+  return 0;
+}
+
+/******************************************************************************************
+ FILE BASICS
+ ******************************************************************************************/
+
+/* With all the variation in file system-call semantics, arguments, return values and
+ * error-handling for the POSIX and STDIO file APIs, the insides of these functions make
+ * me sick, which is why these wrappers exist. */
+
+#define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write")
+#define XOPEN_STDIO  (xfile->mode == XO_READ ? "rb" : "wb")
+#define XOPEN_POSIX  (xfile->mode == XO_READ ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC)
+#define XOPEN_MODE   (xfile->mode == XO_READ ? 0 : 0666)
+
+#define XF_ERROR(op, name, ret) \
+  XPR(NT "file %s failed: %s: %s: %s\n", (op), XOPEN_OPNAME, (name), xd3_mainerror (ret))
+
+#if XD3_STDIO
+#define XFNO(f) fileno(f->file)
+#define XSTDOUT_XF(f) { (f)->file = stdout; (f)->filename = "/dev/stdout"; }
+#define XSTDIN_XF(f)  { (f)->file = stdin;  (f)->filename = "/dev/stdin"; }
+
+#elif XD3_POSIX
+#define XFNO(f) f->file
+#define XSTDOUT_XF(f) { (f)->file = STDOUT_FILENO; (f)->filename = "/dev/stdout"; }
+#define XSTDIN_XF(f)  { (f)->file = STDIN_FILENO;  (f)->filename = "/dev/stdin"; }
+
+#elif XD3_WIN32
+#define XFNO(f) -1
+#define XSTDOUT_XF(f) { (f)->file = winStartupInfo.hStdOutput; (f)->filename = "(stdout)"; }
+#define XSTDIN_XF(f)  { (f)->file = winStartupInfo.hStdInput;  (f)->filename = "(stdin)"; }
+#endif
+
+static void
+main_file_init (main_file *xfile)
+{
+  memset (xfile, 0, sizeof (*xfile));
+
+#if XD3_POSIX
+  xfile->file = -1;
+#endif
+#if XD3_WIN32
+  xfile->file = INVALID_HANDLE_VALUE;
+#endif
+}
+
+static int
+main_file_isopen (main_file *xfile)
+{
+#if XD3_STDIO
+  return xfile->file != NULL;
+
+#elif XD3_POSIX
+  return xfile->file != -1;
+
+#elif XD3_WIN32
+  return xfile->file != INVALID_HANDLE_VALUE;
+#endif
+}
+
+static int
+main_file_close (main_file *xfile)
+{
+  int ret = 0;
+
+  if (! main_file_isopen (xfile))
+    {
+      return 0;
+    }
+
+#if XD3_STDIO
+  ret = fclose (xfile->file);
+  xfile->file = NULL;
+
+#elif XD3_POSIX
+  ret = close (xfile->file);
+  xfile->file = -1;
+
+#elif XD3_WIN32
+  if (!CloseHandle(xfile->file)) {
+    ret = get_errno ();
+  }
+  xfile->file = INVALID_HANDLE_VALUE;
+#endif
+
+  if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); }
+  return ret;
+}
+
+static void
+main_file_cleanup (main_file *xfile)
+{
+  if (main_file_isopen (xfile))
+    {
+      main_file_close (xfile);
+    }
+
+  if (xfile->snprintf_buf != NULL)
+    {
+      main_free(xfile->snprintf_buf);
+      xfile->snprintf_buf = NULL;
+    }
+
+  if (xfile->filename_copy != NULL)
+    {
+      main_free(xfile->filename_copy);
+      xfile->filename_copy = NULL;
+    }
+}
+
+static int
+main_file_open (main_file *xfile, const char* name, int mode)
+{
+  int ret = 0;
+
+  xfile->mode = mode;
+
+  XD3_ASSERT (name != NULL);
+  XD3_ASSERT (! main_file_isopen (xfile));
+  if (name[0] == 0)
+    {
+      XPR(NT "invalid file name: empty string\n");
+      return XD3_INVALID;
+    }
+
+#if XD3_STDIO
+  xfile->file = fopen (name, XOPEN_STDIO);
+
+  ret = (xfile->file == NULL) ? get_errno () : 0;
+
+#elif XD3_POSIX
+  if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) < 0)
+    {
+      ret = get_errno ();
+    }
+  else
+    {
+      xfile->file = ret;
+      ret = 0;
+    }
+
+#elif XD3_WIN32
+  xfile->file = CreateFile(name,
+	  (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE,
+	  FILE_SHARE_READ,
+	  NULL,
+	  (mode == XO_READ) ? OPEN_EXISTING : (option_force ? CREATE_ALWAYS : CREATE_NEW),
+	  FILE_ATTRIBUTE_NORMAL,
+	  NULL);
+  if (xfile->file == INVALID_HANDLE_VALUE) {
+	  ret = get_errno ();
+  }
+#endif
+  if (ret) { XF_ERROR ("open", name, ret); }
+  else     { xfile->realname = name; xfile->nread = 0; }
+  return ret;
+}
+
+static int
+main_file_stat (main_file *xfile, xoff_t *size, int err_ifnoseek)
+{
+  int ret = 0;
+#if XD3_WIN32
+  LARGE_INTEGER li;
+  if (GetFileSizeEx(xfile->file, &li) == 0) {
+	  ret = get_errno ();
+  } else {
+      *size = li.QuadPart;
+  }
+#else
+  struct stat sbuf;
+  if (fstat (XFNO (xfile), & sbuf) < 0)
+    {
+      ret = get_errno ();
+      if (err_ifnoseek) { XF_ERROR ("stat", xfile->filename, ret); }
+      return ret;
+    }
+
+  if (! S_ISREG (sbuf.st_mode))
+    {
+      if (err_ifnoseek) { XPR(NT "source file must be seekable: %s\n", xfile->filename); }
+      return ESPIPE;
+    }
+  (*size) = sbuf.st_size;
+#endif
+  return ret;
+}
+
+static int
+main_file_exists (main_file *xfile)
+{
+  struct stat sbuf;
+  return stat (xfile->filename, & sbuf) == 0 && S_ISREG (sbuf.st_mode);
+}
+
+#if (XD3_POSIX || EXTERNAL_COMPRESSION)
+/* POSIX-generic code takes a function pointer to read() or write().  This calls the
+ * function repeatedly until the buffer is full or EOF.  The NREAD parameter is not
+ * set for write, NULL is passed.  Return is signed, < 0 indicate errors, otherwise
+ * byte count. */
+typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size);
+
+static int
+xd3_posix_io (int fd, uint8_t *buf, usize_t size, xd3_posix_func *func, usize_t *nread)
+{
+  int ret;
+  usize_t nproc = 0;
+
+  while (nproc < size)
+    {
+      int result = (*func) (fd, buf + nproc, size - nproc);
+
+      if (result < 0)
+	{
+	  ret = get_errno ();
+	  if (ret != EAGAIN && ret != EINTR)
+	    {
+	      return ret;
+	    }
+	  result = 0;
+	}
+
+      if (nread != NULL && result == 0) { break; }
+
+      nproc += result;
+    }
+  if (nread != NULL) { (*nread) = nproc; }
+  return 0;
+}
+#endif
+
+/* POSIX is unbuffered, while STDIO is buffered.  main_file_read() should always be called
+ * on blocks. */
+static int
+main_file_read (main_file   *ifile,
+	       uint8_t    *buf,
+	       usize_t      size,
+	       usize_t     *nread,
+	       const char *msg)
+{
+  int ret = 0;
+
+#if XD3_STDIO
+  usize_t result;
+
+  result = fread (buf, 1, size, ifile->file);
+
+  if (result < size && ferror (ifile->file))
+    {
+      ret = get_errno ();
+    }
+  else
+    {
+      *nread = result;
+    }
+
+#elif XD3_POSIX
+  ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread);
+
+#elif XD3_WIN32
+  DWORD nread2;
+  if (ReadFile (ifile->file, buf, size, &nread2, NULL) == 0) {
+	  ret = get_errno();
+  } else {
+      *nread = (usize_t)nread2;
+  }
+#endif
+
+  if (ret)
+    {
+      XPR(NT "%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret));
+    }
+  else
+    {
+      if (option_verbose > 3) { XPR(NT "main read: %s: %u\n", ifile->filename, (*nread)); }
+      ifile->nread += (*nread);
+    }
+
+  return ret;
+}
+
+static int
+main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg)
+{
+  int ret = 0;
+
+#if XD3_STDIO
+  usize_t result;
+
+  result = fwrite (buf, 1, size, ofile->file);
+
+  if (result != size) { ret = get_errno (); }
+
+#elif XD3_POSIX
+  ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL);
+
+#elif XD3_WIN32
+  DWORD nwrite;
+  if (WriteFile(ofile->file, buf, size, &nwrite, NULL) == 0) {
+	  ret = get_errno ();
+  } else {
+	  if (size != nwrite) {
+		  XPR(NT "Incorrect write count");
+		  ret = XD3_INTERNAL;
+	  }
+  }
+#endif
+
+  if (ret)
+    {
+      XPR(NT "%s: %s: %s\n", msg, ofile->filename, xd3_mainerror (ret));
+    }
+  else
+    {
+      if (option_verbose > 3) { XPR(NT "main write: %s: %u\n", ofile->filename, size); }
+      ofile->nwrite += size;
+    }
+
+  return ret;
+}
+
+static int
+main_file_seek (main_file *xfile, xoff_t pos)
+{
+  int ret = 0;
+
+#if XD3_STDIO
+  if (fseek (xfile->file, pos, SEEK_SET) != 0) { ret = get_errno (); }
+
+#elif XD3_POSIX
+  if (lseek (xfile->file, pos, SEEK_SET) != pos) { ret = get_errno (); }
+
+#elif XD3_WIN32
+  LARGE_INTEGER move, out;
+  move.QuadPart = pos;
+  if (SetFilePointerEx(xfile->file, move, &out, FILE_BEGIN) == 0) {
+	  ret = get_errno ();
+  }
+#endif
+
+  if (ret)
+    {
+      XPR(NT "seek failed: %s: %s\n", xfile->filename, xd3_mainerror (ret));
+    }
+
+  return ret;
+}
+
+/******************************************************************************************
+ VCDIFF TOOLS
+ ******************************************************************************************/
+
+#if VCDIFF_TOOLS
+
+/* The following macros let VCDIFF printing something printf-like with
+ * main_file_write(), e.g.,:
+ * 
+ *   VC(UT "trying to be portable: %d\n", x)VE;
+ */
+#define SNPRINTF_BUFSIZE 1024
+#define VC do { if (((ret = snprintf
+#define UT (char*)xfile->snprintf_buf, SNPRINTF_BUFSIZE,
+#define VE ) >= SNPRINTF_BUFSIZE			       \
+  && (ret = main_print_overflow(ret)) != 0)		       \
+  || (ret = main_file_write(xfile, xfile->snprintf_buf,        \
+			    ret, "print")) != 0)	       \
+  { return ret; } } while (0)
+
+#ifdef WIN32
+/* According to the internet, Windows vsnprintf() differs from most Unix
+ * implementations regarding the terminating 0 when the boundary condition
+ * is met. It doesn't matter here, we don't rely on the trailing 0. */
+#include <stdarg.h>
+int
+snprintf (char *str, int n, char *fmt, ...)
+{
+  va_list a;
+  int ret;
+  va_start (a, fmt);
+  ret = vsnprintf (str, n, fmt, a);
+  va_end (a);
+  return ret;
+}
+#endif
+
+static int
+main_print_overflow (int x)
+{
+  XPR(NT "internal print buffer overflow: %d bytes\n", x);
+  return XD3_INTERNAL;
+}
+
+/* This function prints a single VCDIFF window. */
+static int
+main_print_window (xd3_stream* stream, main_file *xfile)
+{
+  int ret;
+  usize_t size = 0;
+
+  VC(UT "  Offset Code Type1 Size1 @Addr1 + Type2 Size2 @Addr2\n")VE;
+
+  while (stream->inst_sect.buf < stream->inst_sect.buf_max)
+    {
+      uint   code = stream->inst_sect.buf[0];
+
+      if ((ret = xd3_decode_instruction (stream))) { return ret; }
+
+      VC(UT "  %06"Q"u %03u  %s %3u", stream->dec_winstart + size, code,
+	 xd3_rtype_to_string (stream->dec_current1.type, option_print_cpymode),
+	 (usize_t) stream->dec_current1.size)VE;
+
+      if (stream->dec_current1.type != XD3_NOOP)
+	{
+	  size += stream->dec_current1.size;
+	  if (stream->dec_current1.type >= XD3_CPY)
+	    {
+	      VC(UT " @%-6u", (usize_t)stream->dec_current1.addr)VE;
+	    }
+	  else
+	    {
+	      VC(UT "        ")VE;
+	    }
+	}
+
+      if (stream->dec_current2.type != XD3_NOOP)
+	{
+	  size += stream->dec_current2.size;
+	  VC(UT "  %s %3u",
+	     xd3_rtype_to_string (stream->dec_current2.type, option_print_cpymode),
+	     (usize_t)stream->dec_current2.size)VE;
+
+	  if (stream->dec_current2.type >= XD3_CPY)
+	    {
+	      VC(UT " @%-6u", (usize_t)stream->dec_current2.addr)VE;
+	    }
+	}
+
+      VC(UT "\n")VE;
+    }
+
+  if (stream->dec_tgtlen != size && (stream->flags & XD3_SKIP_WINDOW) == 0)
+    {
+      XPR(NT "target window size inconsistency");
+      return XD3_INTERNAL;
+    }
+
+  if (stream->dec_position != stream->dec_maxpos)
+    {
+      XPR(NT "target window position inconsistency");
+      return XD3_INTERNAL;
+    }
+
+  if (stream->addr_sect.buf != stream->addr_sect.buf_max)
+    {
+      XPR(NT "address section inconsistency");
+      return XD3_INTERNAL;
+    }
+
+  return 0;
+}
+
+static int
+main_print_vcdiff_file (main_file *xfile, main_file *file, const char *type)
+{
+  int ret;  /* Used by above macros */
+  if (file->filename)
+    {
+      VC(UT "XDELTA filename (%s):     %s\n", type, file->filename)VE;
+    }
+  if (file->compressor)
+    {
+      VC(UT "XDELTA ext comp (%s):     %s\n", type, file->compressor->recomp_cmdname)VE;
+    }
+  return 0;
+}
+
+/* This function prints a VCDIFF input, mainly for debugging purposes. */
+static int
+main_print_func (xd3_stream* stream, main_file *xfile)
+{
+  int ret;
+
+  if (xfile->snprintf_buf == NULL)
+    {
+      if ((xfile->snprintf_buf = main_malloc(SNPRINTF_BUFSIZE)) == NULL)
+	{
+	  return ENOMEM;
+	}
+    }
+
+  if (stream->dec_winstart == 0)
+    {
+      VC(UT "VCDIFF version:               0\n")VE;
+
+      VC(UT "VCDIFF header size:           %d\n", stream->dec_hdrsize)VE;
+      VC(UT "VCDIFF header indicator:      ")VE;
+      if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0) VC(UT "VCD_SECONDARY ")VE;
+      if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0) VC(UT "VCD_CODETABLE ")VE;
+      if ((stream->dec_hdr_ind & VCD_APPHEADER) != 0) VC(UT "VCD_APPHEADER ")VE;
+      if (stream->dec_hdr_ind == 0) VC(UT "none")VE;
+      VC(UT "\n")VE;
+
+      IF_SEC(VC(UT "VCDIFF secondary compressor:  %s\n",
+		stream->sec_type ? stream->sec_type->name : "none")VE);
+      IF_NSEC(VC(UT "VCDIFF secondary compressor: unsupported\n")VE);
+
+      if (stream->dec_hdr_ind & VCD_APPHEADER)
+	{
+	  uint8_t *apphead;
+	  usize_t appheadsz;
+	  ret = xd3_get_appheader (stream, & apphead, & appheadsz);
+
+	  if (ret == 0 && appheadsz > 0)
+	    {
+	      int sq = option_quiet;
+	      main_file i, o, s;
+	      XD3_ASSERT (apphead != NULL);
+	      VC(UT "VCDIFF application header:    ")VE;
+	      if ((ret = main_file_write (xfile, apphead, appheadsz, "print")) != 0) { return ret; }
+	      VC(UT "\n")VE;
+
+	      main_file_init (& i);
+	      main_file_init (& o);
+	      main_file_init (& s);
+	      option_quiet = 1;
+	      main_get_appheader (stream, &i, & o, & s);
+	      option_quiet = sq;
+	      if ((ret = main_print_vcdiff_file (xfile, & o, "output"))) { return ret; }
+	      if ((ret = main_print_vcdiff_file (xfile, & s, "source"))) { return ret; }
+	      main_file_cleanup (& i);
+	      main_file_cleanup (& o);
+	      main_file_cleanup (& s);
+	    }
+	}
+    }
+  else
+    {
+      VC(UT "\n")VE;
+    }
+
+  VC(UT "VCDIFF window number:         %"Q"u\n", stream->current_window)VE;
+  VC(UT "VCDIFF window indicator:      ")VE;
+  if ((stream->dec_win_ind & VCD_SOURCE) != 0) VC(UT "VCD_SOURCE ")VE;
+  if ((stream->dec_win_ind & VCD_TARGET) != 0) VC(UT "VCD_TARGET ")VE;
+  if ((stream->dec_win_ind & VCD_ADLER32) != 0) VC(UT "VCD_ADLER32 ")VE;
+  if (stream->dec_win_ind == 0) VC(UT "none")VE;
+  VC(UT "\n")VE;
+
+  if ((stream->dec_win_ind & VCD_ADLER32) != 0)
+    {
+      VC(UT "VCDIFF adler32 checksum:      %08X\n", (usize_t)stream->dec_adler32)VE;
+    }
+
+  if (stream->dec_del_ind != 0)
+    {
+      VC(UT "VCDIFF delta indicator:       ")VE;
+      if ((stream->dec_del_ind & VCD_DATACOMP) != 0) VC(UT "VCD_DATACOMP ")VE;
+      if ((stream->dec_del_ind & VCD_INSTCOMP) != 0) VC(UT "VCD_INSTCOMP ")VE;
+      if ((stream->dec_del_ind & VCD_ADDRCOMP) != 0) VC(UT "VCD_ADDRCOMP ")VE;
+      if (stream->dec_del_ind == 0) VC(UT "none")VE;
+      VC(UT "\n")VE;
+    }
+
+  if (stream->dec_winstart != 0)
+    {
+      VC(UT "VCDIFF window at offset:      %"Q"u\n", stream->dec_winstart)VE;
+    }
+
+  if (SRCORTGT (stream->dec_win_ind))
+    {
+      VC(UT "VCDIFF copy window length:    %u\n", (usize_t)stream->dec_cpylen)VE;
+      VC(UT "VCDIFF copy window offset:    %"Q"u\n", stream->dec_cpyoff)VE;
+    }
+
+  VC(UT "VCDIFF delta encoding length: %u\n", (usize_t)stream->dec_enclen)VE;
+  VC(UT "VCDIFF target window length:  %u\n", (usize_t)stream->dec_tgtlen)VE;
+
+  VC(UT "VCDIFF data section length:   %u\n", (usize_t)stream->data_sect.size)VE;
+  VC(UT "VCDIFF inst section length:   %u\n", (usize_t)stream->inst_sect.size)VE;
+  VC(UT "VCDIFF addr section length:   %u\n", (usize_t)stream->addr_sect.size)VE;
+
+  ret = 0;
+  if ((stream->flags & XD3_JUST_HDR) != 0)
+    {
+      /* Print a header -- finished! */
+      ret = PRINTHDR_SPECIAL;
+    }
+  else if ((stream->flags & XD3_SKIP_WINDOW) == 0)
+    {
+      ret = main_print_window (stream, xfile);
+    }
+
+  return ret;
+}
+#endif /* VCDIFF_TOOLS */
+
+/******************************************************************************************
+ Input decompression, output recompression
+ ******************************************************************************************/
+
+#if EXTERNAL_COMPRESSION
+/* This is tricky POSIX-specific code with lots of fork(), pipe(), dup(), waitpid(), and
+ * exec() business.  Most of this code originated in PRCS1, which did automatic
+ * package-file decompression.  It works with both XD3_POSIX and XD3_STDIO file
+ * disciplines.
+ *
+ * To automatically detect compressed inputs requires a child process to reconstruct the
+ * input stream, which was advanced in order to detect compression, because it may not be
+ * seekable.  In other words, the main program reads part of the input stream, and if it
+ * detects a compressed input it then forks a pipe copier process, which copies the
+ * first-read block out of the main-program's memory, then streams the remaining
+ * compressed input into the input-decompression pipe.
+ */
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+/* Remember which pipe FD is which. */
+#define PIPE_READ_FD  0
+#define PIPE_WRITE_FD 1
+
+static pid_t ext_subprocs[2];
+static char* ext_tmpfile = NULL;
+
+/* Like write(), but makes repeated calls to empty the buffer. */
+static int
+main_pipe_write (int outfd, const uint8_t *exist_buf, usize_t remain)
+{
+  int ret;
+
+  if ((ret = xd3_posix_io (outfd, (uint8_t*) exist_buf, remain, (xd3_posix_func*) &write, NULL)))
+    {
+      XPR(NT "pipe write failed: %s", xd3_mainerror (ret));
+      return ret;
+    }
+
+  return 0;
+}
+
+/* A simple error-reporting waitpid interface. */
+static int
+main_waitpid_check(pid_t pid)
+{
+  int status;
+  int ret = 0;
+
+  if (waitpid (pid, & status, 0) < 0)
+    {
+      ret = get_errno ();
+      XPR(NT "compression subprocess: wait: %s\n", xd3_mainerror (ret));
+    }
+  else if (! WIFEXITED (status))
+    {
+      ret = ECHILD;
+      XPR(NT "compression subprocess: signal %d\n",
+	 WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status));
+    }
+  else if (WEXITSTATUS (status) != 0)
+    {
+      ret = ECHILD;
+      XPR(NT "compression subprocess: exit %d\n", WEXITSTATUS (status));
+    }
+
+  return ret;
+}
+
+/* Wait for any existing child processes to check for abnormal exit. */
+static int
+main_external_compression_finish (void)
+{
+  int i;
+  int ret;
+
+  for (i = 0; i < 2; i += 1)
+    {
+      if (! ext_subprocs[i]) { continue; }
+
+      if ((ret = main_waitpid_check (ext_subprocs[i])))
+	{
+	  return ret;
+	}
+    }
+
+  return 0;
+}
+
+/* This runs as a forked process of main_input_decompress_setup() to copy input to the
+ * decompression process.  First, the available input is copied out of the existing
+ * buffer, then the buffer is reused to continue reading from the compressed input
+ * file. */
+static int
+main_pipe_copier (uint8_t    *pipe_buf,
+		  usize_t      pipe_bufsize,
+		  usize_t      nread,
+		  main_file   *ifile,
+		  int         outfd)
+{
+  int ret;
+
+  for (;;)
+    {
+      if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread)))
+	{
+	  return ret;
+	}
+
+      if (nread < pipe_bufsize)
+	{
+	  break;
+	}
+
+      if ((ret = main_file_read (ifile, pipe_buf, pipe_bufsize, & nread, "pipe read failed")) < 0)
+	{
+	  return ret;
+	}
+    }
+
+  return 0;
+}
+
+/* This function is called after we have read some amount of data from the input file and
+ * detected a compressed input.  Here we start a decompression subprocess by forking
+ * twice.  The first process runs the decompression command, the second process copies
+ * data to the input of the first. */
+static int
+main_input_decompress_setup (const main_extcomp     *decomp,
+			     main_file              *ifile,
+			     uint8_t               *input_buf,
+			     usize_t                 input_bufsize,
+			     uint8_t               *pipe_buf,
+			     usize_t                 pipe_bufsize,
+			     usize_t                 pipe_avail,
+			     usize_t                *nread)
+{
+  int outpipefd[2], inpipefd[2];  /* The two pipes: input and output file descriptors. */
+  int input_fd = -1;              /* The resulting input_fd (output of decompression). */
+  pid_t decomp_id, copier_id;     /* The two subprocs. */
+  int ret;
+
+  outpipefd[0] = outpipefd[1] = -1;
+  inpipefd[0]  = inpipefd[1]  = -1;
+
+  if (pipe (outpipefd) || pipe (inpipefd))
+    {
+      XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+  if ((decomp_id = fork ()) < 0)
+    {
+      XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+  /* The first child runs the decompression process: */
+  if (decomp_id == 0)
+    {
+      /* Setup pipes: write to the outpipe, read from the inpipe. */
+      if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 ||
+	  dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 ||
+	  close (outpipefd[PIPE_READ_FD]) ||
+	  close (outpipefd[PIPE_WRITE_FD]) ||
+	  close (inpipefd[PIPE_READ_FD]) ||
+	  close (inpipefd[PIPE_WRITE_FD]) ||
+	  execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL))
+	{
+	  XPR(NT "child process %s failed to execute: %s\n", decomp->decomp_cmdname, xd3_mainerror (get_errno ()));
+	}
+
+      _exit (127);
+    }
+
+  ext_subprocs[0] = decomp_id;
+
+  if ((copier_id = fork ()) < 0)
+    {
+      XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+  /* The second child runs the copier process: */
+  if (copier_id == 0)
+    {
+      int exitval = 0;
+
+      if (close (inpipefd[PIPE_READ_FD]) ||
+	  main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail, ifile, inpipefd[PIPE_WRITE_FD]) ||
+	  close (inpipefd[PIPE_WRITE_FD]))
+	{
+	  XPR(NT "child copier process failed: %s\n", xd3_mainerror (get_errno ()));
+	  exitval = 1;
+	}
+
+      _exit (exitval);
+    }
+
+  ext_subprocs[1] = copier_id;
+
+  /* The parent closes both pipes after duplicating the output of compression. */
+  input_fd = dup (outpipefd[PIPE_READ_FD]);
+
+  if (input_fd < 0 ||
+      main_file_close (ifile) ||
+      close (outpipefd[PIPE_READ_FD]) ||
+      close (outpipefd[PIPE_WRITE_FD]) ||
+      close (inpipefd[PIPE_READ_FD]) ||
+      close (inpipefd[PIPE_WRITE_FD]))
+    {
+      XPR(NT "dup/close failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+#if XD3_STDIO
+  /* Note: fdopen() acquires the fd, closes it when finished. */
+  if ((ifile->file = fdopen (input_fd, "r")) == NULL)
+    {
+      XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+#elif XD3_POSIX
+  ifile->file = input_fd;
+#endif
+
+  ifile->compressor = decomp;
+
+  /* Now the input file is decompressed. */
+  return main_file_read (ifile, input_buf, input_bufsize, nread, "input decompression failed");
+
+ pipe_cleanup:
+  close (input_fd);
+  close (outpipefd[PIPE_READ_FD]);
+  close (outpipefd[PIPE_WRITE_FD]);
+  close (inpipefd[PIPE_READ_FD]);
+  close (inpipefd[PIPE_WRITE_FD]);
+  return ret;
+}
+
+
+/* This routine is called when the first buffer of input data is read by the main program
+ * (unless input decompression is disabled by command-line option).  If it recognizes the
+ * magic number of a known input type it invokes decompression.
+ *
+ * Skips decompression if the decompression type or the file type is RD_NONEXTERNAL.
+ *
+ * Behaves exactly like main_file_read, otherwise.
+ *
+ * This function uses a separate buffer to read the first small block of input.  If a
+ * compressed input is detected, the separate buffer is passed to the pipe copier.  This
+ * avoids using the same size buffer in both cases. */
+static int
+main_decompress_input_check (main_file   *ifile,
+			    uint8_t    *input_buf,
+			    usize_t      input_size,
+			    usize_t     *nread)
+{
+  int i;
+  int ret;
+  uint8_t check_buf[XD3_ALLOCSIZE];
+  usize_t  check_nread;
+
+  if ((ret = main_file_read (ifile, check_buf, min (input_size, XD3_ALLOCSIZE), & check_nread, "input read failed")))
+    {
+      return ret;
+    }
+
+  for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
+    {
+      const main_extcomp *decomp = & extcomp_types[i];
+
+      if ((check_nread > decomp->magic_size) &&
+	  /* The following expr skips decompression if we are trying to read a VCDIFF
+	   * input and that is the magic number. */
+	  !((decomp->flags & RD_NONEXTERNAL) && (ifile->flags & RD_NONEXTERNAL)) &&
+	  memcmp (check_buf, decomp->magic, decomp->magic_size) == 0)
+	{
+	  if (! option_quiet)
+	    {
+	      XPR(NT "%s | %s %s\n",
+		 ifile->filename,
+		 decomp->decomp_cmdname,
+		 decomp->decomp_options);
+	    }
+
+	  return main_input_decompress_setup (decomp, ifile,
+					      input_buf, input_size,
+					      check_buf, XD3_ALLOCSIZE,
+					      check_nread, nread);
+	}
+    }
+
+  /* Now read the rest of the input block. */
+  (*nread) = 0;
+
+  if (check_nread == XD3_ALLOCSIZE)
+    {
+      ret = main_file_read (ifile, input_buf + XD3_ALLOCSIZE,
+			    input_size - XD3_ALLOCSIZE, nread,
+			    "input read failed");
+    }
+
+  memcpy (input_buf, check_buf, check_nread);
+
+  (*nread) += check_nread;
+
+  return 0;
+}
+
+/* This is called when the source file needs to be decompressed.  We fork/exec a
+ * decompression command with the proper input and output to a temporary file. */
+static int
+main_decompress_source (main_file *sfile, xd3_source *source)
+{
+  const main_extcomp *decomp = sfile->compressor;
+  pid_t decomp_id;  /* One subproc. */
+  int   input_fd  = -1;
+  int   output_fd = -1;
+  int   ret;
+  char *tmpname = NULL;
+  char *tmpdir  = getenv ("TMPDIR");
+  static const char tmpl[] = "/xd3src.XXXXXX";
+
+  /* Make a template for mkstmp() */
+  if (tmpdir == NULL) { tmpdir = "/tmp"; }
+  if ((tmpname = main_malloc (strlen (tmpdir) + sizeof (tmpl) + 1)) == NULL) { return ENOMEM; }
+  sprintf (tmpname, "%s%s", tmpdir, tmpl);
+
+  XD3_ASSERT (ext_tmpfile == NULL);
+  ext_tmpfile = tmpname;
+
+  /* Open the output FD. */
+  if ((output_fd = mkstemp (tmpname)) < 0)
+    {
+      XPR(NT "mkstemp failed: %s: %s", tmpname, xd3_mainerror (ret = get_errno ()));
+      goto cleanup;
+    }
+
+  /* Copy the input FD, reset file position. */
+  XD3_ASSERT (main_file_isopen (sfile));
+#if XD3_STDIO
+  if ((input_fd = dup (fileno (sfile->file))) < 0)
+    {
+      XPR(NT "dup failed: %s", xd3_mainerror (ret = get_errno ()));
+      goto cleanup;
+    }
+  main_file_close (sfile);
+  sfile->file = NULL;
+#elif XD3_POSIX
+  input_fd = sfile->file;
+  sfile->file = -1;
+#endif
+
+  if ((ret = lseek (input_fd, SEEK_SET, 0)) != 0)
+    {
+      XPR(NT "lseek failed: : %s", xd3_mainerror (ret = get_errno ()));
+      goto cleanup;
+    }
+
+  if ((decomp_id = fork ()) < 0)
+    {
+      XPR(NT "fork failed: %s", xd3_mainerror (ret = get_errno ()));
+      goto cleanup;
+    }
+
+  /* The child runs the decompression process: */
+  if (decomp_id == 0)
+    {
+      /* Setup pipes: write to the output file, read from the pipe. */
+      if (dup2 (input_fd, STDIN_FILENO) < 0 ||
+	  dup2 (output_fd, STDOUT_FILENO) < 0 ||
+	  execlp (decomp->decomp_cmdname, decomp->decomp_cmdname, decomp->decomp_options, NULL))
+	{
+	  XPR(NT "child process %s failed to execute: %s\n",
+		   decomp->decomp_cmdname, xd3_mainerror (get_errno ()));
+	}
+
+      _exit (127);
+    }
+
+  close (input_fd);
+  close (output_fd);
+  input_fd  = -1;
+  output_fd = -1;
+
+  /* Then wait for completion. */
+  if ((ret = main_waitpid_check (decomp_id)))
+    {
+      goto cleanup;
+    }
+
+  /* Open/stat the decompressed source file. */
+  if ((ret = main_file_open (sfile, tmpname, XO_READ))) { goto cleanup; }
+  if ((ret = main_file_stat (sfile, & source->size, 1))) { goto cleanup; }
+  return 0;
+
+ cleanup:
+  close (input_fd);
+  close (output_fd);
+  if (tmpname) { free (tmpname); }
+  ext_tmpfile = NULL;
+  return ret;
+}
+
+/* Initiate re-compression of the output stream.  This is easier than input decompression
+ * because we know beforehand that the stream will be compressed, whereas the input has
+ * already been read when we decide it should be decompressed.  Thus, it only requires one
+ * subprocess and one pipe. */
+static int
+main_recompress_output (main_file *ofile)
+{
+  pid_t recomp_id;  /* One subproc. */
+  int   pipefd[2];  /* One pipe. */
+  int   output_fd = -1;
+  int   ret;
+  const main_extcomp *recomp = ofile->compressor;
+
+  pipefd[0] = pipefd[1] = -1;
+
+  if (pipe (pipefd))
+    {
+      XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+  if ((recomp_id = fork ()) < 0)
+    {
+      XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+  /* The child runs the recompression process: */
+  if (recomp_id == 0)
+    {
+      /* Setup pipes: write to the output file, read from the pipe. */
+      if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 ||
+	  dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 ||
+	  close (pipefd[PIPE_READ_FD]) ||
+	  close (pipefd[PIPE_WRITE_FD]) ||
+	  execlp (recomp->recomp_cmdname, recomp->recomp_cmdname, recomp->recomp_options, NULL))
+	{
+	  XPR(NT "child process %s failed to execute: %s\n", recomp->recomp_cmdname, xd3_mainerror (get_errno ()));
+	}
+
+      _exit (127);
+    }
+
+  ext_subprocs[0] = recomp_id;
+
+  /* The parent closes both pipes after duplicating the output-fd for writing to the
+   * compression pipe. */
+  output_fd = dup (pipefd[PIPE_WRITE_FD]);
+
+  if (output_fd < 0 ||
+      main_file_close (ofile) ||
+      close (pipefd[PIPE_READ_FD]) ||
+      close (pipefd[PIPE_WRITE_FD]))
+    {
+      XPR(NT "close failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+#if XD3_STDIO
+  /* Note: fdopen() acquires the fd, closes it when finished. */
+  if ((ofile->file = fdopen (output_fd, "w")) == NULL)
+    {
+      XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ()));
+      goto pipe_cleanup;
+    }
+
+#elif XD3_POSIX
+  ofile->file = output_fd;
+#endif
+
+  /* Now the output file will be compressed. */
+  return 0;
+
+ pipe_cleanup:
+  close (output_fd);
+  close (pipefd[PIPE_READ_FD]);
+  close (pipefd[PIPE_WRITE_FD]);
+  return ret;
+}
+#endif /* EXTERNAL_COMPRESSION */
+
+/* Identify the compressor that was used based on its ident string, which is passed in the
+ * application header. */
+static const main_extcomp*
+main_ident_compressor (const char *ident)
+{
+  int i;
+
+  for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
+    {
+      if (strcmp (extcomp_types[i].ident, ident) == 0)
+	{
+	  return & extcomp_types[i];
+	}
+    }
+
+  return NULL;
+}
+
+/* Return the main_extcomp record to use for this identifier, if possible. */
+static const main_extcomp*
+main_get_compressor (const char *ident)
+{
+  const main_extcomp *ext = main_ident_compressor (ident);
+
+  if (ext == NULL)
+    {
+      if (! option_quiet)
+	{
+	  XPR(NT "warning: cannot recompress output: "
+		   "unrecognized external compression ID: %s\n", ident);
+	}
+      return NULL;
+    }
+  else if (! EXTERNAL_COMPRESSION)
+    {
+      if (! option_quiet)
+	{
+	  XPR(NT "warning: external support not compiled: "
+		   "original input was compressed: %s\n", ext->recomp_cmdname);
+	}
+      return NULL;
+    }
+  else
+    {
+      return ext;
+    }
+}
+
+/******************************************************************************************
+ APPLICATION HEADER
+ ******************************************************************************************/
+
+#if XD3_ENCODER
+static const char*
+main_apphead_string (const char* x)
+{
+  const char *y;
+
+  if (x == NULL) { return ""; }
+
+  if (strcmp (x, "/dev/stdin") == 0 ||
+      strcmp (x, "/dev/stdout") == 0 ||
+      strcmp (x, "/dev/stderr") == 0) { return "-"; }
+
+  // TODO: this is not portable
+  return (y = strrchr (x, '/')) == NULL ? x : y + 1;
+}
+
+static int
+main_set_appheader (xd3_stream *stream, main_file *input, main_file *sfile)
+{
+  /* The user may disable the application header.  Once the appheader is set, this
+   * disables setting it again. */
+  if (appheader_used || ! option_use_appheader) { return 0; }
+
+  /* The user may specify the application header, otherwise format the default header. */
+  if (option_appheader)
+    {
+      appheader_used = option_appheader;
+    }
+  else
+    {
+      const char *iname;
+      const char *icomp;
+      const char *sname;
+      const char *scomp;
+      int len;
+
+      iname = main_apphead_string (input->filename);
+      icomp = (input->compressor == NULL) ? "" : input->compressor->ident;
+      len = strlen (iname) + strlen (icomp) + 2;
+
+      if (sfile->filename != NULL)
+	{
+	  sname = main_apphead_string (sfile->filename);
+	  scomp = (sfile->compressor == NULL) ? "" : sfile->compressor->ident;
+	  len += strlen (sname) + strlen (scomp) + 2;
+	}
+      else
+	{
+	  sname = scomp = "";
+	}
+
+      if ((appheader_used = main_malloc (len)) == NULL)
+	{
+	  return ENOMEM;
+	}
+
+      if (sfile->filename == NULL)
+	{
+	  sprintf ((char*)appheader_used, "%s/%s", iname, icomp);
+	}
+      else
+	{
+	  sprintf ((char*)appheader_used, "%s/%s/%s/%s", iname, icomp, sname, scomp);
+	}
+    }
+
+  xd3_set_appheader (stream, appheader_used, strlen ((char*)appheader_used));
+
+  return 0;
+}
+#endif
+
+static void
+main_get_appheader_params (main_file *file, char **parsed, int output, const char *type,
+			   main_file *other)
+{
+  /* Set the filename if it was not specified.  If output, option_stdout (-c) overrides. */
+  if (file->filename == NULL && ! (output && option_stdout) && strcmp (parsed[0], "-") != 0)
+    {
+      file->filename = parsed[0];
+
+      if (other->filename != NULL) {
+	/* Take directory from the other file, if it has one. */
+	/* TODO: This results in nonsense names like /dev/foo.tar.gz
+	 * and probably the filename-default logic interferes with
+	 * multi-file operation and the standard file extension?
+	 * Possibly the name header is bad, should be off by default.
+	 * Possibly we just want to remember external/compression
+	 * settings. */
+	char *last_slash = strrchr(other->filename, '/');
+
+	if (last_slash != NULL) {
+	  int dlen = last_slash - other->filename;
+
+	  XD3_ASSERT(file->filename_copy == NULL);
+	  file->filename_copy = main_malloc(dlen + 2 + strlen(file->filename));
+
+	  strncpy(file->filename_copy, other->filename, dlen);
+	  file->filename_copy[dlen] = '/';
+	  strcpy(file->filename_copy + dlen + 1, parsed[0]);
+
+	  file->filename = file->filename_copy;
+	}
+      }
+
+      if (! option_quiet)
+	{
+	  XPR(NT "using default %s filename: %s\n", type, file->filename);
+	}
+    }
+
+  /* Set the compressor, initiate de/recompression later. */
+  if (file->compressor == NULL && *parsed[1] != 0)
+    {
+      file->compressor = main_get_compressor (parsed[1]);
+    }
+}
+
+static void
+main_get_appheader (xd3_stream *stream, main_file *ifile, main_file *output, main_file *sfile)
+{
+  uint8_t *apphead;
+  usize_t appheadsz;
+  int ret;
+
+  /* The user may disable the application header.  Once the appheader is set, this
+   * disables setting it again. */
+  if (! option_use_appheader) { return; }
+
+  ret = xd3_get_appheader (stream, & apphead, & appheadsz);
+
+  /* Ignore failure, it only means we haven't received a header yet. */
+  if (ret != 0) { return; }
+
+  if (appheadsz > 0)
+    {
+      char *start = (char*)apphead;
+      char *slash;
+      int   place = 0;
+      char *parsed[4];
+
+      memset (parsed, 0, sizeof (parsed));
+
+      while ((slash = strchr (start, '/')) != NULL)
+	{
+	  *slash = 0;
+	  parsed[place++] = start;
+	  start = slash + 1;
+	}
+
+      parsed[place++] = start;
+
+      /* First take the output parameters. */
+      if (place == 2 || place == 4)
+	{
+	  main_get_appheader_params (output, parsed, 1, "output", ifile);
+	}
+
+      /* Then take the source parameters. */
+      if (place == 4)
+	{
+	  main_get_appheader_params (sfile, parsed+2, 0, "source", ifile);
+	}
+    }
+
+  option_use_appheader = 0;
+  return;
+}
+
+/******************************************************************************************
+ Main I/O routines
+ ******************************************************************************************/
+
+/* This function acts like the above except it may also try to recognize a compressed
+ * input when the first buffer of data is read.  The EXTERNAL_COMPRESSION code is called
+ * to search for magic numbers. */
+static int
+main_read_primary_input (main_file   *ifile,
+			 uint8_t    *buf,
+			 usize_t      size,
+			 usize_t     *nread)
+{
+#if EXTERNAL_COMPRESSION
+  if (option_decompress_inputs && ifile->flags & RD_FIRST)
+    {
+      ifile->flags &= ~RD_FIRST;
+
+      return main_decompress_input_check (ifile, buf, size, nread);
+    }
+#endif
+
+  return main_file_read (ifile, buf, size, nread, "input read failed");
+}
+
+/* This function simply writes the stream output buffer, if there is any.  This is used
+ * for both encode and decode commands.  (The VCDIFF tools use main_print_func()). */
+static int
+main_write_output (xd3_stream* stream, main_file *ofile)
+{
+  int ret;
+
+  if (stream->avail_out > 0 && (ret = main_file_write (ofile, stream->next_out, stream->avail_out, "write failed")))
+    {
+      return ret;
+    }
+
+  return 0;
+}
+
+/* Open the main output file, sets a default file name, initiate recompression.  This
+ * function is expected to fprint any error messages. */
+static int
+main_open_output (xd3_stream *stream, main_file *ofile)
+{
+  int ret;
+
+  if (ofile->filename == NULL)
+    {
+      XSTDOUT_XF (ofile);
+
+      if (option_verbose > 1) { XPR(NT "using standard output: %s\n", ofile->filename); }
+    }
+  else
+    {
+      /* Stat the file to check for overwrite. */
+      if (option_force == 0 && main_file_exists (ofile))
+	{
+	  XPR(NT "to overwrite output file specify -f: %s\n", ofile->filename);
+	  return EEXIST;
+	}
+
+      if ((ret = main_file_open (ofile, ofile->filename, XO_WRITE)))
+	{
+	  return ret;
+	}
+
+      if (option_verbose > 1) { XPR(NT "output file: %s\n", ofile->filename); }
+    }
+
+#if EXTERNAL_COMPRESSION
+  /* Do output recompression. */
+  if (ofile->compressor != NULL && option_recompress_outputs == 1)
+    {
+      if (! option_quiet)
+	{
+	  XPR(NT "%s %s | %s\n",
+	     ofile->compressor->recomp_cmdname,
+	     ofile->compressor->recomp_options,
+	     ofile->filename);
+	}
+
+      if ((ret = main_recompress_output (ofile)))
+	{
+	  return ret;
+	}
+    }
+#endif
+
+  return 0;
+}
+
+/* This is called at different times for encoding and decoding.  The encoder calls it
+ * immediately, the decoder delays until the application header is received.
+ * Stream may be NULL, in which case xd3_set_source is not called. */
+static int
+main_set_source (xd3_stream *stream, int cmd, main_file *sfile, xd3_source *source)
+{
+  int ret = 0, i;
+  uint8_t *tmp_buf = NULL;
+
+  /* Open it, check for seekability, set required xd3_source fields. */
+  if (allow_fake_source)
+    {
+      sfile->mode = XO_READ;
+      sfile->realname = sfile->filename;
+      sfile->nread = 0;
+      source->size = UINT64_MAX;
+    }
+  else
+    {
+      if ((ret = main_file_open (sfile, sfile->filename, XO_READ)) ||
+	  (ret = main_file_stat (sfile, & source->size, 1)))
+	{
+	  goto error;
+	}
+    }
+
+  source->name     = sfile->filename;
+  source->ioh      = sfile;
+  source->curblkno = (xoff_t) -1;
+  source->curblk   = NULL;
+  
+#if EXTERNAL_COMPRESSION
+  if (option_decompress_inputs)
+    {
+      /* If encoding, read the header to check for decompression. */
+      if (IS_ENCODE (cmd))
+	{
+	  usize_t nread;
+	  tmp_buf = main_malloc(XD3_ALLOCSIZE);
+
+	  if ((ret = main_file_read (sfile, tmp_buf, XD3_ALLOCSIZE,
+				     & nread, "source read failed")))
+	    {
+	      goto error;
+	    }
+
+	  /* Check known magic numbers. */
+	  for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
+	    {
+	      const main_extcomp *decomp = & extcomp_types[i];
+
+	      if ((nread > decomp->magic_size) &&
+		  memcmp (tmp_buf, decomp->magic, decomp->magic_size) == 0)
+		{
+		  sfile->compressor = decomp;
+		  break;
+		}
+	    }
+
+	  if (sfile->compressor == NULL)
+	    {
+	      if (option_verbose > 2)
+		{
+		  XPR(NT "source block 0 read (not compressed)\n");
+		}
+	    }
+	}
+
+      /* In either the encoder or decoder, start decompression. */
+      if (sfile->compressor)
+	{
+	  xoff_t osize = source->size;
+
+	  if (osize > XD3_NODECOMPRESSSIZE)
+	    {
+	      XPR(NT "source file too large for external decompression: %s: %"Q"u\n",
+		       sfile->filename, osize);
+	      ret = XD3_INTERNAL;
+	      goto error;
+	    }
+
+	  if ((ret = main_decompress_source (sfile, source)))
+	    {
+	      goto error;
+	    }
+
+	  if (! option_quiet)
+	    {
+	      char s1[32], s2[32];
+	      XPR(NT "%s | %s %s => %s %.1f%% [ %s , %s ]\n",
+		 sfile->filename,
+		 sfile->compressor->decomp_cmdname,
+		 sfile->compressor->decomp_options,
+		 sfile->realname,
+		 100.0 * source->size / osize,
+		 main_format_bcnt (osize, s1),
+		 main_format_bcnt (source->size, s2));
+	    }
+	}
+    }
+#endif
+
+  /* At this point we know source->size.
+   * Source buffer, blksize, LRU init. */
+  if (source->size < option_srcwinsz)
+    {
+      /* Reduce sizes to actual source size, read whole file */
+      option_srcwinsz = source->size;
+      source->blksize = source->size;
+      lru_size = 1;
+    }
+  else
+    {
+      option_srcwinsz = max(option_srcwinsz, XD3_MINSRCWINSZ);
+
+      source->blksize = (option_srcwinsz / LRU_SIZE);
+      lru_size = LRU_SIZE;
+    }
+
+  main_blklru_list_init (& lru_list);
+  main_blklru_list_init (& lru_free);
+
+  if (option_verbose)
+    {
+      static char buf[32];
+      
+      XPR(NT "source %s winsize %s size %"Q"u\n",
+	  sfile->filename, main_format_bcnt(option_srcwinsz, buf), source->size);
+    }
+
+  if (option_verbose > 1)
+    {
+      XPR(NT "source block size: %u\n", source->blksize);
+    }
+
+  if ((lru = main_malloc (sizeof (main_blklru) * lru_size)) == NULL)
+    {
+      ret = ENOMEM;
+      goto error;
+    }
+
+  for (i = 0; i < lru_size; i += 1)
+    {
+      lru[i].blkno = (xoff_t) -1;
+
+      if ((lru[i].blk = main_malloc (source->blksize)) == NULL)
+	{
+	  ret = ENOMEM;
+	  goto error;
+	}
+
+      main_blklru_list_push_back (& lru_free, & lru[i]);
+    }
+
+  if (stream && (ret = xd3_set_source (stream, source)))
+    {
+      XPR(NT XD3_LIB_ERRMSG (stream, ret));
+      goto error;
+    }
+
+ error:
+  if (tmp_buf != NULL)
+    {
+      main_free (tmp_buf);
+    }
+
+  return ret;
+}
+
+static void
+main_set_winsize (main_file *ifile) {
+  xoff_t file_size;
+
+  if (main_file_stat (ifile, &file_size, 0) == 0)
+    {
+      option_winsize = (usize_t) min(file_size, (xoff_t) option_winsize);
+    }
+
+  option_winsize = max(option_winsize, XD3_ALLOCSIZE);
+
+  if (option_verbose > 1)
+    {
+      XPR(NT "input window size: %u\n", option_winsize);
+    }
+}
+
+/******************************************************************************************
+ Source routines
+ ******************************************************************************************/
+
+/* This is the callback for reading a block of source.  This function is blocking and it
+ * implements a small LRU.
+ *
+ * Note that it is possible for main_input() to handle getblk requests in a non-blocking
+ * manner.  If the callback is NULL then the caller of xd3_*_input() must handle the
+ * XD3_GETSRCBLK return value and fill the source in the same way.  See xd3_getblk for
+ * details.  To see an example of non-blocking getblk, see xdelta-test.h. */
+static int
+main_getblk_func (xd3_stream *stream,
+		  xd3_source *source,
+		  xoff_t      blkno)
+{
+  xoff_t      pos   = blkno * source->blksize;
+  main_file   *sfile = (main_file*) source->ioh;
+  main_blklru *blru  = NULL;
+  usize_t      onblk = xd3_bytes_on_srcblk (source, blkno);
+  usize_t      nread;
+  int         ret;
+  int         i;
+
+  if (allow_fake_source)
+    {
+      source->curblkno = blkno;
+      source->onblk    = onblk;
+      source->curblk   = lru[0].blk;
+      return 0;
+    }
+
+  if (do_not_lru)
+    {
+      /* Direct lookup assumes sequential scan w/o skipping blocks. */
+      int idx = blkno % lru_size;
+      if (lru[idx].blkno == blkno)
+	{
+	  source->curblkno = blkno;
+	  source->onblk    = onblk;
+	  source->curblk   = lru[idx].blk;
+	  lru_hits += 1;
+	  return 0;
+	}
+
+      if (lru[idx].blkno != -1LL &&
+	  lru[idx].blkno != blkno - lru_size)
+	{
+	  return XD3_TOOFARBACK;
+	}
+    }
+  else
+    {
+      /* Sequential search through LRU. */
+      for (i = 0; i < lru_size; i += 1)
+	{
+	  if (lru[i].blkno == blkno)
+	    {
+	      main_blklru_list_remove (& lru[i]);
+	      main_blklru_list_push_back (& lru_list, & lru[i]);
+
+	      source->curblkno = blkno;
+	      source->onblk    = onblk;
+	      source->curblk   = lru[i].blk;
+	      lru_hits += 1;
+	      return 0;
+	    }
+	}
+    }
+
+  if (! main_blklru_list_empty (& lru_free))
+    {
+      blru = main_blklru_list_pop_front (& lru_free);
+    }
+  else if (! main_blklru_list_empty (& lru_list))
+    {
+      if (do_not_lru) {
+	blru = & lru[blkno % lru_size];
+	main_blklru_list_remove(blru);
+      } else {
+	blru = main_blklru_list_pop_front (& lru_list);
+      }
+      lru_misses += 1;
+    }
+
+  lru_filled += 1;
+
+  if ((ret = main_file_seek (sfile, pos)))
+    {
+      return ret;
+    }
+
+  if ((ret = main_file_read (sfile, (uint8_t*) blru->blk, source->blksize,
+			     & nread, "source read failed")))
+    {
+      return ret;
+    }
+
+  if (nread != onblk)
+    {
+      XPR(NT "source file size change: %s\n", sfile->filename);
+      return XD3_INTERNAL;
+    }
+
+  main_blklru_list_push_back (& lru_list, blru);
+
+  if (option_verbose > 3)
+    {
+      if (blru->blkno != -1LL)
+	{
+	  XPR(NT "source block %"Q"u ejects %"Q"u (lru_hits=%u, lru_misses=%u, lru_filled=%u)\n",
+	      blkno, blru->blkno, lru_hits, lru_misses, lru_filled);
+	}
+      else
+	{
+	  XPR(NT "source block %"Q"u read (lru_hits=%u, lru_misses=%u, lru_filled=%u)\n",
+					  blkno, lru_hits, lru_misses, lru_filled);
+	}
+    }
+
+  blru->blkno      = blkno;
+  source->curblk   = blru->blk;
+  source->curblkno = blkno;
+  source->onblk    = onblk;
+
+  return 0;
+}
+
+/******************************************************************************************
+ Main routines
+ ******************************************************************************************/
+
+/* This is a generic input function.  It calls the xd3_encode_input or xd3_decode_input
+ * functions and makes calls to the various input handling routines above, which
+ * coordinate external decompression.
+ */
+static int
+main_input (xd3_cmd     cmd,
+	    main_file   *ifile,
+	    main_file   *ofile,
+	    main_file   *sfile)
+{
+  int        ret;
+  xd3_stream stream;
+  usize_t    nread;
+  int        stream_flags = 0;
+  xd3_config config;
+  xd3_source source;
+  xoff_t     last_total_in = 0;
+  xoff_t     last_total_out = 0;
+  long       start_time;
+  int        stdout_only = 0;
+
+  int (*input_func) (xd3_stream*);
+  int (*output_func) (xd3_stream*, main_file *);
+
+  memset (& source, 0, sizeof (source));
+  memset (& config, 0, sizeof (config));
+
+  config.alloc = main_alloc;
+  config.freef = main_free1;
+  config.sec_data.ngroups = 1;
+  config.sec_addr.ngroups = 1;
+  config.sec_inst.ngroups = 1;
+  config.iopt_size = option_iopt_size;
+  config.sprevsz = option_sprevsz;
+
+  do_not_lru = 0;
+
+  start_time = get_millisecs_now ();
+
+  /* main_input setup. */
+  switch ((int) cmd)
+    {
+#if VCDIFF_TOOLS
+           if (1) { case CMD_PRINTHDR:   stream_flags = XD3_JUST_HDR; }
+      else if (1) { case CMD_PRINTHDRS:  stream_flags = XD3_SKIP_WINDOW; }
+      else        { case CMD_PRINTDELTA: stream_flags = XD3_SKIP_EMIT; }
+      ifile->flags |= RD_NONEXTERNAL;
+      input_func    = xd3_decode_input;
+      output_func   = main_print_func;
+      stream_flags |= XD3_ADLER32_NOVER;
+      stdout_only   = 1;
+      break;
+#endif
+#if XD3_ENCODER
+    case CMD_ENCODE:
+      do_not_lru  = 1;
+      input_func  = xd3_encode_input;
+      output_func = main_write_output;
+
+      if (option_use_checksum) { stream_flags |= XD3_ADLER32; }
+      if (option_use_secondary)
+	{
+	  /* The default secondary compressor is DJW, if it's compiled, being used, etc. */
+	  if (option_secondary == NULL)
+	    {
+	      if (SECONDARY_DJW) { stream_flags |= XD3_SEC_DJW; }
+	    }
+	  else
+	    {
+	      if (strcmp (option_secondary, "fgk") == 0 && SECONDARY_FGK)
+		{
+		  stream_flags |= XD3_SEC_FGK;
+		}
+	      else if (strcmp (option_secondary, "djw") == 0 && SECONDARY_DJW)
+		{
+		  stream_flags |= XD3_SEC_DJW;
+		}
+	      else
+		{
+		  XPR(NT "unrecognized secondary compressor type: %s\n", option_secondary);
+		  return EXIT_FAILURE;
+		}
+	    }
+	}
+      if (option_no_compress)      { stream_flags |= XD3_NOCOMPRESS; }
+      if (option_use_altcodetable) { stream_flags |= XD3_ALT_CODE_TABLE; }
+      if (option_smatch_config)
+	{
+	  char *s = option_smatch_config, *e;
+	  int values[XD3_SOFTCFG_VARCNT];
+	  int got;
+
+	  config.smatch_cfg = XD3_SMATCH_SOFT;
+
+	  for (got = 0; got < XD3_SOFTCFG_VARCNT; got += 1, s = e + 1)
+	    {
+	      values[got] = strtol (s, &e, 10);
+
+	      if ((values[got] < 0) ||
+		  (e == s) ||
+		  (got < XD3_SOFTCFG_VARCNT-1 && *e == 0) ||
+		  (got == XD3_SOFTCFG_VARCNT-1 && *e != 0))
+		{
+		  XPR(NT "invalid string match specifier (-C) %d: %s\n",
+		      got, s);
+		  return EXIT_FAILURE;
+		}
+	    }
+
+	  config.smatcher_soft.large_look    = values[0];
+	  config.smatcher_soft.large_step    = values[1];
+	  config.smatcher_soft.small_look    = values[2];
+	  config.smatcher_soft.small_chain   = values[3];
+	  config.smatcher_soft.small_lchain  = values[4];
+	  config.smatcher_soft.max_lazy      = values[5];
+	  config.smatcher_soft.long_enough   = values[6];
+	}
+      else
+	{
+	  if (option_verbose > 1)
+	    {
+	      XPR(NT "compression level: %d\n", option_level);
+	    }
+	  if (option_level == 0)
+	    {
+	      stream_flags |= XD3_NOCOMPRESS;
+	      config.smatch_cfg = XD3_SMATCH_FASTEST;
+	    }
+	  else if (option_level == 1) { config.smatch_cfg = XD3_SMATCH_FASTEST; }
+	  else if (option_level <= 5) { config.smatch_cfg = XD3_SMATCH_FAST; }
+	  else if (option_level == 6) { config.smatch_cfg = XD3_SMATCH_DEFAULT; }
+	  else                        { config.smatch_cfg = XD3_SMATCH_SLOW; }
+	}
+      break;
+#endif
+    case CMD_DECODE:
+      if (option_use_checksum == 0) { stream_flags |= XD3_ADLER32_NOVER; }
+      stream_flags  = 0;
+      ifile->flags |= RD_NONEXTERNAL;
+      input_func    = xd3_decode_input;
+      output_func   = main_write_output;
+      break;
+    default:
+      XPR(NT "internal error\n");
+      return EXIT_FAILURE;
+    }
+
+  main_set_winsize (ifile);
+
+  if ((main_bdata = main_malloc (option_winsize)) == NULL)
+    {
+      return EXIT_FAILURE;
+    }
+
+  if (IS_ENCODE (cmd))
+    {
+      /* When encoding, open the source file, possibly decompress it.  The decoder delays
+       * this step until XD3_GOTHEADER. */
+      if (sfile->filename != NULL && (ret = main_set_source (NULL, cmd, sfile, & source)))
+	{
+	  return EXIT_FAILURE;
+	}
+    }
+
+  config.winsize = option_winsize;
+  config.srcwin_maxsz = option_srcwinsz;
+  config.getblk = main_getblk_func;
+  config.flags = stream_flags;
+
+  if ((ret = xd3_config_stream (& stream, & config)))
+    {
+      XPR(NT XD3_LIB_ERRMSG (& stream, ret));
+      return EXIT_FAILURE;
+    }
+
+  if (IS_ENCODE (cmd) && sfile->filename != NULL &&
+      (ret = xd3_set_source (& stream, & source)))
+    {
+      XPR(NT XD3_LIB_ERRMSG (& stream, ret));
+      return EXIT_FAILURE;
+    }
+
+  /* This times each window. */
+  get_millisecs_since ();
+
+  /* Main input loop. */
+  do
+    {
+      xoff_t input_offset;
+      xoff_t input_remain;
+      usize_t try_read;
+
+      input_offset = ifile->nread;
+
+      input_remain = XOFF_T_MAX - input_offset;
+
+      try_read = (usize_t) min ((xoff_t) config.winsize, input_remain);
+
+      if ((ret = main_read_primary_input (ifile, main_bdata, try_read, & nread)))
+	{
+	  return EXIT_FAILURE;
+	}
+
+      /* If we've reached EOF tell the stream to flush. */
+      if (nread < try_read)
+	{
+	  stream_flags |= XD3_FLUSH;
+	  xd3_set_flags (& stream, stream_flags);
+	}
+
+#if XD3_ENCODER
+      /* After the first main_read_primary_input completes, we know all the information
+       * needed to encode the application header. */
+      if (cmd == CMD_ENCODE && (ret = main_set_appheader (& stream, ifile, sfile)))
+	{
+	  return EXIT_FAILURE;
+	}
+#endif
+      xd3_avail_input (& stream, main_bdata, nread);
+
+      /* If we read zero bytes after encoding at least one window... */
+      if (nread == 0 && stream.current_window > 0) {
+	break;
+      }
+
+    again:
+      ret = input_func (& stream);
+
+      switch (ret)
+	{
+	case XD3_INPUT:
+	  continue;
+
+	case XD3_GOTHEADER:
+	  {
+	    XD3_ASSERT (stream.current_window == 0);
+
+	    /* Need to process the appheader as soon as possible.  It may contain a
+	     * suggested default filename/decompression routine for the ofile, and it may
+	     * contain default/decompression routine for the sources. */
+	    if (cmd == CMD_DECODE)
+	      {
+		int have_src = sfile->filename != NULL;
+		int need_src = xd3_decoder_needs_source (& stream);
+		int recv_src;
+
+		/* May need to set the sfile->filename if none was given. */
+		main_get_appheader (& stream, ifile, ofile, sfile);
+
+		recv_src = sfile->filename != NULL;
+
+		/* Check if the user expected a source to be required although it was not. */
+		if (have_src && ! need_src && ! option_quiet)
+		  {
+		    XPR(NT "warning: output window %"Q"u does not copy source\n", stream.current_window);
+		  }
+
+		/* Check if we have no source name and need one. */
+		/* TODO: this doesn't fire due to cpyblocks_ calculation check? */
+		if (need_src && ! recv_src)
+		  {
+		    XPR(NT "input requires a source file, use -s\n");
+		    return EXIT_FAILURE;
+		  }
+
+		/* Now open the source file. */
+		if (need_src && (ret = main_set_source (& stream, cmd, sfile, & source)))
+		  {
+		    return EXIT_FAILURE;
+		  }
+	      }
+	    else if (cmd == CMD_PRINTHDR ||
+		     cmd == CMD_PRINTHDRS ||
+		     cmd == CMD_PRINTDELTA)
+	      {
+		if (xd3_decoder_needs_source (& stream) && sfile->filename == NULL)
+		  {
+		    allow_fake_source = 1;
+		    sfile->filename = "<placeholder>";
+		    main_set_source (& stream, cmd, sfile, & source);
+		  }
+	      }
+	  }
+	/* FALLTHROUGH */
+	case XD3_WINSTART:
+	  {
+	    /* e.g., set or unset XD3_SKIP_WINDOW. */
+	    /* xd3_set_flags (& stream, stream_flags); */
+	    goto again;
+	  }
+
+	case XD3_OUTPUT:
+	  {
+	    if (option_no_output == 0)
+	      {
+		/* Defer opening the output file until the stream produces its first
+		 * output for both encoder and decoder, this way we delay long enough for
+		 * the decoder to receive the application header.  (Or longer if there are
+		 * skipped windows, but I can't think of any reason not to delay open.) */
+
+		if (! main_file_isopen (ofile) && (ret = main_open_output (& stream, ofile)) != 0)
+		  {
+		    return EXIT_FAILURE;
+		  }
+		if ((ret = output_func (& stream, ofile)) && (ret != PRINTHDR_SPECIAL))
+		  {
+		    return EXIT_FAILURE;
+		  }
+		if (ret == PRINTHDR_SPECIAL)
+		  {
+		    xd3_abort_stream (& stream);
+		    ret = EXIT_SUCCESS;
+		    goto done;
+		  }
+		ret = 0;
+	      }
+
+	    xd3_consume_output (& stream);
+	    goto again;
+	  }
+
+	case XD3_WINFINISH:
+	  {
+	    if (IS_ENCODE (cmd) || cmd == CMD_DECODE)
+	      {
+		if (! option_quiet && IS_ENCODE (cmd) && main_file_isopen (sfile))
+		  {
+		    /* Warn when no source copies are found */
+		    if (! xd3_encoder_used_source (& stream))
+		      {
+			XPR(NT "warning: input window %"Q"u..%"Q"u has no source copies\n",
+			    stream.current_window * option_winsize,
+			    (stream.current_window+1) * option_winsize);
+		      }
+		    
+		    /* Limited instruction buffer size affects source copies */
+		    if (option_verbose > 1 && stream.i_slots_used > stream.iopt_size)
+		      {
+			XPR(NT "warning: input position %"Q"u overflowed instruction buffer, "
+			    "needed %u (vs. %u), consider raising -I\n",
+			    stream.current_window * option_winsize,
+			    stream.i_slots_used, stream.iopt_size);
+		      }
+		  }
+
+		if (option_verbose)
+		  {
+		    char rrateavg[32], wrateavg[32], tm[32];
+		    char rdb[32], wdb[32];
+		    char trdb[32], twdb[32];
+		    long millis = get_millisecs_since ();
+		    usize_t this_read = (usize_t)(stream.total_in - last_total_in);
+		    usize_t this_write = (usize_t)(stream.total_out - last_total_out);
+		    last_total_in = stream.total_in;
+		    last_total_out = stream.total_out;
+
+		    if (option_verbose > 1)
+		      {
+			XPR(NT "%"Q"u: in %s (%s): out %s (%s): total in %s: out %s: %s\n",
+			    stream.current_window,
+			    main_format_bcnt (this_read, rdb),
+			    main_format_rate (this_read, millis, rrateavg),
+			    main_format_bcnt (this_write, wdb),
+			    main_format_rate (this_write, millis, wrateavg),
+			    main_format_bcnt (stream.total_in, trdb),
+			    main_format_bcnt (stream.total_out, twdb),
+			    main_format_millis (millis, tm));
+		      }
+		    else
+		      {
+			XPR(NT "%"Q"u: in %s: out %s: total in %s: out %s: %s\n",
+ 			    stream.current_window,
+			    main_format_bcnt (this_read, rdb),
+			    main_format_bcnt (this_write, wdb),
+			    main_format_bcnt (stream.total_in, trdb),
+			    main_format_bcnt (stream.total_out, twdb),
+			    main_format_millis (millis, tm));
+		      }
+		  }
+	      }
+	    goto again;
+	  }
+
+	default:
+	  /* input_func() error */
+	  XPR(NT XD3_LIB_ERRMSG (& stream, ret));
+	  return EXIT_FAILURE;
+	}
+    }
+  while (nread == config.winsize);
+done:
+  /* Close the inputs. (ifile must be open, sfile may be open) */
+  main_file_close (ifile);
+  main_file_close (sfile);
+
+  /* If output file is not open yet because of delayed-open, it means we never encountered
+   * a window in the delta, but it could have had a VCDIFF header?  TODO: solve this
+   * elsewhere.  For now, it prints "nothing to output" below, but the check doesn't
+   * happen in case of option_no_output.  */
+  if (! option_no_output)
+    {
+      if (!stdout_only && ! main_file_isopen (ofile))
+	{
+	  XPR(NT "nothing to output: %s\n", ifile->filename);
+	  return EXIT_FAILURE;
+	}
+
+      /* Have to close the output before calling main_external_compression_finish, or else it hangs. */
+      if (main_file_close (ofile) != 0)
+	{
+	  return EXIT_FAILURE;
+	}
+    }
+
+#if EXTERNAL_COMPRESSION
+  if ((ret = main_external_compression_finish ()))
+    {
+      XPR(NT "external compression commands failed\n");
+      return EXIT_FAILURE;
+    }
+#endif
+
+  if ((ret = xd3_close_stream (& stream)))
+    {
+      XPR(NT XD3_LIB_ERRMSG (& stream, ret));
+      return EXIT_FAILURE;
+    }
+
+  if (option_verbose > 1)
+    {
+      XPR(NT "scanner configuration: %s\n", stream.smatcher.name);
+      XPR(NT "target hash table size: %u\n", stream.small_hash.size);
+      if (sfile->filename != NULL)
+	{
+	  XPR(NT "source hash table size: %u\n", stream.large_hash.size);
+	}
+    }
+
+  if (option_verbose > 2)
+    {
+      XPR(NT "source copies: %"Q"u (%"Q"u bytes)\n", stream.n_scpy, stream.l_scpy);
+      XPR(NT "target copies: %"Q"u (%"Q"u bytes)\n", stream.n_tcpy, stream.l_tcpy);
+      XPR(NT "adds: %"Q"u (%"Q"u bytes)\n", stream.n_add, stream.l_add);
+      XPR(NT "runs: %"Q"u (%"Q"u bytes)\n", stream.n_run, stream.l_run);
+    }
+
+  xd3_free_stream (& stream);
+
+  if (option_verbose)
+    {
+      char tm[32];
+      long end_time = get_millisecs_now ();
+      XPR(NT "finished in %s; input %"Q"u output %"Q"u bytes  (%0.2f%%)\n",
+	  main_format_millis (end_time - start_time, tm),
+	  ifile->nread, ofile->nwrite,
+	  100.0 * ofile->nwrite / ifile->nread);
+    }
+
+  return EXIT_SUCCESS;
+}
+
+/* free memory before exit, reset single-use variables. */
+static void
+main_cleanup (void)
+{
+  int i;
+
+  if (appheader_used != NULL &&
+      appheader_used != option_appheader)
+    {
+      main_free (appheader_used);
+      appheader_used = NULL;
+    }
+
+  main_free (main_bdata);
+  main_bdata = NULL;
+
+#if EXTERNAL_COMPRESSION
+  main_free (ext_tmpfile);
+  ext_tmpfile = NULL;
+#endif
+
+  for (i = 0; lru && i < lru_size; i += 1)
+    {
+      main_free (lru[i].blk);
+    }
+
+  main_free (lru);
+  lru = NULL;
+
+  lru_hits = 0;
+  lru_misses = 0;
+  lru_filled = 0;
+
+  XD3_ASSERT (main_mallocs == 0);
+}
+
+static void
+setup_environment (int argc,
+		   char **argv,
+		   int *argc_out,
+		   char ***argv_out,
+		   char ***argv_free,
+		   char **env_free)
+{
+  int n, i, i0;
+  char *p, *v = getenv("XDELTA");
+  if (v == NULL) {
+    (*argc_out) = argc;
+    (*argv_out) = argv;
+    (*argv_free) = NULL;
+    (*env_free) = NULL;
+    return;
+  }
+
+  (*env_free) = main_malloc(strlen(v) + 1);
+  strcpy(*env_free, v);
+
+  /* Space needed for extra args, at least # of spaces */
+  n = argc + 1;
+  for (p = *env_free; *p != 0; ) {
+    if (*p++ == ' ') {
+      n++;
+    }
+  }
+
+  (*argv_free) = main_malloc(sizeof(char*) * (n + 1));
+  (*argv_out) = (*argv_free);
+  (*argv_out)[0] = argv[0];
+  (*argv_out)[n] = NULL;
+
+  i = 1;
+  for (p = *env_free; *p != 0; ) {
+    (*argv_out)[i++] = p;
+    while (*p != ' ' && *p != 0) {
+      p++;
+    }
+    while (*p == ' ') {
+      *p++ = 0;
+    }
+  }
+
+  for (i0 = 1; i0 < argc; i0++) {
+    (*argv_out)[i++] = argv[i0];
+  }
+
+  /* Counting spaces is an upper bound, argv stays NULL terminated. */
+  (*argc_out) = i;
+  while (i <= n) {
+    (*argv_out)[i++] = NULL;
+  }
+}
+
+int
+#if PYTHON_MODULE || SWIG_MODULE
+xd3_main_cmdline (int argc, char **argv)
+#else
+main (int argc, char **argv)
+#endif
+{
+  xd3_cmd cmd;
+  main_file ifile;
+  main_file ofile;
+  main_file sfile;
+  static const char *flags = "0123456789cdefhnqvDJNORTVs:B:C:E:F:I:L:O:M:P:W:A::S::";
+  int my_optind;
+  char *my_optarg;
+  char *my_optstr;
+  char *sfilename;
+  int env_argc;
+  char **env_argv;
+  char **free_argv;  /* malloc() in setup_environment() */
+  char *free_value;  /* malloc() in setup_environment() */
+  int ret;
+
+#ifdef _WIN32
+  GetStartupInfo(&winStartupInfo);
+  setvbuf(stderr, NULL, _IONBF, 0);  /* Do not buffer stderr */
+#endif
+
+  main_file_init (& ifile);
+  main_file_init (& ofile);
+  main_file_init (& sfile);
+
+  reset_defaults();
+
+  free_argv = NULL;
+  free_value = NULL;
+  setup_environment(argc, argv, &env_argc, &env_argv, &free_argv, &free_value);
+  cmd = CMD_NONE;
+  sfilename = NULL;
+  my_optind = 1;
+  argv = env_argv;
+  argc = env_argc;
+  program_name = env_argv[0];
+  extcomp_types[0].recomp_cmdname = program_name;
+  extcomp_types[0].decomp_cmdname = program_name;
+ takearg:
+  my_optarg = NULL;
+  my_optstr = argv[my_optind];
+  /* This doesn't use getopt() because it makes trouble for -P & python which reenter
+   * main() and thus care about freeing all memory.  I never had much trust for getopt
+   * anyway, it's too opaque.  This implements a fairly standard non-long-option getopt
+   * with support for named operations (e.g., "xdelta3 [encode|decode|printhdr...] < in >
+   * out"). */
+  if (my_optstr)
+    {
+      if (*my_optstr == '-')    { my_optstr += 1; }
+      else if (cmd == CMD_NONE) { goto nonflag; }
+      else                      { my_optstr = NULL; }
+    }
+  while (my_optstr)
+    {
+      char *s;
+      my_optarg = NULL;
+      if ((ret = *my_optstr++) == 0) { my_optind += 1; goto takearg; }
+
+      /* Option handling: first check for one ':' following the option in flags, then
+       * check for two.  The syntax allows:
+       *
+       * 1. -Afoo                   defines optarg="foo"
+       * 2. -A foo                  defines optarg="foo"
+       * 3. -A ""                   defines optarg="" (allows optional empty-string)
+       * 4. -A [EOA or -moreargs]   error (mandatory case)
+       * 5. -A [EOA -moreargs]      defines optarg=NULL (optional case)
+       * 6. -A=foo                  defines optarg="foo"
+       * 7. -A=                     defines optarg="" (mandatory case)
+       * 8. -A=                     defines optarg=NULL (optional case)
+       *
+       * See tests in test_command_line_arguments().
+       */
+      s = strchr (flags, ret);
+      if (s && s[1] && s[1] == ':')
+	{
+	  int eqcase = 0;
+	  int option = s[2] && s[2] == ':';
+
+	  /* Case 1, set optarg to the remaining characters. */
+	  my_optarg = my_optstr;
+	  my_optstr = "";
+
+	  /* Case 2-5 */
+	  if (*my_optarg == 0)
+	    {
+	      /* Condition 4-5 */
+	      int have_arg = my_optind < (argc - 1) && *argv[my_optind+1] != '-';
+
+	      if (! have_arg)
+		{
+		  if (! option)
+		  {
+		    /* Case 4 */
+		    XPR(NT "-%c: requires an argument\n", ret);
+		    ret = EXIT_FAILURE;
+		    goto cleanup;
+		  }
+		  /* Case 5. */
+		  my_optarg = NULL;
+		}
+	      else
+		{
+		  /* Case 2-3. */
+		  my_optarg = argv[++my_optind];
+		}
+	    }
+	  /* Case 6-8. */
+	  else if (*my_optarg == '=')
+	    {
+	      /* Remove the = in all cases. */
+	      my_optarg += 1;
+	      eqcase = 1;
+
+	      if (option && *my_optarg == 0)
+		{
+		  /* Case 8. */
+		  my_optarg = NULL;
+		}
+	    }
+	}
+
+      switch (ret)
+	{
+	/* case: if no '-' was found, maybe check for a command name. */
+	nonflag:
+	       if (strcmp (my_optstr, "decode") == 0) { cmd = CMD_DECODE; }
+	  else if (strcmp (my_optstr, "encode") == 0)
+	    {
+#if XD3_ENCODER
+	      cmd = CMD_ENCODE;
+#else
+	      XPR(NT "encoder support not compiled\n");
+	      return EXIT_FAILURE;
+#endif
+	    }
+	  else if (strcmp (my_optstr, "config") == 0) { cmd = CMD_CONFIG; }
+#if REGRESSION_TEST
+	  else if (strcmp (my_optstr, "test") == 0) { cmd = CMD_TEST; }
+#endif
+#if VCDIFF_TOOLS
+	  else if (strcmp (my_optstr, "printhdr") == 0) { cmd = CMD_PRINTHDR; }
+	  else if (strcmp (my_optstr, "printhdrs") == 0) { cmd = CMD_PRINTHDRS; }
+	  else if (strcmp (my_optstr, "printdelta") == 0) { cmd = CMD_PRINTDELTA; }
+#endif
+
+	  /* If no option was found and still no command, let the default command be
+	   * encode.  The remaining args are treated as filenames. */
+	  if (cmd == CMD_NONE)
+	    {
+	      cmd = CMD_DEFAULT;
+	      my_optstr = NULL;
+	      break;
+	    }
+	  else
+	    {
+	      /* But if we find a command name, continue the getopt loop. */
+	      my_optind += 1;
+	      goto takearg;
+	    }
+
+	  /* gzip-like options */
+	case '0': case '1': case '2': case '3': case '4':
+	case '5': case '6': case '7': case '8': case '9':
+	  option_level = ret - '0';
+	  break;
+	case 'f': option_force = 1; break;
+	case 'v': option_verbose += 1; option_quiet = 0; break;
+	case 'q': option_quiet = 1; option_verbose = 0; break;
+	case 'c': option_stdout = 1; break;
+	case 'd':
+	  if (cmd == CMD_NONE) { cmd = CMD_DECODE; }
+	  else { ret = main_help (); goto exit; }
+	  break;
+	case 'e':
+#if XD3_ENCODER
+	  if (cmd == CMD_NONE) { cmd = CMD_ENCODE; }
+	  else { ret = main_help (); goto exit; }
+	  break;
+#else
+	  XPR(NT "encoder support not compiled\n");
+	  return EXIT_FAILURE;
+#endif
+
+	case 'n': option_use_checksum = 0; break;
+	case 'N': option_no_compress = 1; break;
+	case 'T': option_use_altcodetable = 1; break;
+	case 'C': option_smatch_config = my_optarg; break;
+	case 'J': option_no_output = 1; break;
+	case 'S': if (my_optarg == NULL) { option_use_secondary = 0; }
+	          else { option_use_secondary = 1; option_secondary = my_optarg; } break;
+	case 'A': if (my_optarg == NULL) { option_use_appheader = 0; }
+	          else { option_appheader = (uint8_t*) my_optarg; } break;
+	case 'B':
+	  if ((ret = main_atou (my_optarg, & option_srcwinsz, XD3_MINSRCWINSZ,
+				0, 'B')))
+	    {
+	      goto exit;
+	    }
+	  break;
+	case 'I':
+	  if ((ret = main_atou (my_optarg, & option_iopt_size, 0,
+				0, 'I')))
+	    {
+	      goto exit;
+	    }
+	  break;
+	case 'P':
+	  if ((ret = main_atou (my_optarg, & option_sprevsz, 0,
+				0, 'P')))
+	    {
+	      goto exit;
+	    }
+	  break;
+	case 'W':
+	  if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE,
+				XD3_HARDMAXWINSIZE, 'W')))
+	  {
+	    goto exit;
+	  }
+	  break;
+	case 'D':
+#if EXTERNAL_COMPRESSION == 0
+	  if (option_verbose > 0)
+	    {
+	      XPR(NT "warning: -D option ignored, "
+		       "external compression support was not compiled\n");
+	    }
+#else
+	  option_decompress_inputs  = 0;
+#endif
+	  break;
+	case 'R':
+#if EXTERNAL_COMPRESSION == 0
+	  if (option_verbose > 0)
+	    {
+	      XPR(NT "warning: -R option ignored, "
+		       "external compression support was not compiled\n");
+	    }
+#else
+	  option_recompress_outputs = 0;
+#endif
+	  break;
+	case 's':
+	  if (sfilename != NULL)
+	    {
+	      XPR(NT "specify only one source file\n");
+	      goto cleanup;
+	    }
+
+	  sfilename = my_optarg;
+	  break;
+
+	case 'V':
+	  ret = main_version (); goto exit;
+	default:
+	  ret = main_help (); goto exit;
+	}
+    }
+
+  option_source_filename = sfilename;
+
+  /* In case there were no arguments, set the default command. */
+  if (cmd == CMD_NONE) { cmd = CMD_DEFAULT; }
+
+  argc -= my_optind;
+  argv += my_optind;
+
+  /* There may be up to two more arguments. */
+  if (argc > 2)
+    {
+      XPR(NT "too many filenames: %s ...\n", argv[2]);
+      ret = EXIT_FAILURE;
+      goto cleanup;
+    }
+
+  ifile.flags    = RD_FIRST;
+  sfile.flags    = RD_FIRST;
+  sfile.filename = option_source_filename;
+
+  /* The infile takes the next argument, if there is one.  But if not, infile is set to
+   * stdin. */
+  if (argc > 0)
+    {
+      ifile.filename = argv[0];
+
+      if ((ret = main_file_open (& ifile, ifile.filename, XO_READ)))
+	{
+	  goto cleanup;
+	}
+    }
+  else
+    {
+      XSTDIN_XF (& ifile);
+    }
+
+  /* The ofile takes the following argument, if there is one.  But if not, it is left NULL
+   * until the application header is processed.  It will be set in main_open_output. */
+  if (argc > 1)
+    {
+      /* Check for conflicting arguments. */
+      if (option_stdout && ! option_quiet)
+	{
+	  XPR(NT "warning: -c option overrides output filename: %s\n", argv[1]);
+	}
+
+      if (! option_stdout) { ofile.filename = argv[1]; }
+    }
+
+  switch (cmd)
+    {
+    case CMD_PRINTHDR:
+    case CMD_PRINTHDRS:
+    case CMD_PRINTDELTA:
+#if XD3_ENCODER
+    case CMD_ENCODE:
+#endif
+    case CMD_DECODE:
+      ret = main_input (cmd, & ifile, & ofile, & sfile);
+      break;
+
+#if REGRESSION_TEST
+    case CMD_TEST:
+      ret = xd3_selftest ();
+      break;
+#endif
+
+    case CMD_CONFIG:
+      ret = main_config ();
+      break;
+
+    default:
+      ret = main_help ();
+      break;
+    }
+
+#if EXTERNAL_COMPRESSION
+  if (ext_tmpfile != NULL)
+    {
+      unlink (ext_tmpfile);
+    }
+#endif
+
+  if (0)
+    {
+    cleanup:
+      ret = EXIT_FAILURE;
+    exit:
+      (void)0;
+    }
+
+  main_file_cleanup (& ifile);
+  main_file_cleanup (& ofile);
+  main_file_cleanup (& sfile);
+
+  main_free (free_argv);
+  main_free (free_value);
+
+  main_cleanup ();
+
+  fflush (stdout);
+  fflush (stderr);
+  return ret;
+}
+
+static int
+main_help (void)
+{
+  /* Note: update wiki when command-line features change */
+  main_version ();
+  DP(RINT "usage: xdelta3 [command/options] [input [output]]\n");
+  DP(RINT "special command names:\n");
+  DP(RINT "    config      prints xdelta3 configuration\n");
+  DP(RINT "    decode      decompress the input\n");
+  DP(RINT "    encode      compress the input%s\n", XD3_ENCODER ? "" : " [Not compiled]");
+#if REGRESSION_TEST
+  DP(RINT "    test        run the builtin tests\n");
+#endif
+#if VCDIFF_TOOLS
+  DP(RINT "special commands for VCDIFF inputs:\n");
+  DP(RINT "    printdelta  print information about the entire delta\n");
+  DP(RINT "    printhdr    print information about the first window\n");
+  DP(RINT "    printhdrs   print information about all windows\n");
+#endif
+  DP(RINT "standard options:\n");
+  DP(RINT "   -0 .. -9     compression level\n");
+  DP(RINT "   -c           use stdout\n");
+  DP(RINT "   -d           decompress\n");
+  DP(RINT "   -e           compress%s\n", XD3_ENCODER ? "" : " [Not compiled]");
+  DP(RINT "   -f           force overwrite\n");
+  DP(RINT "   -h           show help\n");
+  DP(RINT "   -q           be quiet\n");
+  DP(RINT "   -v           be verbose (max 2)\n");
+  DP(RINT "   -V           show version\n");
+
+  DP(RINT "memory options:\n");
+  DP(RINT "   -B bytes     source window size\n");
+  DP(RINT "   -W bytes     input window size\n");
+  DP(RINT "   -P size      compression duplicates window\n");
+  DP(RINT "   -I size      instruction buffer size (0 = unlimited)\n");
+
+  DP(RINT "compression options:\n");
+  DP(RINT "   -s source    source file to copy from (if any)\n");
+  DP(RINT "   -S [djw|fgk] enable/disable secondary compression\n");
+  DP(RINT "   -N           disable small string-matching compression\n");
+  DP(RINT "   -D           disable external decompression (encode/decode)\n");
+  DP(RINT "   -R           disable external recompression (decode)\n");
+  DP(RINT "   -n           disable checksum (encode/decode)\n");
+  DP(RINT "   -C           soft config (encode, undocumented)\n");
+  DP(RINT "   -A [apphead] disable/provide application header (encode)\n");
+
+#if XD3_DEBUG > 0
+  DP(RINT "developer options:\n");
+  DP(RINT "   -J           disable output (check/compute only)\n");
+  DP(RINT "   -P           repeat count (for profiling)\n");
+  DP(RINT "   -T           use alternate code table\n");
+#endif
+
+  DP(RINT "the XDELTA environment variable may contain extra args:\n");
+  DP(RINT "   XDELTA=\"-s source-x.y.tar.gz\" \\\n");
+  DP(RINT "   tar --use-compress-program=xdelta3 \\\n");
+  DP(RINT "       -cf target-x.z.tar.gz.vcdiff target-x.y/\n");
+  return EXIT_FAILURE;
+}
+
Index: /nikanabo/current/xdelta/diy/xdelta3-python.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-python.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-python.h	(revision 185)
@@ -0,0 +1,88 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "Python.h"
+
+static PyObject *pyxd3_error;
+
+/* spam: xdelta3.main([string,list,...]) */
+PyObject *xdelta3_main_cmdline (PyObject *self, PyObject *args)
+{
+  int ret, i, nargs;
+  char **argv = NULL;
+  int argc = 0;
+  PyObject *result = NULL;
+  PyObject *o;
+
+  if (! PyArg_ParseTuple (args, "O", &o)
+      || ! PyList_Check (o))
+    {
+      goto cleanup;
+    }
+
+  argc  = PyList_Size (o);
+  nargs = argc + 2;
+
+  if (! (argv = malloc (sizeof(argv[0]) * nargs)))
+    {
+      PyErr_NoMemory ();
+      goto cleanup;
+    }
+  memset (argv, 0, sizeof(argv[0]) * nargs);
+
+  for (i = 1; i < nargs-1; i += 1)
+    {
+      char *ps;
+      PyObject *s;
+      if ((s = PyList_GetItem (o, i-1)) == NULL) { goto cleanup; }
+      ps = PyString_AsString (s);
+      /* TODO: ps is NULL if s is not a string, crashes the interpreter */
+      argv[i] = ps;
+    }
+
+  ret = xd3_main_cmdline (argc+1, argv);
+
+  if (ret == 0)
+    {
+      result = Py_BuildValue ("i", ret);
+    }
+  else
+    {
+      PyErr_SetString (pyxd3_error, "failed :(");
+    }
+ cleanup:
+  if (argv)
+    {
+      free (argv);
+    }
+  return result;
+}
+
+static PyMethodDef xdelta3_methods[] = {
+  { "main", xdelta3_main_cmdline, METH_VARARGS, "xdelta3 main()" },
+  { NULL, NULL }
+};
+
+DL_EXPORT(void) initxdelta3main (void)
+{
+  PyObject *m, *d;
+  m = Py_InitModule ("xdelta3main", xdelta3_methods);
+  d = PyModule_GetDict (m);
+  pyxd3_error = PyErr_NewException ("xdelta3main.error", NULL, NULL);
+  PyDict_SetItemString (d, "error", pyxd3_error);
+}
Index: /nikanabo/current/xdelta/diy/xdelta3-regtest.py
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-regtest.py	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-regtest.py	(revision 185)
@@ -0,0 +1,1225 @@
+#!/usr/bin/python2.4
+# xdelta 3 - delta compression tools and library
+# Copyright (C) 2003, 2006, 2007.  Joshua P. MacDonald
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# TODO: test 1.5 vs. greedy
+
+import os, sys, math, re, time, types, array, random
+import xdelta3main
+import xdelta3
+
+#RCSDIR = '/mnt/polaroid/Polaroid/orbit_linux/home/jmacd/PRCS'
+RCSDIR = '/tmp/PRCS_read_copy'
+SAMPLEDIR = "/tmp/WESNOTH_tmp/diff"
+
+#RCSDIR = 'G:/jmacd/PRCS/prcs/b'
+#SAMPLEDIR = "C:/sample_data/Wesnoth/tar"
+
+#
+MIN_SIZE       = 0
+
+TIME_TOO_SHORT = 0.050
+
+SKIP_TRIALS    = 2
+MIN_TRIALS     = 3
+MAX_TRIALS     = 15
+
+SKIP_DECODE = 1
+
+# 10 = fast 1.5 = slow
+MIN_STDDEV_PCT = 1.5
+
+# How many results per round
+MAX_RESULTS = 500
+TEST_ROUNDS = 500
+KEEP_P = (0.5)
+
+# For RCS testing, what percent to select
+FILE_P = (0.30)
+
+# For run-speed tests
+MIN_RUN = 1000 * 1000 * 1
+MAX_RUN = 1000 * 1000 * 10
+
+# Testwide defaults
+ALL_ARGS = [
+    # -v
+    ]
+
+# The first 7 args go to -C
+SOFT_CONFIG_CNT = 7
+
+CONFIG_ORDER = [ 'large_look',
+                 'large_step',
+                 'small_look',
+                 'small_chain',
+                 'small_lchain',
+                 'max_lazy',
+                 'long_enough',
+
+                 # > SOFT_CONFIG_CNT
+                 'nocompress',
+                 'winsize',
+                 'srcwinsize',
+                 'sprevsz',
+                 'iopt',
+                 'djw',
+                 'altcode',
+                 ]
+
+CONFIG_ARGMAP = {
+    'winsize'    : '-W',
+    'srcwinsize' : '-B',
+    'sprevsz'    : '-P',
+    'iopt'       : '-I',
+    'nocompress' : '-N',
+    'djw'        : '-Sdjw',
+    'altcode'    : '-T',
+    }
+
+def INPUT_SPEC(rand):
+    return {
+
+    # Time/space costs:
+
+    # -C 1,2,3,4,5,6,7
+    'large_look' : lambda d: rand.choice([9]),
+    'large_step' : lambda d: rand.choice([3, 5, 7, 8, 15]),
+    'small_chain'  : lambda d: rand.choice([40, 10, 4, 1]),
+    'small_lchain' : lambda d: rand.choice([x for x in [10, 4, 2, 1] if x <= d['small_chain']]),
+    'max_lazy'     : lambda d: rand.choice([9, 18, 27, 36, 72, 108]),
+    'long_enough'  : lambda d: rand.choice([9, 18, 27, 36, 72, 108]),
+    'small_look'   : lambda d: rand.choice([4]),
+
+    # -N
+    'nocompress'   : lambda d: rand.choice(['true']),
+
+    # -T
+    'altcode'      : lambda d: rand.choice(['false']),
+
+    # -S djw
+    'djw'          : lambda d: rand.choice(['false']),
+
+    # Memory costs:
+
+    # -W
+    'winsize'      : lambda d: 8 * (1<<20),
+
+    # -B
+    'srcwinsize'   : lambda d: 64 * (1<<20),
+
+    # -I 0 is unlimited
+    'iopt'         : lambda d: 0,
+
+    # -P only powers of two
+    'sprevsz'      : lambda d: rand.choice([x * (1<<16) for x in [4]]),
+  }
+#end
+
+#
+TMPDIR = '/tmp/xd3regtest.%d' % os.getpid()
+
+RUNFILE = os.path.join(TMPDIR, 'run')
+DFILE   = os.path.join(TMPDIR, 'output')
+RFILE   = os.path.join(TMPDIR, 'recon')
+
+HEAD_STATE = 0
+BAR_STATE  = 1
+REV_STATE  = 2
+DATE_STATE = 3
+
+#
+IGNORE_FILENAME  = re.compile('.*\\.(gif|jpg).*')
+
+# rcs output
+RE_TOTREV  = re.compile('total revisions: (\\d+)')
+RE_BAR     = re.compile('----------------------------')
+RE_REV     = re.compile('revision (.+)')
+RE_DATE    = re.compile('date: ([^;]+);.*')
+# xdelta output
+RE_HDRSZ   = re.compile('VCDIFF header size: +(\\d+)')
+RE_EXTCOMP = re.compile('XDELTA ext comp.*')
+
+def c2str(c):
+    return ' '.join(['%s' % x for x in c])
+#end
+
+def SumList(l):
+    return reduce(lambda x,y: x+y, l)
+#end
+
+# returns (total, mean, stddev, q2 (median),
+#          (q3-q1)/2 ("semi-interquartile range"), max-min (spread))
+class StatList:
+    def __init__(self,l,desc):
+        cnt = len(l)
+        assert(cnt > 1)
+        l.sort()
+        self.cnt    = cnt
+        self.l      = l
+        self.total  = SumList(l)
+        self.mean   = self.total / float(self.cnt)
+        self.s      = math.sqrt(SumList([(x-self.mean) * (x - self.mean) for x in l]) / float(self.cnt-1))
+        self.q0     = l[0]
+        self.q1     = l[int(self.cnt/4.0+0.5)]
+        self.q2     = l[int(self.cnt/2.0+0.5)]
+        self.q3     = l[min(self.cnt-1,int((3.0*self.cnt)/4.0+0.5))]
+        self.q4     = l[self.cnt-1]+1
+        self.siqr   = (self.q3-self.q1)/2.0;
+        self.spread = (self.q4-self.q0)
+        self.str    = '%s %d; mean %d; sdev %d; q2 %d; .5(q3-q1) %.1f; spread %d' % \
+                      (desc, self.total, self.mean, self.s, self.q2, self.siqr, self.spread)
+    #end
+#end
+
+def RunCommand(args, ok = [0]):
+    #print 'run command %s' % (' '.join(args))
+    p = os.spawnvp(os.P_WAIT, args[0], args)
+    if p not in ok:
+        raise CommandError(args, 'exited %d' % p)
+    #end
+#end
+
+def RunCommandIO(args,infn,outfn):
+    p = os.fork()
+    if p == 0:
+        os.dup2(os.open(infn,os.O_RDONLY),0)
+        os.dup2(os.open(outfn,os.O_CREAT|os.O_TRUNC|os.O_WRONLY),1)
+        os.execvp(args[0], args)
+    else:
+        s = os.waitpid(p,0)
+        o = os.WEXITSTATUS(s[1])
+        if not os.WIFEXITED(s[1]) or o != 0:
+            raise CommandError(args, 'exited %d' % o)
+        #end
+    #end
+#end
+
+class TimedTest:
+    def __init__(self, target, source, runnable,
+                 skip_trials = SKIP_TRIALS,
+                 min_trials = MIN_TRIALS,
+                 max_trials = MAX_TRIALS,
+                 min_stddev_pct = MIN_STDDEV_PCT):
+        self.target = target
+        self.source = source
+        self.runnable = runnable
+
+        self.skip_trials = skip_trials
+        self.min_trials = min(min_trials, max_trials)
+        self.max_trials = max_trials
+        self.min_stddev_pct = min_stddev_pct
+
+        self.encode_time = self.DoTest(DFILE,
+                                       lambda x: x.Encode(self.target, self.source, DFILE))
+        self.encode_size = runnable.EncodeSize(DFILE)
+
+        if SKIP_DECODE:
+            self.decode_time = StatList([1, 1], 'not decoded')
+            return
+        #end
+
+        self.decode_time = self.DoTest(RFILE,
+                                       lambda x: x.Decode(DFILE, self.source, RFILE),
+                                       )
+
+        # verify
+        runnable.Verify(self.target, RFILE)
+    #end
+
+    def DoTest(self, fname, func):
+        trials   = 0
+        measured = []
+
+        while 1:
+            try:
+                os.remove(fname)
+            except OSError:
+                pass
+
+            start_time  = time.time()
+            start_clock = time.clock()
+
+            func(self.runnable)
+
+            total_clock = (time.clock() - start_clock)
+            total_time  = (time.time() - start_time)
+
+            elap_time  = max(total_time,  0.0000001)
+            elap_clock = max(total_clock, 0.0000001)
+
+            trials = trials + 1
+
+            # skip some of the first trials
+            if trials > self.skip_trials:
+                measured.append((elap_clock, elap_time))
+                #print 'measurement total: %.1f ms' % (total_time * 1000.0)
+
+            # at least so many
+            if trials < (self.skip_trials + self.min_trials):
+                #print 'continue: need more trials: %d' % trials
+                continue
+
+            # compute %variance
+            done = 0
+            if self.skip_trials + self.min_trials <= 2:
+                measured = measured + measured;
+                done = 1
+            #end
+
+            time_stat = StatList([x[1] for x in measured], 'elap time')
+            sp = float(time_stat.s) / float(time_stat.mean)
+
+            # what if MAX_TRIALS is exceeded?
+            too_many = (trials - self.skip_trials) >= self.max_trials
+            good = (100.0 * sp) < self.min_stddev_pct
+            if done or too_many or good:
+                trials = trials - self.skip_trials
+                if not done and not good:
+                    #print 'too many trials: %d' % trials
+                    pass
+                #clock = StatList([x[0] for x in measured], 'elap clock')
+                return time_stat
+            #end
+        #end
+    #end
+#end
+
+def Decimals(start, end):
+    l = []
+    step = start
+    while 1:
+        r = range(step, step * 10, step)
+        l = l + r
+        if step * 10 >= end:
+            l.append(step * 10)
+            break
+        step = step * 10
+    return l
+#end
+
+# This tests the raw speed of 0-byte inputs
+def RunSpeedTest():
+    for L in Decimals(MIN_RUN, MAX_RUN):
+        SetFileSize(RUNFILE, L)
+
+        trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<20)]))
+        ReportSpeed(L, trx, '1MB ')
+
+        trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<19)]))
+        ReportSpeed(L, trx, '512k')
+
+        trx = TimedTest(RUNFILE, None, Xdelta3Runner(['-W', str(1<<18)]))
+        ReportSpeed(L, trx, '256k')
+
+        trm = TimedTest(RUNFILE, None, Xdelta3Mod1(RUNFILE))
+        ReportSpeed(L, trm, 'swig')
+
+        trg = TimedTest(RUNFILE, None, GzipRun1())
+        ReportSpeed(L,trg,'gzip')
+    #end
+#end
+
+def SetFileSize(F,L):
+    fd = os.open(F, os.O_CREAT | os.O_WRONLY)
+    os.ftruncate(fd,L)
+    assert os.fstat(fd).st_size == L
+    os.close(fd)
+#end
+
+def ReportSpeed(L,tr,desc):
+    print '%s run length %u: size %u: time %.3f ms: decode %.3f ms' % \
+          (desc, L,
+           tr.encode_size,
+           tr.encode_time.mean * 1000.0,
+           tr.decode_time.mean * 1000.0)
+#end
+
+class Xdelta3RunClass:
+    def __init__(self, extra):
+        self.extra = extra
+    #end
+
+    def __str__(self):
+        return ' '.join(self.extra)
+    #end
+
+    def New(self):
+        return Xdelta3Runner(self.extra)
+    #end
+#end
+
+class Xdelta3Runner:
+    def __init__(self, extra):
+        self.extra = extra
+    #end
+
+    def Encode(self, target, source, output):
+        args = (ALL_ARGS +
+                self.extra +
+                ['-e'])
+        if source:
+            args.append('-s')
+            args.append(source)
+        #end
+        args = args + [target, output]
+        self.Main(args)
+    #end
+
+    def Decode(self, input, source, output):
+        args = (ALL_ARGS +
+                ['-d'])
+        if source:
+            args.append('-s')
+            args.append(source)
+        #end
+        args = args + [input, output]
+        self.Main(args)
+    #end
+
+    def Verify(self, target, recon):
+        RunCommand(('cmp', target, recon))
+    #end
+
+    def EncodeSize(self, output):
+        return os.stat(output).st_size
+    #end
+
+    def Main(self, args):
+        try:
+            xdelta3main.main(args)
+        except Exception, e:
+            raise CommandError(args, "xdelta3.main exception")
+        #end
+    #end
+#end
+
+class Xdelta3Mod1:
+    def __init__(self, file):
+        self.target_data = open(file, 'r').read()
+    #end
+
+    def Encode(self, ignore1, ignore2, ignore3):
+        r1, encoded = xdelta3.xd3_encode_memory(self.target_data, None, 1000000, 1<<10)
+        if r1 != 0:
+            raise CommandError('memory', 'encode failed: %s' % r1)
+        #end
+        self.encoded = encoded
+    #end
+
+    def Decode(self, ignore1, ignore2, ignore3):
+        r2, data1 = xdelta3.xd3_decode_memory(self.encoded, None, len(self.target_data))
+        if r2 != 0:
+            raise CommandError('memory', 'decode failed: %s' % r1)
+        #end
+        self.decoded = data1
+    #end
+
+    def Verify(self, ignore1, ignore2):
+        if self.target_data != self.decoded:
+            raise CommandError('memory', 'bad decode')
+        #end
+    #end
+
+    def EncodeSize(self, ignore1):
+        return len(self.encoded)
+    #end
+#end
+
+class GzipRun1:
+    def Encode(self, target, source, output):
+        assert source == None
+        RunCommandIO(['gzip', '-cf'], target, output)
+    #end
+
+    def Decode(self, input, source, output):
+        assert source == None
+        RunCommandIO(['gzip', '-dcf'], input, output)
+    #end
+
+    def Verify(self, target, recon):
+        RunCommand(('cmp', target, recon))
+    #end
+
+    def EncodeSize(self, output):
+        return os.stat(output).st_size
+    #end
+#end
+
+class Xdelta1RunClass:
+    def __str__(self):
+        return 'xdelta1'
+    #end
+
+    def New(self):
+        return Xdelta1Runner()
+    #end
+#end
+
+class Xdelta1Runner:
+    def Encode(self, target, source, output):
+        assert source != None
+        args = ['xdelta1', 'delta', '-q', source, target, output]
+        RunCommand(args, [0, 1])
+    #end
+
+    def Decode(self, input, source, output):
+        assert source != None
+        args = ['xdelta1', 'patch', '-q', input, source, output]
+        # Note: for dumb historical reasons, xdelta1 returns 1 or 0
+        RunCommand(args)
+    #end
+
+    def Verify(self, target, recon):
+        RunCommand(('cmp', target, recon))
+    #end
+
+    def EncodeSize(self, output):
+        return os.stat(output).st_size
+    #end
+#end
+
+# exceptions
+class SkipRcsException:
+    def __init__(self,reason):
+        self.reason = reason
+    #end
+#end
+
+class NotEnoughVersions:
+    def __init__(self):
+        pass
+    #end
+#end
+
+class CommandError:
+    def __init__(self,cmd,str):
+        if type(cmd) is types.TupleType or \
+           type(cmd) is types.ListType:
+            cmd = reduce(lambda x,y: '%s %s' % (x,y),cmd)
+        #end
+        print 'command was: ',cmd
+        print 'command failed: ',str
+        print 'have fun debugging'
+    #end
+#end
+
+class RcsVersion:
+    def __init__(self,vstr):
+        self.vstr = vstr
+    #end
+    def __cmp__(self,other):
+        return cmp(self.date, other.date)
+    #end
+    def __str__(self):
+        return str(self.vstr)
+    #end
+#end
+
+class RcsFile:
+
+    def __init__(self, fname):
+        self.fname    = fname
+        self.versions = []
+        self.state    = HEAD_STATE
+    #end
+
+    def SetTotRev(self,s):
+        self.totrev = int(s)
+    #end
+
+    def Rev(self,s):
+        self.rev = RcsVersion(s)
+        if len(self.versions) >= self.totrev:
+            raise SkipRcsException('too many versions (in log messages)')
+        #end
+        self.versions.append(self.rev)
+    #end
+
+    def Date(self,s):
+        self.rev.date = s
+    #end
+
+    def Match(self, line, state, rx, gp, newstate, f):
+        if state == self.state:
+            m = rx.match(line)
+            if m:
+                if f:
+                    f(m.group(gp))
+                #end
+                self.state = newstate
+                return 1
+            #end
+        #end
+        return None
+    #end
+
+    def Sum1Rlog(self):
+        f = os.popen('rlog '+self.fname, "r")
+        l = f.readline()
+        while l:
+            if self.Match(l, HEAD_STATE, RE_TOTREV, 1, BAR_STATE, self.SetTotRev):
+                pass
+            elif self.Match(l, BAR_STATE, RE_BAR, 1, REV_STATE, None):
+                pass
+            elif self.Match(l, REV_STATE, RE_REV, 1, DATE_STATE, self.Rev):
+                pass
+            elif self.Match(l, DATE_STATE, RE_DATE, 1, BAR_STATE, self.Date):
+                pass
+            #end
+            l = f.readline()
+        #end
+        c = f.close()
+        if c != None:
+            raise c
+        #end
+    #end
+
+    def Sum1(self):
+        st = os.stat(self.fname)
+        self.rcssize = st.st_size
+        self.Sum1Rlog()
+        if self.totrev != len(self.versions):
+            raise SkipRcsException('wrong version count')
+        #end
+        self.versions.sort()
+    #end
+
+    def Checkout(self,n):
+        v      = self.versions[n]
+        out    = open(self.Verf(n), "w")
+        cmd    = 'co -ko -p%s %s' % (v.vstr, self.fname)
+        total  = 0
+        (inf,
+         stream,
+         err)  = os.popen3(cmd, "r")
+        inf.close()
+        buf    = stream.read()
+        while buf:
+            total = total + len(buf)
+            out.write(buf)
+            buf = stream.read()
+        #end
+        v.vsize = total
+        estr = ''
+        buf = err.read()
+        while buf:
+            estr = estr + buf
+            buf = err.read()
+        #end
+        if stream.close():
+            raise CommandError(cmd, 'checkout failed: %s\n%s\n%s' % (v.vstr, self.fname, estr))
+        #end
+        out.close()
+        err.close()
+    #end
+
+    def Vdate(self,n):
+        return self.versions[n].date
+    #end
+
+    def Vstr(self,n):
+        return self.versions[n].vstr
+    #end
+
+    def Verf(self,n):
+        return os.path.join(TMPDIR, 'input.%d' % n)
+    #end
+
+    def FilePairsByDate(self, runclass):
+        if self.totrev < 2:
+            raise NotEnoughVersions()
+        #end
+        self.Checkout(0)
+        ntrials = []
+        if self.totrev < 2:
+            return vtrials
+        #end
+        for v in range(0,self.totrev-1):
+            if v > 1:
+                os.remove(self.Verf(v-1))
+            #end
+            self.Checkout(v+1)
+            if os.stat(self.Verf(v)).st_size < MIN_SIZE or \
+               os.stat(self.Verf(v+1)).st_size < MIN_SIZE:
+                continue
+            #end
+
+            result = TimedTest(self.Verf(v+1),
+                               self.Verf(v),
+                               runclass.New())
+
+            target_size = os.stat(self.Verf(v+1)).st_size
+
+            ntrials.append(result)
+        #end
+
+        os.remove(self.Verf(self.totrev-1))
+        os.remove(self.Verf(self.totrev-2))
+        return ntrials
+    #end
+
+    def AppendVersion(self, f, n):
+        self.Checkout(n)
+        rf = open(self.Verf(n), "r")
+        data = rf.read()
+        f.write(data)
+        rf.close()
+        return len(data)
+    #end
+
+class RcsFinder:
+    def __init__(self):
+        self.subdirs  = []
+        self.rcsfiles = []
+        self.others   = []
+        self.skipped  = []
+        self.biground = 0
+    #end
+
+    def Scan1(self,dir):
+        dents = os.listdir(dir)
+        subdirs  = []
+        rcsfiles = []
+        others   = []
+        for dent in dents:
+            full = os.path.join(dir, dent)
+            if os.path.isdir(full):
+                subdirs.append(full)
+            elif dent[len(dent)-2:] == ",v":
+                rcsfiles.append(RcsFile(full))
+            else:
+                others.append(full)
+            #end
+        #end
+        self.subdirs  = self.subdirs  + subdirs
+        self.rcsfiles = self.rcsfiles + rcsfiles
+        self.others   = self.others   + others
+        return subdirs
+    #end
+
+    def Crawl(self, dir):
+        subdirs = [dir]
+        while subdirs:
+            s1 = self.Scan1(subdirs[0])
+            subdirs = subdirs[1:] + s1
+        #end
+    #end
+
+    def Summarize(self):
+        good = []
+        for rf in self.rcsfiles:
+            try:
+                rf.Sum1()
+                if rf.totrev < 2:
+                    raise SkipRcsException('too few versions (< 2)')
+                #end
+            except SkipRcsException, e:
+                #print 'skipping file %s: %s' % (rf.fname, e.reason)
+                self.skipped.append(rf)
+            else:
+                good.append(rf)
+            #end
+        self.rcsfiles = good
+    #end
+
+    def AllPairsByDate(self, runclass):
+        results = []
+        good = []
+        for rf in self.rcsfiles:
+            try:
+                results = results + rf.FilePairsByDate(runclass)
+            except SkipRcsException:
+                print 'file %s has compressed versions: skipping' % (rf.fname)
+            except NotEnoughVersions:
+                print 'testing %s on %s: not enough versions' % (runclass, rf.fname)
+            else:
+                good.append(rf)
+            #end
+        self.rcsfiles = good
+        self.ReportPairs(runclass, results)
+        return results
+    #end
+
+    def ReportPairs(self, name, results):
+        encode_time = 0
+        decode_time = 0
+        encode_size = 0
+        for r in results:
+            encode_time += r.encode_time.mean
+            decode_time += r.decode_time.mean
+            encode_size += r.encode_size
+        #end
+        print '%s rcs: encode %.2f s: decode %.2f s: size %d' % \
+              (name, encode_time, decode_time, encode_size)
+    #end
+
+    def MakeBigFiles(self, rand):
+        f1 = open(TMPDIR + "/big.1", "w")
+        f2 = open(TMPDIR + "/big.2", "w")
+        population = []
+        for file in self.rcsfiles:
+            if len(file.versions) < 2:
+                continue
+            population.append(file)
+        #end
+        f1sz = 0
+        f2sz = 0
+        fcount = int(len(population) * FILE_P)
+        assert fcount > 0
+        for file in rand.sample(population, fcount):
+            m = IGNORE_FILENAME.match(file.fname)
+            if m != None:
+                continue
+            #end
+            r1, r2 = rand.sample(xrange(0, len(file.versions)), 2)
+            f1sz += file.AppendVersion(f1, r1)
+            f2sz += file.AppendVersion(f2, r2)
+            #m.update('%s,%s,%s ' % (file.fname[len(RCSDIR):], file.Vstr(r1), file.Vstr(r2)))
+        #end
+        testkey = 'rcs%d' % self.biground
+        self.biground = self.biground + 1
+
+        print '%s; source %u bytes; target %u bytes' % (testkey, f1sz, f2sz)
+        f1.close()
+        f2.close()
+        return (TMPDIR + "/big.1",
+                TMPDIR + "/big.2",
+                testkey)
+    #end
+
+    def Generator(self):
+        return lambda rand: self.MakeBigFiles(rand)
+    #end
+#end
+
+# find a set of RCS files for testing
+def GetTestRcsFiles():
+    rcsf = RcsFinder()
+    rcsf.Crawl(RCSDIR)
+    if len(rcsf.rcsfiles) == 0:
+        raise CommandError('', 'no RCS files')
+    #end
+    rcsf.Summarize()
+    print "rcsfiles: rcsfiles %d; subdirs %d; others %d; skipped %d" % (len(rcsf.rcsfiles),
+                                                                        len(rcsf.subdirs),
+                                                                        len(rcsf.others),
+                                                                        len(rcsf.skipped))
+    print StatList([x.rcssize for x in rcsf.rcsfiles], "rcssize").str
+    print StatList([x.totrev for x in rcsf.rcsfiles], "totrev").str
+    return rcsf
+#end
+
+class SampleDataTest:
+    def __init__(self, dirs):
+        self.pairs = []
+        while dirs:
+            d = dirs[0]
+            dirs = dirs[1:]
+            l = os.listdir(d)
+            files = []
+            for e in l:
+                p = os.path.join(d, e)
+                if os.path.isdir(p):
+                    dirs.append(p)
+                else:
+                    files.append(p)
+                #end
+            #end
+            if len(files) > 1:
+                files.sort()
+                for x in xrange(len(files) - 1):
+                    self.pairs.append((files[x], files[x+1],
+                                       '%s-%s' % (files[x], files[x+1])))
+                #end
+            #end
+        #end
+    #end
+
+    def Generator(self):
+        return lambda rand: rand.choice(self.pairs)
+    #end
+#end
+
+# configs are represented as a list of values,
+# program takes a list of strings:
+def ConfigToArgs(config):
+    args = [ '-C',
+             ','.join([str(x) for x in config[0:SOFT_CONFIG_CNT]])]
+    for i in range(SOFT_CONFIG_CNT, len(CONFIG_ORDER)):
+        key = CONFIG_ARGMAP[CONFIG_ORDER[i]]
+        val = config[i]
+        if val == 'true' or val == 'false':
+            if val == 'true':
+                args.append('%s' % key)
+            #end
+        else:
+            args.append('%s=%s' % (key, val))
+        #end
+    #end
+    return args
+#end
+
+#
+class RandomTest:
+    def __init__(self, tnum, tinput, config, syntuple = None):
+        self.mytinput = tinput[2]
+        self.myconfig = config
+        self.tnum = tnum
+
+        if syntuple != None:
+            self.runtime = syntuple[0]
+            self.compsize = syntuple[1]
+            self.decodetime = None
+        else:
+            args = ConfigToArgs(config)
+            result = TimedTest(tinput[1], tinput[0], Xdelta3Runner(args))
+
+            self.runtime = result.encode_time.mean
+            self.compsize = result.encode_size
+            self.decodetime = result.decode_time.mean
+        #end
+
+        self.score = None
+        self.time_pos = None
+        self.size_pos = None
+        self.score_pos = None
+    #end
+
+    def __str__(self):
+        decodestr = ''
+        if not SKIP_DECODE:
+            decodestr = ' %.6f' % self.decodetime
+        #end
+        return 'time %.6f%s size %d%s << %s >>%s' % (
+            self.time(), ((self.time_pos != None) and (" (%s)" % self.time_pos) or ""),
+            self.size(), ((self.size_pos != None) and (" (%s)" % self.size_pos) or ""),
+            c2str(self.config()),
+            decodestr)
+    #end
+
+    def time(self):
+        return self.runtime
+    #end
+
+    def size(self):
+        return self.compsize
+    #end
+
+    def config(self):
+        return self.myconfig
+    #end
+
+    def score(self):
+        return self.score
+    #end
+
+    def tinput(self):
+        return self.mytinput
+    #end
+#end
+
+def PosInAlist(l, e):
+    for i in range(0, len(l)):
+        if l[i][1] == e:
+            return i;
+        #end
+    #end
+    return -1
+#end
+
+# Generates a set of num_results test configurations, given the list of
+# retest-configs.
+def RandomTestConfigs(rand, input_configs, num_results):
+
+    outputs = input_configs[:]
+    have_set = dict([(c,c) for c in input_configs])
+
+    # Compute a random configuration
+    def RandomConfig():
+        config = []
+        cmap = {}
+        for key in CONFIG_ORDER:
+            val = cmap[key] = (INPUT_SPEC(rand)[key])(cmap)
+            config.append(val)
+        #end
+        return tuple(config)
+    #end
+
+    while len(outputs) < num_results:
+        newc = None
+        for i in xrange(10):
+            c = RandomConfig()
+            if have_set.has_key(c):
+                continue
+            #end
+            have_set[c] = c
+            newc = c
+            break
+        if newc is None:
+            print 'stopped looking for configs at %d' % len(outputs)
+            break
+        #end
+        outputs.append(c)
+    #end
+    outputs.sort()
+    return outputs
+#end
+
+def RunTestLoop(rand, generator, rounds):
+    configs = []
+    for rnum in xrange(rounds):
+        configs = RandomTestConfigs(rand, configs, MAX_RESULTS)
+        tinput = generator(rand)
+        tests = []
+        for x in xrange(len(configs)):
+            t = RandomTest(x, tinput, configs[x])
+            print 'Round %d test %d: %s' % (rnum, x, t)
+            tests.append(t)
+        #end
+        results = ScoreTests(tests)
+
+        for r in results:
+            c = r.config()
+            if not test_all_config_results.has_key(c):
+                test_all_config_results[c] = [r]
+            else:
+                test_all_config_results[c].append(r)
+            #end
+        #end
+
+        GraphResults('expt%d' % rnum, results)
+        GraphSummary('sum%d' % rnum, results)
+
+        # re-test some fraction
+        configs = [r.config() for r in results[0:int(MAX_RESULTS * KEEP_P)]]
+    #end
+#end
+
+# TODO: cleanup
+test_all_config_results = {}
+
+def ScoreTests(results):
+    scored = []
+    timed = []
+    sized = []
+
+    t_min = float(min([test.time() for test in results]))
+    #t_max = float(max([test.time() for test in results]))
+    s_min = float(min([test.size() for test in results]))
+    #s_max = float(max([test.size() for test in results]))
+
+    for test in results:
+
+        # Hyperbolic function. Smaller scores still better
+        red = 0.999  # minimum factors for each dimension are 1/1000
+        test.score = ((test.size() - s_min * red) *
+                      (test.time() - t_min * red))
+
+        scored.append((test.score, test))
+        timed.append((test.time(), test))
+        sized.append((test.size(), test))
+    #end
+
+    scored.sort()
+    timed.sort()
+    sized.sort()
+
+    best_by_size = []
+    best_by_time = []
+
+    pos = 0
+    for (score, test) in scored:
+        pos += 1
+        test.score_pos = pos
+    #end
+
+    scored = [x[1] for x in scored]
+
+    for test in scored:
+        test.size_pos = PosInAlist(sized, test)
+        test.time_pos = PosInAlist(timed, test)
+    #end
+
+    for test in scored:
+        c = test.config()
+        s = 0.0
+        print 'H-Score: %0.9f %s' % (test.score, test)
+    #end
+
+    return scored
+#end
+
+def GraphResults(desc, results):
+    f = open("data-%s.csv" % desc, "w")
+    for r in results:
+        f.write("%0.9f\t%d\t# %s\n" % (r.time(), r.size(), r))
+    #end
+    f.close()
+    os.system("./plot.sh data-%s.csv plot-%s.jpg" % (desc, desc))
+#end
+
+def GraphSummary(desc, results_ignore):
+    test_population = 0
+    config_ordered = []
+
+    # drops duplicate test/config pairs (TODO: don't retest them)
+    for config, cresults in test_all_config_results.items():
+        input_config_map = {}
+        uniq = []
+        for test in cresults:
+            assert test.config() == config
+            test_population += 1
+            key = test.tinput()
+            if not input_config_map.has_key(key):
+                input_config_map[key] = {}
+            #end
+            if input_config_map[key].has_key(config):
+                print 'skipping repeat test %s vs. %s' % (input_config_map[key][config], test)
+                continue
+            #end
+            input_config_map[key][config] = test
+            uniq.append(test)
+        #end
+        config_ordered.append(uniq)
+    #end
+
+    # sort configs descending by number of tests
+    config_ordered.sort(lambda x, y: len(y) - len(x))
+
+    print 'population %d: %d configs %d results' % \
+          (test_population,
+           len(config_ordered),
+           len(config_ordered[0]))
+
+    if config_ordered[0] == 1:
+        return
+    #end
+
+    # a map from test-key to test-list w/ various configs
+    input_set = {}
+    osize = len(config_ordered)
+
+    for i in xrange(len(config_ordered)):
+        config = config_ordered[i][0].config()
+        config_tests = config_ordered[i]
+
+        #print '%s has %d tested inputs' % (config, len(config_tests))
+
+        if len(input_set) == 0:
+            input_set = dict([(t.tinput(), [t]) for t in config_tests])
+            continue
+        #end
+
+        # a map from test-key to test-list w/ various configs
+        update_set = {}
+        for r in config_tests:
+            t = r.tinput()
+            if input_set.has_key(t):
+                update_set[t] = input_set[t] + [r]
+            else:
+                #print 'config %s does not have test %s' % (config, t)
+                pass
+            #end
+        #end
+
+        if len(update_set) <= 1:
+            break
+        #end
+
+        input_set = update_set
+
+        # continue if there are more w/ the same number of inputs
+        if i < (len(config_ordered) - 1) and \
+           len(config_ordered[i + 1]) == len(config_tests):
+            continue
+        #end
+
+        # synthesize results for multi-test inputs
+        config_num = None
+
+        # map of config to sum(various test-keys)
+        smap = {}
+        for (key, tests) in input_set.items():
+            if config_num == None:
+                # config_num should be the same in all elements
+                config_num = len(tests)
+                smap = dict([(r.config(),
+                              (r.time(),
+                               r.size()))
+                             for r in tests])
+            else:
+                # compuate the per-config sum of time/size
+                assert config_num == len(tests)
+                smap = dict([(r.config(),
+                              (smap[r.config()][0] + r.time(),
+                               smap[r.config()][1] + r.size()))
+                             for r in tests])
+            #end
+        #end
+
+        if config_num == 1:
+            continue
+        #end
+
+        if len(input_set) == osize:
+            break
+        #end
+
+        summary = '%s-%d' % (desc, len(input_set))
+        osize = len(input_set)
+
+        print 'generate %s w/ %d configs' % (summary, config_num)
+        syn = [RandomTest(0, (None, None, summary), config,
+                          syntuple = (smap[config][0], smap[config][1]))
+               for config in smap.keys()]
+        syn = ScoreTests(syn)
+        #print 'smap is %s' % (smap,)
+        #print 'syn is %s' % (' and '.join([str(x) for x in syn]))
+        GraphResults(summary, syn)
+    #end
+#end
+
+if __name__ == "__main__":
+    try:
+        RunCommand(['rm', '-rf', TMPDIR])
+        os.mkdir(TMPDIR)
+
+        rcsf = GetTestRcsFiles()
+        generator = rcsf.Generator()
+
+        #sample = SampleDataTest([SAMPLEDIR])
+        #generator = sample.Generator()
+
+        rand = random.Random(135135135135135)
+        RunTestLoop(rand, generator, TEST_ROUNDS)
+
+        #RunSpeedTest()
+
+        #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9']))
+        #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9', '-S', 'djw']))
+        #x3r = rcsf.AllPairsByDate(Xdelta3RunClass(['-9', '-T']))
+
+        #x1r = rcsf.AllPairsByDate(Xdelta1RunClass())
+
+    except CommandError:
+        pass
+    else:
+        RunCommand(['rm', '-rf', TMPDIR])
+        pass
+    #end
+#end
Index: /nikanabo/current/xdelta/diy/xdelta3-second.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-second.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-second.h	(revision 185)
@@ -0,0 +1,336 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2002, 2003, 2006, 2007.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _XDELTA3_SECOND_H_
+#define _XDELTA3_SECOND_H_
+
+/******************************************************************************************
+ Secondary compression
+ ******************************************************************************************/
+
+#define xd3_sec_data(s) ((s)->sec_stream_d)
+#define xd3_sec_inst(s) ((s)->sec_stream_i)
+#define xd3_sec_addr(s) ((s)->sec_stream_a)
+
+struct _xd3_sec_type
+{
+  int         id;
+  const char *name;
+  xd3_secondary_flags flags;
+
+  /* xd3_sec_stream is opaque to the generic code */
+  xd3_sec_stream* (*alloc)   (xd3_stream     *stream);
+  void            (*destroy) (xd3_stream     *stream,
+			      xd3_sec_stream *sec);
+  void            (*init)    (xd3_sec_stream *sec);
+  int             (*decode)  (xd3_stream     *stream,
+			      xd3_sec_stream *sec_stream,
+			      const uint8_t **input,
+			      const uint8_t  *input_end,
+			      uint8_t       **output,
+			      const uint8_t  *output_end);
+#if XD3_ENCODER
+  int             (*encode)  (xd3_stream     *stream,
+			      xd3_sec_stream *sec_stream,
+			      xd3_output     *input,
+			      xd3_output     *output,
+			      xd3_sec_cfg    *cfg);
+#endif
+};
+
+#define BIT_STATE_ENCODE_INIT { 0, 1 }
+#define BIT_STATE_DECODE_INIT { 0, 0x100 }
+
+typedef struct _bit_state bit_state;
+struct _bit_state
+{
+  usize_t cur_byte;
+  usize_t cur_mask;
+};
+
+static INLINE void xd3_bit_state_encode_init  (bit_state       *bits)
+{
+  bits->cur_byte = 0;
+  bits->cur_mask = 1;
+}
+
+static INLINE int xd3_decode_bits     (xd3_stream     *stream,
+				       bit_state      *bits,
+				       const uint8_t **input,
+				       const uint8_t  *input_max,
+				       usize_t          nbits,
+				       usize_t         *valuep)
+{
+  usize_t value = 0;
+  usize_t vmask = 1 << nbits;
+
+  if (bits->cur_mask == 0x100) { goto next_byte; }
+
+  for (;;)
+    {
+      do
+	{
+	  vmask >>= 1;
+
+	  if (bits->cur_byte & bits->cur_mask)
+	    {
+	      value |= vmask;
+	    }
+
+	  bits->cur_mask <<= 1;
+
+	  if (vmask == 1) { goto done; }
+	}
+      while (bits->cur_mask != 0x100);
+
+    next_byte:
+
+      if (*input == input_max)
+	{
+	  stream->msg = "secondary decoder end of input";
+	  return XD3_INTERNAL;
+	}
+
+      bits->cur_byte = *(*input)++;
+      bits->cur_mask = 1;
+    }
+
+ done:
+
+  IF_DEBUG2 (DP(RINT "(d) %u ", value));
+
+  (*valuep) = value;
+  return 0;
+}
+
+#if REGRESSION_TEST
+/* There may be extra bits at the end of secondary decompression, this macro checks for
+ * non-zero bits.  This is overly strict, but helps pass the single-bit-error regression
+ * test. */
+static int
+xd3_test_clean_bits (xd3_stream *stream, bit_state *bits)
+{
+  for (; bits->cur_mask != 0x100; bits->cur_mask <<= 1)
+    {
+      if (bits->cur_byte & bits->cur_mask)
+	{
+	  stream->msg = "secondary decoder garbage";
+	  return XD3_INTERNAL;
+	}
+    }
+
+  return 0;
+}
+#endif
+
+static xd3_sec_stream*
+xd3_get_secondary (xd3_stream *stream, xd3_sec_stream **sec_streamp)
+{
+  xd3_sec_stream *sec_stream;
+
+  if ((sec_stream = *sec_streamp) == NULL)
+    {
+      if ((*sec_streamp = stream->sec_type->alloc (stream)) == NULL)
+	{
+	  return NULL;
+	}
+
+      sec_stream = *sec_streamp;
+
+      /* If cuumulative stats, init once. */
+      stream->sec_type->init (sec_stream);
+    }
+
+  return sec_stream;
+}
+
+static int
+xd3_decode_secondary (xd3_stream      *stream,
+		      xd3_desect      *sect,
+		      xd3_sec_stream **sec_streamp)
+{
+  xd3_sec_stream *sec_stream;
+  uint32_t dec_size;
+  uint8_t *out_used;
+  int ret;
+
+  if ((sec_stream = xd3_get_secondary (stream, sec_streamp)) == NULL) { return ENOMEM; }
+
+  /* Decode the size, allocate the buffer. */
+  if ((ret = xd3_read_size (stream, & sect->buf, sect->buf_max, & dec_size)) ||
+      (ret = xd3_decode_allocate (stream, dec_size, & sect->copied2, & sect->alloc2, NULL, NULL)))
+    {
+      return ret;
+    }
+
+  out_used = sect->copied2;
+
+  if ((ret = stream->sec_type->decode (stream, sec_stream,
+				       & sect->buf, sect->buf_max,
+				       & out_used, out_used + dec_size))) { return ret; }
+
+  if (sect->buf != sect->buf_max)
+    {
+      stream->msg = "secondary decoder finished with unused input";
+      return XD3_INTERNAL;
+    }
+
+  if (out_used != sect->copied2 + dec_size)
+    {
+      stream->msg = "secondary decoder short output";
+      return XD3_INTERNAL;
+    }
+
+  sect->buf     = sect->copied2;
+  sect->buf_max = sect->copied2 + dec_size;
+
+  return 0;
+}
+
+#if XD3_ENCODER
+/* OPT: Should these be inline? */
+static INLINE int xd3_encode_bit       (xd3_stream      *stream,
+					xd3_output     **output,
+					bit_state       *bits,
+					int              bit)
+{
+  int ret;
+
+  if (bit)
+    {
+      bits->cur_byte |= bits->cur_mask;
+    }
+
+  /* OPT: Might help to buffer more than 8 bits at once. */
+  if (bits->cur_mask == 0x80)
+    {
+      if ((ret = xd3_emit_byte (stream, output, bits->cur_byte)) != 0) { return ret; }
+
+      bits->cur_mask = 1;
+      bits->cur_byte = 0;
+    }
+  else
+    {
+      bits->cur_mask <<= 1;
+    }
+
+  return 0;
+}
+
+static INLINE int xd3_flush_bits       (xd3_stream      *stream,
+					xd3_output     **output,
+					bit_state       *bits)
+{
+  return (bits->cur_mask == 1) ? 0 : xd3_emit_byte (stream, output, bits->cur_byte);
+}
+
+static INLINE int xd3_encode_bits      (xd3_stream      *stream,
+					xd3_output     **output,
+					bit_state       *bits,
+					usize_t           nbits,
+					usize_t           value)
+{
+  int ret;
+  usize_t mask = 1 << nbits;
+
+  XD3_ASSERT (nbits > 0);
+  XD3_ASSERT (nbits < sizeof (usize_t) * 8);
+  XD3_ASSERT (value < mask);
+
+  do
+    {
+      mask >>= 1;
+
+      if ((ret = xd3_encode_bit (stream, output, bits, value & mask))) { return ret; }
+    }
+  while (mask != 1);
+
+  IF_DEBUG2 (DP(RINT "(e) %u ", value));
+
+  return 0;
+}
+
+static int
+xd3_encode_secondary (xd3_stream      *stream,
+		      xd3_output     **head,
+		      xd3_output     **tail,
+		      xd3_sec_stream **sec_streamp,
+		      xd3_sec_cfg     *cfg,
+		      int             *did_it)
+{
+  xd3_sec_stream *sec_stream;
+  xd3_output     *tmp_head;
+  xd3_output     *tmp_tail;
+
+  usize_t comp_size;
+  usize_t orig_size;
+
+  int ret;
+
+  orig_size = xd3_sizeof_output (*head);
+
+  if (orig_size < SECONDARY_MIN_INPUT) { return 0; }
+
+  if ((sec_stream = xd3_get_secondary (stream, sec_streamp)) == NULL) { return ENOMEM; }
+
+  tmp_head = xd3_alloc_output (stream, NULL);
+
+  /* Encode the size, encode the data.  @@ Encoding the size makes it simpler, but is a
+   * little gross.  Should not need the entire section in contiguous memory, but it is
+   * much easier this way. */
+  if ((ret = xd3_emit_size (stream, & tmp_head, orig_size)) ||
+      (ret = stream->sec_type->encode (stream, sec_stream, *head, tmp_head, cfg))) { goto getout; }
+
+  /* If the secondary compressor determines its no good, it returns XD3_NOSECOND. */
+
+  /* Setup tmp_tail, comp_size */
+  tmp_tail  = tmp_head;
+  comp_size = tmp_head->next;
+
+  while (tmp_tail->next_page != NULL)
+    {
+      tmp_tail = tmp_tail->next_page;
+      comp_size += tmp_tail->next;
+    }
+
+  XD3_ASSERT (comp_size == xd3_sizeof_output (tmp_head));
+  XD3_ASSERT (tmp_tail != NULL);
+
+  if (comp_size < (orig_size - SECONDARY_MIN_SAVINGS))
+    {
+      IF_DEBUG1(DP(RINT "secondary saved %u bytes: %u -> %u (%0.2f%%)\n",
+			 orig_size - comp_size, orig_size, comp_size,
+			 (double) comp_size / (double) orig_size));
+
+      xd3_free_output (stream, *head);
+
+      *head = tmp_head;
+      *tail = tmp_tail;
+      *did_it = 1;
+    }
+  else
+    {
+    getout:
+      if (ret == XD3_NOSECOND) { ret = 0; }
+      xd3_free_output (stream, tmp_head);
+    }
+
+  return ret;
+}
+#endif /* XD3_ENCODER */
+#endif /* _XDELTA3_SECOND_H_ */
Index: /nikanabo/current/xdelta/diy/xdelta3-test.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-test.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-test.h	(revision 185)
@@ -0,0 +1,2324 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2001, 2003, 2004, 2005, 2006.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <math.h>
+
+#ifndef WIN32
+#include <sys/wait.h>
+#endif
+
+#define MSG_IS(x) (stream->msg != NULL && strcmp ((x), stream->msg) == 0)
+
+static const usize_t TWO_MEGS_AND_DELTA = (2 << 20) + (1 << 10);
+static const usize_t ADDR_CACHE_ROUNDS = 10000;
+
+static const usize_t TEST_FILE_MEAN    = 16384;
+static const double TEST_ADD_MEAN     = 16;
+static const double TEST_ADD_MAX      = 256;
+static const double TEST_ADD_RATIO    = 0.1;
+static const double TEST_EPSILON      = 0.55;
+
+#define TESTBUFSIZE (1024 * 16)
+
+#define TESTFILESIZE (1024)
+
+static char   TEST_TARGET_FILE[TESTFILESIZE];
+static char   TEST_SOURCE_FILE[TESTFILESIZE];
+static char   TEST_DELTA_FILE[TESTFILESIZE];
+static char   TEST_RECON_FILE[TESTFILESIZE];
+static char   TEST_RECON2_FILE[TESTFILESIZE];
+static char   TEST_COPY_FILE[TESTFILESIZE];
+static char   TEST_NOPERM_FILE[TESTFILESIZE];
+
+static int test_exponential_dist (usize_t mean, usize_t max);
+
+#define CHECK(cond) if (!(cond)) { DP(RINT "check failure: " #cond); abort(); }
+
+/* Use a fixed soft config so that test values are fixed.  See also test_compress_text(). */
+static const char* test_softcfg_str = "-C64,64,4,128,16,8,128";
+
+/******************************************************************************************
+ TEST HELPERS
+ ******************************************************************************************/
+
+static void DOT (void) { DP(RINT "."); }
+static int do_cmd (xd3_stream *stream, const char *buf)
+{
+  int ret;
+  if ((ret = system (buf)) != 0)
+    {
+      if (WIFEXITED (ret))
+	{
+	  stream->msg = "command exited non-zero";
+	}
+      else
+	{
+	  stream->msg = "abnormal command termination";
+	}
+      return XD3_INTERNAL;
+    }
+  DOT ();
+  return 0;
+}
+static int do_fail (xd3_stream *stream, const char *buf)
+{
+  int ret;
+  ret = system (buf);
+  if (! WIFEXITED (ret) || WEXITSTATUS (ret) != 1)
+    {
+      stream->msg = "command should have not succeeded";
+      DP(RINT "command was %s", buf);
+      return XD3_INTERNAL;
+    }
+  DOT ();
+  return 0;
+}
+
+static int
+test_exponential_dist (usize_t mean, usize_t max)
+{
+  double mean_d = mean;
+  double erand  = log (1.0 / (rand () / (double)RAND_MAX));
+  usize_t x = (usize_t) (mean_d * erand + 0.5);
+
+  return min (x, max);
+}
+
+/* Test that the exponential distribution actually produces its mean. */
+static int
+test_random_numbers (xd3_stream *stream, int ignore)
+{
+  int i;
+  usize_t sum = 0;
+  usize_t mean = 50;
+  usize_t n_rounds = 10000;
+  double average, error;
+  double allowed_error = 1.0;
+
+  for (i = 0; i < n_rounds; i += 1)
+    {
+      sum += test_exponential_dist (mean, USIZE_T_MAX);
+    }
+
+  average = (double) sum / (double) n_rounds;
+  error   = average - (double) mean;
+
+  if (error < allowed_error && error > -allowed_error)
+    {
+      /*DP(RINT "error is %f\n", error);*/
+      return 0;
+    }
+
+  stream->msg = "random distribution looks broken";
+  return XD3_INTERNAL;
+}
+
+static int
+test_setup (void)
+{
+  static int x = 0;
+  x++;
+  //DP(RINT "test setup: %d", x);
+  sprintf (TEST_TARGET_FILE, "/tmp/xdtest.target.%d", x);
+  sprintf (TEST_SOURCE_FILE, "/tmp/xdtest.source.%d", x);
+  sprintf (TEST_DELTA_FILE, "/tmp/xdtest.delta.%d", x);
+  sprintf (TEST_RECON_FILE, "/tmp/xdtest.recon.%d", x);
+  sprintf (TEST_RECON2_FILE, "/tmp/xdtest.recon2.%d", x);
+  sprintf (TEST_COPY_FILE, "/tmp/xdtest.copy.%d", x);
+  sprintf (TEST_NOPERM_FILE, "/tmp/xdtest.noperm.%d", x);
+  return 0;
+}
+
+static void
+test_unlink (char* file)
+{
+  char buf[TESTBUFSIZE];
+  while (unlink (file) != 0)
+    {
+      if (errno == ENOENT)
+	    {
+	      break;
+	    }
+      sprintf (buf, "rm -f %s", file);
+      system (buf);
+    }
+}
+
+static void
+test_cleanup (void)
+{
+  static int x = 0;
+  x++;
+  //DP(RINT "test cleanup: %d", x);  
+  test_unlink (TEST_TARGET_FILE);
+  test_unlink (TEST_SOURCE_FILE);
+  test_unlink (TEST_DELTA_FILE);
+  test_unlink (TEST_RECON_FILE);
+  test_unlink (TEST_RECON2_FILE);
+  test_unlink (TEST_COPY_FILE);
+  test_unlink (TEST_NOPERM_FILE);
+}
+
+static int
+test_make_inputs (xd3_stream *stream, xoff_t *ss_out, xoff_t *ts_out)
+{
+  usize_t ts = (rand () % TEST_FILE_MEAN) + TEST_FILE_MEAN;
+  usize_t ss = (rand () % TEST_FILE_MEAN) + TEST_FILE_MEAN;
+  uint8_t *buf = malloc (ts + ss), *sbuf = buf /*, *tbuf = buf + ss*/;
+  usize_t sadd = 0, sadd_max = ss * TEST_ADD_RATIO;
+  FILE  *tf /*, *sf*/;
+  usize_t i, j;
+  int ret;
+
+  if (buf == NULL) { return ENOMEM; }
+
+  if ((tf = fopen (TEST_TARGET_FILE, "w")) == NULL)
+    {
+      stream->msg = "write failed";
+      ret = get_errno ();
+      goto failure;
+    }
+
+  /* Then modify the data to produce copies, everything not copied is an add.  The
+   * following logic produces the TEST_ADD_RATIO.  The variable SADD contains the number
+   * of adds so far, which should not exceed SADD_MAX. */
+  for (i = 0; i < ss; )
+    {
+      usize_t left = ss - i;
+      usize_t next = test_exponential_dist (TEST_ADD_MEAN, TEST_ADD_MAX);
+      usize_t add_left = sadd_max - sadd;
+      double add_prob = (left == 0) ? 0 : (add_left / left);
+
+      next = min (left, next);
+
+      if (i > 0 && (next > add_left || (rand() / (double)RAND_MAX) >= add_prob))
+	{
+	  /* Copy */
+	  usize_t offset = rand () % i;
+
+	  for (j = 0; j < next; j += 1)
+	    {
+	      sbuf[i++] = sbuf[offset + j];
+	    }
+	}
+      else
+	{
+	  /* Add */
+	  for (j = 0; j < next; j += 1)
+	    {
+	      sbuf[i++] = rand ();
+	    }
+	}
+    }
+
+  if ((fwrite (sbuf, 1, ss, tf) != ss))
+    {
+      stream->msg = "write failed";
+      ret = get_errno ();
+      goto failure;
+    }
+
+  if ((ret = fclose (tf)) /* || (ret = fclose (sf))*/)
+    {
+      stream->msg = "close failed";
+      ret = get_errno ();
+      goto failure;
+    }
+
+  if (ts_out) { (*ts_out) = ts; }
+  if (ss_out) { (*ss_out) = ss; }
+
+ failure:
+  free (buf);
+  return ret;
+}
+
+static int
+compare_files (xd3_stream *stream, const char* tgt, const char *rec)
+{
+  FILE *orig, *recons;
+  static uint8_t obuf[TESTBUFSIZE], rbuf[TESTBUFSIZE];
+  int offset = 0;
+  int i;
+  int oc, rc;
+
+  if ((orig = fopen (tgt, "r")) == NULL)
+    {
+      DP(RINT "open %s failed", tgt);
+      stream->msg = "open failed";
+      return get_errno ();
+    }
+
+    if ((recons = fopen (rec, "r")) == NULL)
+      {
+	DP(RINT "open %s failed", rec);
+	stream->msg = "open failed";
+	return get_errno ();
+      }
+
+  for (;;)
+    {
+      oc = fread (obuf, 1, TESTBUFSIZE, orig);
+      rc = fread (rbuf, 1, TESTBUFSIZE, recons);
+
+      if (oc < 0 || rc < 0)
+	{
+	  stream->msg = "read failed";
+	  return get_errno ();
+	}
+
+	if (oc != rc)
+	  {
+	    stream->msg = "compare files: different length";
+	    return XD3_INTERNAL;
+	  }
+
+	if (oc == 0)
+	  {
+	    break;
+	  }
+
+	for (i = 0; i < oc; i += 1)
+	  {
+	    if (obuf[i] != rbuf[i])
+	      {
+		stream->msg = "compare files: different values";
+		return XD3_INTERNAL;
+	      }
+	  }
+
+	offset += oc;
+    }
+
+    fclose (orig);
+    fclose (recons);
+    return 0;
+}
+
+static int
+test_save_copy (const char *origname)
+{
+  char buf[TESTBUFSIZE];
+  int ret;
+
+  sprintf (buf, "cp -f %s %s", origname, TEST_COPY_FILE);
+
+  if ((ret = system (buf)) != 0)
+    {
+      return XD3_INTERNAL;
+    }
+
+  return 0;
+}
+
+static int
+test_file_size (const char* file, xoff_t *size)
+{
+  struct stat sbuf;
+  int ret;
+  (*size) = 0;
+
+  if (stat (file, & sbuf) < 0)
+    {
+      ret = get_errno ();
+      DP(RINT "xdelta3: stat failed: %s: %s\n", file, strerror (ret));
+      return ret;
+    }
+
+  if (! S_ISREG (sbuf.st_mode))
+    {
+      ret = XD3_INTERNAL;
+      DP(RINT "xdelta3: not a regular file: %s: %s\n", file, strerror (ret));
+      return ret;
+    }
+
+  (*size) = sbuf.st_size;
+  return 0;
+}
+
+/******************************************************************************************
+ READ OFFSET
+ ******************************************************************************************/
+
+/* Common test for read_integer errors: encodes a 64-bit value and then attempts to read
+ * as a 32-bit value.  If TRUNC is non-zero, attempts to get errors by shortening the
+ * input, otherwise it should overflow.  Expects XD3_INTERNAL and MSG. */
+static int
+test_read_integer_error (xd3_stream *stream, int trunto, const char *msg)
+{
+  uint64_t eval = 1ULL << 34;
+  uint32_t rval;
+  xd3_output *buf = NULL;
+  const uint8_t *max;
+  const uint8_t *inp;
+  int ret;
+
+  buf = xd3_alloc_output (stream, buf);
+
+  if ((ret = xd3_emit_uint64_t (stream, & buf, eval)))
+    {
+      goto fail;
+    }
+
+ again:
+
+  inp = buf->base;
+  max = buf->base + buf->next - trunto;
+
+  if ((ret = xd3_read_uint32_t (stream, & inp, max, & rval)) != XD3_INVALID_INPUT ||
+      !MSG_IS (msg))
+    {
+      ret = XD3_INTERNAL;
+    }
+  else if (trunto && trunto < buf->next)
+    {
+      trunto += 1;
+      goto again;
+    }
+  else
+    {
+      ret = 0;
+    }
+
+ fail:
+  xd3_free_output (stream, buf);
+  return ret;
+}
+
+/* Test integer overflow using the above routine. */
+static int
+test_decode_integer_overflow (xd3_stream *stream, int unused)
+{
+  return test_read_integer_error (stream, 0, "overflow in read_intger");
+}
+
+/* Test integer EOI using the above routine. */
+static int
+test_decode_integer_end_of_input (xd3_stream *stream, int unused)
+{
+  return test_read_integer_error (stream, 1, "end-of-input in read_integer");
+}
+
+/* Test that emit_integer/decode_integer/sizeof_integer/read_integer work on correct
+ * inputs.  Tests powers of (2^7), plus or minus, up to the maximum value. */
+#define TEST_ENCODE_DECODE_INTEGER(TYPE,ONE,MAX)                                \
+  xd3_output *rbuf = NULL;                                                      \
+  xd3_output *dbuf = NULL;                                                      \
+  TYPE values[64];                                                              \
+  int nvalues = 0;                                                              \
+  int i, ret = 0;                                                               \
+                                                                                \
+  for (i = 0; i < (sizeof (TYPE) * 8); i += 7)                                  \
+    {                                                                           \
+      values[nvalues++] = (ONE << i) - ONE;                                     \
+      values[nvalues++] = (ONE << i);                                           \
+      values[nvalues++] = (ONE << i) + ONE;                                     \
+    }                                                                           \
+                                                                                \
+  values[nvalues++] = MAX-ONE;                                                  \
+  values[nvalues++] = MAX;                                                      \
+                                                                                \
+  rbuf = xd3_alloc_output (stream, rbuf);                                       \
+  dbuf = xd3_alloc_output (stream, dbuf);                                       \
+                                                                                \
+  for (i = 0; i < nvalues; i += 1)                                              \
+    {                                                                           \
+      const uint8_t *max;                                                       \
+      const uint8_t *inp;                                                       \
+      TYPE val;                                                                 \
+                                                                                \
+      DOT ();                                                                   \
+      rbuf->next = 0;                                                           \
+                                                                                \
+      if ((ret = xd3_emit_ ## TYPE (stream, & rbuf, values[i])) ||              \
+	  (ret = xd3_emit_ ## TYPE (stream, & dbuf, values[i])))                \
+	{                                                                       \
+	  goto fail;                                                            \
+	}                                                                       \
+                                                                                \
+      inp = rbuf->base;                                                         \
+      max = rbuf->base + rbuf->next;                                            \
+                                                                                \
+      if (rbuf->next != xd3_sizeof_ ## TYPE (values[i]))                        \
+	{                                                                       \
+	  ret = XD3_INTERNAL;                                                         \
+	  goto fail;                                                            \
+	}                                                                       \
+                                                                                \
+      if ((ret = xd3_read_ ## TYPE (stream, & inp, max, & val)))                \
+	{                                                                       \
+	  goto fail;                                                            \
+	}                                                                       \
+                                                                                \
+      if (val != values[i])                                                     \
+	{                                                                       \
+	  ret = XD3_INTERNAL;                                                         \
+	  goto fail;                                                            \
+	}                                                                       \
+                                                                                \
+      DOT ();                                                                   \
+    }                                                                           \
+                                                                                \
+  stream->next_in  = dbuf->base;                                                \
+  stream->avail_in = dbuf->next;                                                \
+                                                                                \
+  for (i = 0; i < nvalues; i += 1)                                              \
+    {                                                                           \
+      TYPE val;                                                                 \
+                                                                                \
+      if ((ret = xd3_decode_ ## TYPE (stream, & val)))                          \
+        {                                                                       \
+          goto fail;                                                            \
+        }                                                                       \
+                                                                                \
+      if (val != values[i])                                                     \
+        {                                                                       \
+          ret = XD3_INTERNAL;                                                         \
+          goto fail;                                                            \
+        }                                                                       \
+    }                                                                           \
+                                                                                \
+  if (stream->avail_in != 0)                                                    \
+    {                                                                           \
+      ret = XD3_INTERNAL;                                                             \
+      goto fail;                                                                \
+    }                                                                           \
+                                                                                \
+ fail:                                                                          \
+  xd3_free_output (stream, rbuf);                                               \
+  xd3_free_output (stream, dbuf);                                               \
+                                                                                \
+  return ret
+
+static int
+test_encode_decode_uint32_t (xd3_stream *stream, int unused)
+{
+  TEST_ENCODE_DECODE_INTEGER(uint32_t,1U,UINT32_MAX);
+}
+
+static int
+test_encode_decode_uint64_t (xd3_stream *stream, int unused)
+{
+  TEST_ENCODE_DECODE_INTEGER(uint64_t,1ULL,UINT64_MAX);
+}
+
+static int
+test_usize_t_overflow (xd3_stream *stream, int unused)
+{
+  if (USIZE_T_OVERFLOW (0, 0)) { goto fail; }
+  if (USIZE_T_OVERFLOW (USIZE_T_MAX, 0)) { goto fail; }
+  if (USIZE_T_OVERFLOW (0, USIZE_T_MAX)) { goto fail; }
+  if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, 0)) { goto fail; }
+  if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2)) { goto fail; }
+  if (USIZE_T_OVERFLOW (USIZE_T_MAX / 2, USIZE_T_MAX / 2 + 1)) { goto fail; }
+
+  if (! USIZE_T_OVERFLOW (USIZE_T_MAX, 1)) { goto fail; }
+  if (! USIZE_T_OVERFLOW (1, USIZE_T_MAX)) { goto fail; }
+  if (! USIZE_T_OVERFLOW (USIZE_T_MAX / 2 + 1, USIZE_T_MAX / 2 + 1)) { goto fail; }
+
+  return 0;
+
+ fail:
+  stream->msg = "incorrect overflow computation";
+  return XD3_INTERNAL;
+}
+
+/******************************************************************************************
+ Address cache
+ ******************************************************************************************/
+
+static int
+test_address_cache (xd3_stream *stream, int unused)
+{
+  int ret, i;
+  usize_t offset;
+  usize_t *addrs;
+  uint8_t *big_buf, *buf_max;
+  const uint8_t *buf;
+  xd3_output *outp;
+  uint8_t *modes;
+  int mode_counts[16];
+
+  stream->acache.s_near = stream->code_table_desc->near_modes;
+  stream->acache.s_same = stream->code_table_desc->same_modes;
+
+  if ((ret = xd3_encode_init (stream))) { return ret; }
+
+  addrs = xd3_alloc (stream, sizeof (usize_t), ADDR_CACHE_ROUNDS);
+  modes = xd3_alloc (stream, sizeof (uint8_t), ADDR_CACHE_ROUNDS);
+
+  memset (mode_counts, 0, sizeof (mode_counts));
+  memset (modes, 0, ADDR_CACHE_ROUNDS);
+
+  addrs[0] = 0;
+
+  srand (0x9f73f7fc);
+
+  /* First pass: encode addresses */
+  xd3_init_cache (& stream->acache);
+
+  for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1)
+    {
+      double p;
+      usize_t addr;
+      usize_t prev_i;
+      usize_t nearby;
+
+      p         = (rand () / (double)RAND_MAX);
+      prev_i    = rand () % offset;
+      nearby    = (rand () % 256) % offset, 1;
+      nearby    = max (1U, nearby);
+
+      if (p < 0.1)      { addr = addrs[offset-nearby]; }
+      else if (p < 0.4) { addr = min (addrs[prev_i] + nearby, offset-1); }
+      else              { addr = prev_i; }
+
+      if ((ret = xd3_encode_address (stream, addr, offset, & modes[offset]))) { return ret; }
+
+      addrs[offset] = addr;
+      mode_counts[modes[offset]] += 1;
+    }
+
+  /* Copy addresses into a contiguous buffer. */
+  big_buf = xd3_alloc (stream, xd3_sizeof_output (ADDR_HEAD (stream)), 1);
+
+  for (offset = 0, outp = ADDR_HEAD (stream); outp != NULL; offset += outp->next, outp = outp->next_page)
+    {
+      memcpy (big_buf + offset, outp->base, outp->next);
+    }
+
+  buf_max = big_buf + offset;
+  buf     = big_buf;
+
+  /* Second pass: decode addresses */
+  xd3_init_cache (& stream->acache);
+
+  for (offset = 1; offset < ADDR_CACHE_ROUNDS; offset += 1)
+    {
+      uint32_t addr;
+
+      if ((ret = xd3_decode_address (stream, offset, modes[offset], & buf, buf_max, & addr))) { return ret; }
+
+      if (addr != addrs[offset])
+	{
+	  stream->msg = "incorrect decoded address";
+	  return XD3_INTERNAL;
+	}
+    }
+
+  /* Check that every byte, mode was used. */
+  if (buf != buf_max)
+    {
+      stream->msg = "address bytes not used";
+      return XD3_INTERNAL;
+    }
+
+  for (i = 0; i < (2 + stream->acache.s_same + stream->acache.s_near); i += 1)
+    {
+      if (mode_counts[i] == 0)
+	{
+	  stream->msg = "address mode not used";
+	  return XD3_INTERNAL;
+	}
+    }
+
+  xd3_free (stream, modes);
+  xd3_free (stream, addrs);
+  xd3_free (stream, big_buf);
+
+  return 0;
+}
+
+/******************************************************************************************
+ Encode and decode with single bit error
+ ******************************************************************************************/
+
+/* It compresses from 256 to around 185 bytes.
+ * Avoids matching addresses that are a single-bit difference.
+ * Avoids matching address 0. */
+static const uint8_t test_text[] =
+"this is a story\n"
+"abouttttttttttt\n"
+"- his is a stor\n"
+"- about nothing "
+" all. boutique -"
+"his story is a -"
+"about           "
+"what happens all"
+" the time what -"
+"am I ttttttt the"
+" person said, so"
+" what, per son -"
+" gory story is -"
+" about nothing -"
+"tttttt to test -"
+"his sto nothing";
+
+static const uint8_t test_apphead[] = "header test";
+
+static int
+test_compress_text (xd3_stream  *stream,
+		    uint8_t     *encoded,
+		    usize_t     *encoded_size)
+{
+  int ret;
+  xd3_config cfg;
+  int oflags = stream->flags;
+  int flags = stream->flags | XD3_FLUSH;
+
+  xd3_free_stream (stream);
+  xd3_init_config (& cfg, flags);
+
+  /* This configuration is fixed so that the "expected non-error" the counts in
+   * decompress_single_bit_errors are too.  See test_coftcfg_str. */
+  cfg.smatch_cfg = XD3_SMATCH_SOFT;
+  cfg.smatcher_soft.name = "test";
+  cfg.smatcher_soft.large_look = 64; /* no source, not used */
+  cfg.smatcher_soft.large_step = 64; /* no source, not used */
+  cfg.smatcher_soft.small_look = 4;
+  cfg.smatcher_soft.small_chain = 128;
+  cfg.smatcher_soft.small_lchain = 16;
+  cfg.smatcher_soft.max_lazy = 8;
+  cfg.smatcher_soft.long_enough = 128;
+  
+  xd3_config_stream (stream, & cfg);
+
+  (*encoded_size) = 0;
+
+  xd3_set_appheader (stream, test_apphead, sizeof (test_apphead));
+
+  if ((ret = xd3_encode_stream (stream, test_text, sizeof (test_text),
+				encoded, encoded_size, 4*sizeof (test_text)))) { goto fail; }
+
+  if ((ret = xd3_close_stream (stream))) { goto fail; }
+
+ fail:
+  xd3_free_stream (stream);
+  xd3_init_config (& cfg, oflags);
+  xd3_config_stream (stream, & cfg);
+  return ret;
+}
+
+static int
+test_decompress_text (xd3_stream *stream, uint8_t *enc, usize_t enc_size, usize_t test_desize)
+{
+  xd3_config cfg;
+  char decoded[sizeof (test_text)];
+  uint8_t *apphead;
+  usize_t apphead_size;
+  usize_t decoded_size;
+  const char *msg;
+  int  ret;
+  usize_t pos = 0;
+  int flags = stream->flags;
+  usize_t take;
+
+ input:
+  /* Test decoding test_desize input bytes at a time */
+  take = min (enc_size - pos, test_desize);
+  CHECK(take > 0);
+
+  xd3_avail_input (stream, enc + pos, take);
+ again:
+  ret = xd3_decode_input (stream);
+
+  pos += take;
+  take = 0;
+
+  switch (ret)
+    {
+    case XD3_OUTPUT:
+      break;
+    case XD3_WINSTART:
+    case XD3_GOTHEADER:
+      goto again;
+    case XD3_INPUT:
+      if (pos < enc_size) { goto input; }
+      /* else fallthrough */
+    case XD3_WINFINISH:
+    default:
+      goto fail;
+    }
+
+  CHECK(ret == XD3_OUTPUT);
+  CHECK(pos == enc_size);
+
+  if (stream->avail_out != sizeof (test_text))
+    {
+      stream->msg = "incorrect output size";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+  decoded_size = stream->avail_out;
+  memcpy (decoded, stream->next_out, stream->avail_out);
+
+  xd3_consume_output (stream);
+
+  if ((ret = xd3_get_appheader (stream, & apphead, & apphead_size))) { goto fail; }
+
+  if (apphead_size != sizeof (test_apphead) || memcmp (apphead, test_apphead, sizeof (test_apphead)) != 0)
+    {
+      stream->msg = "incorrect appheader";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+  if ((ret = xd3_decode_input (stream)) != XD3_WINFINISH ||
+      (ret = xd3_close_stream (stream)) != 0)
+    {
+      goto fail;
+    }
+
+  if (decoded_size != sizeof (test_text) || memcmp (decoded, test_text, sizeof (test_text)) != 0)
+    {
+      stream->msg = "incorrect output text";
+      ret = EIO;
+    }
+
+ fail:
+  msg = stream->msg;
+  xd3_free_stream (stream);
+  xd3_init_config (& cfg, flags);
+  xd3_config_stream (stream, & cfg);
+  stream->msg = msg;
+
+  return ret;
+}
+
+static int
+test_decompress_single_bit_error (xd3_stream *stream, int expected_non_failures)
+{
+  int ret;
+  int i;
+  uint8_t encoded[4*sizeof (test_text)]; /* make room for alt code table */
+  usize_t  encoded_size;
+  int non_failures = 0;
+  int cksum = (stream->flags & XD3_ADLER32) != 0;
+
+#if 1
+#define TEST_FAILURES()
+#else
+  /* For checking non-failure cases by hand, enable this macro and run xdelta printdelta
+   * with print_cpymode enabled.  Every non-failure should change a copy address mode,
+   * which doesn't cause a failure because the address cache starts out with all zeros.
+
+    ./xdelta3 test
+    for i in test_text.xz.*; do ./xdelta3 printdelta $i > $i.out; diff $i.out test_text.xz.0.out; done
+
+   */
+  system ("rm -rf test_text.*");
+  {
+    char buf[TESTBUFSIZE];
+    FILE *f;
+    sprintf (buf, "test_text");
+    f = fopen (buf, "w");
+    fwrite (test_text,1,sizeof (test_text),f);
+    fclose (f);
+  }
+#define TEST_FAILURES()                                                         \
+  do {                                                                          \
+    char buf[TESTBUFSIZE]                                                       \
+    FILE *f;                                                                    \
+    sprintf (buf, "test_text.xz.%d", non_failures);                             \
+    f = fopen (buf, "w");                                                       \
+    fwrite (encoded,1,encoded_size,f);                                          \
+    fclose (f);                                                                 \
+  } while (0)
+#endif
+
+  stream->sec_data.inefficient = 1;
+  stream->sec_inst.inefficient = 1;
+  stream->sec_addr.inefficient = 1;
+
+  /* Encode text, test correct input */
+  if ((ret = test_compress_text (stream, encoded, & encoded_size)))
+    {
+      /*stream->msg = "without error: encode failure";*/
+      return ret;
+    }
+  if ((ret = test_decompress_text (stream, encoded, encoded_size, sizeof (test_text) / 4)))
+    {
+      /*stream->msg = "without error: decode failure";*/
+      return ret;
+    }
+
+  TEST_FAILURES();
+
+  for (i = 0; i < encoded_size*8; i += 1)
+    {
+      /* Single bit error. */
+      encoded[i/8] ^= 1 << (i%8);
+
+      if ((ret = test_decompress_text (stream, encoded, encoded_size, sizeof (test_text))) == 0)
+	{
+	  non_failures += 1;
+	  /*DP(RINT "%u[%u] non-failure %u\n", i/8, i%8, non_failures);*/
+	  TEST_FAILURES();
+	}
+      else
+	{
+	  /*DP(RINT "%u[%u] failure: %s\n", i/8, i%8, stream->msg);*/
+	}
+
+      /* decompress_text returns EIO when the final memcmp() fails, but that
+       * should never happen with checksumming on. */
+      if (cksum && ret == EIO)
+	{
+	  /*DP(RINT "%u[%u] cksum mismatch\n", i/8, i%8);*/
+	  stream->msg = "checksum mismatch";
+	  return XD3_INTERNAL;
+	}
+
+      /* Undo single bit error. */
+      encoded[i/8] ^= 1 << (i%8);
+    }
+
+  /* Test correct input again */
+  if ((ret = test_decompress_text (stream, encoded, encoded_size, 1)))
+    {
+      /*stream->msg = "without error: decode failure";*/
+      return ret;
+    }
+
+  /* Check expected non-failures */
+  if (non_failures != expected_non_failures)
+    {
+      DP(RINT "non-failures %u; expected %u", non_failures, expected_non_failures);
+      stream->msg = "incorrect";
+      return XD3_INTERNAL;
+    }
+
+  DOT ();
+
+  return 0;
+}
+
+/******************************************************************************************
+ Secondary compression tests
+ ******************************************************************************************/
+
+#if SECONDARY_ANY
+typedef int (*sec_dist_func) (xd3_stream *stream, xd3_output *data);
+
+static int sec_dist_func1 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func2 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func3 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func4 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func5 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func6 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func7 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func8 (xd3_stream *stream, xd3_output *data);
+static int sec_dist_func9 (xd3_stream *stream, xd3_output *data);
+
+static sec_dist_func sec_dists[] =
+{
+  sec_dist_func1,
+  sec_dist_func2,
+  sec_dist_func3,
+  sec_dist_func4,
+  sec_dist_func5,
+  sec_dist_func6,
+  sec_dist_func7,
+  sec_dist_func8,
+  sec_dist_func9,
+};
+
+/* Test ditsribution: 100 bytes of the same character (13). */
+static int
+sec_dist_func1 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret;
+  for (i = 0; i < 100; i += 1)
+    {
+      if ((ret = xd3_emit_byte (stream, & data, 13))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test ditsribution: uniform covering half the alphabet. */
+static int
+sec_dist_func2 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret;
+  for (i = 0; i < ALPHABET_SIZE; i += 1)
+    {
+      if ((ret = xd3_emit_byte (stream, & data, i%(ALPHABET_SIZE/2)))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test ditsribution: uniform covering the entire alphabet. */
+static int
+sec_dist_func3 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret;
+  for (i = 0; i < ALPHABET_SIZE; i += 1)
+    {
+      if ((ret = xd3_emit_byte (stream, & data, i%ALPHABET_SIZE))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: An exponential distribution covering half the alphabet */
+static int
+sec_dist_func4 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret, x;
+  for (i = 0; i < ALPHABET_SIZE*20; i += 1)
+    {
+      x = test_exponential_dist (10, ALPHABET_SIZE/2);
+      if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: An exponential distribution covering the entire alphabet */
+static int
+sec_dist_func5 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret, x;
+  for (i = 0; i < ALPHABET_SIZE*20; i += 1)
+    {
+      x = test_exponential_dist (10, ALPHABET_SIZE-1);
+      if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: An uniform random distribution covering half the alphabet */
+static int
+sec_dist_func6 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret, x;
+  for (i = 0; i < ALPHABET_SIZE*20; i += 1)
+    {
+      x = rand () % (ALPHABET_SIZE/2);
+      if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: An uniform random distribution covering the entire alphabet */
+static int
+sec_dist_func7 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret, x;
+  for (i = 0; i < ALPHABET_SIZE*20; i += 1)
+    {
+      x = rand () % ALPHABET_SIZE;
+      if ((ret = xd3_emit_byte (stream, & data, x))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: A small number of frequent characters, difficult to divide into many
+ * groups */
+static int
+sec_dist_func8 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret;
+  for (i = 0; i < ALPHABET_SIZE*5; i += 1)
+    {
+      if ((ret = xd3_emit_byte (stream, & data, 0))) { return ret; }
+      if ((ret = xd3_emit_byte (stream, & data, 64))) { return ret; }
+      if ((ret = xd3_emit_byte (stream, & data, 128))) { return ret; }
+      if ((ret = xd3_emit_byte (stream, & data, 255))) { return ret; }
+    }
+  return 0;
+}
+
+/* Test distribution: One that causes many FGK block promotions (found a bug) */
+static int
+sec_dist_func9 (xd3_stream *stream, xd3_output *data)
+{
+  int i, ret;
+
+  int ramp   = 0;
+  int rcount = 0;
+  int prom   = 0;
+  int pcount = 0;
+
+  /* 200 was long enough to trigger it--only when stricter checking that counted all
+   * blocks was turned on, but it seems I deleted this code. (missing fgk_free_block on
+   * line 398). */
+  for (i = 0; i < ALPHABET_SIZE*200; i += 1)
+    {
+    repeat:
+      if (ramp < ALPHABET_SIZE)
+	{
+	  /* Initially Nth symbol has (N+1) frequency */
+	  if (rcount <= ramp)
+	    {
+	      rcount += 1;
+	      if ((ret = xd3_emit_byte (stream, & data, ramp))) { return ret; }
+	      continue;
+	    }
+
+	  ramp   += 1;
+	  rcount  = 0;
+	  goto repeat;
+	}
+
+      /* Thereafter, promote least freq to max freq */
+      if (pcount == ALPHABET_SIZE)
+	{
+	  pcount = 0;
+	  prom   = (prom + 1) % ALPHABET_SIZE;
+	}
+
+      pcount += 1;
+      if ((ret = xd3_emit_byte (stream, & data, prom))) { return ret; }
+    }
+
+  return 0;
+}
+
+static int
+test_secondary_decode (xd3_stream         *stream,
+		       const xd3_sec_type *sec,
+		       usize_t              input_size,
+		       usize_t              compress_size,
+		       const uint8_t      *dec_input,
+		       const uint8_t      *dec_correct,
+		       uint8_t            *dec_output)
+{
+  int ret;
+  xd3_sec_stream *dec_stream;
+  const uint8_t *dec_input_used, *dec_input_end;
+  uint8_t *dec_output_used, *dec_output_end;
+
+  if ((dec_stream = sec->alloc (stream)) == NULL) { return ENOMEM; }
+
+  sec->init (dec_stream);
+
+  dec_input_used = dec_input;
+  dec_input_end  = dec_input + compress_size;
+
+  dec_output_used = dec_output;
+  dec_output_end  = dec_output + input_size;
+
+  if ((ret = sec->decode (stream, dec_stream,
+			  & dec_input_used, dec_input_end,
+			  & dec_output_used, dec_output_end)))
+    {
+      goto fail;
+    }
+
+  if (dec_input_used != dec_input_end)
+    {
+      stream->msg = "unused input";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+  if (dec_output_used != dec_output_end)
+    {
+      stream->msg = "unfinished output";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+  if (memcmp (dec_output, dec_correct, input_size) != 0)
+    {
+      stream->msg = "incorrect output";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+ fail:
+  sec->destroy (stream, dec_stream);
+  return ret;
+}
+
+static int
+test_secondary (xd3_stream *stream, const xd3_sec_type *sec, int groups)
+{
+  int test_i, ret;
+  xd3_output *in_head, *out_head, *p;
+  usize_t p_off, input_size, compress_size;
+  uint8_t *dec_input = NULL, *dec_output = NULL, *dec_correct = NULL;
+  xd3_sec_stream *enc_stream;
+  xd3_sec_cfg cfg;
+
+  memset (& cfg, 0, sizeof (cfg));
+
+  cfg.inefficient = 1;
+
+  for (cfg.ngroups = 1; cfg.ngroups <= groups; cfg.ngroups += 1)
+    {
+      DP(RINT "\n...");
+      for (test_i = 0; test_i < SIZEOF_ARRAY (sec_dists); test_i += 1)
+	{
+	  srand (0x84687674);
+
+	  in_head  = xd3_alloc_output (stream, NULL);
+	  out_head = xd3_alloc_output (stream, NULL);
+	  enc_stream = sec->alloc (stream);
+	  dec_input = NULL;
+	  dec_output = NULL;
+	  dec_correct = NULL;
+
+	  if (in_head == NULL || out_head == NULL || enc_stream == NULL) { goto nomem; }
+
+	  if ((ret = sec_dists[test_i] (stream, in_head))) { goto fail; }
+
+	  sec->init (enc_stream);
+
+	  /* Encode data */
+	  if ((ret = sec->encode (stream, enc_stream, in_head, out_head, & cfg)))
+	    {
+	      DP(RINT "test %u: encode: %s", test_i, stream->msg);
+	      goto fail;
+	    }
+
+	  /* Calculate sizes, allocate contiguous arrays for decoding */
+	  input_size    = xd3_sizeof_output (in_head);
+	  compress_size = xd3_sizeof_output (out_head);
+
+	  DP(RINT "%.3f", 8.0 * (double) compress_size / (double) input_size);
+
+	  if ((dec_input   = xd3_alloc (stream, compress_size, 1)) == NULL ||
+	      (dec_output  = xd3_alloc (stream, input_size, 1)) == NULL ||
+	      (dec_correct = xd3_alloc (stream, input_size, 1)) == NULL) { goto nomem; }
+
+	  /* Fill the compressed data array */
+	  for (p_off = 0, p = out_head; p != NULL; p_off += p->next, p = p->next_page)
+	    {
+	      memcpy (dec_input + p_off, p->base, p->next);
+	    }
+
+	  CHECK(p_off == compress_size);
+
+	  /* Fill the input data array */
+	  for (p_off = 0, p = in_head; p != NULL; p_off += p->next, p = p->next_page)
+	    {
+	      memcpy (dec_correct + p_off, p->base, p->next);
+	    }
+
+	  CHECK(p_off == input_size);
+
+	  if ((ret = test_secondary_decode (stream, sec, input_size, compress_size, dec_input, dec_correct, dec_output)))
+	    {
+	      DP(RINT "test %u: decode: %s", test_i, stream->msg);
+	      goto fail;
+	    }
+
+	  /* Single-bit error test, only cover the first 10 bytes.  Some non-failures are
+	   * expected in the Huffman case: Changing the clclen array, for example, may not
+	   * harm the decoding.  Really looking for faults here. */
+	  {
+	    int i;
+	    int bytes = min (compress_size, 10U);
+	    for (i = 0; i < bytes * 8; i += 1)
+	      {
+		dec_input[i/8] ^= 1 << (i%8);
+
+		if ((ret = test_secondary_decode (stream, sec, input_size, compress_size, dec_input, dec_correct, dec_output)) == 0)
+		  {
+		    /*DP(RINT "test %u: decode single-bit [%u/%u] error non-failure", test_i, i/8, i%8);*/
+		  }
+
+		dec_input[i/8] ^= 1 << (i%8);
+
+		if ((i % (2*bytes)) == (2*bytes)-1)
+		  {
+		    DOT ();
+		  }
+	      }
+	    ret = 0;
+	  }
+
+	  if (0) { nomem: ret = ENOMEM; }
+
+	fail:
+	  sec->destroy (stream, enc_stream);
+	  xd3_free_output (stream, in_head);
+	  xd3_free_output (stream, out_head);
+	  xd3_free (stream, dec_input);
+	  xd3_free (stream, dec_output);
+	  xd3_free (stream, dec_correct);
+
+	  if (ret != 0) { return ret; }
+	}
+    }
+
+  return 0;
+}
+
+IF_FGK (static int test_secondary_fgk  (xd3_stream *stream, int gp) { return test_secondary (stream, & fgk_sec_type, gp); })
+IF_DJW (static int test_secondary_huff (xd3_stream *stream, int gp) { return test_secondary (stream, & djw_sec_type, gp); })
+#endif
+
+/******************************************************************************************
+ TEST INSTRUCTION TABLE
+ ******************************************************************************************/
+
+/* Test that xd3_choose_instruction() does the right thing for its code table. */
+static int
+test_choose_instruction (xd3_stream *stream, int ignore)
+{
+  int i;
+
+  stream->code_table = (*stream->code_table_func) ();
+
+  for (i = 0; i < 256; i += 1)
+    {
+      const xd3_dinst *d = stream->code_table + i;
+      xd3_rinst prev, inst;
+
+      CHECK(d->type1 > 0);
+
+      memset (& prev, 0, sizeof (prev));
+      memset (& inst, 0, sizeof (inst));
+
+      if (d->type2 == 0)
+	{
+	  inst.type = d->type1;
+
+	  if ((inst.size = d->size1) == 0)
+	    {
+	      inst.size = TESTBUFSIZE;
+	    }
+
+	  XD3_CHOOSE_INSTRUCTION (stream, NULL, & inst);
+
+	  if (inst.code2 != 0 || inst.code1 != i)
+	    {
+	      stream->msg = "wrong single instruction";
+	      return XD3_INTERNAL;
+	    }
+	}
+      else
+	{
+	  prev.type = d->type1;
+	  prev.size = d->size1;
+	  inst.type = d->type2;
+	  inst.size = d->size2;
+
+	  XD3_CHOOSE_INSTRUCTION (stream, & prev, & inst);
+
+	  if (prev.code2 != i)
+	    {
+	      stream->msg = "wrong double instruction";
+	      return XD3_INTERNAL;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ TEST INSTRUCTION TABLE CODING
+ ******************************************************************************************/
+
+#if GENERIC_ENCODE_TABLES
+/* Test that encoding and decoding a code table works */
+static int
+test_encode_code_table (xd3_stream *stream, int ignore)
+{
+  int ret;
+  const uint8_t *comp_data;
+  usize_t comp_size;
+
+  if ((ret = xd3_compute_alternate_table_encoding (stream, & comp_data, & comp_size)))
+    {
+      return ret;
+    }
+
+  stream->acache.s_near = __alternate_code_table_desc.near_modes;
+  stream->acache.s_same = __alternate_code_table_desc.same_modes;
+
+  if ((ret = xd3_apply_table_encoding (stream, comp_data, comp_size)))
+    {
+      return ret;
+    }
+
+  if (memcmp (stream->code_table, xd3_alternate_code_table (), sizeof (xd3_dinst) * 256) != 0)
+    {
+      stream->msg = "wrong code table reconstruction";
+      return XD3_INTERNAL;
+    }
+
+  return 0;
+}
+#endif
+
+/******************************************************************************************
+ 64BIT STREAMING
+ ******************************************************************************************/
+
+/* This test encodes and decodes a series of 1 megabyte windows, each containing a long
+ * run of zeros along with a single xoff_t size record to indicate the sequence. */
+static int
+test_streaming (xd3_stream *in_stream, uint8_t *encbuf, uint8_t *decbuf, uint8_t *delbuf, usize_t megs)
+{
+  xd3_stream estream, dstream;
+  int ret;
+  usize_t i, delsize, decsize;
+
+  if ((ret = xd3_config_stream (& estream, NULL)) ||
+      (ret = xd3_config_stream (& dstream, NULL)))
+    {
+      goto fail;
+    }
+
+  for (i = 0; i < megs; i += 1)
+    {
+      ((usize_t*) encbuf)[0] = i;
+
+      if ((i % 200) == 199) { DOT (); }
+
+      if ((ret = xd3_process_stream (1, & estream, xd3_encode_input, 0,
+				     encbuf, 1 << 20,
+				     delbuf, & delsize, 1 << 10)))
+	{
+	  in_stream->msg = estream.msg;
+	  goto fail;
+	}
+
+      if ((ret = xd3_process_stream (0, & dstream, xd3_decode_input, 0,
+				     delbuf, delsize,
+				     decbuf, & decsize, 1 << 20)))
+	{
+	  in_stream->msg = dstream.msg;
+	  goto fail;
+	}
+
+      if (decsize != 1 << 20 ||
+	  memcmp (encbuf, decbuf, 1 << 20) != 0)
+	{
+	  in_stream->msg = "wrong result";
+	  ret = XD3_INTERNAL;
+	  goto fail;
+	}
+    }
+
+  if ((ret = xd3_close_stream (& estream)) ||
+      (ret = xd3_close_stream (& dstream)))
+    {
+      goto fail;
+    }
+
+ fail:
+  xd3_free_stream (& estream);
+  xd3_free_stream (& dstream);
+  return ret;
+}
+
+/* Run tests of data streaming of over and around 4GB of data. */
+static int
+test_compressed_stream_overflow (xd3_stream *stream, int ignore)
+{
+  int ret;
+  uint8_t *buf;
+
+  if ((buf = malloc (TWO_MEGS_AND_DELTA)) == NULL) { return ENOMEM; }
+
+  memset (buf, 0, TWO_MEGS_AND_DELTA);
+
+  /* Test overflow of a 32-bit file offset. */
+  if (SIZEOF_XOFF_T == 4)
+    {
+      ret = test_streaming (stream, buf, buf + (1 << 20), buf + (2 << 20), (1 << 12) + 1);
+
+      if (ret == XD3_INTERNAL && MSG_IS ("decoder file offset overflow"))
+	{
+	  ret = 0;
+	}
+      else
+	{
+	  stream->msg = "expected overflow condition";
+	  ret = XD3_INTERNAL;
+	  goto fail;
+	}
+    }
+
+  /* Test transfer of exactly 32bits worth of data. */
+  if ((ret = test_streaming (stream, buf, buf + (1 << 20), buf + (2 << 20), 1 << 12))) { goto fail; }
+
+ fail:
+  free (buf);
+  return ret;
+}
+
+/******************************************************************************************
+ COMMAND LINE
+ ******************************************************************************************/
+
+/* For each pair of command templates in the array below, test that encoding and decoding
+ * commands work.  Also check for the expected size delta, which should be approximately
+ * TEST_ADD_RATIO times the file size created by test_make_inputs.  Due to differences in
+ * the application header, it is suppressed (-A) so that all delta files are the same. */
+static int
+test_command_line_arguments (xd3_stream *stream, int ignore)
+{
+  int i, ret;
+
+  static const char* cmdpairs[] =
+  {
+    /* standard input, output */
+    "%s %s -A < %s > %s", "%s -d < %s > %s",
+    "%s %s -A -e < %s > %s", "%s -d < %s > %s",
+    "%s %s -A= encode < %s > %s", "%s decode < %s > %s",
+    "%s %s -A -q encode < %s > %s", "%s -qdq < %s > %s",
+
+    /* file input, standard output */
+    "%s %s -A= %s > %s", "%s -d %s > %s",
+    "%s %s -A -e %s > %s", "%s -d %s > %s",
+    "%s %s encode -A= %s > %s", "%s decode %s > %s",
+
+    /* file input, output */
+    "%s %s -A= %s %s", "%s -d %s %s",
+    "%s %s -A -e %s %s", "%s -d %s %s",
+    "%s %s -A= encode %s %s", "%s decode %s %s",
+
+    /* option placement */
+    "%s %s -A -f %s %s", "%s -f -d %s %s",
+    "%s %s -e -A= %s %s", "%s -d -f %s %s",
+    "%s %s -f encode -A= %s %s", "%s -f decode -f %s %s",
+  };
+
+  char ecmd[TESTBUFSIZE], dcmd[TESTBUFSIZE];
+  int pairs = SIZEOF_ARRAY (cmdpairs) / 2;
+  xoff_t tsize;
+  xoff_t dsize;
+  double ratio;
+
+  srand (0x89162337);
+
+  for (i = 0; i < pairs; i += 1)
+    {
+      test_setup ();
+      if ((ret = test_make_inputs (stream, NULL, & tsize))) { return ret; }
+
+      sprintf (ecmd, cmdpairs[2*i], program_name, test_softcfg_str, TEST_TARGET_FILE, TEST_DELTA_FILE);
+      sprintf (dcmd, cmdpairs[2*i+1], program_name, TEST_DELTA_FILE, TEST_RECON_FILE);
+    
+      /* Encode and decode. */
+      if ((ret = system (ecmd)) != 0)
+	{
+	  DP(RINT "xdelta3: encode command: %s\n", ecmd);
+	  stream->msg = "encode cmd failed";
+	  return XD3_INTERNAL;
+	}
+
+      if ((ret = system (dcmd)) != 0)
+	{
+	  DP(RINT "xdelta3: decode command: %s\n", dcmd);
+	  stream->msg = "decode cmd failed";
+	  return XD3_INTERNAL;
+	}
+
+      /* Compare the target file. */
+      if ((ret = compare_files (stream, TEST_TARGET_FILE, TEST_RECON_FILE)))
+	{
+	  return ret;
+	}
+
+      if ((ret = test_file_size (TEST_DELTA_FILE, & dsize)))
+	{
+	  return ret;
+	}
+
+      ratio = (double) dsize / (double) tsize;
+
+      /* Check that it is not too small, not too large. */
+      if (ratio >= TEST_ADD_RATIO + TEST_EPSILON)
+	{
+	  DP(RINT "xdelta3: test encode with size ratio %.3f, expected < %.3f (%"Q"u, %"Q"u)\n",
+	    ratio, TEST_ADD_RATIO + TEST_EPSILON, dsize, tsize);
+	  stream->msg = "strange encoding";
+	  return XD3_INTERNAL;
+	}
+
+      if (ratio <= TEST_ADD_RATIO - TEST_EPSILON)
+	{
+	  DP(RINT "xdelta3: test encode with size ratio %.3f, expected > %.3f\n",
+	    ratio, TEST_ADD_RATIO - TEST_EPSILON);
+	  stream->msg = "strange encoding";
+	  return XD3_INTERNAL;
+	}
+
+      /* Also check that compare_files works.  The delta and original should not be
+       * identical. */
+      if ((ret = compare_files (stream, TEST_DELTA_FILE, TEST_TARGET_FILE)) == 0)
+	{
+	  stream->msg = "broken compare_files";
+	  return XD3_INTERNAL;
+	}
+
+      test_cleanup ();
+      DOT ();
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ EXTERNAL I/O DECOMPRESSION/RECOMPRESSION
+ ******************************************************************************************/
+
+#if EXTERNAL_COMPRESSION
+/* This performs one step of the test_externally_compressed_io function described below.
+ * It builds a pipe containing both Xdelta and external compression/decompression that
+ * should not modify the data passing through. */
+static int
+test_compressed_pipe (xd3_stream *stream, main_extcomp *ext, char* buf,
+		      const char* comp_options, const char* decomp_options,
+		      int do_ext_recomp, const char* msg)
+{
+  int ret;
+  char decomp_buf[TESTBUFSIZE];
+
+  if (do_ext_recomp)
+    {
+      sprintf (decomp_buf, " | %s %s", ext->decomp_cmdname, ext->decomp_options);
+    }
+  else
+    {
+      decomp_buf[0] = 0;
+    }
+
+  sprintf (buf, "%s %s < %s | %s %s | %s %s%s > %s",
+	   ext->recomp_cmdname, ext->recomp_options,
+	   TEST_TARGET_FILE,
+	   program_name, comp_options,
+	   program_name, decomp_options,
+	   decomp_buf,
+	   TEST_RECON_FILE);
+
+  if ((ret = system (buf)) != 0)
+    {
+      stream->msg = msg;
+      return XD3_INTERNAL;
+    }
+
+  if ((ret = compare_files (stream, TEST_TARGET_FILE, TEST_RECON_FILE)))
+    {
+      return XD3_INTERNAL;
+    }
+
+  DOT ();
+  return 0;
+}
+
+/* We want to test that a pipe such as:
+ *
+ * --> | gzip -cf | xdelta3 -cf | xdelta3 -dcf | gzip -dcf | -->
+ *
+ * is transparent, i.e., does not modify the stream of data.  However, we also want to
+ * verify that at the center the data is properly compressed, i.e., that we do not just
+ * have a re-compressed gzip format, that we have an VCDIFF format.  We do this in two
+ * steps.  First test the above pipe, then test with suppressed output recompression
+ * (-D).  The result should be the original input:
+ *
+ * --> | gzip -cf | xdelta3 -cf | xdelta3 -Ddcf | -->
+ *
+ * Finally we want to test that -D also disables input decompression:
+ *
+ * --> | gzip -cf | xdelta3 -Dcf | xdelta3 -Ddcf | gzip -dcf | -->
+ */
+static int
+test_externally_compressed_io (xd3_stream *stream, int ignore)
+{
+  int i, ret;
+  char buf[TESTBUFSIZE];
+
+  srand (0x91723913);
+
+  if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
+
+  for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
+    {
+      main_extcomp *ext = & extcomp_types[i];
+
+      /* Test for the existence of the external command first, if not skip. */
+      sprintf (buf, "%s %s < /dev/null > /dev/null", ext->recomp_cmdname, ext->recomp_options);
+
+      if ((ret = system (buf)) != 0)
+	{
+	  DP(RINT "%s=0", ext->recomp_cmdname);
+	  continue;
+	}
+
+      if ((ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-dcfq", 1,
+				       "compression failed: identity pipe")) ||
+	  (ret = test_compressed_pipe (stream, ext, buf, "-cfq", "-Rdcfq", 0,
+				       "compression failed: without recompression")) ||
+	  (ret = test_compressed_pipe (stream, ext, buf, "-Dcfq", "-Rdcfq", 1,
+				       "compression failed: without decompression")))
+	{
+	  return ret;
+	}
+    }
+
+  return 0;
+}
+
+/* This tests the proper functioning of external decompression for source files.  The
+ * source and target files are identical and compressed by gzip.  Decoding such a delta
+ * with recompression disbaled (-R) should produce the original, uncompressed
+ * source/target file.  Then it checks with output recompression enabled--in this case the
+ * output should be a compressed copy of the original source/target file.  Then it checks
+ * that encoding with decompression disabled works--the compressed files are identical and
+ * decoding them should always produce a compressed output, regardless of -R since the
+ * encoded delta file had decompression disabled..
+ */
+static int
+test_source_decompression (xd3_stream *stream, int ignore)
+{
+  int ret;
+  char buf[TESTBUFSIZE];
+  const main_extcomp *ext;
+
+  srand (0x9ff56acb);
+
+  test_setup ();
+  if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
+
+  /* Use gzip. */
+  if ((ext = main_get_compressor ("G")) == NULL) { DP(RINT "skipped"); return 0; }
+
+  /* Save an uncompressed copy. */
+  if ((ret = test_save_copy (TEST_TARGET_FILE))) { return ret; }
+
+  /* Compress the target. */
+  sprintf (buf, "%s %s < %s > %s", ext->recomp_cmdname, ext->recomp_options, TEST_TARGET_FILE, TEST_SOURCE_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Copy back to the source. */
+  sprintf (buf, "cp -f %s %s", TEST_SOURCE_FILE, TEST_TARGET_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Now the two identical files are compressed.  Delta-encode the target, with decompression. */
+  sprintf (buf, "%s -eq -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Decode the delta file with recompression disabled, should get an uncompressed file
+   * out. */
+  sprintf (buf, "%s -dq -R -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  if ((ret = compare_files (stream, TEST_COPY_FILE, TEST_RECON_FILE))) { return ret; }
+
+  /* Decode the delta file with recompression, should get a compressed file out.  But we
+   * can't compare compressed files directly. */
+  sprintf (buf, "%s -dqf -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  sprintf (buf, "%s %s < %s > %s", ext->decomp_cmdname, ext->decomp_options, TEST_RECON_FILE, TEST_RECON2_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  if ((ret = compare_files (stream, TEST_COPY_FILE, TEST_RECON2_FILE))) { return ret; }
+
+  /* Encode with decompression disabled */
+  sprintf (buf, "%s -feqD -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Decode the delta file with recompression enabled, it doesn't matter, should get the
+   * compressed file out. */
+  sprintf (buf, "%s -fdq -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  if ((ret = compare_files (stream, TEST_TARGET_FILE, TEST_RECON_FILE))) { return ret; }
+
+  /* Try again with recompression disabled, it doesn't make a difference. */
+  sprintf (buf, "%s -fqRd -s%s %s %s", program_name, TEST_SOURCE_FILE, TEST_DELTA_FILE, TEST_RECON_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  if ((ret = compare_files (stream, TEST_TARGET_FILE, TEST_RECON_FILE))) { return ret; }
+  test_cleanup();
+  return 0;
+}
+#endif
+
+/******************************************************************************************
+ FORCE, STDOUT
+ ******************************************************************************************/
+
+/* This tests that output will not overwrite an existing file unless -f was specified.
+ * The test is for encoding (the same code handles it for decoding). */
+static int
+test_force_behavior (xd3_stream *stream, int ignore)
+{
+  int ret;
+  char buf[TESTBUFSIZE];
+
+  /* Create empty target file */
+  test_setup ();
+  sprintf (buf, "cp /dev/null %s", TEST_TARGET_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Encode to delta file */
+  sprintf (buf, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Encode again, should fail. */
+  sprintf (buf, "%s -e %s %s ", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_fail (stream, buf))) { return ret; }
+
+  /* Force it, should succeed. */
+  sprintf (buf, "%s -f -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  test_cleanup();
+  return 0;
+}
+
+/* This checks the proper operation of the -c flag.  When specified the default output
+ * becomes stdout, otherwise the input must be provided (encode) or it may be defaulted
+ * (decode w/ app header). */
+static int
+test_stdout_behavior (xd3_stream *stream, int ignore)
+{
+  int ret;
+  char buf[TESTBUFSIZE];
+
+  test_setup();
+  sprintf (buf, "cp /dev/null %s", TEST_TARGET_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Without -c, encode writes to delta file */
+  sprintf (buf, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* With -c, encode writes to stdout */
+  sprintf (buf, "%s -e -c %s > %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Without -c, decode writes to target file name, but it fails because the file exists. */
+  sprintf (buf, "%s -d %s ", program_name, TEST_DELTA_FILE);
+  if ((ret = do_fail (stream, buf))) { return ret; }
+
+  /* With -c, decode writes to stdout */
+  sprintf (buf, "%s -d -c %s > /dev/null", program_name, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  test_cleanup();
+
+  return 0;
+}
+
+/* This tests that the no-output flag (-J) works. */
+static int
+test_no_output (xd3_stream *stream, int ignore)
+{
+  int ret;
+  char buf[TESTBUFSIZE];
+  
+  test_setup ();
+
+  sprintf (buf, "touch %s && chmod 0000 %s", TEST_NOPERM_FILE, TEST_NOPERM_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  if ((ret = test_make_inputs (stream, NULL, NULL))) { return ret; }
+
+  /* Try no_output encode w/out unwritable output file */
+  sprintf (buf, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_NOPERM_FILE);
+  if ((ret = do_fail (stream, buf))) { return ret; }
+  sprintf (buf, "%s -J -e %s %s", program_name, TEST_TARGET_FILE, TEST_NOPERM_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  /* Now really write the delta to test decode no-output */
+  sprintf (buf, "%s -e %s %s", program_name, TEST_TARGET_FILE, TEST_DELTA_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+
+  sprintf (buf, "%s -d %s %s", program_name, TEST_DELTA_FILE, TEST_NOPERM_FILE);
+  if ((ret = do_fail (stream, buf))) { return ret; }
+  sprintf (buf, "%s -J -d %s %s", program_name, TEST_DELTA_FILE, TEST_NOPERM_FILE);
+  if ((ret = do_cmd (stream, buf))) { return ret; }
+  test_cleanup ();
+  return 0;
+}
+
+/******************************************************************************************
+ Source identical optimization
+ ******************************************************************************************/
+
+/* Computing a delta should be fastest when the two inputs are identical, this checks it.
+ * The library is called to compute a delta between a 10000 byte file, 1000 byte winsize,
+ * 500 byte source blocksize.  The same buffer is used for both source and target. */
+static int
+test_identical_behavior (xd3_stream *stream, int ignore)
+{
+#define IDB_TGTSZ 10000
+#define IDB_BLKSZ 500
+#define IDB_WINSZ 1000
+#define IDB_DELSZ 1000
+#define IDB_WINCNT (IDB_TGTSZ / IDB_WINSZ)
+
+  int ret, i;
+  uint8_t buf[IDB_TGTSZ];
+  uint8_t del[IDB_DELSZ];
+  uint8_t rec[IDB_TGTSZ];
+  xd3_source source;
+  int    encwin = 0;
+  usize_t delpos = 0, recsize;
+  xd3_config config;
+
+  for (i = 0; i < IDB_TGTSZ; i += 1) { buf[i] = rand (); } 
+
+  stream->winsize = IDB_WINSZ;
+
+  source.size     = IDB_TGTSZ;
+  source.blksize  = IDB_BLKSZ;
+  source.name     = "";
+  source.curblk   = NULL;
+  source.curblkno = -1;
+
+  if ((ret = xd3_set_source (stream, & source))) { goto fail; }
+
+  /* Compute an delta between identical source and targets. */
+  for (;;)
+    {
+      ret = xd3_encode_input (stream);
+
+      if (ret == XD3_INPUT)
+	{
+	  if (encwin == IDB_WINCNT-1) { break; }
+	  xd3_avail_input (stream, buf + (IDB_WINSZ * encwin), IDB_WINSZ);
+	  encwin += 1;
+	  continue;
+	}
+
+      if (ret == XD3_GETSRCBLK)
+	{
+	  source.curblkno = source.getblkno;
+	  source.onblk    = IDB_BLKSZ;
+	  source.curblk   = buf + source.getblkno * IDB_BLKSZ;
+	  continue;
+	}
+
+      if (ret == XD3_WINSTART) { continue; }
+      if (ret == XD3_WINFINISH) { continue; }
+
+      if (ret != XD3_OUTPUT) { goto fail; }
+
+      CHECK(delpos + stream->avail_out <= IDB_DELSZ);
+
+      memcpy (del + delpos, stream->next_out, stream->avail_out);
+
+      delpos += stream->avail_out;
+
+      xd3_consume_output (stream);
+    }
+
+  /* Reset. */
+  source.blksize  = IDB_TGTSZ;
+  source.onblk    = IDB_TGTSZ;
+  source.curblk   = buf;
+  source.curblkno = 0;
+
+  if ((ret = xd3_close_stream (stream))) { goto fail; }
+  xd3_free_stream (stream);
+  xd3_init_config (& config, 0);
+  if ((ret = xd3_config_stream (stream, & config))) { goto fail; }
+  if ((ret = xd3_set_source (stream, & source))) { goto fail; }
+
+  /* Decode. */
+  if ((ret = xd3_decode_stream (stream, del, delpos, rec, & recsize, IDB_TGTSZ))) { goto fail; }
+
+  /* Check result size and data. */
+  if (recsize != IDB_TGTSZ) { stream->msg = "wrong size reconstruction"; goto fail; }
+  if (memcmp (rec, buf, IDB_TGTSZ) != 0) { stream->msg = "wrong data reconstruction"; goto fail; }
+
+  /* Check that there was one copy per window. */
+  IF_DEBUG (if (stream->n_scpy != IDB_WINCNT ||
+		stream->n_add != 0 ||
+		stream->n_run != 0) { stream->msg = "wrong copy count"; goto fail; });
+
+  /* Check that no checksums were computed because the initial match was presumed. */
+  IF_DEBUG (if (stream->large_ckcnt != 0) { stream->msg = "wrong checksum behavior"; goto fail; });
+
+  ret = 0;
+ fail:
+  return ret;
+}
+
+/******************************************************************************************
+ String matching test
+ ******************************************************************************************/
+
+/* Check particular matching behaviors by calling xd3_string_match_soft directly with
+ * specific arguments. */
+typedef struct _string_match_test string_match_test;
+
+typedef enum
+{
+  SM_NONE    = 0,
+  SM_LAZY    = (1 << 1),
+} string_match_flags;
+
+struct _string_match_test
+{
+  const char *input;
+  int         flags;
+  const char *result;
+};
+
+static const string_match_test match_tests[] =
+{
+  /* nothing */
+  { "1234567890", SM_NONE, "" },
+
+  /* basic run, copy */
+  { "11111111112323232323", SM_NONE, "R0/10 C12/8@10" },
+
+  /* no run smaller than MIN_RUN=8 */
+  { "1111111",  SM_NONE, "C1/6@0" },
+  { "11111111", SM_NONE, "R0/8" },
+
+  /* simple promotion: the third copy address depends on promotion */
+  { "ABCDEF_ABCDEF^ABCDEF", SM_NONE,    "C7/6@0 C14/6@7" },
+  /* { "ABCDEF_ABCDEF^ABCDEF", SM_PROMOTE, "C7/6@0 C14/6@0" }, forgotten */
+
+  /* simple lazy: there is a better copy starting with "23 X" than "123 " */
+  { "123 23 XYZ 123 XYZ", SM_NONE, "C11/4@0" },
+  { "123 23 XYZ 123 XYZ", SM_LAZY, "C11/4@0 C12/6@4" },
+
+  /* trylazy: no lazy matches unless there are at least two characters beyond the first
+   * match */
+  { "2123_121212",   SM_LAZY, "C7/4@5" },
+  { "2123_1212123",  SM_LAZY, "C7/4@5" },
+  { "2123_1212123_", SM_LAZY, "C7/4@5 C8/5@0" },
+
+  /* trylazy: no lazy matches if the copy is >= MAXLAZY=10 */
+  { "2123_121212123_",   SM_LAZY, "C7/6@5 C10/5@0" },
+  { "2123_12121212123_", SM_LAZY, "C7/8@5 C12/5@0" },
+  { "2123_1212121212123_", SM_LAZY, "C7/10@5" },
+
+  /* lazy run: check a run overlapped by a longer copy */
+  { "11111112 111111112 1", SM_LAZY, "C1/6@0 R9/8 C10/10@0" },
+
+  /* lazy match: match_length,run_l >= min_match tests, shouldn't get any copies within
+   * the run, no run within the copy */
+  { "^________^________  ", SM_LAZY, "R1/8 C9/9@0" },
+
+  /* chain depth: it only goes back 10. this checks that the 10th match hits and the 11th
+   * misses. */
+  { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234 ", SM_NONE,
+    "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/5@0" },
+  { "1234 1234_1234-1234=1234+1234[1234]1234{1234}1234<1234>1234 ", SM_NONE,
+    "C5/4@0 C10/4@5 C15/4@10 C20/4@15 C25/4@20 C30/4@25 C35/4@30 C40/4@35 C45/4@40 C50/4@45 C55/4@50" },
+
+  /* ssmatch test */
+  { "ABCDE___ABCDE*** BCDE***", SM_NONE, "C8/5@0 C17/4@1" },
+  /*{ "ABCDE___ABCDE*** BCDE***", SM_SSMATCH, "C8/5@0 C17/7@9" }, forgotten */
+};
+
+static int
+test_string_matching (xd3_stream *stream, int ignore)
+{
+  int i, ret;
+  xd3_config config;
+  char rbuf[TESTBUFSIZE];
+
+  for (i = 0; i < SIZEOF_ARRAY (match_tests); i += 1)
+    {
+      const string_match_test *test = & match_tests[i];
+      char *rptr = rbuf;
+      usize_t len = strlen (test->input);
+
+      xd3_free_stream (stream);
+      xd3_init_config (& config, 0);
+
+      config.smatch_cfg   = XD3_SMATCH_SOFT;
+      config.smatcher_soft.large_look   = 4;
+      config.smatcher_soft.large_step   = 4;
+      config.smatcher_soft.small_look   = 4;
+      config.smatcher_soft.small_chain  = 10;
+      config.smatcher_soft.small_lchain = 10;
+      config.smatcher_soft.max_lazy     = (test->flags & SM_LAZY) ? 10 : 0;
+      config.smatcher_soft.long_enough  = 10;
+
+      if ((ret = xd3_config_stream (stream, & config))) { return ret; }
+      if ((ret = xd3_encode_init (stream))) { return ret; }
+
+      xd3_avail_input (stream, (uint8_t*)test->input, len);
+
+      if ((ret = stream->smatcher.string_match (stream))) { return ret; }
+
+      *rptr = 0;
+      while (! xd3_rlist_empty (& stream->iopt_used))
+	{
+	  xd3_rinst *inst = xd3_rlist_pop_front (& stream->iopt_used);
+
+	  switch (inst->type)
+	    {
+	    case XD3_RUN: *rptr++ = 'R'; break;
+	    case XD3_CPY: *rptr++ = 'C'; break;
+	    default: CHECK(0);
+	    }
+
+	  sprintf (rptr, "%d/%d", inst->pos, inst->size);
+	  rptr += strlen (rptr);
+
+	  if (inst->type == XD3_CPY)
+	    {
+	      *rptr++ = '@';
+	      sprintf (rptr, "%"Q"d", inst->addr);
+	      rptr += strlen (rptr);
+	    }
+
+	  *rptr++ = ' ';
+
+	  xd3_rlist_push_back (& stream->iopt_free, inst);
+	}
+
+      if (rptr != rbuf)
+	{
+	  rptr -= 1; *rptr = 0;
+	}
+
+      if (strcmp (rbuf, test->result) != 0)
+	{
+	  DP(RINT "test %u: expected %s: got %s", i, test->result, rbuf);
+	  stream->msg = "wrong result";
+	  return XD3_INTERNAL;
+	}
+    }
+
+  return 0;
+}
+
+/*
+ * This is a test for many overlapping instructions. It must be a lazy
+ * matcher.
+ */
+static int
+test_iopt_flush_instructions (xd3_stream *stream, int ignore)
+{
+  int ret, i, tpos = 0;
+  usize_t delta_size, recon_size;
+  xd3_config config;
+  uint8_t target[TESTBUFSIZE];
+  uint8_t delta[TESTBUFSIZE];
+  uint8_t recon[TESTBUFSIZE];
+
+  xd3_free_stream (stream);
+  xd3_init_config (& config, 0);
+
+  config.smatch_cfg    = XD3_SMATCH_SOFT;
+  config.smatcher_soft.large_look    = 16;
+  config.smatcher_soft.large_step    = 16;
+  config.smatcher_soft.small_look    = 4;
+  config.smatcher_soft.small_chain   = 128;
+  config.smatcher_soft.small_lchain  = 16;
+  config.smatcher_soft.max_lazy      = 8;
+  config.smatcher_soft.long_enough   = 128;
+
+  if ((ret = xd3_config_stream (stream, & config))) { return ret; }
+
+  for (i = 1; i < 250; i++)
+    {
+      target[tpos++] = i;
+      target[tpos++] = i+1;
+      target[tpos++] = i+2;
+      target[tpos++] = i+3;
+      target[tpos++] = 0;
+    }
+  for (i = 1; i < 253; i++)
+    {
+      target[tpos++] = i;
+    }
+
+  if ((ret = xd3_encode_stream (stream, target, tpos,
+				    delta, & delta_size, sizeof (delta))))
+    {
+      return ret;
+    }
+
+  xd3_free_stream(stream);
+  if ((ret = xd3_config_stream (stream, & config))) { return ret; }
+
+  if ((ret = xd3_decode_stream (stream, delta, delta_size,
+				recon, & recon_size, sizeof (recon))))
+    {
+      return ret;
+    }
+
+  CHECK(tpos == recon_size);
+  CHECK(memcmp(target, recon, recon_size) == 0);
+
+  return 0;
+}
+
+/*
+ * This tests the 32/64bit ambiguity for source-window matching.
+ */
+static int
+test_source_cksum_offset (xd3_stream *stream, int ignore)
+{
+  xd3_source source;
+
+  // Inputs are:
+  struct {
+    xoff_t   cpos;   // stream->srcwin_cksum_pos;
+    xoff_t   ipos;   // stream->total_in;
+    xoff_t   size;   // stream->src->size;
+
+    usize_t  input;  // input  32-bit offset
+    xoff_t   output; // output 64-bit offset
+
+  } cksum_test[] = {
+    // If cpos is <= 2^32 
+    { 1, 1, 1, 1, 1 },
+
+#if XD3_USE_LARGEFILE64
+//    cpos            ipos            size            input         output
+//    0x____xxxxxULL, 0x____xxxxxULL, 0x____xxxxxULL, 0x___xxxxxUL, 0x____xxxxxULL
+    { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0x00000000UL, 0x100000000ULL },
+    { 0x100100000ULL, 0x100000000ULL, 0x100200000ULL, 0xF0000000UL, 0x0F0000000ULL },
+
+    { 0x100200000ULL, 0x100100000ULL, 0x100200000ULL, 0x00300000UL, 0x000300000ULL },
+
+    { 25771983104ULL, 25770000000ULL, 26414808769ULL, 2139216707UL, 23614053187ULL },
+
+#endif
+
+    { 0, 0, 0, 0, 0 },
+  }, *test_ptr;
+
+  stream->src = &source;
+
+  for (test_ptr = cksum_test; test_ptr->cpos; test_ptr++) {
+	xoff_t r;
+    stream->srcwin_cksum_pos = test_ptr->cpos;
+    stream->total_in = test_ptr->ipos;
+    stream->src->size = test_ptr->size;
+
+    r = xd3_source_cksum_offset(stream, test_ptr->input);
+    CHECK(r == test_ptr->output);
+  }
+  return 0;
+}
+
+static int
+test_in_memory (xd3_stream *stream, int ignore)
+{
+  // test_text is 256 bytes
+  uint8_t ibuf[sizeof(test_text)];
+  uint8_t dbuf[sizeof(test_text)];
+  uint8_t obuf[sizeof(test_text)];
+  usize_t size = sizeof(test_text);
+  usize_t dsize, osize;
+  int r1, r2;
+  int eflags = SECONDARY_DJW ? XD3_SEC_DJW : 0;
+
+  memcpy(ibuf, test_text, size);
+  memset(ibuf + 128, 0, 16);
+
+  r1 = xd3_encode_memory(ibuf, size,
+			 test_text, size,
+			 dbuf, &dsize, size, eflags);
+
+  r2 = xd3_decode_memory(dbuf, dsize,
+			 test_text, size,
+			 obuf, &osize, size, 0);
+
+  if (r1 != 0 || r2 != 0 || dsize >= (size/2) || dsize < 1 ||
+      osize != size) {
+    stream->msg = "encode/decode size error";
+    return XD3_INTERNAL;
+  }
+
+  if (memcmp(obuf, ibuf, size) != 0) {
+    stream->msg = "encode/decode data error";
+    return XD3_INTERNAL;
+  }
+
+  return 0;
+}
+
+/******************************************************************************************
+ TEST MAIN
+ ******************************************************************************************/
+
+static int
+xd3_selftest (void)
+{
+#define DO_TEST(fn,flags,arg)                                         \
+  do {                                                                \
+    xd3_stream stream;                                                \
+    xd3_config config;                                                \
+    xd3_init_config (& config, flags);                                \
+    DP(RINT "xdelta3: testing " #fn "%s...",                           \
+             flags ? (" (" #flags ")") : "");                         \
+    if ((ret = xd3_config_stream (& stream, & config) == 0) &&        \
+        (ret = test_ ## fn (& stream, arg)) == 0) {                   \
+      DP(RINT " success\n");                                           \
+    } else {                                                          \
+      DP(RINT " failed: %s: %s\n", xd3_errstring (& stream),           \
+               xd3_mainerror (ret)); }                                \
+    xd3_free_stream (& stream);                                       \
+    if (ret != 0) { goto failure; }                                   \
+  } while (0)
+
+  int ret;
+
+  DO_TEST (random_numbers, 0, 0);
+  DO_TEST (decode_integer_end_of_input, 0, 0);
+  DO_TEST (decode_integer_overflow, 0, 0);
+  DO_TEST (encode_decode_uint32_t, 0, 0);
+  DO_TEST (encode_decode_uint64_t, 0, 0);
+  DO_TEST (usize_t_overflow, 0, 0);
+
+  DO_TEST (address_cache, 0, 0);
+  IF_GENCODETBL (DO_TEST (address_cache, XD3_ALT_CODE_TABLE, 0));
+
+  DO_TEST (string_matching, 0, 0);
+
+  DO_TEST (choose_instruction, 0, 0);
+  IF_GENCODETBL (DO_TEST (choose_instruction, XD3_ALT_CODE_TABLE, 0));
+  IF_GENCODETBL (DO_TEST (encode_code_table, 0, 0));
+
+  DO_TEST (in_memory, 0, 0);
+  DO_TEST (identical_behavior, 0, 0);
+  DO_TEST (iopt_flush_instructions, 0, 0);
+  DO_TEST (source_cksum_offset, 0, 0);
+
+  IF_DJW (DO_TEST (secondary_huff, 0, DJW_MAX_GROUPS));
+  IF_FGK (DO_TEST (secondary_fgk, 0, 1));
+
+  DO_TEST (decompress_single_bit_error, 0, 3);
+  DO_TEST (decompress_single_bit_error, XD3_ADLER32, 3);
+
+  IF_FGK (DO_TEST (decompress_single_bit_error, XD3_SEC_FGK, 3));
+  IF_DJW (DO_TEST (decompress_single_bit_error, XD3_SEC_DJW, 8));
+
+  /* There are many expected non-failures for ALT_CODE_TABLE because not all of the
+   * instruction codes are used. */
+  IF_GENCODETBL (DO_TEST (decompress_single_bit_error, XD3_ALT_CODE_TABLE, 224));
+
+#ifndef WIN32
+  DO_TEST (force_behavior, 0, 0);
+  DO_TEST (stdout_behavior, 0, 0);
+  DO_TEST (no_output, 0, 0);
+  DO_TEST (command_line_arguments, 0, 0);
+
+#if EXTERNAL_COMPRESSION
+  DO_TEST (source_decompression, 0, 0);
+  DO_TEST (externally_compressed_io, 0, 0);
+#endif
+
+#endif /* WIN32 */
+
+  /* This test takes a while.
+   */
+  DO_TEST (compressed_stream_overflow, 0, 0);
+
+failure:
+  test_cleanup ();
+  return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+#undef DO_TEST
+}
Index: /nikanabo/current/xdelta/diy/xdelta3-test.py
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3-test.py	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3-test.py	(revision 185)
@@ -0,0 +1,147 @@
+#!/usr/bin/python2.4
+# xdelta 3 - delta compression tools and library
+# Copyright (C) 2003, 2006, 2007.  Joshua P. MacDonald
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import xdelta3
+
+# the test data section is expected to be len('target')
+source = 'source source input0 source source'
+target = 'source source target source source'
+
+#
+#
+
+print 'encode: basic ...'
+result, patch = xdelta3.xd3_encode_memory(target, source, 50)
+
+assert result == 0
+assert len(patch) < len(source)
+
+print 'encode: adler32 ...'
+result, patch_adler32 = xdelta3.xd3_encode_memory(target, source, 50,
+                                                  xdelta3.XD3_ADLER32)
+
+assert result == 0
+assert len(patch_adler32) < len(source)
+assert len(patch_adler32) > len(patch)
+
+print 'encode: secondary ...'
+result, patch_djw = xdelta3.xd3_encode_memory(target, source, 50,
+                                              xdelta3.XD3_SEC_DJW)
+
+assert result == 0
+# secondary compression doesn't help
+assert len(patch_djw) > len(patch)
+
+print 'encode: exact ...'
+result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch))
+
+assert result == 0
+assert len(ignore) < len(source)
+
+print 'encode: out of space ...'
+result, ignore = xdelta3.xd3_encode_memory(target, source, len(patch) - 1)
+
+assert result == 28
+assert ignore == None
+
+print 'encode: zero space ...'
+result, ignore = xdelta3.xd3_encode_memory(target, source, 0)
+
+assert result == 28
+assert ignore == None
+
+print 'encode: no source ...'
+result, zdata = xdelta3.xd3_encode_memory(target, None, 50)
+
+assert result == 0
+assert len(zdata) > len(patch)
+
+print 'encode: no input ...'
+result, ignore = xdelta3.xd3_encode_memory(None, None, 50)
+
+assert result != 0
+
+print 'decode: basic ...'
+result, target1 = xdelta3.xd3_decode_memory(patch, source, len(target))
+
+assert result == 0
+assert len(target1) == len(target)
+assert target1 == target
+
+print 'decode: out of space ...'
+result, ignore = xdelta3.xd3_decode_memory(patch, source, len(target) - 1)
+
+assert result == 28
+assert ignore == None
+
+print 'decode: zero space ...'
+result, ignore = xdelta3.xd3_decode_memory(patch, source, 0)
+
+assert result == 28
+assert ignore == None
+
+print 'decode: single byte error ...'
+# a few expected single-byte errors, e.g., unused address cache bits, see
+# xdelta3-test.h's single-bit error tests
+extra_count = 4
+noverify_count = 0
+for corrupt_pos in range(len(patch_adler32)):
+    input = ''.join([j == corrupt_pos and '\xff' or patch_adler32[j]
+                     for j in range(len(patch_adler32))])
+
+    result, ignore = xdelta3.xd3_decode_memory(input, source, len(target), 0)
+    assert result == -17712
+    assert ignore == None
+
+    # without adler32 verification, the error may be in the data section which
+    # in this case is 6 bytes 'target'
+    result, corrupt = xdelta3.xd3_decode_memory(input, source, len(target),
+                                                xdelta3.XD3_ADLER32_NOVER)
+    if result == 0:
+        noverify_count = noverify_count + 1
+        #print "got %s" % corrupt
+    #end
+#end
+assert noverify_count == len('target') + extra_count
+
+print 'decode: no source ...'
+result, target2 = xdelta3.xd3_decode_memory(zdata, None, len(target))
+
+assert result == 0
+assert target == target2
+
+# Test compression level setting via flags.  assumes a 9 byte checksum
+# and that level 9 steps 2, level 1 steps 15:
+#         01234567890123456789012345678901
+# level 1 only indexes 2 checksums "abcdefghi" and "ABCDEFGHI"
+# outputs 43 vs. 23 bytes
+print 'encode: compression level ...'
+
+source = '_la_la_abcdefghi_la_la_ABCDEFGHI'
+target = 'la_la_ABCDEFGH__la_la_abcdefgh__'
+
+result1, level1 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_1)
+result9, level9 = xdelta3.xd3_encode_memory(target, source, 50, xdelta3.XD3_COMPLEVEL_9)
+
+assert result1 == 0 and result9 == 0
+assert len(level1) > len(level9)
+
+#
+#
+
+print 'PASS'
Index: /nikanabo/current/xdelta/diy/xdelta3.c
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3.c	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3.c	(revision 185)
@@ -0,0 +1,5060 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2001, 2003, 2004, 2005, 2006.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   -------------------------------------------------------------------
+
+			       Xdelta 3
+
+   The goal of this library is to to implement both the (stand-alone)
+   data-compression and delta-compression aspects of VCDIFF encoding, and
+   to support a programming interface that works like Zlib
+   (http://www.gzip.org/zlib.html). See RFC3284: The VCDIFF Generic
+   Differencing and Compression Data Format.
+
+   VCDIFF is a unified encoding that combines data-compression and
+   delta-encoding ("differencing").
+
+   VCDIFF has a detailed byte-code instruction set with many features.
+   The instruction format supports an immediate size operand for small
+   COPYs and ADDs (e.g., under 18 bytes).  There are also instruction
+   "modes", which are used to compress COPY addresses by using two
+   address caches.  An instruction mode refers to slots in the NEAR
+   and SAME caches for recent addresses.  NEAR remembers the
+   previous 4 (by default) COPY addresses, and SAME catches
+   frequent re-uses of the same address using a 3-way (by default)
+   256-entry associative cache of [ADDR mod 256], the encoded byte.
+   A hit in the NEAR/SAME cache requires 0/1 ADDR bytes.
+
+   VCDIFF has a default instruction table, but an alternate
+   instruction tables may themselves be be delta-compressed and
+   included in the encoding header.  This allows even more freedom.
+   There are 9 instruction modes in the default code table, 4 near, 3
+   same, VCD_SELF (absolute encoding) and VCD_HERE (relative to the
+   current position).
+
+   ----------------------------------------------------------------------
+
+  			      Algorithms
+
+   Aside from the details of encoding and decoding, there are a bunch
+   of algorithms needed.
+
+   1. STRING-MATCH.  A two-level fingerprinting approach is used.  A
+   single loop computes the two checksums -- small and large -- at
+   successive offsets in the TARGET file.  The large checksum is more
+   accurate and is used to discover SOURCE matches, which are
+   potentially very long.  The small checksum is used to discover
+   copies within the TARGET.  Small matching, which is more expensive,
+   usually dominates the large STRING-MATCH costs in this code - the
+   more exhaustive the search, the better the results.  Either of the
+   two string-matching mechanisms may be disabled.
+
+   2. INSTRUCTION SELECTION.  The IOPT buffer here represents a queue
+   used to store overlapping copy instructions.  There are two possible
+   optimizations that go beyond a greedy search.  Both of these fall
+   into the category of "non-greedy matching" optimizations.
+
+   The first optimization stems from backward SOURCE-COPY matching.
+   When a new SOURCE-COPY instruction covers a previous instruction in
+   the target completely, it is erased from the queue.  Randal Burns
+   originally analyzed these algorithms and did a lot of related work
+   (\cite the 1.5-pass algorithm).
+
+   The second optimization comes by the encoding of common very-small
+   COPY and ADD instructions, for which there are special DOUBLE-code
+   instructions, which code two instructions in a single byte.
+
+   The cost of bad instruction-selection overhead is relatively high
+   for data-compression, relative to delta-compression, so this second
+   optimization is fairly important.  With "lazy" matching (the name
+   used in Zlib for a similar optimization), the string-match
+   algorithm searches after a match for potential overlapping copy
+   instructions.  In Xdelta and by default, VCDIFF, the minimum match
+   size is 4 bytes, whereas Zlib searches with a 3-byte minimum.  This
+   feature, combined with double instructions, provides a nice
+   challenge.  Search in this file for "black magic", a heuristic.
+
+   3. STREAM ALIGNMENT.  Stream alignment is needed to compress large
+   inputs in constant space.  See xd3_srcwin_move_point().
+
+   4. WINDOW SELECTION.  When the IOPT buffer flushes, in the first call
+   to xd3_iopt_finish_encoding containing any kind of copy instruction,
+   the parameters of the source window must be decided: the offset into
+   the source and the length of the window.  Since the IOPT buffer is
+   finite, the program may be forced to fix these values before knowing
+   the best offset/length.
+
+   5. SECONDARY COMPRESSION.  VCDIFF supports a secondary encoding to
+   be applied to the individual sections of the data format, which are
+   ADDRess, INSTruction, and DATA.  Several secondary compressor
+   variations are implemented here, although none is standardized yet.
+
+   One is an adaptive huffman algorithm -- the FGK algorithm (Faller,
+   Gallager, and Knuth, 1985).  This compressor is extremely slow.
+
+   The other is a simple static Huffman routine, which is the base
+   case of a semi-adaptive scheme published by D.J. Wheeler and first
+   widely used in bzip2 (by Julian Seward).  This is a very
+   interesting algorithm, originally published in nearly cryptic form
+   by D.J. Wheeler. !!!NOTE!!! Because these are not standardized,
+   secondary compression remains off by default.
+   ftp://ftp.cl.cam.ac.uk/users/djw3/bred3.{c,ps}
+   --------------------------------------------------------------------
+
+			    Other Features
+
+   1. USER CONVENIENCE
+
+   For user convenience, it is essential to recognize Gzip-compressed
+   files and automatically Gzip-decompress them prior to
+   delta-compression (or else no delta-compression will be achieved
+   unless the user manually decompresses the inputs).  The compressed
+   represention competes with Xdelta, and this must be hidden from the
+   command-line user interface.  The Xdelta-1.x encoding was simple, not
+   compressed itself, so Xdelta-1.x uses Zlib internally to compress the
+   representation.
+
+   This implementation supports external compression, which implements
+   the necessary fork() and pipe() mechanics.  There is a tricky step
+   involved to support automatic detection of a compressed input in a
+   non-seekable input.  First you read a bit of the input to detect
+   magic headers.  When a compressed format is recognized, exec() the
+   external compression program and create a second child process to
+   copy the original input stream. [Footnote: There is a difficulty
+   related to using Gzip externally. It is not possible to decompress
+   and recompress a Gzip file transparently.  If FILE.GZ had a
+   cryptographic signature, then, after: (1) Gzip-decompression, (2)
+   Xdelta-encoding, (3) Gzip-compression the signature could be
+   broken.  The only way to solve this problem is to guess at Gzip's
+   compression level or control it by other means.  I recommend that
+   specific implementations of any compression scheme store
+   information needed to exactly re-compress the input, that way
+   external compression is transparent - however, this won't happen
+   here until it has stabilized.]
+
+   2. APPLICATION-HEADER
+
+   This feature was introduced in RFC3284.  It allows any application
+   to include a header within the VCDIFF file format.  This allows
+   general inter-application data exchange with support for
+   application-specific extensions to communicate metadata.
+
+   3. VCDIFF CHECKSUM
+
+   An optional checksum value is included with each window, which can
+   be used to validate the final result.  This verifies the correct source
+   file was used for decompression as well as the obvious advantage:
+   checking the implementation (and underlying) correctness.
+
+   4. LIGHT WEIGHT
+
+   The code makes efforts to avoid copying data more than necessary.
+   The code delays many initialization tasks until the first use, it
+   optimizes for identical (perfectly matching) inputs.  It does not
+   compute any checksums until the first lookup misses.  Memory usage
+   is reduced.  String-matching is templatized (by slightly gross use
+   of CPP) to hard-code alternative compile-time defaults.  The code
+   has few outside dependencies.
+   ----------------------------------------------------------------------
+
+		The default rfc3284 instruction table:
+		    (see RFC for the explanation)
+
+           TYPE      SIZE     MODE    TYPE     SIZE     MODE     INDEX
+   --------------------------------------------------------------------
+       1.  Run         0        0     Noop       0        0        0
+       2.  Add    0, [1,17]     0     Noop       0        0      [1,18]
+       3.  Copy   0, [4,18]     0     Noop       0        0     [19,34]
+       4.  Copy   0, [4,18]     1     Noop       0        0     [35,50]
+       5.  Copy   0, [4,18]     2     Noop       0        0     [51,66]
+       6.  Copy   0, [4,18]     3     Noop       0        0     [67,82]
+       7.  Copy   0, [4,18]     4     Noop       0        0     [83,98]
+       8.  Copy   0, [4,18]     5     Noop       0        0     [99,114]
+       9.  Copy   0, [4,18]     6     Noop       0        0    [115,130]
+      10.  Copy   0, [4,18]     7     Noop       0        0    [131,146]
+      11.  Copy   0, [4,18]     8     Noop       0        0    [147,162]
+      12.  Add       [1,4]      0     Copy     [4,6]      0    [163,174]
+      13.  Add       [1,4]      0     Copy     [4,6]      1    [175,186]
+      14.  Add       [1,4]      0     Copy     [4,6]      2    [187,198]
+      15.  Add       [1,4]      0     Copy     [4,6]      3    [199,210]
+      16.  Add       [1,4]      0     Copy     [4,6]      4    [211,222]
+      17.  Add       [1,4]      0     Copy     [4,6]      5    [223,234]
+      18.  Add       [1,4]      0     Copy       4        6    [235,238]
+      19.  Add       [1,4]      0     Copy       4        7    [239,242]
+      20.  Add       [1,4]      0     Copy       4        8    [243,246]
+      21.  Copy        4      [0,8]   Add        1        0    [247,255]
+   --------------------------------------------------------------------
+
+		     Reading the source: Overview
+
+   This file includes itself in several passes to macro-expand certain
+   sections with variable forms.  Just read ahead, there's only a
+   little confusion.  I know this sounds ugly, but hard-coding some of
+   the string-matching parameters results in a 10-15% increase in
+   string-match performance.  The only time this hurts is when you have
+   unbalanced #if/endifs.
+
+   A single compilation unit tames the Makefile.  In short, this is to
+   allow the above-described hack without an explodingMakefile.  The
+   single compilation unit includes the core library features,
+   configurable string-match templates, optional main() command-line
+   tool, misc optional features, and a regression test.  Features are
+   controled with CPP #defines, see Makefile.am.
+
+   The initial __XDELTA3_C_HEADER_PASS__ starts first, the INLINE and
+   TEMPLATE sections follow.  Easy stuff first, hard stuff last.
+
+   Optional features include:
+
+     xdelta3-main.h     The command-line interface, external compression
+                        support, POSIX-specific, info & VCDIFF-debug tools.
+     xdelta3-second.h   The common secondary compression routines.
+     xdelta3-decoder.h  All decoding routines.
+     xdelta3-djw.h      The semi-adaptive huffman secondary encoder.
+     xdelta3-fgk.h      The adaptive huffman secondary encoder.
+     xdelta3-test.h     The unit test covers major algorithms,
+                        encoding and decoding.  There are single-bit
+                        error decoding tests.  There are 32/64-bit file size
+                        boundary tests.  There are command-line tests.
+                        There are compression tests.  There are external
+                        compression tests.  There are string-matching tests.
+			There should be more tests...
+
+   Additional headers include:
+
+     xdelta3.h          The public header file.
+     xdelta3-cfgs.h     The default settings for default, built-in
+                        encoders.  These are hard-coded at
+                        compile-time.  There is also a single
+                        soft-coded string matcher for experimenting
+                        with arbitrary values.
+     xdelta3-list.h     A cyclic list template
+
+   Misc little debug utilities:
+
+     badcopy.c          Randomly modifies an input file based on two
+                        parameters: (1) the probability that a byte in
+                        the file is replaced with a pseudo-random value,
+                        and (2) the mean change size.  Changes are
+                        generated using an expoential distribution
+                        which approximates the expected error_prob
+			distribution.
+   --------------------------------------------------------------------
+
+   This file itself is unusually large.  I hope to defend this layout
+   with lots of comments.  Everything in this file is related to
+   encoding and decoding.  I like it all together - the template stuff
+   is just a hack. */
+
+#ifndef __XDELTA3_C_HEADER_PASS__
+#define __XDELTA3_C_HEADER_PASS__
+
+#include <errno.h>
+#include <string.h>
+
+#include "xdelta3.h"
+
+/******************************************************************************************
+ STATIC CONFIGURATION
+ ******************************************************************************************/
+
+#ifndef XD3_MAIN                  /* the main application */
+#define XD3_MAIN 0
+#endif
+
+#ifndef VCDIFF_TOOLS
+#define VCDIFF_TOOLS XD3_MAIN
+#endif
+
+#ifndef SECONDARY_FGK             /* one from the algorithm preservation department: */
+#define SECONDARY_FGK 0           /* adaptive Huffman routines */
+#endif
+
+#ifndef SECONDARY_DJW             /* semi-adaptive/static Huffman for the eventual */
+#define SECONDARY_DJW 0           /* standardization, off by default until such time. */
+#endif
+
+#ifndef GENERIC_ENCODE_TABLES    /* These three are the RFC-spec'd app-specific */
+#define GENERIC_ENCODE_TABLES 0  /* code features.  This is tested but not recommended */
+#endif  			 /* unless there's a real application. */
+#ifndef GENERIC_ENCODE_TABLES_COMPUTE
+#define GENERIC_ENCODE_TABLES_COMPUTE 0
+#endif
+#ifndef GENERIC_ENCODE_TABLES_COMPUTE_PRINT
+#define GENERIC_ENCODE_TABLES_COMPUTE_PRINT 0
+#endif
+
+#if XD3_USE_LARGEFILE64          /* How does everyone else do this? */
+#ifndef WIN32
+#define Q "q"
+#else
+#define Q "I64"
+#endif
+#else
+#define Q
+#endif
+
+#if XD3_ENCODER
+#define IF_ENCODER(x) x
+#else
+#define IF_ENCODER(x)
+#endif
+
+/******************************************************************************************/
+
+typedef enum {
+
+  /* header indicator bits */
+  VCD_SECONDARY  = (1 << 0),  /* uses secondary compressor */
+  VCD_CODETABLE  = (1 << 1),  /* supplies code table data */
+  VCD_APPHEADER  = (1 << 2),  /* supplies application data */
+  VCD_INVHDR     = ~7U,
+
+  /* window indicator bits */
+  VCD_SOURCE     = (1 << 0),  /* copy window in source file */
+  VCD_TARGET     = (1 << 1),  /* copy window in target file */
+  VCD_ADLER32    = (1 << 2),  /* has adler32 checksum */
+  VCD_INVWIN     = ~7U,
+
+  VCD_SRCORTGT   = VCD_SOURCE | VCD_TARGET,
+
+  /* delta indicator bits */
+  VCD_DATACOMP   = (1 << 0),
+  VCD_INSTCOMP   = (1 << 1),
+  VCD_ADDRCOMP   = (1 << 2),
+  VCD_INVDEL     = ~0x7U,
+
+} xd3_indicator;
+
+typedef enum {
+  VCD_DJW_ID    = 1,
+  VCD_FGK_ID    = 16, /* !!!Note: these are not a standard IANA-allocated ID!!! */
+} xd3_secondary_ids;
+
+typedef enum {
+  SEC_NOFLAGS     = 0,
+  SEC_COUNT_FREQS = (1 << 0), /* OPT: Not implemented: Could eliminate first pass of Huffman... */
+} xd3_secondary_flags;
+
+typedef enum {
+  DATA_SECTION, /* These indicate which section to the secondary compressor. */
+  INST_SECTION, /* The header section is not compressed, therefore not listed here. */
+  ADDR_SECTION,
+} xd3_section_type;
+
+typedef enum
+{
+  XD3_NOOP = 0,
+  XD3_ADD  = 1,
+  XD3_RUN  = 2,
+  XD3_CPY  = 3, /* XD3_CPY rtypes are represented as (XD3_CPY + copy-mode value) */
+} xd3_rtype;
+
+/******************************************************************************************/
+
+#include "xdelta3-list.h"
+
+XD3_MAKELIST(xd3_rlist, xd3_rinst, link);
+
+/******************************************************************************************/
+
+#ifndef unlikely              /* The unlikely macro - any good? */
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define unlikely(x) __builtin_expect((x),0)
+#define likely(x)   __builtin_expect((x),1)
+#else
+#define unlikely(x) (x)
+#define likely(x)   (x)
+#endif
+#endif
+
+#define SECONDARY_MIN_SAVINGS 2  /* Secondary compression has to save at least this many bytes. */
+#define SECONDARY_MIN_INPUT   10 /* Secondary compression needs at least this many bytes. */
+
+#define VCDIFF_MAGIC1  0xd6  /* 1st file byte */
+#define VCDIFF_MAGIC2  0xc3  /* 2nd file byte */
+#define VCDIFF_MAGIC3  0xc4  /* 3rd file byte */
+#define VCDIFF_VERSION 0x00  /* 4th file byte */
+
+#define VCD_SELF       0     /* 1st address mode */
+#define VCD_HERE       1     /* 2nd address mode */
+
+#define CODE_TABLE_STRING_SIZE (6 * 256) /* Should fit a code table string. */
+#define CODE_TABLE_VCDIFF_SIZE (6 * 256) /* Should fit a compressed code table string */
+
+#define SECONDARY_ANY (SECONDARY_DJW || SECONDARY_FGK) /* True if any secondary compressor is used. */
+
+#define ALPHABET_SIZE      256  /* Used in test code--size of the secondary compressor alphabet. */
+
+#define HASH_PRIME         0    /* Old hashing experiments */
+#define HASH_PERMUTE       1
+#define ARITH_SMALL_CKSUM  1
+
+#define HASH_CKOFFSET      1U   /* Table entries distinguish "no-entry" from offset 0 using this offset. */
+
+#define MIN_SMALL_LOOK    2U    /* Match-optimization stuff. */
+#define MIN_LARGE_LOOK    2U
+#define MIN_MATCH_OFFSET  1U
+#define MAX_MATCH_SPLIT   18U   /* VCDIFF code table: 18 is the default limit for direct-coded ADD sizes */
+
+#define LEAST_MATCH_INCR  0   /* The least number of bytes an overlapping match must beat
+			       * the preceding match by.  This is a bias for the lazy
+			       * match optimization.  A non-zero value means that an
+			       * adjacent match has to be better by more than the step
+			       * between them.  0. */
+
+#define MIN_MATCH         4U  /* VCDIFF code table: MIN_MATCH=4 */
+#define MIN_ADD           1U  /* 1 */
+#define MIN_RUN           8U  /* The shortest run, if it is shorter than this an immediate
+			       * add/copy will be just as good.  ADD1/COPY6 = 1I+1D+1A bytes,
+			       * RUN18 = 1I+1D+1A. */
+
+#define MAX_MODES         9  /* Maximum number of nodes used for compression--does not limit decompression. */
+
+#define ENC_SECTS         4  /* Number of separate output sections. */
+
+#define HDR_TAIL(s)  (stream->enc_tails[0])
+#define DATA_TAIL(s) (stream->enc_tails[1])
+#define INST_TAIL(s) (stream->enc_tails[2])
+#define ADDR_TAIL(s) (stream->enc_tails[3])
+
+#define HDR_HEAD(s)  (stream->enc_heads[0])
+#define DATA_HEAD(s) (stream->enc_heads[1])
+#define INST_HEAD(s) (stream->enc_heads[2])
+#define ADDR_HEAD(s) (stream->enc_heads[3])
+
+#define SIZEOF_ARRAY(x) (sizeof(x) / sizeof(x[0]))
+
+#define TOTAL_MODES(x) (2+(x)->acache.s_same+(x)->acache.s_near)
+
+/* Template instances. */
+#if XD3_BUILD_SLOW
+#define IF_BUILD_SLOW(x) x
+#else
+#define IF_BUILD_SLOW(x)
+#endif
+#if XD3_BUILD_FAST
+#define IF_BUILD_FAST(x) x
+#else
+#define IF_BUILD_FAST(x)
+#endif
+#if XD3_BUILD_FASTEST
+#define IF_BUILD_FASTEST(x) x
+#else
+#define IF_BUILD_FASTEST(x)
+#endif
+#if XD3_BUILD_SOFT
+#define IF_BUILD_SOFT(x) x
+#else
+#define IF_BUILD_SOFT(x)
+#endif
+#if XD3_BUILD_DEFAULT
+#define IF_BUILD_DEFAULT(x) x
+#else
+#define IF_BUILD_DEFAULT(x)
+#endif
+
+IF_BUILD_SOFT(static const xd3_smatcher    __smatcher_soft;)
+IF_BUILD_FAST(static const xd3_smatcher    __smatcher_fast;)
+IF_BUILD_SLOW(static const xd3_smatcher    __smatcher_slow;)
+IF_BUILD_FASTEST(static const xd3_smatcher    __smatcher_fastest;)
+IF_BUILD_DEFAULT(static const xd3_smatcher    __smatcher_default;)
+
+#if XD3_DEBUG
+#define SMALL_HASH_DEBUG1(s,inp)                                  \
+  usize_t debug_hval = xd3_checksum_hash (& (s)->small_hash,       \
+         xd3_scksum ((inp), (s)->smatcher.small_look))
+#define SMALL_HASH_DEBUG2(s,inp)                                  \
+  XD3_ASSERT (debug_hval == xd3_checksum_hash (& (s)->small_hash, \
+	 xd3_scksum ((inp), (s)->smatcher.small_look)))
+#else
+#define SMALL_HASH_DEBUG1(s,inp)
+#define SMALL_HASH_DEBUG2(s,inp)
+#endif /* XD3_DEBUG */
+
+/* Update the run-length state */
+#define NEXTRUN(c) do { if ((c) == run_c) { run_l += 1; } else { run_c = (c); run_l = 1; } } while (0)
+
+/* Update the checksum state. */
+#define LARGE_CKSUM_UPDATE(cksum,base,look)                              \
+  do {                                                                   \
+    uint32_t old_c = PERMUTE((base)[0]);                                    \
+    uint32_t new_c = PERMUTE((base)[(look)]);                               \
+    uint32_t low   = (((cksum) & 0xffff) - old_c + new_c) & 0xffff;         \
+    uint32_t high  = (((cksum) >> 16) - (old_c * (look)) + low) & 0xffff;   \
+    (cksum) = (high << 16) | low;                                        \
+  } while (0)
+
+/* Multiply and add hash function */
+#if ARITH_SMALL_CKSUM
+#define SMALL_CKSUM_UPDATE(cksum,base,look) (cksum) = ((*(unsigned long*)(base+1)) * 71143)
+#else
+#define SMALL_CKSUM_UPDATE LARGE_CKSUM_UPDATE
+#endif
+
+/* Consume N bytes of input, only used by the decoder. */
+#define DECODE_INPUT(n)             \
+  do {                              \
+  stream->total_in += (xoff_t) (n); \
+  stream->avail_in -= (n);          \
+  stream->next_in  += (n);          \
+  } while (0)
+
+/* This CPP-conditional stuff can be cleaned up... */
+#if XD3_DEBUG
+#define IF_DEBUG(x) x
+#define DEBUG_ARG(x) , x
+#else
+#define IF_DEBUG(x)
+#define DEBUG_ARG(x)
+#endif
+#if XD3_DEBUG > 1
+#define IF_DEBUG1(x) x
+#else
+#define IF_DEBUG1(x)
+#endif
+#if XD3_DEBUG > 2
+#define IF_DEBUG2(x) x
+#else
+#define IF_DEBUG2(x)
+#endif
+#if REGRESSION_TEST
+#define IF_REGRESSION(x) x
+#else
+#define IF_REGRESSION(x)
+#endif
+
+/******************************************************************************************/
+
+#if XD3_ENCODER
+static void*       xd3_alloc0 (xd3_stream *stream,
+			       usize_t      elts,
+			       usize_t      size);
+
+
+static xd3_output* xd3_alloc_output (xd3_stream *stream,
+				     xd3_output *old_output);
+
+static int         xd3_alloc_iopt (xd3_stream *stream, int elts);
+
+static void        xd3_free_output (xd3_stream *stream,
+				    xd3_output *output);
+
+static int         xd3_emit_byte (xd3_stream  *stream,
+				  xd3_output **outputp,
+				  uint8_t      code);
+
+static int         xd3_emit_bytes (xd3_stream     *stream,
+				   xd3_output    **outputp,
+				   const uint8_t  *base,
+				   usize_t          size);
+
+static int         xd3_emit_double (xd3_stream *stream, xd3_rinst *first, xd3_rinst *second, uint code);
+static int         xd3_emit_single (xd3_stream *stream, xd3_rinst *single, uint code);
+
+static usize_t      xd3_sizeof_output (xd3_output *output);
+
+static int         xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos);
+static int         xd3_source_extend_match (xd3_stream *stream);
+static int         xd3_srcwin_setup (xd3_stream *stream);
+static usize_t     xd3_iopt_last_matched (xd3_stream *stream);
+static int         xd3_emit_uint32_t (xd3_stream *stream, xd3_output **output, uint32_t num);
+
+#endif /* XD3_ENCODER */
+
+static int         xd3_decode_allocate (xd3_stream  *stream, usize_t       size,
+					uint8_t    **copied1, usize_t      *alloc1,
+					uint8_t    **copied2, usize_t      *alloc2);
+
+static void        xd3_compute_code_table_string (const xd3_dinst *code_table, uint8_t *str);
+static void*       xd3_alloc (xd3_stream *stream, usize_t      elts, usize_t      size);
+static void        xd3_free  (xd3_stream *stream, void       *ptr);
+
+static int         xd3_read_uint32_t (xd3_stream *stream, const uint8_t **inpp,
+				      const uint8_t *max, uint32_t *valp);
+
+#if REGRESSION_TEST
+static int         xd3_selftest      (void);
+#endif
+
+/******************************************************************************************/
+
+#define UINT32_OFLOW_MASK 0xfe000000U
+#define UINT64_OFLOW_MASK 0xfe00000000000000ULL
+
+#ifndef UINT32_MAX
+#define UINT32_MAX 4294967295U
+#endif
+
+#ifndef UINT64_MAX
+#define UINT64_MAX 18446744073709551615ULL
+#endif
+
+#if SIZEOF_USIZE_T == 4
+#define USIZE_T_MAX        UINT32_MAX
+#define xd3_decode_size   xd3_decode_uint32_t
+#define xd3_emit_size     xd3_emit_uint32_t
+#define xd3_sizeof_size   xd3_sizeof_uint32_t
+#define xd3_read_size     xd3_read_uint32_t
+#elif SIZEOF_USIZE_T == 8
+#define USIZE_T_MAX        UINT64_MAX
+#define xd3_decode_size   xd3_decode_uint64_t
+#define xd3_emit_size     xd3_emit_uint64_t
+#define xd3_sizeof_size   xd3_sizeof_uint64_t
+#define xd3_read_size     xd3_read_uint64_t
+#endif
+
+#if SIZEOF_XOFF_T == 4
+#define XOFF_T_MAX        UINT32_MAX
+#define xd3_decode_offset xd3_decode_uint32_t
+#define xd3_emit_offset   xd3_emit_uint32_t
+#elif SIZEOF_XOFF_T == 8
+#define XOFF_T_MAX        UINT64_MAX
+#define xd3_decode_offset xd3_decode_uint64_t
+#define xd3_emit_offset   xd3_emit_uint64_t
+#endif
+
+#define USIZE_T_OVERFLOW(a,b) ((USIZE_T_MAX - (usize_t) (a)) < (usize_t) (b))
+#define XOFF_T_OVERFLOW(a,b) ((XOFF_T_MAX - (xoff_t) (a)) < (xoff_t) (b))
+
+const char* xd3_strerror (int ret)
+{
+  switch (ret)
+    {
+    case XD3_INPUT: return "XD3_INPUT";
+    case XD3_OUTPUT: return "XD3_OUTPUT";
+    case XD3_GETSRCBLK: return "XD3_GETSRCBLK";
+    case XD3_GOTHEADER: return "XD3_GOTHEADER";
+    case XD3_WINSTART: return "XD3_WINSTART";
+    case XD3_WINFINISH: return "XD3_WINFINISH";
+    case XD3_TOOFARBACK: return "XD3_TOOFARBACK";
+    case XD3_INTERNAL: return "XD3_INTERNAL";
+    }
+  return NULL;
+}
+
+/******************************************************************************************/
+
+#if SECONDARY_ANY == 0
+#define IF_SEC(x)
+#define IF_NSEC(x) x
+#else /* yuck */
+#define IF_SEC(x) x
+#define IF_NSEC(x)
+#include "xdelta3-second.h"
+#endif /* SECONDARY_ANY */
+
+#if SECONDARY_FGK
+#include "xdelta3-fgk.h"
+
+static const xd3_sec_type fgk_sec_type =
+{
+  VCD_FGK_ID,
+  "FGK Adaptive Huffman",
+  SEC_NOFLAGS,
+  (xd3_sec_stream* (*)())  fgk_alloc,
+  (void (*)())             fgk_destroy,
+  (void (*)())             fgk_init,
+  (int (*)())              xd3_decode_fgk,
+  IF_ENCODER((int (*)())   xd3_encode_fgk)
+};
+
+#define IF_FGK(x) x
+#define FGK_CASE(s) \
+  s->sec_type = & fgk_sec_type; \
+  break;
+#else
+#define IF_FGK(x)
+#define FGK_CASE(s) \
+  s->msg = "unavailable secondary compressor: FGK Adaptive Huffman"; \
+  return XD3_INTERNAL;
+#endif
+
+#if SECONDARY_DJW
+#include "xdelta3-djw.h"
+
+static const xd3_sec_type djw_sec_type =
+{
+  VCD_DJW_ID,
+  "Static Huffman",
+  SEC_COUNT_FREQS,
+  (xd3_sec_stream* (*)())  djw_alloc,
+  (void (*)())             djw_destroy,
+  (void (*)())             djw_init,
+  (int (*)())              xd3_decode_huff,
+  IF_ENCODER((int (*)())   xd3_encode_huff)
+};
+
+#define IF_DJW(x) x
+#define DJW_CASE(s) \
+  s->sec_type = & djw_sec_type; \
+  break;
+#else
+#define IF_DJW(x)
+#define DJW_CASE(s) \
+  s->msg = "unavailable secondary compressor: DJW Static Huffman"; \
+  return XD3_INTERNAL;
+#endif
+
+/******************************************************************************************/
+
+/* Process the inline pass. */
+#define __XDELTA3_C_INLINE_PASS__
+#include "xdelta3.c"
+#undef __XDELTA3_C_INLINE_PASS__
+
+/* Process template passes - this includes xdelta3.c several times. */
+#define __XDELTA3_C_TEMPLATE_PASS__
+#include "xdelta3-cfgs.h"
+#undef __XDELTA3_C_TEMPLATE_PASS__
+
+#if XD3_MAIN || PYTHON_MODULE || SWIG_MODULE
+#include "xdelta3-main.h"
+#endif
+
+#if REGRESSION_TEST
+#include "xdelta3-test.h"
+#endif
+
+#if PYTHON_MODULE
+#include "xdelta3-python.h"
+#endif
+
+#endif /* __XDELTA3_C_HEADER_PASS__ */
+#ifdef __XDELTA3_C_INLINE_PASS__
+
+/******************************************************************************************
+ Instruction tables
+ ******************************************************************************************/
+
+/* The following code implements a parametrized description of the
+ * code table given above for a few reasons.  It is not necessary for
+ * implementing the standard, to support compression with variable
+ * tables, so an implementation is only required to know the default
+ * code table to begin decompression.  (If the encoder uses an
+ * alternate table, the table is included in compressed form inside
+ * the VCDIFF file.)
+ *
+ * Before adding variable-table support there were two functions which
+ * were hard-coded to the default table above.
+ * xd3_compute_default_table() would create the default table by
+ * filling a 256-elt array of xd3_dinst values.  The corresponding
+ * function, xd3_choose_instruction(), would choose an instruction
+ * based on the hard-coded parameters of the default code table.
+ *
+ * Notes: The parametrized code table description here only generates
+ * tables of a certain regularity similar to the default table by
+ * allowing to vary the distribution of single- and
+ * double-instructions and change the number of near and same copy
+ * modes.  More exotic tables are only possible by extending this
+ * code.
+ *
+ * For performance reasons, both the parametrized and non-parametrized
+ * versions of xd3_choose_instruction remain.  The parametrized
+ * version is only needed for testing multi-table decoding support.
+ * If ever multi-table encoding is required, this can be optimized by
+ * compiling static functions for each table.
+ */
+
+/* The XD3_CHOOSE_INSTRUCTION calls xd3_choose_instruction with the
+ * table description when GENERIC_ENCODE_TABLES are in use.  The
+ * IF_GENCODETBL macro enables generic-code-table specific code. */
+#if GENERIC_ENCODE_TABLES
+#define XD3_CHOOSE_INSTRUCTION(stream,prev,inst) xd3_choose_instruction (stream->code_table_desc, prev, inst)
+#define IF_GENCODETBL(x) x
+#else
+#define XD3_CHOOSE_INSTRUCTION(stream,prev,inst) xd3_choose_instruction (prev, inst)
+#define IF_GENCODETBL(x)
+#endif
+
+/* This structure maintains information needed by
+ * xd3_choose_instruction to compute the code for a double instruction
+ * by first indexing an array of code_table_sizes by copy mode, then
+ * using (offset + (muliplier * X)) */
+struct _xd3_code_table_sizes {
+  uint8_t cpy_max;
+  uint8_t offset;
+  uint8_t mult;
+};
+
+/* This contains a complete description of a code table. */
+struct _xd3_code_table_desc
+{
+  /* Assumes a single RUN instruction */
+  /* Assumes that MIN_MATCH is 4 */
+
+  uint8_t add_sizes;            /* Number of immediate-size single adds (default 17) */
+  uint8_t near_modes;           /* Number of near copy modes (default 4) */
+  uint8_t same_modes;           /* Number of same copy modes (default 3) */
+  uint8_t cpy_sizes;            /* Number of immediate-size single copies (default 15) */
+
+  uint8_t addcopy_add_max;      /* Maximum add size for an add-copy double instruction, all modes (default 4) */
+  uint8_t addcopy_near_cpy_max; /* Maximum cpy size for an add-copy double instruction, up through VCD_NEAR modes (default 6) */
+  uint8_t addcopy_same_cpy_max; /* Maximum cpy size for an add-copy double instruction, VCD_SAME modes (default 4) */
+
+  uint8_t copyadd_add_max;      /* Maximum add size for a copy-add double instruction, all modes (default 1) */
+  uint8_t copyadd_near_cpy_max; /* Maximum cpy size for a copy-add double instruction, up through VCD_NEAR modes (default 4) */
+  uint8_t copyadd_same_cpy_max; /* Maximum cpy size for a copy-add double instruction, VCD_SAME modes (default 4) */
+
+  xd3_code_table_sizes addcopy_max_sizes[MAX_MODES];
+  xd3_code_table_sizes copyadd_max_sizes[MAX_MODES];
+};
+
+/* The rfc3284 code table is represented: */
+static const xd3_code_table_desc __rfc3284_code_table_desc = {
+  17, /* add sizes */
+  4,  /* near modes */
+  3,  /* same modes */
+  15, /* copy sizes */
+
+  4,  /* add-copy max add */
+  6,  /* add-copy max cpy, near */
+  4,  /* add-copy max cpy, same */
+
+  1,  /* copy-add max add */
+  4,  /* copy-add max cpy, near */
+  4,  /* copy-add max cpy, same */
+
+  /* addcopy */
+  { {6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3},{4,235,1},{4,239,1},{4,243,1} },
+  /* copyadd */
+  { {4,247,1},{4,248,1},{4,249,1},{4,250,1},{4,251,1},{4,252,1},{4,253,1},{4,254,1},{4,255,1} },
+};
+
+#if GENERIC_ENCODE_TABLES
+/* An alternate code table for testing (5 near, 0 same):
+ *
+ *         TYPE      SIZE     MODE    TYPE     SIZE     MODE     INDEX
+ *        ---------------------------------------------------------------
+ *     1.  Run         0        0     Noop       0        0        0
+ *     2.  Add    0, [1,23]     0     Noop       0        0      [1,24]
+ *     3.  Copy   0, [4,20]     0     Noop       0        0     [25,42]
+ *     4.  Copy   0, [4,20]     1     Noop       0        0     [43,60]
+ *     5.  Copy   0, [4,20]     2     Noop       0        0     [61,78]
+ *     6.  Copy   0, [4,20]     3     Noop       0        0     [79,96]
+ *     7.  Copy   0, [4,20]     4     Noop       0        0     [97,114]
+ *     8.  Copy   0, [4,20]     5     Noop       0        0    [115,132]
+ *     9.  Copy   0, [4,20]     6     Noop       0        0    [133,150]
+ *    10.  Add       [1,4]      0     Copy     [4,6]      0    [151,162]
+ *    11.  Add       [1,4]      0     Copy     [4,6]      1    [163,174]
+ *    12.  Add       [1,4]      0     Copy     [4,6]      2    [175,186]
+ *    13.  Add       [1,4]      0     Copy     [4,6]      3    [187,198]
+ *    14.  Add       [1,4]      0     Copy     [4,6]      4    [199,210]
+ *    15.  Add       [1,4]      0     Copy     [4,6]      5    [211,222]
+ *    16.  Add       [1,4]      0     Copy     [4,6]      6    [223,234]
+ *    17.  Copy        4      [0,6]   Add      [1,3]      0    [235,255]
+ *        --------------------------------------------------------------- */
+static const xd3_code_table_desc __alternate_code_table_desc = {
+  23, /* add sizes */
+  5,  /* near modes */
+  0,  /* same modes */
+  17, /* copy sizes */
+
+  4,  /* add-copy max add */
+  6,  /* add-copy max cpy, near */
+  0,  /* add-copy max cpy, same */
+
+  3,  /* copy-add max add */
+  4,  /* copy-add max cpy, near */
+  0,  /* copy-add max cpy, same */
+
+  /* addcopy */
+  { {6,151,3},{6,163,3},{6,175,3},{6,187,3},{6,199,3},{6,211,3},{6,223,3},{0,0,0},{0,0,0} },
+  /* copyadd */
+  { {4,235,1},{4,238,1},{4,241,1},{4,244,1},{4,247,1},{4,250,1},{4,253,1},{0,0,0},{0,0,0} },
+};
+#endif
+
+/* Computes code table entries of TBL using the specified description. */
+static void
+xd3_build_code_table (const xd3_code_table_desc *desc, xd3_dinst *tbl)
+{
+  int size1, size2, mode;
+  int cpy_modes = 2 + desc->near_modes + desc->same_modes;
+  xd3_dinst *d = tbl;
+
+  (d++)->type1 = XD3_RUN;
+  (d++)->type1 = XD3_ADD;
+
+  for (size1 = 1; size1 <= desc->add_sizes; size1 += 1, d += 1)
+    {
+      d->type1 = XD3_ADD;
+      d->size1 = size1;
+    }
+
+  for (mode = 0; mode < cpy_modes; mode += 1)
+    {
+      (d++)->type1 = XD3_CPY + mode;
+
+      for (size1 = MIN_MATCH; size1 < MIN_MATCH + desc->cpy_sizes; size1 += 1, d += 1)
+	{
+	  d->type1 = XD3_CPY + mode;
+	  d->size1 = size1;
+	}
+    }
+
+  for (mode = 0; mode < cpy_modes; mode += 1)
+    {
+      for (size1 = 1; size1 <= desc->addcopy_add_max; size1 += 1)
+	{
+	  int max = (mode < 2 + desc->near_modes) ? desc->addcopy_near_cpy_max : desc->addcopy_same_cpy_max;
+
+	  for (size2 = MIN_MATCH; size2 <= max; size2 += 1, d += 1)
+	    {
+	      d->type1 = XD3_ADD;
+	      d->size1 = size1;
+	      d->type2 = XD3_CPY + mode;
+	      d->size2 = size2;
+	    }
+	}
+    }
+
+  for (mode = 0; mode < cpy_modes; mode += 1)
+    {
+      int max = (mode < 2 + desc->near_modes) ? desc->copyadd_near_cpy_max : desc->copyadd_same_cpy_max;
+
+      for (size1 = MIN_MATCH; size1 <= max; size1 += 1)
+	{
+	  for (size2 = 1; size2 <= desc->copyadd_add_max; size2 += 1, d += 1)
+	    {
+	      d->type1 = XD3_CPY + mode;
+	      d->size1 = size1;
+	      d->type2 = XD3_ADD;
+	      d->size2 = size2;
+	    }
+	}
+    }
+
+  XD3_ASSERT (d - tbl == 256);
+}
+
+/* This function generates the static default code table. */
+static const xd3_dinst*
+xd3_rfc3284_code_table (void)
+{
+  static xd3_dinst __rfc3284_code_table[256];
+
+  if (__rfc3284_code_table[0].type1 != XD3_RUN)
+    {
+      xd3_build_code_table (& __rfc3284_code_table_desc, __rfc3284_code_table);
+    }
+
+  return __rfc3284_code_table;
+}
+
+#if XD3_ENCODER
+#if GENERIC_ENCODE_TABLES
+/* This function generates the alternate code table. */
+static const xd3_dinst*
+xd3_alternate_code_table (void)
+{
+  static xd3_dinst __alternate_code_table[256];
+
+  if (__alternate_code_table[0].type1 != XD3_RUN)
+    {
+      xd3_build_code_table (& __alternate_code_table_desc, __alternate_code_table);
+    }
+
+  return __alternate_code_table;
+}
+
+/* This function computes the ideal second instruction INST based on preceding instruction
+ * PREV.  If it is possible to issue a double instruction based on this pair it sets
+ * PREV->code2, otherwise it sets INST->code1. */
+static void
+xd3_choose_instruction (const xd3_code_table_desc *desc, xd3_rinst *prev, xd3_rinst *inst)
+{
+  switch (inst->type)
+    {
+    case XD3_RUN:
+      /* The 0th instruction is RUN */
+      inst->code1 = 0;
+      break;
+
+    case XD3_ADD:
+
+      if (inst->size > desc->add_sizes)
+	{
+	  /* The first instruction is non-immediate ADD */
+	  inst->code1 = 1;
+	}
+      else
+	{
+	  /* The following ADD_SIZES instructions are immediate ADDs */
+	  inst->code1 = 1 + inst->size;
+
+	  /* Now check for a possible COPY-ADD double instruction */
+	  if (prev != NULL)
+	    {
+	      int prev_mode = prev->type - XD3_CPY;
+
+	      /* If previous is a copy.  Note: as long as the previous is not a RUN
+	       * instruction, it should be a copy because it cannot be an add.  This check
+	       * is more clear. */
+	      if (prev_mode >= 0 && inst->size <= desc->copyadd_add_max)
+		{
+		  const xd3_code_table_sizes *sizes = & desc->copyadd_max_sizes[prev_mode];
+
+		  /* This check and the inst->size-<= above are == in the default table. */
+		  if (prev->size <= sizes->cpy_max)
+		    {
+		      /* The second and third exprs are 0 in the default table. */
+		      prev->code2 = sizes->offset + (sizes->mult * (prev->size - MIN_MATCH)) + (inst->size - MIN_ADD);
+		    }
+		}
+	    }
+	}
+      break;
+
+    default:
+      {
+	int mode = inst->type - XD3_CPY;
+
+	/* The large copy instruction is offset by the run, large add, and immediate adds,
+	 * then multipled by the number of immediate copies plus one (the large copy)
+	 * (i.e., if there are 15 immediate copy instructions then there are 16 copy
+	 * instructions per mode). */
+	inst->code1 = 2 + desc->add_sizes + (1 + desc->cpy_sizes) * mode;
+
+	/* Now if the copy is short enough for an immediate instruction. */
+	if (inst->size < MIN_MATCH + desc->cpy_sizes)
+	  {
+	    inst->code1 += inst->size + 1 - MIN_MATCH;
+
+	    /* Now check for a possible ADD-COPY double instruction. */
+	    if ( (prev != NULL) &&
+		 (prev->type == XD3_ADD) &&
+		 (prev->size <= desc->addcopy_add_max) )
+	      {
+		const xd3_code_table_sizes *sizes = & desc->addcopy_max_sizes[mode];
+
+		if (inst->size <= sizes->cpy_max)
+		  {
+		    prev->code2 = sizes->offset + (sizes->mult * (prev->size - MIN_ADD)) + (inst->size - MIN_MATCH);
+		  }
+	      }
+	  }
+      }
+    }
+}
+#else /* GENERIC_ENCODE_TABLES */
+
+/* This version of xd3_choose_instruction is hard-coded for the default table. */
+static void
+xd3_choose_instruction (/* const xd3_code_table_desc *desc,*/ xd3_rinst *prev, xd3_rinst *inst)
+{
+  switch (inst->type)
+    {
+    case XD3_RUN:
+      inst->code1 = 0;
+      break;
+
+    case XD3_ADD:
+      inst->code1 = 1;
+
+      if (inst->size <= 17)
+	{
+	  inst->code1 += inst->size;
+
+	  if ( (inst->size == 1) &&
+	       (prev != NULL) &&
+	       (prev->size == 4) &&
+	       (prev->type >= XD3_CPY) )
+	    {
+	      prev->code2 = 247 + (prev->type - XD3_CPY);
+	    }
+	}
+
+      break;
+
+    default:
+      {
+	int mode = inst->type - XD3_CPY;
+
+	XD3_ASSERT (inst->type >= XD3_CPY && inst->type < 12);
+
+	inst->code1 = 19 + 16 * mode;
+
+	if (inst->size <= 18)
+	  {
+	    inst->code1 += inst->size - 3;
+
+	    if ( (prev != NULL) &&
+		 (prev->type == XD3_ADD) &&
+		 (prev->size <= 4) )
+	      {
+		if ( (inst->size <= 6) &&
+		     (mode       <= 5) )
+		  {
+		    prev->code2 = 163 + (mode * 12) + (3 * (prev->size - 1)) + (inst->size - 4);
+
+		    XD3_ASSERT (prev->code2 <= 234);
+		  }
+		else if ( (inst->size == 4) &&
+			  (mode       >= 6) )
+		  {
+		    prev->code2 = 235 + ((mode - 6) * 4) + (prev->size - 1);
+
+		    XD3_ASSERT (prev->code2 <= 246);
+		  }
+	      }
+	  }
+
+	XD3_ASSERT (inst->code1 <= 162);
+      }
+      break;
+    }
+}
+#endif /* GENERIC_ENCODE_TABLES */
+
+/******************************************************************************************
+ Instruction table encoder/decoder
+ ******************************************************************************************/
+
+#if GENERIC_ENCODE_TABLES
+#if GENERIC_ENCODE_TABLES_COMPUTE == 0
+
+/* In this case, we hard-code the result of compute_code_table_encoding for each alternate
+ * code table, presuming that saves time/space.  This has been 131 bytes, but secondary
+ * compression was turned off. */
+static const uint8_t __alternate_code_table_compressed[178] =
+{0xd6,0xc3,0xc4,0x00,0x00,0x01,0x8a,0x6f,0x40,0x81,0x27,0x8c,0x00,0x00,0x4a,0x4a,0x0d,0x02,0x01,0x03,
+0x01,0x03,0x00,0x01,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,
+0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x00,0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x03,0x04,
+0x04,0x04,0x04,0x00,0x04,0x05,0x06,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x05,0x05,0x05,
+0x06,0x06,0x06,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x00,0x02,0x00,0x18,0x13,0x63,0x00,0x1b,0x00,0x54,
+0x00,0x15,0x23,0x6f,0x00,0x28,0x13,0x54,0x00,0x15,0x01,0x1a,0x31,0x23,0x6c,0x0d,0x23,0x48,0x00,0x15,
+0x93,0x6f,0x00,0x28,0x04,0x23,0x51,0x04,0x32,0x00,0x2b,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x12,0x00,
+0x12,0x00,0x12,0x53,0x57,0x9c,0x07,0x43,0x6f,0x00,0x34,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,
+0x0c,0x00,0x0c,0x00,0x15,0x00,0x82,0x6f,0x00,0x15,0x12,0x0c,0x00,0x03,0x03,0x00,0x06,0x00,};
+
+static int
+xd3_compute_alternate_table_encoding (xd3_stream *stream, const uint8_t **data, usize_t *size)
+{
+  (*data) = __alternate_code_table_compressed;
+  (*size) = sizeof (__alternate_code_table_compressed);
+  return 0;
+}
+
+#else
+
+/* The alternate code table will be computed and stored here. */
+static uint8_t __alternate_code_table_compressed[CODE_TABLE_VCDIFF_SIZE];
+static usize_t  __alternate_code_table_compressed_size;
+
+/* This function generates a delta describing the code table for encoding within a VCDIFF
+ * file.  This function is NOT thread safe because it is only intended that this function
+ * is used to generate statically-compiled strings. */
+int xd3_compute_code_table_encoding (xd3_stream *in_stream, const xd3_dinst *code_table,
+				     uint8_t *comp_string, usize_t *comp_string_size)
+{
+  /* TODO: use xd3_encode_memory() */
+  uint8_t dflt_string[CODE_TABLE_STRING_SIZE];
+  uint8_t code_string[CODE_TABLE_STRING_SIZE];
+  xd3_stream stream;
+  xd3_source source;
+  xd3_config config;
+  int ret;
+
+  memset (& source, 0, sizeof (source));
+
+  xd3_compute_code_table_string (xd3_rfc3284_code_table (), dflt_string);
+  xd3_compute_code_table_string (code_table, code_string);
+
+  /* Use DJW secondary compression if it is on by default.  This saves about 20 bytes. */
+  xd3_init_config (& config, XD3_FLUSH | (SECONDARY_DJW ? XD3_SEC_DJW : 0));
+
+  /* Be exhaustive. */
+  config.sprevsz = 1<<11;
+  config.srcwin_maxsz = CODE_TABLE_STRING_SIZE;
+
+  config.smatch_cfg = XD3_SMATCH_SOFT;
+  config.smatcher_soft.large_look    = 4;
+  config.smatcher_soft.large_step    = 1;
+  config.smatcher_soft.small_look    = 4;
+  config.smatcher_soft.small_chain   = CODE_TABLE_STRING_SIZE;
+  config.smatcher_soft.small_lchain  = CODE_TABLE_STRING_SIZE;
+  config.smatcher_soft.max_lazy      = CODE_TABLE_STRING_SIZE;
+  config.smatcher_soft.long_enough   = CODE_TABLE_STRING_SIZE;
+
+  if ((ret = xd3_config_stream (& stream, & config))) { goto fail; }
+
+  source.size     = CODE_TABLE_STRING_SIZE;
+  source.blksize  = CODE_TABLE_STRING_SIZE;
+  source.onblk    = CODE_TABLE_STRING_SIZE;
+  source.name     = "";
+  source.curblk   = dflt_string;
+  source.curblkno = 0;
+
+  if ((ret = xd3_set_source (& stream, & source))) { goto fail; }
+
+  if ((ret = xd3_encode_stream (& stream, code_string, CODE_TABLE_STRING_SIZE,
+				comp_string, comp_string_size, CODE_TABLE_VCDIFF_SIZE))) { goto fail; }
+
+ fail:
+
+  in_stream->msg = stream.msg;
+  xd3_free_stream (& stream);
+  return ret;
+}
+
+/* Compute a delta between alternate and rfc3284 tables.  As soon as another alternate
+ * table is added, this code should become generic.  For now there is only one alternate
+ * table for testing. */
+static int
+xd3_compute_alternate_table_encoding (xd3_stream *stream, const uint8_t **data, usize_t *size)
+{
+  int ret;
+
+  if (__alternate_code_table_compressed[0] == 0)
+    {
+      if ((ret = xd3_compute_code_table_encoding (stream, xd3_alternate_code_table (),
+						  __alternate_code_table_compressed,
+						  & __alternate_code_table_compressed_size)))
+	{
+	  return ret;
+	}
+
+      /* During development of a new code table, enable this variable to print the new
+       * static contents and determine its size.  At run time the table will be filled in
+       * appropriately, but at least it should have the proper size beforehand. */
+#if GENERIC_ENCODE_TABLES_COMPUTE_PRINT
+      {
+	int i;
+
+	DP(RINT, "\nstatic const usize_t __alternate_code_table_compressed_size = %u;\n",
+		 __alternate_code_table_compressed_size);
+
+	DP(RINT, "static const uint8_t __alternate_code_table_compressed[%u] =\n{",
+		 __alternate_code_table_compressed_size);
+
+	for (i = 0; i < __alternate_code_table_compressed_size; i += 1)
+	  {
+	    DP(RINT, "0x%02x,", __alternate_code_table_compressed[i]);
+	    if ((i % 20) == 19) { DP(RINT, "\n"); }
+	  }
+
+	DP(RINT, "};\n");
+      }
+#endif
+    }
+
+  (*data) = __alternate_code_table_compressed;
+  (*size) = __alternate_code_table_compressed_size;
+
+  return 0;
+}
+#endif /* GENERIC_ENCODE_TABLES_COMPUTE != 0 */
+#endif /* GENERIC_ENCODE_TABLES */
+
+#endif /* XD3_ENCODER */
+
+/* This function generates the 1536-byte string specified in sections 5.4 and 7 of
+ * rfc3284, which is used to represent a code table within a VCDIFF file. */
+void xd3_compute_code_table_string (const xd3_dinst *code_table, uint8_t *str)
+{
+  int i, s;
+
+  XD3_ASSERT (CODE_TABLE_STRING_SIZE == 6 * 256);
+
+  for (s = 0; s < 6; s += 1)
+    {
+      for (i = 0; i < 256; i += 1)
+	{
+	  switch (s)
+	    {
+	    case 0: *str++ = (code_table[i].type1 >= XD3_CPY ? XD3_CPY : code_table[i].type1); break;
+	    case 1: *str++ = (code_table[i].type2 >= XD3_CPY ? XD3_CPY : code_table[i].type2); break;
+	    case 2: *str++ = (code_table[i].size1); break;
+	    case 3: *str++ = (code_table[i].size2); break;
+	    case 4: *str++ = (code_table[i].type1 >= XD3_CPY ? code_table[i].type1 - XD3_CPY : 0); break;
+	    case 5: *str++ = (code_table[i].type2 >= XD3_CPY ? code_table[i].type2 - XD3_CPY : 0); break;
+	    }
+	}
+    }
+}
+
+/* This function translates the code table string into the internal representation.  The
+ * stream's near and same-modes should already be set. */
+static int
+xd3_apply_table_string (xd3_stream *stream, const uint8_t *code_string)
+{
+  int i, s;
+  int modes = TOTAL_MODES (stream);
+  xd3_dinst *code_table;
+
+  if ((code_table = stream->code_table_alloc = xd3_alloc (stream, sizeof (xd3_dinst), 256)) == NULL)
+    {
+      return ENOMEM;
+    }
+
+  for (s = 0; s < 6; s += 1)
+    {
+      for (i = 0; i < 256; i += 1)
+	{
+	  switch (s)
+	    {
+	    case 0:
+	      if (*code_string > XD3_CPY)
+		{
+		  stream->msg = "invalid code-table opcode";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].type1 = *code_string++;
+	      break;
+	    case 1:
+	      if (*code_string > XD3_CPY)
+		{
+		  stream->msg = "invalid code-table opcode";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].type2 = *code_string++;
+	      break;
+	    case 2:
+	      if (*code_string != 0 && code_table[i].type1 == XD3_NOOP)
+		{
+		  stream->msg = "invalid code-table size";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].size1 = *code_string++;
+	      break;
+	    case 3:
+	      if (*code_string != 0 && code_table[i].type2 == XD3_NOOP)
+		{
+		  stream->msg = "invalid code-table size";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].size2 = *code_string++;
+	      break;
+	    case 4:
+	      if (*code_string >= modes)
+		{
+		  stream->msg = "invalid code-table mode";
+		  return XD3_INTERNAL;
+		}
+	      if (*code_string != 0 && code_table[i].type1 != XD3_CPY)
+		{
+		  stream->msg = "invalid code-table mode";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].type1 += *code_string++;
+	      break;
+	    case 5:
+	      if (*code_string >= modes)
+		{
+		  stream->msg = "invalid code-table mode";
+		  return XD3_INTERNAL;
+		}
+	      if (*code_string != 0 && code_table[i].type2 != XD3_CPY)
+		{
+		  stream->msg = "invalid code-table mode";
+		  return XD3_INTERNAL;
+		}
+	      code_table[i].type2 += *code_string++;
+	      break;
+	    }
+	}
+    }
+
+  stream->code_table = code_table;
+  return 0;
+}
+
+/* This function applies a code table delta and returns an actual code table. */
+static int
+xd3_apply_table_encoding (xd3_stream *in_stream, const uint8_t *data, usize_t size)
+{
+  uint8_t dflt_string[CODE_TABLE_STRING_SIZE];
+  uint8_t code_string[CODE_TABLE_STRING_SIZE];
+  usize_t code_size;
+  xd3_stream stream;
+  xd3_source source;
+  int ret;
+
+  /* The default code table string can be cached if alternate code tables ever become
+   * popular. */
+  xd3_compute_code_table_string (xd3_rfc3284_code_table (), dflt_string);
+
+  source.size     = CODE_TABLE_STRING_SIZE;
+  source.blksize  = CODE_TABLE_STRING_SIZE;
+  source.onblk    = CODE_TABLE_STRING_SIZE;
+  source.name     = "rfc3284 code table";
+  source.curblk   = dflt_string;
+  source.curblkno = 0;
+
+  if ((ret = xd3_config_stream (& stream, NULL)) ||
+      (ret = xd3_set_source (& stream, & source)) ||
+      (ret = xd3_decode_stream (& stream, data, size, code_string, & code_size, sizeof (code_string))))
+    {
+      in_stream->msg = stream.msg;
+      goto fail;
+    }
+
+  if (code_size != sizeof (code_string))
+    {
+      stream.msg = "corrupt code-table encoding";
+      ret = XD3_INTERNAL;
+      goto fail;
+    }
+
+  if ((ret = xd3_apply_table_string (in_stream, code_string))) { goto fail; }
+
+ fail:
+
+  xd3_free_stream (& stream);
+  return ret;
+}
+
+/******************************************************************************************
+ Permute stuff
+ ******************************************************************************************/
+
+#if HASH_PERMUTE == 0
+#define PERMUTE(x) (x)
+#else
+#define PERMUTE(x) (__single_hash[(uint)x])
+
+static const uint16_t __single_hash[256] =
+{
+  /* Random numbers generated using SLIB's pseudo-random number generator.  This hashes
+   * the input alphabet. */
+  0xbcd1, 0xbb65, 0x42c2, 0xdffe, 0x9666, 0x431b, 0x8504, 0xeb46,
+  0x6379, 0xd460, 0xcf14, 0x53cf, 0xdb51, 0xdb08, 0x12c8, 0xf602,
+  0xe766, 0x2394, 0x250d, 0xdcbb, 0xa678, 0x02af, 0xa5c6, 0x7ea6,
+  0xb645, 0xcb4d, 0xc44b, 0xe5dc, 0x9fe6, 0x5b5c, 0x35f5, 0x701a,
+  0x220f, 0x6c38, 0x1a56, 0x4ca3, 0xffc6, 0xb152, 0x8d61, 0x7a58,
+  0x9025, 0x8b3d, 0xbf0f, 0x95a3, 0xe5f4, 0xc127, 0x3bed, 0x320b,
+  0xb7f3, 0x6054, 0x333c, 0xd383, 0x8154, 0x5242, 0x4e0d, 0x0a94,
+  0x7028, 0x8689, 0x3a22, 0x0980, 0x1847, 0xb0f1, 0x9b5c, 0x4176,
+  0xb858, 0xd542, 0x1f6c, 0x2497, 0x6a5a, 0x9fa9, 0x8c5a, 0x7743,
+  0xa8a9, 0x9a02, 0x4918, 0x438c, 0xc388, 0x9e2b, 0x4cad, 0x01b6,
+  0xab19, 0xf777, 0x365f, 0x1eb2, 0x091e, 0x7bf8, 0x7a8e, 0x5227,
+  0xeab1, 0x2074, 0x4523, 0xe781, 0x01a3, 0x163d, 0x3b2e, 0x287d,
+  0x5e7f, 0xa063, 0xb134, 0x8fae, 0x5e8e, 0xb7b7, 0x4548, 0x1f5a,
+  0xfa56, 0x7a24, 0x900f, 0x42dc, 0xcc69, 0x02a0, 0x0b22, 0xdb31,
+  0x71fe, 0x0c7d, 0x1732, 0x1159, 0xcb09, 0xe1d2, 0x1351, 0x52e9,
+  0xf536, 0x5a4f, 0xc316, 0x6bf9, 0x8994, 0xb774, 0x5f3e, 0xf6d6,
+  0x3a61, 0xf82c, 0xcc22, 0x9d06, 0x299c, 0x09e5, 0x1eec, 0x514f,
+  0x8d53, 0xa650, 0x5c6e, 0xc577, 0x7958, 0x71ac, 0x8916, 0x9b4f,
+  0x2c09, 0x5211, 0xf6d8, 0xcaaa, 0xf7ef, 0x287f, 0x7a94, 0xab49,
+  0xfa2c, 0x7222, 0xe457, 0xd71a, 0x00c3, 0x1a76, 0xe98c, 0xc037,
+  0x8208, 0x5c2d, 0xdfda, 0xe5f5, 0x0b45, 0x15ce, 0x8a7e, 0xfcad,
+  0xaa2d, 0x4b5c, 0xd42e, 0xb251, 0x907e, 0x9a47, 0xc9a6, 0xd93f,
+  0x085e, 0x35ce, 0xa153, 0x7e7b, 0x9f0b, 0x25aa, 0x5d9f, 0xc04d,
+  0x8a0e, 0x2875, 0x4a1c, 0x295f, 0x1393, 0xf760, 0x9178, 0x0f5b,
+  0xfa7d, 0x83b4, 0x2082, 0x721d, 0x6462, 0x0368, 0x67e2, 0x8624,
+  0x194d, 0x22f6, 0x78fb, 0x6791, 0xb238, 0xb332, 0x7276, 0xf272,
+  0x47ec, 0x4504, 0xa961, 0x9fc8, 0x3fdc, 0xb413, 0x007a, 0x0806,
+  0x7458, 0x95c6, 0xccaa, 0x18d6, 0xe2ae, 0x1b06, 0xf3f6, 0x5050,
+  0xc8e8, 0xf4ac, 0xc04c, 0xf41c, 0x992f, 0xae44, 0x5f1b, 0x1113,
+  0x1738, 0xd9a8, 0x19ea, 0x2d33, 0x9698, 0x2fe9, 0x323f, 0xcde2,
+  0x6d71, 0xe37d, 0xb697, 0x2c4f, 0x4373, 0x9102, 0x075d, 0x8e25,
+  0x1672, 0xec28, 0x6acb, 0x86cc, 0x186e, 0x9414, 0xd674, 0xd1a5
+};
+#endif
+
+/******************************************************************************************
+ Ctable stuff
+ ******************************************************************************************/
+
+#if HASH_PRIME
+static const usize_t __primes[] =
+{
+  11, 19, 37, 73, 109,
+  163, 251, 367, 557, 823,
+  1237, 1861, 2777, 4177, 6247,
+  9371, 14057, 21089, 31627, 47431,
+  71143, 106721, 160073, 240101, 360163,
+  540217, 810343, 1215497, 1823231, 2734867,
+  4102283, 6153409, 9230113, 13845163, 20767711,
+  31151543, 46727321, 70090921, 105136301, 157704401,
+  236556601, 354834919, 532252367, 798378509, 1197567719,
+  1796351503
+};
+
+static const usize_t __nprimes = SIZEOF_ARRAY (__primes);
+#endif
+
+static INLINE uint32_t
+xd3_checksum_hash (const xd3_hash_cfg *cfg, const uint32_t cksum)
+{
+#if HASH_PRIME
+  /* If the table is prime compute the modulus. */
+  return (cksum % cfg->size);
+#else
+  /* If the table is power-of-two compute the mask.*/
+  return (cksum ^ (cksum >> cfg->shift)) & cfg->mask;
+#endif
+}
+
+/******************************************************************************************
+ Create the hash table.
+ ******************************************************************************************/
+
+static INLINE void
+xd3_swap_uint8p (uint8_t** p1, uint8_t** p2)
+{
+  uint8_t *t = (*p1);
+  (*p1) = (*p2);
+  (*p2) = t;
+}
+
+static INLINE void
+xd3_swap_usize_t (usize_t* p1, usize_t* p2)
+{
+  usize_t t = (*p1);
+  (*p1) = (*p2);
+  (*p2) = t;
+}
+
+/* It's not constant time, but it computes the log. */
+static int
+xd3_check_pow2 (usize_t value, usize_t *logof)
+{
+  usize_t x = 1;
+  usize_t nolog;
+  if (logof == NULL) {
+    logof = &nolog;
+  }
+
+  *logof = 0;
+
+  for (; x != 0; x <<= 1, *logof += 1)
+    {
+      if (x == value)
+	{
+	  return 0;
+	}
+    }
+
+  return XD3_INTERNAL;
+}
+
+static usize_t
+xd3_round_blksize (usize_t sz, usize_t blksz)
+{
+  usize_t mod = sz & (blksz-1);
+
+  XD3_ASSERT (xd3_check_pow2 (blksz, NULL) == 0);
+
+  return mod ? (sz + (blksz - mod)) : sz;
+}
+
+#if XD3_ENCODER
+#if !HASH_PRIME
+static usize_t
+xd3_size_log2 (usize_t slots)
+{
+  int bits = 28; /* This should not be an unreasonable limit. */
+  int i;
+
+  for (i = 3; i <= bits; i += 1)
+    {
+      if (slots < (1 << i))
+	{
+	  bits = i-1;
+	  break;
+	}
+    }
+
+  return bits;
+}
+#endif
+
+static void
+xd3_size_hashtable (xd3_stream    *stream,
+		    usize_t        slots,
+		    xd3_hash_cfg  *cfg)
+{
+  /* initialize ctable: the number of hash buckets is computed from the table of primes or
+   * the nearest power-of-two, in both cases rounding down in favor of using less
+   * memory. */
+
+#if HASH_PRIME
+  usize_t i;
+
+  cfg->size = __primes[__nprimes-1];
+
+  for (i = 1; i < __nprimes; i += 1)
+    {
+      if (slots < __primes[i])
+	{
+	  cfg->size = __primes[i-1];
+	  break;
+	}
+    }
+#else
+  int bits = xd3_size_log2 (slots);
+
+  cfg->size  = (1 << bits);
+  cfg->mask  = (cfg->size - 1);
+  cfg->shift = min (32 - bits, 16);
+#endif
+}
+#endif
+
+/******************************************************************************************
+ Cksum function
+ ******************************************************************************************/
+
+/* OPT: It turns out that the compiler can't unroll the loop as well as you can by hand. */
+static INLINE uint32_t
+xd3_lcksum (const uint8_t *seg, const int ln)
+{
+  int   i    = 0;
+  uint32_t low  = 0;
+  uint32_t high = 0;
+
+  for (; i < ln; i += 1)
+    {
+      low  += PERMUTE(*seg++);
+      high += low;
+    }
+
+  return ((high & 0xffff) << 16) | (low & 0xffff);
+}
+
+#if ARITH_SMALL_CKSUM
+static INLINE usize_t
+xd3_scksum (const uint8_t *seg, const int ln)
+{
+  usize_t c;
+  /* The -1 is because UPDATE operates on seg[1..ln] */
+  SMALL_CKSUM_UPDATE (c,(seg-1),ln);
+  return c;
+}
+#else
+#define xd3_scksum(seg,ln) xd3_lcksum(seg,ln)
+#endif
+
+/******************************************************************************************
+ Adler32 stream function: code copied from Zlib, defined in RFC1950
+ ******************************************************************************************/
+
+#define A32_BASE 65521L /* Largest prime smaller than 2^16 */
+#define A32_NMAX 5552   /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define A32_DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define A32_DO2(buf,i)  A32_DO1(buf,i); A32_DO1(buf,i+1);
+#define A32_DO4(buf,i)  A32_DO2(buf,i); A32_DO2(buf,i+2);
+#define A32_DO8(buf,i)  A32_DO4(buf,i); A32_DO4(buf,i+4);
+#define A32_DO16(buf)   A32_DO8(buf,0); A32_DO8(buf,8);
+
+static unsigned long adler32 (unsigned long adler, const uint8_t *buf, usize_t len)
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    while (len > 0)
+      {
+        k    = (len < A32_NMAX) ? len : A32_NMAX;
+        len -= k;
+
+	while (k >= 16)
+	  {
+	    A32_DO16(buf);
+	    buf += 16;
+            k -= 16;
+	  }
+
+	if (k != 0)
+	  {
+	    do
+	      {
+		s1 += *buf++;
+		s2 += s1;
+	      }
+	    while (--k);
+	  }
+
+        s1 %= A32_BASE;
+        s2 %= A32_BASE;
+    }
+
+    return (s2 << 16) | s1;
+}
+
+/******************************************************************************************
+ Run-length function
+ ******************************************************************************************/
+
+static INLINE int
+xd3_comprun (const uint8_t *seg, int slook, uint8_t *run_cp)
+{
+  int i;
+  int     run_l = 0;
+  uint8_t run_c = 0;
+
+  for (i = 0; i < slook; i += 1)
+    {
+      NEXTRUN(seg[i]);
+    }
+
+  (*run_cp) = run_c;
+
+  return run_l;
+}
+
+/******************************************************************************************
+ Basic encoder/decoder functions
+ ******************************************************************************************/
+
+static int
+xd3_decode_byte (xd3_stream *stream, uint *val)
+{
+  if (stream->avail_in == 0)
+    {
+      stream->msg = "further input required";
+      return XD3_INPUT;
+    }
+
+  (*val) = stream->next_in[0];
+
+  DECODE_INPUT (1);
+  return 0;
+}
+
+static int
+xd3_decode_bytes (xd3_stream *stream, uint8_t *buf, usize_t *pos, usize_t size)
+{
+  usize_t want;
+  usize_t take;
+
+  /* Note: The case where (*pos == size) happens when a zero-length appheader or code
+   * table is transmitted, but there is nothing in the standard against that. */
+
+  while (*pos < size)
+    {
+      if (stream->avail_in == 0)
+	{
+	  stream->msg = "further input required";
+	  return XD3_INPUT;
+	}
+
+      want = size - *pos;
+      take = min (want, stream->avail_in);
+
+      memcpy (buf + *pos, stream->next_in, take);
+
+      DECODE_INPUT (take);
+      (*pos) += take;
+    }
+
+  return 0;
+}
+
+#if XD3_ENCODER
+static int
+xd3_emit_byte (xd3_stream  *stream,
+	       xd3_output **outputp,
+	       uint8_t      code)
+{
+  xd3_output *output = (*outputp);
+
+  if (output->next == output->avail)
+    {
+      xd3_output *aoutput;
+
+      if ((aoutput = xd3_alloc_output (stream, output)) == NULL)
+	{
+	  return ENOMEM;
+	}
+
+      output = (*outputp) = aoutput;
+    }
+
+  output->base[output->next++] = code;
+
+  return 0;
+}
+
+static int
+xd3_emit_bytes (xd3_stream     *stream,
+		xd3_output    **outputp,
+		const uint8_t  *base,
+		usize_t          size)
+{
+  xd3_output *output = (*outputp);
+
+  do
+    {
+      usize_t take;
+
+      if (output->next == output->avail)
+	{
+	  xd3_output *aoutput;
+
+	  if ((aoutput = xd3_alloc_output (stream, output)) == NULL)
+	    {
+	      return ENOMEM;
+	    }
+
+	  output = (*outputp) = aoutput;
+	}
+
+      take = min (output->avail - output->next, size);
+
+      memcpy (output->base + output->next, base, take);
+
+      output->next += take;
+      size -= take;
+      base += take;
+    }
+  while (size > 0);
+
+  return 0;
+}
+#endif /* XD3_ENCODER */
+
+/******************************************************************************************
+ Integer encoder/decoder functions
+ ******************************************************************************************/
+
+#define DECODE_INTEGER_TYPE(PART,OFLOW)                                \
+  while (stream->avail_in != 0)                                        \
+    {                                                                  \
+      uint next = stream->next_in[0];                                  \
+                                                                       \
+      DECODE_INPUT(1);                                                 \
+                                                                       \
+      if (PART & OFLOW)                                                \
+	{                                                              \
+	  stream->msg = "overflow in decode_integer";                  \
+	  return XD3_INVALID_INPUT;                                         \
+	}                                                              \
+                                                                       \
+      PART = (PART << 7) | (next & 127);                               \
+                                                                       \
+      if ((next & 128) == 0)                                           \
+	{                                                              \
+	  (*val) = PART;                                               \
+	  PART = 0;                                                    \
+	  return 0;                                                    \
+	}                                                              \
+    }                                                                  \
+                                                                       \
+  stream->msg = "further input required";                              \
+  return XD3_INPUT
+
+#define READ_INTEGER_TYPE(TYPE, OFLOW)                                 \
+  TYPE val = 0;                                                        \
+  const uint8_t *inp = (*inpp);                                        \
+  uint next;                                                           \
+                                                                       \
+  do                                                                   \
+    {                                                                  \
+      if (inp == max)                                                  \
+	{                                                              \
+	  stream->msg = "end-of-input in read_integer";                \
+	  return XD3_INVALID_INPUT;                                         \
+	}                                                              \
+                                                                       \
+      if (val & OFLOW)                                                 \
+	{                                                              \
+	  stream->msg = "overflow in read_intger";                     \
+	  return XD3_INVALID_INPUT;                                         \
+	}                                                              \
+                                                                       \
+      next = (*inp++);                                                 \
+      val  = (val << 7) | (next & 127);                                \
+    }                                                                  \
+  while (next & 128);                                                  \
+                                                                       \
+  (*valp) = val;                                                       \
+  (*inpp) = inp;                                                       \
+                                                                       \
+  return 0
+
+#define EMIT_INTEGER_TYPE()                                            \
+  /* max 64-bit value in base-7 encoding is 9.1 bytes */               \
+  uint8_t buf[10];                                                     \
+  usize_t  bufi = 10;                                                  \
+                                                                       \
+  XD3_ASSERT (num >= 0);                                               \
+                                                                       \
+  /* This loop performs division and turns on all MSBs. */             \
+  do                                                                   \
+    {                                                                  \
+      buf[--bufi] = (num & 127) | 128;                                 \
+      num >>= 7;                                                       \
+    }                                                                  \
+  while (num != 0);                                                    \
+                                                                       \
+  /* Turn off MSB of the last byte. */                                 \
+  buf[9] &= 127;                                                       \
+                                                                       \
+  XD3_ASSERT (bufi >= 0);                                              \
+                                                                       \
+  return xd3_emit_bytes (stream, output, buf + bufi, 10 - bufi)
+
+#define IF_SIZEOF32(x) if (num < (1U   << (7 * (x)))) return (x);
+#define IF_SIZEOF64(x) if (num < (1ULL << (7 * (x)))) return (x);
+
+#if USE_UINT32
+static uint
+xd3_sizeof_uint32_t (uint32_t num)
+{
+  IF_SIZEOF32(1);
+  IF_SIZEOF32(2);
+  IF_SIZEOF32(3);
+  IF_SIZEOF32(4);
+  return 5;
+}
+
+static int
+xd3_decode_uint32_t (xd3_stream *stream, uint32_t *val)
+{ DECODE_INTEGER_TYPE (stream->dec_32part, UINT32_OFLOW_MASK); }
+
+static int
+xd3_read_uint32_t (xd3_stream *stream, const uint8_t **inpp, const uint8_t *max, uint32_t *valp)
+{ READ_INTEGER_TYPE (uint32_t, UINT32_OFLOW_MASK); }
+
+#if XD3_ENCODER
+static int
+xd3_emit_uint32_t (xd3_stream *stream, xd3_output **output, uint32_t num)
+{ EMIT_INTEGER_TYPE (); }
+#endif
+#endif
+
+#if USE_UINT64
+static int
+xd3_decode_uint64_t (xd3_stream *stream, uint64_t *val)
+{ DECODE_INTEGER_TYPE (stream->dec_64part, UINT64_OFLOW_MASK); }
+
+#if XD3_ENCODER
+static int
+xd3_emit_uint64_t (xd3_stream *stream, xd3_output **output, uint64_t num)
+{ EMIT_INTEGER_TYPE (); }
+#endif
+
+/* These are tested but not used */
+#if REGRESSION_TEST
+static int
+xd3_read_uint64_t (xd3_stream *stream, const uint8_t **inpp, const uint8_t *max, uint64_t *valp)
+{ READ_INTEGER_TYPE (uint64_t, UINT64_OFLOW_MASK); }
+
+static uint
+xd3_sizeof_uint64_t (uint64_t num)
+{
+  IF_SIZEOF64(1);
+  IF_SIZEOF64(2);
+  IF_SIZEOF64(3);
+  IF_SIZEOF64(4);
+  IF_SIZEOF64(5);
+  IF_SIZEOF64(6);
+  IF_SIZEOF64(7);
+  IF_SIZEOF64(8);
+  IF_SIZEOF64(9);
+
+  return 10;
+}
+#endif
+
+#endif
+
+/******************************************************************************************
+ Address cache stuff
+ ******************************************************************************************/
+
+static int
+xd3_alloc_cache (xd3_stream *stream)
+{
+  if (((stream->acache.s_near > 0) &&
+       (stream->acache.near_array = xd3_alloc (stream, stream->acache.s_near, sizeof (usize_t))) == NULL) ||
+      ((stream->acache.s_same > 0) &&
+       (stream->acache.same_array = xd3_alloc (stream, stream->acache.s_same * 256, sizeof (usize_t))) == NULL))
+    {
+      return ENOMEM;
+    }
+
+  return 0;
+}
+
+static void
+xd3_init_cache (xd3_addr_cache* acache)
+{
+  if (acache->s_near > 0)
+    {
+      memset (acache->near_array, 0, acache->s_near * sizeof (usize_t));
+      acache->next_slot = 0;
+    }
+
+  if (acache->s_same > 0)
+    {
+      memset (acache->same_array, 0, acache->s_same * 256 * sizeof (usize_t));
+    }
+}
+
+static void
+xd3_update_cache (xd3_addr_cache* acache, usize_t addr)
+{
+  if (acache->s_near > 0)
+    {
+      acache->near_array[acache->next_slot] = addr;
+      acache->next_slot = (acache->next_slot + 1) % acache->s_near;
+    }
+
+  if (acache->s_same > 0)
+    {
+      acache->same_array[addr % (acache->s_same*256)] = addr;
+    }
+}
+
+#if XD3_ENCODER
+/* OPT: this gets called a lot, can it be optimized? */
+static int
+xd3_encode_address (xd3_stream *stream, usize_t addr, usize_t here, uint8_t* mode)
+{
+  usize_t d, bestd;
+  int   i, bestm, ret;
+  xd3_addr_cache* acache = & stream->acache;
+
+#define SMALLEST_INT(x) do { if (((x) & ~127) == 0) { goto good; } } while (0)
+
+  /* Attempt to find the address mode that yields the smallest integer value for "d", the
+   * encoded address value, thereby minimizing the encoded size of the address. */
+  bestd = addr;
+  bestm = VCD_SELF;
+
+  XD3_ASSERT (addr < here);
+
+  SMALLEST_INT (bestd);
+
+  if ((d = here-addr) < bestd)
+    {
+      bestd = d;
+      bestm = VCD_HERE;
+
+      SMALLEST_INT (bestd);
+    }
+
+  for (i = 0; i < acache->s_near; i += 1)
+    {
+      d = addr - acache->near_array[i];
+
+      if (d >= 0 && d < bestd)
+	{
+	  bestd = d;
+	  bestm = i+2; /* 2 counts the VCD_SELF, VCD_HERE modes */
+
+	  SMALLEST_INT (bestd);
+	}
+    }
+
+  if (acache->s_same > 0 && acache->same_array[d = addr%(acache->s_same*256)] == addr)
+    {
+      bestd = d%256;
+      bestm = acache->s_near + 2 + d/256; /* 2 + s_near offsets past the VCD_NEAR modes */
+
+      if ((ret = xd3_emit_byte (stream, & ADDR_TAIL (stream), bestd))) { return ret; }
+    }
+  else
+    {
+    good:
+
+      if ((ret = xd3_emit_size (stream, & ADDR_TAIL (stream), bestd))) { return ret; }
+    }
+
+  xd3_update_cache (acache, addr);
+
+  (*mode) += bestm;
+
+  return 0;
+}
+#endif
+
+static int
+xd3_decode_address (xd3_stream *stream, usize_t here, uint mode, const uint8_t **inpp, const uint8_t *max, uint32_t *valp)
+{
+  int ret;
+  uint same_start = 2 + stream->acache.s_near;
+
+  if (mode < same_start)
+    {
+      if ((ret = xd3_read_size (stream, inpp, max, valp))) { return ret; }
+
+      switch (mode)
+	{
+	case VCD_SELF:
+	  break;
+	case VCD_HERE:
+	  (*valp) = here - (*valp);
+	  break;
+	default:
+	  (*valp) += stream->acache.near_array[mode - 2];
+	  break;
+	}
+    }
+  else
+    {
+      if (*inpp == max)
+	{
+	  stream->msg = "address underflow";
+	  return XD3_INVALID_INPUT;
+	}
+
+      mode -= same_start;
+
+      (*valp) = stream->acache.same_array[mode*256 + (**inpp)];
+
+      (*inpp) += 1;
+    }
+
+  xd3_update_cache (& stream->acache, *valp);
+
+  return 0;
+}
+
+/******************************************************************************************
+ Alloc/free
+ ******************************************************************************************/
+
+static void*
+__xd3_alloc_func (void* opaque, usize_t items, usize_t size)
+{
+  return malloc (items * size);
+}
+
+static void
+__xd3_free_func (void* opaque, void* address)
+{
+  free (address);
+}
+
+static void*
+xd3_alloc (xd3_stream *stream,
+	   usize_t      elts,
+	   usize_t      size)
+{
+  void *a = stream->alloc (stream->opaque, elts, size);
+
+  if (a != NULL)
+    {
+      IF_DEBUG (stream->alloc_cnt += 1);
+    }
+  else
+    {
+      stream->msg = "out of memory";
+    }
+
+  return a;
+}
+
+static void
+xd3_free (xd3_stream *stream,
+	  void       *ptr)
+{
+  if (ptr != NULL)
+    {
+      IF_DEBUG (stream->free_cnt += 1);
+      XD3_ASSERT (stream->free_cnt <= stream->alloc_cnt);
+      stream->free (stream->opaque, ptr);
+    }
+}
+
+#if XD3_ENCODER
+static void*
+xd3_alloc0 (xd3_stream *stream,
+	    usize_t      elts,
+	    usize_t      size)
+{
+  void *a = xd3_alloc (stream, elts, size);
+
+  if (a != NULL)
+    {
+      memset (a, 0, elts * size);
+    }
+
+  return a;
+}
+
+static xd3_output*
+xd3_alloc_output (xd3_stream *stream,
+		  xd3_output *old_output)
+{
+  xd3_output *output;
+  uint8_t    *base;
+
+  if (stream->enc_free != NULL)
+    {
+      output = stream->enc_free;
+      stream->enc_free = output->next_page;
+    }
+  else
+    {
+      if ((output = xd3_alloc (stream, 1, sizeof (xd3_output))) == NULL)
+	{
+	  return NULL;
+	}
+
+      if ((base = xd3_alloc (stream, XD3_ALLOCSIZE, sizeof (uint8_t))) == NULL)
+	{
+	  xd3_free (stream, output);
+	  return NULL;
+	}
+
+      output->base  = base;
+      output->avail = XD3_ALLOCSIZE;
+    }
+
+  output->next = 0;
+
+  if (old_output)
+    {
+      old_output->next_page = output;
+    }
+
+  output->next_page = NULL;
+
+  return output;
+}
+
+static usize_t
+xd3_sizeof_output (xd3_output *output)
+{
+  usize_t s = 0;
+
+  for (; output; output = output->next_page)
+    {
+      s += output->next;
+    }
+
+  return s;
+}
+
+static void
+xd3_freelist_output (xd3_stream *stream,
+		     xd3_output *output)
+{
+  xd3_output *tmp;
+
+  while (output)
+    {
+      tmp    = output;
+      output = output->next_page;
+
+      tmp->next = 0;
+      tmp->next_page = stream->enc_free;
+      stream->enc_free = tmp;
+    }
+}
+
+static void
+xd3_free_output (xd3_stream *stream,
+		 xd3_output *output)
+{
+  xd3_output *next;
+
+ again:
+  if (output == NULL)
+    {
+      return;
+    }
+
+  next = output->next_page;
+
+  xd3_free (stream, output->base);
+  xd3_free (stream, output);
+
+  output = next;
+  goto again;
+}
+#endif /* XD3_ENCODER */
+
+void
+xd3_free_stream (xd3_stream *stream)
+{
+  xd3_iopt_buflist *blist = stream->iopt_alloc;
+
+  while (blist != NULL)
+    {
+      xd3_iopt_buflist *tmp = blist;
+      blist = blist->next;
+      xd3_free (stream, tmp->buffer);
+      xd3_free (stream, tmp);
+    }
+
+  xd3_free (stream, stream->large_table);
+  xd3_free (stream, stream->small_table);
+  xd3_free (stream, stream->small_prev);
+
+#if XD3_ENCODER
+  {
+    int i;
+    for (i = 0; i < ENC_SECTS; i += 1)
+      {
+	xd3_free_output (stream, stream->enc_heads[i]);
+      }
+    xd3_free_output (stream, stream->enc_free);
+  }
+#endif
+
+  xd3_free (stream, stream->acache.near_array);
+  xd3_free (stream, stream->acache.same_array);
+
+  xd3_free (stream, stream->inst_sect.copied1);
+  xd3_free (stream, stream->addr_sect.copied1);
+  xd3_free (stream, stream->data_sect.copied1);
+
+  xd3_free (stream, stream->dec_buffer);
+  xd3_free (stream, (uint8_t*) stream->dec_lastwin);
+
+  xd3_free (stream, stream->buf_in);
+  xd3_free (stream, stream->dec_appheader);
+  xd3_free (stream, stream->dec_codetbl);
+  xd3_free (stream, stream->code_table_alloc);
+
+#if SECONDARY_ANY
+  xd3_free (stream, stream->inst_sect.copied2);
+  xd3_free (stream, stream->addr_sect.copied2);
+  xd3_free (stream, stream->data_sect.copied2);
+
+  if (stream->sec_type != NULL)
+    {
+      stream->sec_type->destroy (stream, stream->sec_stream_d);
+      stream->sec_type->destroy (stream, stream->sec_stream_i);
+      stream->sec_type->destroy (stream, stream->sec_stream_a);
+    }
+#endif
+
+  XD3_ASSERT (stream->alloc_cnt == stream->free_cnt);
+
+  memset (stream, 0, sizeof (xd3_stream));
+}
+
+#if (XD3_DEBUG > 1 || VCDIFF_TOOLS)
+static const char*
+xd3_rtype_to_string (xd3_rtype type, int print_mode)
+{
+  switch (type)
+    {
+    case XD3_NOOP:
+      return "NOOP ";
+    case XD3_RUN:
+      return "RUN  ";
+    case XD3_ADD:
+      return "ADD  ";
+    default: break;
+    }
+  if (! print_mode)
+    {
+      return "CPY  ";
+    }
+  switch (type)
+    {
+    case XD3_CPY + 0: return "CPY_0";
+    case XD3_CPY + 1: return "CPY_1";
+    case XD3_CPY + 2: return "CPY_2";
+    case XD3_CPY + 3: return "CPY_3";
+    case XD3_CPY + 4: return "CPY_4";
+    case XD3_CPY + 5: return "CPY_5";
+    case XD3_CPY + 6: return "CPY_6";
+    case XD3_CPY + 7: return "CPY_7";
+    case XD3_CPY + 8: return "CPY_8";
+    case XD3_CPY + 9: return "CPY_9";
+    default:          return "CPY>9";
+    }
+}
+#endif
+
+/******************************************************************************************
+ Stream configuration
+ ******************************************************************************************/
+
+int
+xd3_config_stream(xd3_stream *stream,
+		  xd3_config *config)
+{
+  int ret;
+  xd3_config defcfg;
+  xd3_smatcher *smatcher = &stream->smatcher;
+
+  if (config == NULL)
+    {
+      config = & defcfg;
+      memset (config, 0, sizeof (*config));
+    }
+
+  /* Initial setup: no error checks yet */
+  memset (stream, 0, sizeof (*stream));
+
+  stream->winsize   = config->winsize   ? config->winsize : XD3_DEFAULT_WINSIZE;
+  stream->sprevsz   = config->sprevsz   ? config->sprevsz : XD3_DEFAULT_SPREVSZ;
+  stream->srcwin_maxsz = config->srcwin_maxsz ? config->srcwin_maxsz : XD3_DEFAULT_SRCWINSZ;
+
+  if (config->iopt_size == 0)
+    {
+      stream->iopt_size = XD3_ALLOCSIZE / sizeof(xd3_rinst);
+      stream->iopt_unlimited = 1;
+    }
+  else
+    {
+      stream->iopt_size = config->iopt_size;
+    }
+
+  stream->getblk    = config->getblk;
+  stream->alloc     = config->alloc ? config->alloc : __xd3_alloc_func;
+  stream->free      = config->freef ? config->freef : __xd3_free_func;
+  stream->opaque    = config->opaque;
+  stream->flags     = config->flags;
+
+  /* Secondary setup. */
+  stream->sec_data  = config->sec_data;
+  stream->sec_inst  = config->sec_inst;
+  stream->sec_addr  = config->sec_addr;
+
+  stream->sec_data.data_type = DATA_SECTION;
+  stream->sec_inst.data_type = INST_SECTION;
+  stream->sec_addr.data_type = ADDR_SECTION;
+
+  /* Check static sizes. */
+  if (sizeof (usize_t) != SIZEOF_USIZE_T ||
+      sizeof (xoff_t) != SIZEOF_XOFF_T ||
+      (ret = xd3_check_pow2(XD3_ALLOCSIZE, NULL)))
+    {
+      stream->msg = "incorrect compilation: wrong integer sizes";
+      return XD3_INTERNAL;
+    }
+
+  /* Check/set secondary compressor. */
+  switch (stream->flags & XD3_SEC_TYPE)
+    {
+    case 0:
+      if (stream->flags & XD3_SEC_OTHER)
+	{
+	  stream->msg = "XD3_SEC flags require a secondary compressor type";
+	  return XD3_INTERNAL;
+	}
+      break;
+    case XD3_SEC_FGK:
+      FGK_CASE (stream);
+    case XD3_SEC_DJW:
+      DJW_CASE (stream);
+    default:
+      stream->msg = "too many secondary compressor types set";
+      return XD3_INTERNAL;
+    }
+
+  /* Check/set encoder code table. */
+  switch (stream->flags & XD3_ALT_CODE_TABLE) {
+  case 0:
+    stream->code_table_desc = & __rfc3284_code_table_desc;
+    stream->code_table_func = xd3_rfc3284_code_table;
+    break;
+#if GENERIC_ENCODE_TABLES
+  case XD3_ALT_CODE_TABLE:
+    stream->code_table_desc = & __alternate_code_table_desc;
+    stream->code_table_func = xd3_alternate_code_table;
+    stream->comp_table_func = xd3_compute_alternate_table_encoding;
+    break;
+#endif
+  default:
+    stream->msg = "alternate code table support was not compiled";
+    return XD3_INTERNAL;
+  }
+
+  /* Check sprevsz */
+  if (smatcher->small_chain == 1)
+    {
+      stream->sprevsz = 0;
+    }
+  else
+    {
+      if ((ret = xd3_check_pow2 (stream->sprevsz, NULL)))
+	{
+	  stream->msg = "sprevsz is required to be a power of two";
+	  return XD3_INTERNAL;
+	}
+
+      stream->sprevmask = stream->sprevsz - 1;
+    }
+
+  /* Default scanner settings. */
+  switch (config->smatch_cfg)
+    {
+      IF_BUILD_SOFT(case XD3_SMATCH_SOFT:
+      {
+	*smatcher = config->smatcher_soft;
+	smatcher->string_match = __smatcher_soft.string_match;
+	smatcher->name = __smatcher_soft.name;
+	if (smatcher->large_look  < MIN_MATCH ||
+	    smatcher->large_step  < 1         ||
+	    smatcher->small_look  < MIN_MATCH)
+	  {
+	    stream->msg = "invalid soft string-match config";
+	    return XD3_INVALID;
+	  }
+	break;
+      })
+
+      IF_BUILD_DEFAULT(case XD3_SMATCH_DEFAULT:
+		    *smatcher = __smatcher_default;
+		    break;)
+      IF_BUILD_SLOW(case XD3_SMATCH_SLOW:
+		    *smatcher = __smatcher_slow;
+		    break;)
+      IF_BUILD_FASTEST(case XD3_SMATCH_FASTEST:
+		    *smatcher = __smatcher_fastest;
+		    break;)
+      IF_BUILD_FAST(case XD3_SMATCH_FAST:
+		    *smatcher = __smatcher_fast;
+		    break;)
+    default:
+      stream->msg = "invalid string match config type";
+      return XD3_INTERNAL;
+    }
+
+  if (config->smatch_cfg == XD3_SMATCH_DEFAULT &&
+      (stream->flags & XD3_COMPLEVEL_MASK) != 0)
+    {
+      int level = (stream->flags & XD3_COMPLEVEL_MASK) >> XD3_COMPLEVEL_SHIFT;
+
+      switch (level)
+	{
+	case 1: case 2:
+	  IF_BUILD_FASTEST(*smatcher = __smatcher_fastest;
+			   break;)
+	case 3: case 4: case 5:
+	  IF_BUILD_FAST(*smatcher = __smatcher_fast;
+			break;)
+	case 6:
+	  IF_BUILD_DEFAULT(*smatcher = __smatcher_default;
+			   break;)
+	default:
+	  IF_BUILD_SLOW(*smatcher = __smatcher_slow;
+			break;)
+	}
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ Getblk interface
+ ******************************************************************************************/
+
+/* This function interfaces with the client getblk function, checks its results, etc. */
+static int
+xd3_getblk (xd3_stream *stream/*, xd3_source *source*/, xoff_t blkno)
+{
+  int ret;
+  xd3_source *source = stream->src;
+
+  if (blkno >= source->blocks)
+    {
+      IF_DEBUG1 (DP(RINT "[getblk] block %"Q"u\n", blkno));
+      stream->msg = "source file too short";
+      return XD3_INTERNAL;
+    }
+
+  if (blkno != source->curblkno || source->curblk == NULL)
+    {
+      XD3_ASSERT (source->curblk != NULL || blkno != source->curblkno);
+
+      source->getblkno = blkno;
+
+      if (stream->getblk == NULL)
+	{
+	  stream->msg = "getblk source input";
+	  return XD3_GETSRCBLK;
+	}
+      else if ((ret = stream->getblk (stream, source, blkno)) != 0)
+	{
+	  stream->msg = "getblk failed";
+	  return ret;
+	}
+
+      XD3_ASSERT (source->curblk != NULL);
+    }
+
+  if (source->onblk != xd3_bytes_on_srcblk (source, blkno))
+    {
+      stream->msg = "getblk returned short block";
+      return XD3_INTERNAL;
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ Stream open/close
+ ******************************************************************************************/
+
+int
+xd3_set_source (xd3_stream *stream,
+		xd3_source *src)
+{
+  xoff_t blk_num;
+  xoff_t tail_size;
+
+  IF_DEBUG1 (DP(RINT "[set source] size %"Q"u\n", src->size));
+
+  if (src == NULL || src->size < stream->smatcher.large_look) { return 0; }
+
+  stream->src  = src;
+  blk_num      = src->size / src->blksize;
+  tail_size    = src->size % src->blksize;
+  src->blocks  = blk_num + (tail_size > 0);
+  src->srclen  = 0;
+  src->srcbase = 0;
+
+  return 0;
+}
+
+void
+xd3_abort_stream (xd3_stream *stream)
+{
+  stream->dec_state = DEC_ABORTED;
+  stream->enc_state = ENC_ABORTED;
+}
+
+int
+xd3_close_stream (xd3_stream *stream)
+{
+  if (stream->enc_state != 0 && stream->enc_state != ENC_ABORTED)
+    {
+      /* If encoding, should be ready for more input but not actually have any. */
+      if (stream->enc_state != ENC_INPUT || stream->avail_in != 0)
+	{
+	  stream->msg = "encoding is incomplete";
+	  return XD3_INTERNAL;
+	}
+    }
+  else
+    {
+      switch (stream->dec_state)
+	{
+	case DEC_VCHEAD:
+	case DEC_WININD:
+	  /* TODO: Address the zero-byte ambiguity.  Does the encoder emit a window or
+	   * not?  If so, then catch an error here.  If not, need another routine to say
+	   * decode_at_least_one_if_empty. */
+	case DEC_ABORTED:
+	  break;
+	default:
+	  /* If decoding, should be ready for the next window. */
+	  stream->msg = "EOF in decode";
+	  return XD3_INTERNAL;
+	}
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ Application header
+ ******************************************************************************************/
+
+int
+xd3_get_appheader (xd3_stream  *stream,
+		   uint8_t    **data,
+		   usize_t      *size)
+{
+  if (stream->dec_state < DEC_WININD)
+    {
+      stream->msg = "application header not available";
+      return XD3_INTERNAL;
+    }
+
+  (*data) = stream->dec_appheader;
+  (*size) = stream->dec_appheadsz;
+  return 0;
+}
+
+/******************************************************************************************
+ Decoder stuff
+ ******************************************************************************************/
+
+#include "xdelta3-decode.h"
+
+/******************************************************************************************
+ Encoder stuff
+ ******************************************************************************************/
+
+#if XD3_ENCODER
+void
+xd3_set_appheader (xd3_stream    *stream,
+		   const uint8_t *data,
+		   usize_t         size)
+{
+  stream->enc_appheader = data;
+  stream->enc_appheadsz = size;
+}
+
+#if XD3_DEBUG
+static int
+xd3_iopt_check (xd3_stream *stream)
+{
+  int ul = xd3_rlist_length (& stream->iopt_used);
+  int fl = xd3_rlist_length (& stream->iopt_free);
+
+  return (ul + fl + (stream->iout ? 1 : 0)) == stream->iopt_size;
+}
+#endif
+
+static xd3_rinst*
+xd3_iopt_free (xd3_stream *stream, xd3_rinst *i)
+{
+  xd3_rinst *n = xd3_rlist_remove (i);
+  xd3_rlist_push_back (& stream->iopt_free, i);
+  return n;
+}
+
+static void
+xd3_iopt_free_nonadd (xd3_stream *stream, xd3_rinst *i)
+{
+  if (i->type != XD3_ADD)
+    {
+      xd3_rlist_push_back (& stream->iopt_free, i);
+    }
+}
+
+/* When an instruction is ready to flush from the iopt buffer, this function is called to
+ * produce an encoding.  It writes the instruction plus size, address, and data to the
+ * various encoding sections. */
+static int
+xd3_iopt_finish_encoding (xd3_stream *stream, xd3_rinst *inst)
+{
+  int ret;
+
+  /* Check for input overflow. */
+  XD3_ASSERT (inst->pos + inst->size <= stream->avail_in);
+
+  switch (inst->type)
+    {
+    case XD3_CPY:
+      {
+	/* the address may have an offset if there is a source window. */
+	usize_t addr;
+	xd3_source *src = stream->src;
+
+	if (src != NULL)
+	  {
+	    /* If there is a source copy, the source must have its source window decided
+	     * before we can encode.  This can be bad -- we have to make this decision
+	     * even if no source matches have been found. */
+	    if (stream->srcwin_decided == 0)
+	      {
+		if ((ret = xd3_srcwin_setup (stream))) { return ret; }
+	      }
+
+	    /* xtra field indicates the copy is from the source */
+	    if (inst->xtra)
+	      {
+		XD3_ASSERT (inst->addr >= src->srcbase);
+		XD3_ASSERT (inst->addr + inst->size <= src->srcbase + src->srclen);
+		addr = (inst->addr - src->srcbase);
+		stream->n_scpy += 1;
+		stream->l_scpy += inst->size;
+	      }
+	    else
+	      {
+		/* with source window: target copy address is offset by taroff. */
+		addr = stream->taroff + (usize_t) inst->addr;
+		stream->n_tcpy += 1;
+		stream->l_tcpy += inst->size;
+	      }
+	  }
+	else
+	  {
+	    addr = (usize_t) inst->addr;
+	    stream->n_tcpy += 1;
+	    stream->l_tcpy += inst->size;
+	  }
+
+	XD3_ASSERT (inst->size >= MIN_MATCH);
+
+	/* the "here" position is always offset by taroff */
+	if ((ret = xd3_encode_address (stream, addr, inst->pos + stream->taroff, & inst->type)))
+	  {
+	    return ret;
+	  }
+
+	IF_DEBUG1 ({
+	  static int cnt;
+	  DP(RINT "[iopt copy:%d] pos %"Q"u-%"Q"u addr %"Q"u-%"Q"u size %u\n",
+		   cnt++,
+		   stream->total_in + inst->pos,
+		   stream->total_in + inst->pos + inst->size,
+		   inst->addr, inst->addr + inst->size, inst->size);
+	});
+	break;
+      }
+    case XD3_RUN:
+      {
+	XD3_ASSERT (inst->size >= MIN_MATCH);
+
+	if ((ret = xd3_emit_byte (stream, & DATA_TAIL (stream), inst->xtra))) { return ret; }
+
+	stream->n_run += 1;
+	stream->l_run += inst->size;
+
+	IF_DEBUG1 ({
+	  static int cnt;
+	  DP(RINT "[iopt run:%d] pos %"Q"u size %u\n", cnt++, stream->total_in + inst->pos, inst->size);
+	});
+	break;
+      }
+    case XD3_ADD:
+      {
+	if ((ret = xd3_emit_bytes (stream, & DATA_TAIL (stream),
+				   stream->next_in + inst->pos, inst->size))) { return ret; }
+
+	stream->n_add += 1;
+	stream->l_add += inst->size;
+
+	IF_DEBUG1 ({
+	  static int cnt;
+	  DP(RINT "[iopt add:%d] pos %"Q"u size %u\n", cnt++, stream->total_in + inst->pos, inst->size);
+	});
+
+	break;
+      }
+    }
+
+  /* This is the only place stream->unencoded_offset is incremented. */
+  XD3_ASSERT (stream->unencoded_offset == inst->pos);
+  stream->unencoded_offset += inst->size;
+
+  IF_DEBUG (stream->n_emit += inst->size);
+
+  inst->code2 = 0;
+
+  XD3_CHOOSE_INSTRUCTION (stream, stream->iout, inst);
+
+  if (stream->iout != NULL)
+    {
+      if (stream->iout->code2 != 0)
+	{
+	  if ((ret = xd3_emit_double (stream, stream->iout, inst, stream->iout->code2))) { return ret; }
+
+	  xd3_iopt_free_nonadd (stream, stream->iout);
+	  xd3_iopt_free_nonadd (stream, inst);
+	  stream->iout = NULL;
+	  return 0;
+	}
+      else
+	{
+	  if ((ret = xd3_emit_single (stream, stream->iout, stream->iout->code1))) { return ret; }
+
+	  xd3_iopt_free_nonadd (stream, stream->iout);
+	}
+    }
+
+  stream->iout = inst;
+
+  return 0;
+}
+
+/* This possibly encodes an add instruction, iadd, which must remain on the stack until
+ * the following call to xd3_iopt_finish_encoding. */
+static int
+xd3_iopt_add (xd3_stream *stream, usize_t pos, xd3_rinst *iadd)
+{
+  int ret;
+  usize_t off = stream->unencoded_offset;
+
+  if (pos > off)
+    {
+      iadd->type = XD3_ADD;
+      iadd->pos  = off;
+      iadd->size = pos - off;
+
+      if ((ret = xd3_iopt_finish_encoding (stream, iadd))) { return ret; }
+    }
+
+  return 0;
+}
+
+/* This function calls xd3_iopt_finish_encoding to finish encoding an instruction, and it
+ * may also produce an add instruction for an unmatched region. */
+static int
+xd3_iopt_add_encoding (xd3_stream *stream, xd3_rinst *inst)
+{
+  int ret;
+  xd3_rinst iadd;
+
+  if ((ret = xd3_iopt_add (stream, inst->pos, & iadd))) { return ret; }
+
+  if ((ret = xd3_iopt_finish_encoding (stream, inst))) { return ret; }
+
+  return 0;
+}
+
+/* Generates a final add instruction to encode the remaining input. */
+static int
+xd3_iopt_add_finalize (xd3_stream *stream)
+{
+  int ret;
+  xd3_rinst iadd;
+
+  if ((ret = xd3_iopt_add (stream, stream->avail_in, & iadd))) { return ret; }
+
+  if (stream->iout)
+    {
+      if ((ret = xd3_emit_single (stream, stream->iout, stream->iout->code1))) { return ret; }
+
+      xd3_iopt_free_nonadd (stream, stream->iout);
+      stream->iout = NULL;
+    }
+
+  return 0;
+}
+
+/* Compact the instruction buffer by choosing the best non-overlapping instructions when
+ * lazy string-matching.  There are no ADDs in the iopt buffer because those are
+ * synthesized in xd3_iopt_add_encoding and during xd3_iopt_add_finalize. */
+static int
+xd3_iopt_flush_instructions (xd3_stream *stream, int force)
+{
+  xd3_rinst *r1 = xd3_rlist_front (& stream->iopt_used);
+  xd3_rinst *r2;
+  xd3_rinst *r3;
+  usize_t r1end;
+  usize_t r2end;
+  usize_t r2off;
+  usize_t r2moff;
+  usize_t gap;
+  usize_t flushed;
+  int ret;
+
+  XD3_ASSERT (xd3_iopt_check (stream));
+
+  /* Note: once tried to skip this step if it's possible to assert there are no
+   * overlapping instructions.  Doesn't work because xd3_opt_erase leaves overlapping
+   * instructions. */
+  while (! xd3_rlist_end (& stream->iopt_used, r1) &&
+	 ! xd3_rlist_end (& stream->iopt_used, r2 = xd3_rlist_next (r1)))
+    {
+      r1end = r1->pos + r1->size;
+
+      /* If the instructions do not overlap, continue. */
+      if (r1end <= r2->pos)
+	{
+	  r1 = r2;
+	  continue;
+	}
+
+      r2end = r2->pos + r2->size;
+
+      /* The min_match adjustments prevent this. */
+      XD3_ASSERT (r2end > (r1end + LEAST_MATCH_INCR));
+
+      /* If r3 is available... */
+      if (! xd3_rlist_end (& stream->iopt_used, r3 = xd3_rlist_next (r2)))
+	{
+	  /* If r3 starts before r1 finishes or just about, r2 is irrelevant */
+	  if (r3->pos <= r1end + 1)
+	    {
+	      xd3_iopt_free (stream, r2);
+	      continue;
+	    }
+	}
+      else if (! force)
+	{
+	  /* Unless force, end the loop when r3 is not available. */
+	  break;
+	}
+
+      r2off  = r2->pos - r1->pos;
+      r2moff = r2end - r1end;
+      gap    = r2end - r1->pos;
+
+      /* If the two matches overlap almost entirely, choose the better match and discard
+       * the other.  This heuristic is BLACK MAGIC.  Havesomething better? */
+      if (gap < 2*MIN_MATCH || r2moff <= 2 || r2off <= 2)
+	{
+	  /* Only one match should be used, choose the longer one. */
+	  if (r1->size < r2->size)
+	    {
+	      xd3_iopt_free (stream, r1);
+	      r1 = r2;
+	    }
+	  else
+	    {
+	      /* We are guaranteed that r1 does not overlap now, so advance past r2 */
+	      r1 = xd3_iopt_free (stream, r2);
+	    }
+	  continue;
+	}
+      else
+	{
+	  /* Shorten one of the instructions -- could be optimized based on the address
+	   * cache. */
+	  usize_t average;
+	  usize_t newsize;
+	  usize_t adjust1;
+
+	  XD3_ASSERT (r1end > r2->pos && r2end > r1->pos);
+
+	  /* Try to balance the length of both instructions, but avoid making both longer
+	   * than MAX_MATCH_SPLIT . */
+	  average = (gap) / 2;
+	  newsize = min (MAX_MATCH_SPLIT, gap - average);
+
+	  /* Should be possible to simplify this code. */
+	  if (newsize > r1->size)
+	    {
+	      /* shorten r2 */
+	      adjust1 = r1end - r2->pos;
+	    }
+	  else if (newsize > r2->size)
+	    {
+	      /* shorten r1 */
+	      adjust1 = r1end - r2->pos;
+
+	      XD3_ASSERT (r1->size > adjust1);
+
+	      r1->size -= adjust1;
+
+	      /* don't shorten r2 */
+	      adjust1 = 0;
+	    }
+	  else
+	    {
+	      /* shorten r1 */
+	      adjust1 = r1->size - newsize;
+
+	      if (r2->pos > r1end - adjust1)
+		{
+		  adjust1 -= r2->pos - (r1end - adjust1);
+		}
+
+	      XD3_ASSERT (r1->size > adjust1);
+
+	      r1->size -= adjust1;
+
+	      /* shorten r2 */
+	      XD3_ASSERT (r1->pos + r1->size >= r2->pos);
+
+	      adjust1 = r1->pos + r1->size - r2->pos;
+	    }
+
+	  /* Fallthrough above if-else, shorten r2 */
+	  XD3_ASSERT (r2->size > adjust1);
+
+	  r2->size -= adjust1;
+	  r2->pos  += adjust1;
+	  r2->addr += adjust1;
+
+	  XD3_ASSERT (r1->size >= MIN_MATCH);
+	  XD3_ASSERT (r2->size >= MIN_MATCH);
+
+	  r1 = r2;
+	}
+    }
+
+  XD3_ASSERT (xd3_iopt_check (stream));
+
+  /* If forcing, pick instructions until the list is empty, otherwise this empties 50% of
+   * the queue. */
+  for (flushed = 0; ! xd3_rlist_empty (& stream->iopt_used); )
+    {
+      xd3_rinst *renc = xd3_rlist_pop_front (& stream->iopt_used);
+      if ((ret = xd3_iopt_add_encoding (stream, renc)))
+	{
+	  return ret;
+	}
+
+      if (! force)
+	{
+	  if (++flushed > stream->iopt_size / 2)
+	    {
+	      break;
+	    }
+
+	  /* If there are only two instructions remaining, break, because they were
+	   * not optimized.  This means there were more than 50% eliminated by the
+	   * loop above. */
+ 	  r1 = xd3_rlist_front (& stream->iopt_used);
+ 	  if (xd3_rlist_end(& stream->iopt_used, r1) ||
+ 	      xd3_rlist_end(& stream->iopt_used, r2 = xd3_rlist_next (r1)) ||
+ 	      xd3_rlist_end(& stream->iopt_used, r3 = xd3_rlist_next (r2)))
+ 	    {
+ 	      break;
+ 	    }
+	}
+    }
+
+  XD3_ASSERT (xd3_iopt_check (stream));
+
+  XD3_ASSERT (!force || xd3_rlist_length (& stream->iopt_used) == 0);
+
+  return 0;
+}
+
+static int
+xd3_iopt_get_slot (xd3_stream *stream, xd3_rinst** iptr)
+{
+  xd3_rinst *i;
+  int ret;
+
+  if (xd3_rlist_empty (& stream->iopt_free))
+    {
+      if (stream->iopt_unlimited)
+	{
+	  int elts = XD3_ALLOCSIZE / sizeof(xd3_rinst);
+
+	  if ((ret = xd3_alloc_iopt (stream, elts)))
+	    {
+	      return ret;
+	    }
+
+	  stream->iopt_size += elts;
+	}
+      else
+	{
+	  if ((ret = xd3_iopt_flush_instructions (stream, 0))) { return ret; }
+
+	  XD3_ASSERT (! xd3_rlist_empty (& stream->iopt_free));
+	}
+    }
+
+  i = xd3_rlist_pop_back (& stream->iopt_free);
+
+  xd3_rlist_push_back (& stream->iopt_used, i);
+
+  (*iptr) = i;
+
+  ++stream->i_slots_used;
+
+  return 0;
+}
+
+/* A copy is about to be emitted that extends backwards to POS, therefore it may
+ * completely cover some existing instructions in the buffer.  If an instruction is
+ * completely covered by this new match, erase it.  If the new instruction is covered by
+ * the previous one, return 1 to skip it. */
+static void
+xd3_iopt_erase (xd3_stream *stream, usize_t pos, usize_t size)
+{
+  while (! xd3_rlist_empty (& stream->iopt_used))
+    {
+      xd3_rinst *r = xd3_rlist_back (& stream->iopt_used);
+
+      /* Verify that greedy is working.  The previous instruction should end before the
+       * new one begins. */
+      XD3_ASSERT ((stream->flags & XD3_BEGREEDY) == 0 || (r->pos + r->size <= pos));
+      /* Verify that min_match is working.  The previous instruction should end before the
+       * new one ends. */
+      XD3_ASSERT ((stream->flags & XD3_BEGREEDY) != 0 || (r->pos + r->size < pos + size));
+
+      /* See if the last instruction starts before the new instruction.  If so, there is
+       * nothing to erase. */
+      if (r->pos < pos)
+	{
+	  return;
+	}
+
+      /* Otherwise, the new instruction covers the old one, delete it and repeat. */
+      xd3_rlist_remove (r);
+      xd3_rlist_push_back (& stream->iopt_free, r);
+      --stream->i_slots_used;
+    }
+}
+
+/* This function tells the last matched input position. */
+static usize_t
+xd3_iopt_last_matched (xd3_stream *stream)
+{
+  xd3_rinst *r;
+
+  if (xd3_rlist_empty (& stream->iopt_used))
+    {
+      return 0;
+    }
+
+  r = xd3_rlist_back (& stream->iopt_used);
+
+  return r->pos + r->size;
+}
+
+/******************************************************************************************
+ Emit routines
+ ******************************************************************************************/
+
+static int
+xd3_emit_single (xd3_stream *stream, xd3_rinst *single, uint code)
+{
+  int has_size = stream->code_table[code].size1 == 0;
+  int ret;
+
+  IF_DEBUG1 (DP(RINT "[emit1] %u %s (%u) code %u\n",
+	       single->pos,
+	       xd3_rtype_to_string (single->type, 0),
+	       single->size,
+	       code));
+
+  if ((ret = xd3_emit_byte (stream, & INST_TAIL (stream), code))) { return ret; }
+
+  if (has_size)
+    {
+      if ((ret = xd3_emit_size (stream, & INST_TAIL (stream), single->size))) { return ret; }
+    }
+
+  return 0;
+}
+
+static int
+xd3_emit_double (xd3_stream *stream, xd3_rinst *first, xd3_rinst *second, uint code)
+{
+  int ret;
+
+  /* All double instructions use fixed sizes, so all we need to do is output the
+   * instruction code, no sizes. */
+  XD3_ASSERT (stream->code_table[code].size1 != 0 &&
+	      stream->code_table[code].size2 != 0);
+
+  if ((ret = xd3_emit_byte (stream, & INST_TAIL (stream), code))) { return ret; }
+
+  IF_DEBUG1 (DP(RINT "[emit2]: %u %s (%u) %s (%u) code %u\n",
+	       first->pos,
+	       xd3_rtype_to_string (first->type, 0),
+	       first->size,
+	       xd3_rtype_to_string (second->type, 0),
+	       second->size,
+	       code));
+
+  return 0;
+}
+
+/* This enters a potential run instruction into the iopt buffer.  The position argument is
+ * relative to the target window. */
+static INLINE int
+xd3_emit_run (xd3_stream *stream, usize_t pos, usize_t size, uint8_t run_c)
+{
+  xd3_rinst* ri;
+  int ret;
+
+  XD3_ASSERT (pos + size <= stream->avail_in);
+
+  if ((ret = xd3_iopt_get_slot (stream, & ri))) { return ret; }
+
+  ri->type = XD3_RUN;
+  ri->xtra = run_c;
+  ri->pos  = pos;
+  ri->size = size;
+
+  return 0;
+}
+
+/* This enters a potential copy instruction into the iopt buffer.  The position argument
+ * is relative to the target window.. */
+static INLINE int
+xd3_found_match (xd3_stream *stream, usize_t pos, usize_t size, xoff_t addr, int is_source)
+{
+  xd3_rinst* ri;
+  int ret;
+
+  XD3_ASSERT (pos + size <= stream->avail_in);
+
+  if ((ret = xd3_iopt_get_slot (stream, & ri))) { return ret; }
+
+  ri->type = XD3_CPY;
+  ri->xtra = is_source;
+  ri->pos  = pos;
+  ri->size = size;
+  ri->addr = addr;
+
+  return 0;
+}
+
+static int
+xd3_emit_hdr (xd3_stream *stream)
+{
+  int  ret;
+  int  use_secondary = stream->sec_type != NULL;
+  int  use_adler32   = stream->flags & XD3_ADLER32;
+  int  vcd_source    = xd3_encoder_used_source (stream);
+  uint win_ind = 0;
+  uint del_ind = 0;
+  usize_t enc_len;
+  usize_t tgt_len;
+  usize_t data_len;
+  usize_t inst_len;
+  usize_t addr_len;
+
+  XD3_ASSERT (stream->n_emit == stream->avail_in);
+
+  if (stream->current_window == 0)
+    {
+      uint hdr_ind = 0;
+      int use_appheader  = stream->enc_appheader != NULL;
+      int use_gencodetbl = GENERIC_ENCODE_TABLES && (stream->code_table_desc != & __rfc3284_code_table_desc);
+
+      if (use_secondary)  { hdr_ind |= VCD_SECONDARY; }
+      if (use_gencodetbl) { hdr_ind |= VCD_CODETABLE; }
+      if (use_appheader)  { hdr_ind |= VCD_APPHEADER; }
+
+      if ((ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC1)) != 0 ||
+	  (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC2)) != 0 ||
+	  (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_MAGIC3)) != 0 ||
+	  (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), VCDIFF_VERSION)) != 0 ||
+	  (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), hdr_ind)) != 0)
+	{
+	  return ret;
+	}
+
+      /* Secondary compressor ID */
+#if SECONDARY_ANY
+      if (use_secondary && (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), stream->sec_type->id))) { return ret; }
+#endif
+
+      /* Compressed code table */
+      if (use_gencodetbl)
+	{
+	  usize_t code_table_size;
+	  const uint8_t *code_table_data;
+
+	  if ((ret = stream->comp_table_func (stream, & code_table_data, & code_table_size))) { return ret; }
+
+	  if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), code_table_size + 2)) ||
+	      (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), stream->code_table_desc->near_modes)) ||
+	      (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), stream->code_table_desc->same_modes)) ||
+	      (ret = xd3_emit_bytes (stream, & HDR_TAIL (stream), code_table_data, code_table_size))) { return ret; }
+	}
+
+      /* Application header */
+      if (use_appheader)
+	{
+	  if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), stream->enc_appheadsz)) ||
+	      (ret = xd3_emit_bytes (stream, & HDR_TAIL (stream), stream->enc_appheader, stream->enc_appheadsz)))
+	    {
+	      return ret;
+	    }
+	}
+    }
+
+  /* try to compress this window */
+#if SECONDARY_ANY
+  if (use_secondary)
+    {
+      int data_sec = 0;
+      int inst_sec = 0;
+      int addr_sec = 0;
+
+#     define ENCODE_SECONDARY_SECTION(UPPER,LOWER) \
+             ((stream->flags & XD3_SEC_NO ## UPPER) == 0 && \
+              (ret = xd3_encode_secondary (stream, & UPPER ## _HEAD (stream), & UPPER ## _TAIL (stream), \
+					& xd3_sec_ ## LOWER (stream), \
+				        & stream->sec_ ## LOWER, & LOWER ## _sec)))
+
+      if (ENCODE_SECONDARY_SECTION (DATA, data) ||
+	  ENCODE_SECONDARY_SECTION (INST, inst) ||
+	  ENCODE_SECONDARY_SECTION (ADDR, addr))
+	{
+	  return ret;
+	}
+
+      del_ind |= (data_sec ? VCD_DATACOMP : 0);
+      del_ind |= (inst_sec ? VCD_INSTCOMP : 0);
+      del_ind |= (addr_sec ? VCD_ADDRCOMP : 0);
+    }
+#endif
+
+  /* if (vcd_target) { win_ind |= VCD_TARGET; } */
+  if (vcd_source)  { win_ind |= VCD_SOURCE; }
+  if (use_adler32) { win_ind |= VCD_ADLER32; }
+
+  /* window indicator */
+  if ((ret = xd3_emit_byte (stream, & HDR_TAIL (stream), win_ind))) { return ret; }
+
+  /* source window */
+  if (vcd_source)
+    {
+      /* or (vcd_target) { ... } */
+      if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), stream->src->srclen)) ||
+	  (ret = xd3_emit_offset (stream, & HDR_TAIL (stream), stream->src->srcbase))) { return ret; }
+    }
+
+  tgt_len  = stream->avail_in;
+  data_len = xd3_sizeof_output (DATA_HEAD (stream));
+  inst_len = xd3_sizeof_output (INST_HEAD (stream));
+  addr_len = xd3_sizeof_output (ADDR_HEAD (stream));
+
+  /* The enc_len field is redundent... doh! */
+  enc_len = (1 + (xd3_sizeof_size (tgt_len) +
+		  xd3_sizeof_size (data_len) +
+		  xd3_sizeof_size (inst_len) +
+		  xd3_sizeof_size (addr_len)) +
+	     data_len +
+	     inst_len +
+	     addr_len +
+	     (use_adler32 ? 4 : 0));
+
+  if ((ret = xd3_emit_size (stream, & HDR_TAIL (stream), enc_len)) ||
+      (ret = xd3_emit_size (stream, & HDR_TAIL (stream), tgt_len)) ||
+      (ret = xd3_emit_byte (stream, & HDR_TAIL (stream), del_ind)) ||
+      (ret = xd3_emit_size (stream, & HDR_TAIL (stream), data_len)) ||
+      (ret = xd3_emit_size (stream, & HDR_TAIL (stream), inst_len)) ||
+      (ret = xd3_emit_size (stream, & HDR_TAIL (stream), addr_len)))
+    {
+      return ret;
+    }
+
+  if (use_adler32)
+    {
+      uint8_t  send[4];
+      uint32_t a32 = adler32 (1L, stream->next_in, stream->avail_in);
+
+      send[0] = (a32 >> 24);
+      send[1] = (a32 >> 16);
+      send[2] = (a32 >> 8);
+      send[3] = (a32 & 0xff);
+
+      if ((ret = xd3_emit_bytes (stream, & HDR_TAIL (stream), send, 4))) { return ret; }
+    }
+
+  return 0;
+}
+
+/******************************************************************************************
+ Encode routines
+ ******************************************************************************************/
+
+static int
+xd3_encode_buffer_leftover (xd3_stream *stream)
+{
+  usize_t take;
+  usize_t room;
+
+  /* Allocate the buffer. */
+  if (stream->buf_in == NULL && (stream->buf_in = xd3_alloc (stream, stream->winsize, 1)) == NULL)
+    {
+      return ENOMEM;
+    }
+
+  /* Take leftover input first. */
+  if (stream->buf_leftover != NULL)
+    {
+      XD3_ASSERT (stream->buf_avail == 0);
+      XD3_ASSERT (stream->buf_leftavail < stream->winsize);
+
+      IF_DEBUG1 (DP(RINT "[leftover] previous %u avail %u\n", stream->buf_leftavail, stream->avail_in));
+
+      memcpy (stream->buf_in, stream->buf_leftover, stream->buf_leftavail);
+
+      stream->buf_leftover = NULL;
+      stream->buf_avail    = stream->buf_leftavail;
+    }
+
+  /* Copy into the buffer. */
+  room = stream->winsize - stream->buf_avail;
+  take = min (room, stream->avail_in);
+
+  memcpy (stream->buf_in + stream->buf_avail, stream->next_in, take);
+
+  stream->buf_avail += take;
+
+  if (take < stream->avail_in)
+    {
+      /* Buffer is full */
+      stream->buf_leftover  = stream->next_in  + take;
+      stream->buf_leftavail = stream->avail_in - take;
+
+      IF_DEBUG1 (DP(RINT "[leftover] take %u remaining %u\n", take, stream->buf_leftavail));
+    }
+  else if ((stream->buf_avail < stream->winsize) && !(stream->flags & XD3_FLUSH))
+    {
+      /* Buffer has space */
+      IF_DEBUG1 (DP(RINT "[leftover] %u emptied\n", take));
+      return XD3_INPUT;
+    }
+
+  /* Use the buffer: */
+  stream->next_in   = stream->buf_in;
+  stream->avail_in  = stream->buf_avail;
+  stream->buf_avail = 0;
+
+  return 0;
+}
+
+/* Allocates one block of xd3_rlist elements */
+static int
+xd3_alloc_iopt (xd3_stream *stream, int elts)
+{
+  int i;
+  xd3_iopt_buflist* last = xd3_alloc (stream, sizeof (xd3_iopt_buflist), 1);
+
+  if (last == NULL ||
+      (last->buffer = xd3_alloc (stream, sizeof (xd3_rinst), elts)) == NULL)
+    {
+      return ENOMEM;
+    }
+
+  last->next = stream->iopt_alloc;
+  stream->iopt_alloc = last;
+
+  for (i = 0; i < elts; i += 1)
+    {
+      xd3_rlist_push_back (& stream->iopt_free, & last->buffer[i]);
+    }
+
+  return 0;
+}
+
+/* This function allocates all memory initially used by the encoder. */
+static int
+xd3_encode_init (xd3_stream *stream)
+{
+  int i;
+  int large_comp = (stream->src != NULL);
+  int small_comp = ! (stream->flags & XD3_NOCOMPRESS);
+
+  /* Memory allocations for checksum tables are delayed until xd3_string_match_init in the
+   * first call to string_match--that way identical or short inputs require no table
+   * allocation. */
+  if (large_comp)
+    {
+      usize_t hash_values = (stream->srcwin_maxsz / stream->smatcher.large_step);
+
+      xd3_size_hashtable (stream,
+			  hash_values,
+			  & stream->large_hash);
+    }
+
+  if (small_comp)
+    {
+      usize_t hash_values = min(stream->winsize, stream->sprevsz);
+
+      xd3_size_hashtable (stream,
+			  hash_values,
+			  & stream->small_hash);
+    }
+
+  for (i = 0; i < ENC_SECTS; i += 1)
+    {
+      if ((stream->enc_heads[i] =
+	   stream->enc_tails[i] =
+	   xd3_alloc_output (stream, NULL)) == NULL)
+	{
+	  goto fail;
+	}
+    }
+
+  /* iopt buffer */
+  xd3_rlist_init (& stream->iopt_used);
+  xd3_rlist_init (& stream->iopt_free);
+
+  if (xd3_alloc_iopt (stream, stream->iopt_size) != 0) { goto fail; }
+
+  XD3_ASSERT (xd3_rlist_length (& stream->iopt_free) == stream->iopt_size);
+  XD3_ASSERT (xd3_rlist_length (& stream->iopt_used) == 0);
+
+  /* address cache, code table */
+  stream->acache.s_near = stream->code_table_desc->near_modes;
+  stream->acache.s_same = stream->code_table_desc->same_modes;
+  stream->code_table    = stream->code_table_func ();
+
+  return xd3_alloc_cache (stream);
+
+ fail:
+
+  return ENOMEM;
+}
+
+/* Called after the ENC_POSTOUT state, this puts the output buffers back into separate
+ * lists and re-initializes some variables.  (The output lists were spliced together
+ * during the ENC_FLUSH state.) */
+static void
+xd3_encode_reset (xd3_stream *stream)
+{
+  int i;
+  xd3_output *olist;
+
+  IF_DEBUG (stream->n_emit = 0);
+  stream->avail_in     = 0;
+  stream->small_reset  = 1;
+  stream->i_slots_used = 0;
+
+  if (stream->src != NULL)
+    {
+      stream->src->srcbase   = 0;
+      stream->src->srclen    = 0;
+      stream->srcwin_decided = 0;
+      stream->match_minaddr  = 0;
+      stream->match_maxaddr  = 0;
+      stream->taroff         = 0;
+    }
+
+  /* Reset output chains. */
+  olist = stream->enc_heads[0];
+
+  for (i = 0; i < ENC_SECTS; i += 1)
+    {
+      XD3_ASSERT (olist != NULL);
+
+      stream->enc_heads[i] = olist;
+      stream->enc_tails[i] = olist;
+      olist = olist->next_page;
+
+      stream->enc_heads[i]->next = 0;
+      stream->enc_heads[i]->next_page = NULL;
+
+      stream->enc_tails[i]->next_page = NULL;
+      stream->enc_tails[i] = stream->enc_heads[i];
+    }
+
+  xd3_freelist_output (stream, olist);
+}
+
+/* The main encoding routine. */
+int
+xd3_encode_input (xd3_stream *stream)
+{
+  int ret, i;
+
+  if (stream->dec_state != 0)
+    {
+      stream->msg = "encoder/decoder transition";
+      return XD3_INTERNAL;
+    }
+
+  switch (stream->enc_state)
+    {
+    case ENC_INIT:
+      /* Only reached on first time through: memory setup. */
+      if ((ret = xd3_encode_init (stream))) { return ret; }
+
+      stream->enc_state = ENC_INPUT;
+
+    case ENC_INPUT:
+
+      /* If there is no input yet, just return.  This checks for next_in == NULL, not
+       * avail_in == 0 since zero bytes is a valid input.  There is an assertion in
+       * xd3_avail_input() that next_in != NULL for this reason.  By returning right away
+       * we avoid creating an input buffer before the caller has supplied its first data.
+       * It is possible for xd3_avail_input to be called both before and after the first
+       * call to xd3_encode_input(). */
+      if (stream->next_in == NULL)
+	{
+	  return XD3_INPUT;
+	}
+
+    enc_flush:
+      /* See if we should buffer the input: either if there is already a leftover buffer,
+       * or if the input is short of winsize without flush.  The label at this point is
+       * reached by a goto below, when there is leftover input after postout. */
+      if ((stream->buf_leftover != NULL) ||
+	  (stream->avail_in < stream->winsize && ! (stream->flags & XD3_FLUSH)))
+	{
+	  if ((ret = xd3_encode_buffer_leftover (stream))) { return ret; }
+	}
+
+      /* Initalize the address cache before each window. */
+      xd3_init_cache (& stream->acache);
+
+      stream->input_position    = 0;
+      stream->min_match = MIN_MATCH;
+      stream->unencoded_offset = 0;
+
+      stream->enc_state = ENC_SEARCH;
+
+      IF_DEBUG1 (DP(RINT "[input window:%"Q"u] input bytes %u offset %"Q"u\n",
+		   stream->current_window, stream->avail_in, stream->total_in));
+
+      return XD3_WINSTART;
+
+    case ENC_SEARCH:
+
+      /* Reentrant matching. */
+      if (stream->src != NULL)
+	{
+	  switch (stream->match_state)
+	    {
+	    case MATCH_TARGET:
+	      /* Try matching forward at the start of the target.  This is entered the
+	       * first time through, to check for a perfect match, and whenever there is a
+	       * source match that extends to the end of the previous window.  The
+	       * match_srcpos field is initially zero and later set during
+	       * xd3_source_extend_match. */
+	      if (stream->avail_in > 0)
+		{
+		  /* This call can't fail because the source window is unrestricted. */
+		  ret = xd3_source_match_setup (stream, stream->match_srcpos);
+		  XD3_ASSERT (ret == 0);
+		  stream->match_state = MATCH_FORWARD;
+		}
+	      else
+		{
+		  stream->match_state = MATCH_SEARCHING;
+		}
+	      XD3_ASSERT (stream->match_fwd == 0);
+
+	    case MATCH_FORWARD:
+	    case MATCH_BACKWARD:
+	      if (stream->avail_in != 0)
+		{
+		  if ((ret = xd3_source_extend_match (stream)) != 0)
+		    {
+		      return ret;
+		    }
+
+		  stream->input_position += stream->match_fwd;
+		}
+
+	    case MATCH_SEARCHING:
+	      /* Continue string matching.  (It's possible that the initial match
+	       * continued through the entire input, in which case we're still in
+	       * MATCH_FORWARD and should remain so for the next input window.) */
+	      break;
+	    }
+	}
+
+      /* String matching... */
+      if (stream->avail_in != 0 &&
+	  (ret = stream->smatcher.string_match (stream)))
+	{
+	  return ret;
+	}
+
+      /* Flush the instrution buffer, then possibly add one more instruction, then emit
+       * the header. */
+      stream->enc_state = ENC_FLUSH;
+      if ((ret = xd3_iopt_flush_instructions (stream, 1)) ||
+          (ret = xd3_iopt_add_finalize (stream)) ||
+	  (ret = xd3_emit_hdr (stream)))
+	{
+	  return ret;
+	}
+
+      /* Begin output. */
+      stream->enc_current = HDR_HEAD (stream);
+
+      /* Chain all the outputs together.  After doing this, it looks as if there is only
+       * one section.  The other enc_heads are set to NULL to avoid freeing them more than
+       * once. */
+       for (i = 1; i < ENC_SECTS; i += 1)
+	{
+	  stream->enc_tails[i-1]->next_page = stream->enc_heads[i];
+	  stream->enc_heads[i] = NULL;
+	}
+
+    enc_output:
+
+      stream->enc_state  = ENC_POSTOUT;
+      stream->next_out   = stream->enc_current->base;
+      stream->avail_out  = stream->enc_current->next;
+      stream->total_out += (xoff_t) stream->avail_out;
+
+      /* If there is any output in this buffer, return it, otherwise fall through to
+       * handle the next buffer or finish the window after all buffers have been
+       * output. */
+      if (stream->avail_out > 0)
+	{
+	  /* This is the only place xd3_encode returns XD3_OUTPUT */
+	  return XD3_OUTPUT;
+	}
+
+    case ENC_POSTOUT:
+
+      if (stream->avail_out != 0)
+	{
+	  stream->msg = "missed call to consume output";
+	  return XD3_INTERNAL;
+	}
+
+      /* Continue outputting one buffer at a time, until the next is NULL. */
+      if ((stream->enc_current = stream->enc_current->next_page) != NULL)
+	{
+	  goto enc_output;
+	}
+
+      stream->total_in += (xoff_t) stream->avail_in;
+      stream->enc_state = ENC_POSTWIN;
+
+      return XD3_WINFINISH;
+
+    case ENC_POSTWIN:
+
+      xd3_encode_reset (stream);
+
+      stream->current_window += 1;
+      stream->enc_state = ENC_INPUT;
+
+      /* If there is leftover input to flush, repeat. */
+      if ((stream->buf_leftover != NULL) && (stream->flags & XD3_FLUSH))
+	{
+	  goto enc_flush;
+	}
+
+      /* Ready for more input. */
+      return XD3_INPUT;
+
+    default:
+      stream->msg = "invalid state";
+      return XD3_INTERNAL;
+    }
+}
+#endif /* XD3_ENCODER */
+
+/******************************************************************************************
+ Client convenience functions
+ ******************************************************************************************/
+
+static int
+xd3_process_stream (int            is_encode,
+		    xd3_stream    *stream,
+		    int          (*func) (xd3_stream *),
+		    int            close_stream,
+		    const uint8_t *input,
+		    usize_t        input_size,
+		    uint8_t       *output,
+		    usize_t       *output_size,
+		    usize_t        output_size_max)
+{
+  usize_t ipos = 0;
+  usize_t n = min(stream->winsize, input_size);
+
+  (*output_size) = 0;
+
+  stream->flags |= XD3_FLUSH; 
+
+  xd3_avail_input (stream, input + ipos, n);
+  ipos += n;
+
+  for (;;)
+    {
+      int ret;
+      switch((ret = func (stream)))
+	{
+	case XD3_OUTPUT: { /* memcpy below */ break; }
+	case XD3_INPUT: {
+	  n = min(stream->winsize, input_size - ipos);
+	  if (n == 0) {
+	    goto done;
+	  }
+	  xd3_avail_input (stream, input + ipos, n);
+	  ipos += n;
+	  continue;
+	}
+	case XD3_GOTHEADER: { /* ignore */ continue; }
+	case XD3_WINSTART: { /* ignore */ continue; }
+	case XD3_WINFINISH: { /* ignore */ continue; }
+	case XD3_GETSRCBLK:
+	  {
+	    stream->msg = "stream requires source input";
+	    return XD3_INTERNAL;
+	  }
+	case 0:
+	  {
+	    /* xd3_encode_input/xd3_decode_input never return 0 */
+	    stream->msg = "invalid return: 0";
+	    return XD3_INTERNAL;
+	  }
+	default:
+	  return ret;
+	}
+
+      if (*output_size + stream->avail_out > output_size_max)
+	{
+	  stream->msg = "insufficient output space";
+	  return ENOSPC;
+	}
+
+      memcpy (output + *output_size, stream->next_out, stream->avail_out);
+
+      *output_size += stream->avail_out;
+
+      xd3_consume_output (stream);
+    }
+ done:
+  return (close_stream == 0) ? 0 : xd3_close_stream (stream);
+}
+
+static int
+xd3_process_memory (int            is_encode,
+		    int          (*func) (xd3_stream *),
+		    int            close_stream,
+		    const uint8_t *input,
+		    usize_t        input_size,
+		    const uint8_t *source,
+		    usize_t        source_size,
+		    uint8_t       *output,
+		    usize_t       *output_size,
+		    usize_t        output_size_max,
+		    int            flags) {
+  xd3_stream stream;
+  xd3_config config;
+  xd3_source src;
+  int ret;
+
+  if (input == NULL || output == NULL) {
+    stream.msg = "invalid input/output buffer";
+    return XD3_INTERNAL;
+  }
+
+  memset (& stream, 0, sizeof (stream));
+  memset (& config, 0, sizeof (config));
+
+  config.flags = flags;
+
+  if (is_encode)
+    {
+      config.srcwin_maxsz = source_size;
+      config.winsize = min(input_size, (usize_t) XD3_DEFAULT_WINSIZE);
+      config.iopt_size = min(input_size / 32, XD3_DEFAULT_IOPT_SIZE);
+      config.iopt_size = max(config.iopt_size, 128U);
+
+      config.sprevsz = XD3_DEFAULT_SPREVSZ;
+
+      while (config.sprevsz / 2 > input_size)
+	{
+	  config.sprevsz /=  2;
+	}
+    }
+
+  if ((ret = xd3_config_stream (&stream, &config)) != 0)
+    {
+      goto exit;
+    }
+
+  if (source != NULL)
+    {
+      memset (& src, 0, sizeof (src));
+      src.size = source_size;
+      src.blksize = source_size;
+      src.onblk = source_size;
+      src.curblk = source;
+      src.curblkno = 0;
+
+      if ((ret = xd3_set_source (&stream, &src)) != 0)
+	{
+	  goto exit;
+	}
+    }
+
+  if ((ret = xd3_process_stream (is_encode,
+				 & stream,
+				 func, 1,
+				 input, input_size,
+				 output,
+				 output_size,
+				 output_size_max)) != 0)
+    {
+      goto exit;
+    }
+
+ exit:
+  xd3_free_stream(&stream);
+  return ret;
+}
+
+int
+xd3_decode_stream (xd3_stream    *stream,
+		   const uint8_t *input,
+		   usize_t        input_size,
+		   uint8_t       *output,
+		   usize_t       *output_size,
+		   usize_t        output_size_max)
+{
+  return xd3_process_stream (0, stream, & xd3_decode_input, 1,
+			     input, input_size,
+			     output, output_size, output_size_max);
+}
+
+int
+xd3_decode_memory (const uint8_t *input,
+		   usize_t        input_size,
+		   const uint8_t *source,
+		   usize_t        source_size,
+		   uint8_t       *output,
+		   usize_t       *output_size,
+		   usize_t        output_size_max,
+		   int            flags) {
+  return xd3_process_memory (0, & xd3_decode_input, 1,
+			     input, input_size,
+			     source, source_size,
+			     output, output_size, output_size_max,
+			     flags);
+}
+
+
+#if XD3_ENCODER
+int
+xd3_encode_stream (xd3_stream    *stream,
+		   const uint8_t *input,
+		   usize_t         input_size,
+		   uint8_t       *output,
+		   usize_t        *output_size,
+		   usize_t         output_size_max)
+{
+  return xd3_process_stream (1, stream, & xd3_encode_input, 1,
+			     input, input_size,
+			     output, output_size, output_size_max);
+}
+
+int
+xd3_encode_memory (const uint8_t *input,
+		   usize_t        input_size,
+		   const uint8_t *source,
+		   usize_t        source_size,
+		   uint8_t       *output,
+		   usize_t        *output_size,
+		   usize_t        output_size_max,
+		   int            flags) {
+  return xd3_process_memory (1, & xd3_encode_input, 1,
+			     input, input_size,
+			     source, source_size,
+			     output, output_size, output_size_max,
+			     flags);
+}
+#endif
+
+
+/******************************************************************************************
+ String matching helpers
+ ******************************************************************************************/
+
+#if XD3_ENCODER
+/* Do the initial xd3_string_match() checksum table setup.  Allocations are delayed until
+ * first use to avoid allocation sometimes (e.g., perfect matches, zero-length inputs). */
+static int
+xd3_string_match_init (xd3_stream *stream)
+{
+  const int DO_SMALL = ! (stream->flags & XD3_NOCOMPRESS);
+  const int DO_LARGE = (stream->src != NULL);
+
+  if (DO_LARGE && stream->large_table == NULL)
+    {
+      if ((stream->large_table = xd3_alloc0 (stream, stream->large_hash.size, sizeof (usize_t))) == NULL)
+	{
+	  return ENOMEM;
+	}
+    }
+
+  if (DO_SMALL)
+    {
+      /* Subsequent calls can return immediately after checking reset. */
+      if (stream->small_table != NULL)
+	{
+	  /* The target hash table is reinitialized once per window. */
+	  /* TODO: This would not have to be reinitialized if absolute offsets
+	   * were being stored, as we would do for VCD_TARGET encoding. */
+	  if (stream->small_reset)
+	    {
+	      stream->small_reset = 0;
+	      memset (stream->small_table, 0, sizeof (usize_t) * stream->small_hash.size);
+	    }
+
+	  return 0;
+	}
+
+      if ((stream->small_table = xd3_alloc0 (stream,
+					     stream->small_hash.size,
+					     sizeof (usize_t))) == NULL)
+	{
+	  return ENOMEM;
+	}
+
+      /* If there is a previous table needed. */
+      if (stream->smatcher.small_lchain > 1 ||
+	  stream->smatcher.small_chain > 1)
+	{
+	  if ((stream->small_prev = xd3_alloc (stream,
+					       stream->sprevsz,
+					       sizeof (xd3_slist))) == NULL)
+	    {
+	      return ENOMEM;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+#if XD3_USE_LARGEFILE64
+/* This function handles the 32/64bit ambiguity -- file positions are 64bit but the hash
+ * table for source-offsets is 32bit. */
+static xoff_t
+xd3_source_cksum_offset(xd3_stream *stream, usize_t low)
+{
+  xoff_t scp = stream->srcwin_cksum_pos;
+  xoff_t s0 = scp >> 32;
+
+  usize_t sr = (usize_t) scp;
+
+  if (s0 == 0) {
+    return low;
+  }
+
+  /* This should not be >= because srcwin_cksum_pos is the next
+   * position to index. */
+  if (low > sr) {
+    return (--s0 << 32) | low;
+  }
+
+  return (s0 << 32) | low;
+}
+#else
+static xoff_t
+xd3_source_cksum_offset(xd3_stream *stream, usize_t low)
+{
+  return (xoff_t) low;
+}
+#endif
+
+/* This function sets up the stream->src fields srcbase, srclen.  The call is delayed
+ * until these values are needed to encode a copy address.  At this point the decision has
+ * to be made. */
+static int
+xd3_srcwin_setup (xd3_stream *stream)
+{
+  xd3_source *src = stream->src;
+  xoff_t length;
+
+  /* Check the undecided state. */
+  XD3_ASSERT (src->srclen == 0 && src->srcbase == 0);
+
+  /* Avoid repeating this call. */
+  stream->srcwin_decided = 1;
+
+  /* If the stream is flushing, then the iopt buffer was able to contain the complete
+   * encoding.  If no copies were issued no source window is actually needed.  This
+   * prevents the VCDIFF header from including source base/len.  xd3_emit_hdr checks
+   * for srclen == 0. */
+  if (stream->enc_state == ENC_FLUSH && stream->match_maxaddr == 0)
+    {
+      goto done;
+    }
+
+  /* Check for overflow, srclen is usize_t - this can't happen unless XD3_DEFAULT_SRCBACK
+   * and related parameters are extreme - should use smaller windows. */
+  length = stream->match_maxaddr - stream->match_minaddr;
+
+  if (length > (xoff_t) USIZE_T_MAX)
+    {
+      stream->msg = "source window length overflow (not 64bit)";
+      return XD3_INTERNAL;
+    }
+
+  /* If ENC_FLUSH, then we know the exact source window to use because no more copies can
+   * be issued. */
+  if (stream->enc_state == ENC_FLUSH)
+    {
+      src->srcbase = stream->match_minaddr;
+      src->srclen  = (usize_t) length;
+      XD3_ASSERT (src->srclen);
+      goto done;
+    }
+
+  /* Otherwise, we have to make a guess.  More copies may still be issued, but we have to
+   * decide the source window base and length now.  */
+  src->srcbase = stream->match_minaddr;
+  src->srclen  = max ((usize_t) length, stream->avail_in + (stream->avail_in >> 2));
+  if (src->size < src->srcbase + (xoff_t) src->srclen)
+    {
+      /* Could reduce srcbase, as well. */
+      src->srclen = src->size - src->srcbase;
+    }
+
+  XD3_ASSERT (src->srclen);
+ done:
+  /* Set the taroff.  This convenience variable is used even when stream->src == NULL. */
+  stream->taroff = src->srclen;
+  return 0;
+}
+
+/* This function computes more source checksums to advance the window.
+ * Called at every entrance to the string-match loop and each time
+ * stream->input_position reaches the value returned as
+ * *next_move_point.  NB: this is one of the most expensive functions
+ * in this code and also the most critical for good compression.
+ *
+ * TODO: really would like a good test for this logic. how?
+ * TODO: optimize the inner loop
+ */
+static int
+xd3_srcwin_move_point (xd3_stream *stream, usize_t *next_move_point)
+{
+  xoff_t logical_input_cksum_pos;
+
+  XD3_ASSERT(stream->srcwin_cksum_pos <= stream->src->size);
+  if (stream->srcwin_cksum_pos == stream->src->size)
+    {
+      *next_move_point = USIZE_T_MAX;
+      return 0;
+    }
+
+  /* Begin by advancing at twice the input rate, up to half the
+   * maximum window size. */
+  logical_input_cksum_pos = min((stream->total_in + stream->input_position) * 2,
+				(stream->total_in + stream->input_position) +
+				  (stream->srcwin_maxsz / 2));
+
+  /* If srcwin_cksum_pos is already greater, wait until the difference
+   * is met. */
+  if (stream->srcwin_cksum_pos > logical_input_cksum_pos)
+    {
+      *next_move_point = stream->input_position +
+	(usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos);
+      return 0;
+    }
+
+  /* A long match may have extended past srcwin_cksum_pos.  Don't
+   * start checksumming already-matched source data. */
+  if (stream->maxsrcaddr > stream->srcwin_cksum_pos)
+    {
+      stream->srcwin_cksum_pos = stream->maxsrcaddr;
+    }
+
+  if (logical_input_cksum_pos < stream->srcwin_cksum_pos)
+    {
+      logical_input_cksum_pos = stream->srcwin_cksum_pos;
+    }
+
+  /* Advance at least one source block.  With the command-line
+   * defaults this means:
+   *
+   * if (src->size <= srcwin_maxsz), index the entire source at once
+   * using the position of the first non-match.  This is good for
+   * small inputs, especially when the content may have moved anywhere
+   * in the file (e.g., tar files).
+   *
+   * if (src->size > srcwin_maxsz), index at least one block (which
+   * the command-line sets to 1/32 of srcwin_maxsz) ahead of the
+   * logical position.  This is good for different reasons: when a
+   * long match spanning several source blocks is encountered, this
+   * avoids computing checksums for those blocks.  If the data can
+   * move anywhere, this is bad.
+   */
+  logical_input_cksum_pos += stream->src->blksize;
+
+  IF_DEBUG1 (DP(RINT "[srcwin_move_point] T=%"Q"u S=%"Q"u/%"Q"u\n",
+	       stream->total_in + stream->input_position,
+	       stream->srcwin_cksum_pos,
+	       logical_input_cksum_pos));
+
+  while (stream->srcwin_cksum_pos < logical_input_cksum_pos &&
+	 stream->srcwin_cksum_pos < stream->src->size)
+    {
+      xoff_t  blkno = stream->srcwin_cksum_pos / stream->src->blksize;
+      ssize_t oldpos = stream->srcwin_cksum_pos % stream->src->blksize;
+      ssize_t blkpos = xd3_bytes_on_srcblk (stream->src, blkno);
+      int ret;
+
+      if (oldpos + stream->smatcher.large_look > blkpos)
+	{
+	  stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize;
+	  continue;
+	}
+
+      if ((ret = xd3_getblk (stream, blkno)))
+	{
+	  /* TOOFARBACK should never occur here, since we read forward. */
+	  if (ret == XD3_TOOFARBACK)
+	    {
+ 	      ret = XD3_INTERNAL;
+	    }
+	  return ret;
+	}
+
+      /* This inserts checksums for the entire block, in reverse,
+       * starting from the end of the block.  This logic does not test
+       * stream->srcwin_cksum_pos because it always advances it to the
+       * start of the next block.
+       *
+       * oldpos is the srcwin_cksum_pos within this block.  blkpos is
+       * the number of bytes available.  Each iteration inspects
+       * large_look bytes then steps back large_step bytes.  The
+       * if-stmt above ensures at least one large_look of data. */
+      blkpos -= stream->smatcher.large_look;
+
+      do
+	{
+	  uint32_t cksum = xd3_lcksum (stream->src->curblk + blkpos,
+				       stream->smatcher.large_look);
+	  usize_t hval = xd3_checksum_hash (& stream->large_hash, cksum);
+
+	  stream->large_table[hval] =
+	    (usize_t) ((stream->src->blksize * blkno) +
+		       (xoff_t)(blkpos + HASH_CKOFFSET));
+
+	  IF_DEBUG (stream->large_ckcnt += 1);
+
+	  blkpos -= stream->smatcher.large_step;
+	}
+      while (blkpos >= oldpos);
+
+      stream->srcwin_cksum_pos = (blkno + 1) * stream->src->blksize;
+    }
+
+  if (stream->srcwin_cksum_pos >= stream->src->size)
+    {
+      /* This invariant is needed for xd3_source_cksum_offset() */
+      stream->srcwin_cksum_pos = stream->src->size;
+      *next_move_point = USIZE_T_MAX;
+      return 0;
+    }
+
+  /* How long until this function should be called again. */
+  XD3_ASSERT(stream->srcwin_cksum_pos >= logical_input_cksum_pos);
+  *next_move_point = stream->input_position + 1 +
+    (usize_t)(stream->srcwin_cksum_pos - logical_input_cksum_pos);
+  return 0;
+}
+
+/* Sets the bounding region for a newly discovered source match, prior to calling
+ * xd3_source_extend_match().  This sets the match_maxfwd, match_maxback variables.  Note:
+ * srcpos is an absolute position (xoff_t) but the match_maxfwd, match_maxback variables
+ * are usize_t.  Returns 0 if the setup succeeds, or 1 if the source position lies outside
+ * an already-decided srcbase/srclen window. */
+static int
+xd3_source_match_setup (xd3_stream *stream, xoff_t srcpos)
+{
+  xd3_source *src = stream->src;
+  usize_t greedy_or_not;
+
+  stream->match_maxback = 0;
+  stream->match_maxfwd  = 0;
+  stream->match_back    = 0;
+  stream->match_fwd     = 0;
+
+  /* Going backwards, the 1.5-pass algorithm allows some already-matched input may be
+   * covered by a longer source match.  The greedy algorithm does not allow this. */
+  if (stream->flags & XD3_BEGREEDY)
+    {
+      /* The greedy algorithm allows backward matching to the last matched position. */
+      greedy_or_not = xd3_iopt_last_matched (stream);
+    }
+  else
+    {
+      /* The 1.5-pass algorithm allows backward matching to go back as far as the
+       * unencoded offset, which is updated as instructions pass out of the iopt buffer.
+       * If this (default) is chosen, it means xd3_iopt_erase may be called to eliminate
+       * instructions when a covering source match is found. */
+      greedy_or_not = stream->unencoded_offset;
+    }
+
+
+
+  /* Backward target match limit. */
+  XD3_ASSERT (stream->input_position >= greedy_or_not);
+  stream->match_maxback = stream->input_position - greedy_or_not;
+
+  /* Forward target match limit. */
+  XD3_ASSERT (stream->avail_in > stream->input_position);
+  stream->match_maxfwd = stream->avail_in - stream->input_position;
+
+  /* Now we take the source position into account.  It depends whether the srclen/srcbase
+   * have been decided yet. */
+  if (stream->srcwin_decided == 0)
+    {
+      /* Unrestricted case: the match can cover the entire source, 0--src->size.  We
+       * compare the usize_t match_maxfwd/match_maxback against the xoff_t src->size/srcpos values
+       * and take the min. */
+      xoff_t srcavail;
+
+      if (srcpos < (xoff_t) stream->match_maxback)
+	{
+	  stream->match_maxback = srcpos;
+	}
+
+      srcavail = src->size - srcpos;
+      if (srcavail < (xoff_t) stream->match_maxfwd)
+	{
+	  stream->match_maxfwd = srcavail;
+	}
+
+      goto good;
+    }
+
+  /* Decided some source window. */
+  XD3_ASSERT (src->srclen > 0);
+
+  /* Restricted case: fail if the srcpos lies outside the source window */
+  if ((srcpos < src->srcbase) || (srcpos > (src->srcbase + (xoff_t) src->srclen)))
+    {
+      goto bad;
+    }
+  else
+    {
+      usize_t srcavail;
+
+      srcavail = (usize_t) (srcpos - src->srcbase);
+      if (srcavail < stream->match_maxback)
+	{
+	  stream->match_maxback = srcavail;
+	}
+
+      srcavail = (usize_t) (src->srcbase + (xoff_t) src->srclen - srcpos);
+      if (srcavail < stream->match_maxfwd)	{
+	  stream->match_maxfwd = srcavail;
+	}
+
+      goto good;
+    }
+
+ good:
+  stream->match_state  = MATCH_BACKWARD;
+  stream->match_srcpos = srcpos;
+  return 0;
+
+ bad:
+  stream->match_state  = MATCH_SEARCHING;
+  return 1;
+}
+
+/* This function expands the source match backward and forward.  It is reentrant, since
+ * xd3_getblk may return XD3_GETSRCBLK, so most variables are kept in xd3_stream.  There
+ * are two callers of this function, the string_matching routine when a checksum match is
+ * discovered, and xd3_encode_input whenever a continuing (or initial) match is suspected.
+ * The two callers do different things with the input_position, thus this function leaves
+ * that variable untouched.  If a match is taken the resulting stream->match_fwd is left
+ * non-zero. */
+static int
+xd3_source_extend_match (xd3_stream *stream)
+{
+  int ret;
+  xd3_source *src = stream->src;
+  xoff_t matchoff;  /* matchoff is the current right/left-boundary of the source match being tested. */
+  usize_t streamoff; /* streamoff is the current right/left-boundary of the input match being tested. */
+  xoff_t tryblk;    /* tryblk, tryoff are the block, offset position of matchoff */
+  usize_t tryoff;
+  usize_t tryrem;    /* tryrem is the number of matchable bytes on the source block */
+
+  XD3_ASSERT (src != NULL);
+
+  /* Does it make sense to compute backward match AFTER forward match? */
+  if (stream->match_state == MATCH_BACKWARD)
+    {
+      /* Note: this code is practically duplicated below, substituting
+       * match_fwd/match_back and direction.  Consolidate? */
+      matchoff  = stream->match_srcpos - stream->match_back;
+      streamoff = stream->input_position - stream->match_back;
+      tryblk    = matchoff / src->blksize;
+      tryoff    = matchoff % src->blksize;
+
+      /* this loops backward over source blocks */
+      while (stream->match_back < stream->match_maxback)
+	{
+	  /* see if we're backing across a source block boundary */
+	  if (tryoff == 0)
+	    {
+	      tryoff  = src->blksize;
+	      tryblk -= 1;
+	    }
+
+	  if ((ret = xd3_getblk (stream, tryblk)))
+	    {
+	      /* if search went too far back, continue forward. */
+	      if (ret == XD3_TOOFARBACK)
+		{
+		  break;
+		}
+
+	      /* could be a XD3_GETSRCBLK failure. */
+	      return ret;
+	    }
+
+	  /* OPT: This code can be optimized. */
+	  for (tryrem = min (tryoff, stream->match_maxback - stream->match_back);
+	       tryrem != 0;
+	       tryrem -= 1, stream->match_back += 1)
+	    {
+	      if (src->curblk[tryoff-1] != stream->next_in[streamoff-1])
+		{
+		  goto doneback;
+		}
+
+	      tryoff    -= 1;
+	      streamoff -= 1;
+	    }
+	}
+
+    doneback:
+      stream->match_state = MATCH_FORWARD;
+    }
+
+  XD3_ASSERT (stream->match_state == MATCH_FORWARD);
+
+  matchoff  = stream->match_srcpos + stream->match_fwd;
+  streamoff = stream->input_position + stream->match_fwd;
+  tryblk    = matchoff / src->blksize;
+  tryoff    = matchoff % src->blksize;
+
+  /* Note: practically the same code as backwards case above: same comments */
+  while (stream->match_fwd < stream->match_maxfwd)
+    {
+      if ((ret = xd3_getblk (stream, tryblk)))
+	{
+	  /* if search went too far back, continue forward. */
+	  if (ret == XD3_TOOFARBACK)
+	    {
+	      break;
+	    }
+
+	  /* could be a XD3_GETSRCBLK failure. */
+	  return ret;
+	}
+
+      /* There's a good speedup for doing word comparions: see zlib. */
+      for (tryrem = min(stream->match_maxfwd - stream->match_fwd,
+			src->blksize - tryoff);
+	   tryrem != 0;
+	   tryrem -= 1, stream->match_fwd += 1)
+	{
+	  if (src->curblk[tryoff] != stream->next_in[streamoff])
+	    {
+	      goto donefwd;
+	    }
+
+	  tryoff    += 1;
+	  streamoff += 1;
+	}
+
+      if (tryoff == src->blksize)
+	{
+	  tryoff  = 0;
+	  tryblk += 1;
+	}
+    }
+
+ donefwd:
+  stream->match_state = MATCH_SEARCHING;
+
+  /* Now decide whether to take the match.  There are several ways to answer this
+   * question and this is likely the best answer.  There is currently an assertion
+   * in xd3_iopt_erase that checks whether min_match works.  This variable maintains
+   * that every match exceeds the end of the previous match.  However, it is
+   * possible that match_back allows us to find a match that goes a long way back
+   * but not enough forward.  We could try an alternate approach, which might help
+   * or it might just be extra complexity: eliminate the next match_fwd >= min_match
+   * test and call xd3_iopt_erase right away.  Erase instructions as far as it goes
+   * back, then either remember what was deleted and re-insert it, or count on the
+   * string-matching algorithm to find that match again.  I think it is more
+   * worthwhile to implement large_hash duplicates. */
+  if (stream->match_fwd < stream->min_match)
+    {
+      stream->match_fwd = 0;
+    }
+  else
+    {
+      usize_t total  = stream->match_fwd + stream->match_back;
+
+      /* Correct the variables to remove match_back from the equation. */
+      usize_t target_position = stream->input_position - stream->match_back;
+      usize_t match_length   = stream->match_back      + stream->match_fwd;
+      xoff_t match_position  = stream->match_srcpos    - stream->match_back;
+      xoff_t match_end       = stream->match_srcpos    + stream->match_fwd;
+
+      /* At this point we may have to erase any iopt-buffer instructions that are
+       * fully covered by a backward-extending copy. */
+      if (stream->match_back > 0)
+	{
+	  xd3_iopt_erase (stream, target_position, total);
+	}
+
+      stream->match_back = 0;
+
+      /* Update ranges.  The first source match occurs with both values set to 0. */
+      if (stream->match_maxaddr == 0 ||
+	  match_position < stream->match_minaddr)
+	{
+	  stream->match_minaddr = match_position;
+	}
+
+      if (match_end > stream->match_maxaddr)
+	{
+	  /* Note: per-window */
+	  stream->match_maxaddr = match_end;
+	}
+
+      if (match_end > stream->maxsrcaddr)
+	{
+	  /* Note: across windows */
+	  stream->maxsrcaddr = match_end;
+	}
+
+      IF_DEBUG1 ({
+	static int x = 0;
+	DP(RINT "[source match:%d] <inp %"Q"u %"Q"u>  <src %"Q"u %"Q"u> (%s) [ %u bytes ]\n",
+	   x++,
+	   stream->total_in + target_position,
+	   stream->total_in + target_position + match_length,
+	   match_position,
+	   match_position + match_length,
+	   (stream->total_in + target_position == match_position) ? "same" : "diff",
+	   match_length);
+      });
+
+      if ((ret = xd3_found_match (stream,
+				  /* decoder position */ target_position,
+				  /* length */ match_length,
+				  /* address */ match_position,
+				  /* is_source */ 1)))
+	{
+	  return ret;
+	}
+
+      /* If the match ends with the available input: */
+      if (target_position + match_length == stream->avail_in)
+	{
+	  /* Setup continuing match for the next window. */
+	  stream->match_state  = MATCH_TARGET;
+	  stream->match_srcpos = match_end;
+	}
+    }
+
+  return 0;
+}
+
+/* Update the small hash.  Values in the small_table are offset by
+ * HASH_CKOFFSET (1) to distinguish empty buckets from real offsets. */
+static void
+xd3_scksum_insert (xd3_stream *stream,
+		   usize_t inx,
+		   usize_t scksum,
+		   usize_t pos)
+{
+  /* If we are maintaining previous duplicates. */
+  if (stream->small_prev)
+    {
+      usize_t    last_pos = stream->small_table[inx];
+      xd3_slist *pos_list = & stream->small_prev[pos & stream->sprevmask];
+
+      /* Note last_pos is offset by HASH_CKOFFSET. */
+      pos_list->last_pos = last_pos;
+    }
+
+  /* Enter the new position into the hash bucket. */
+  stream->small_table[inx] = pos + HASH_CKOFFSET;
+}
+
+#if XD3_DEBUG
+static int
+xd3_check_smatch (const uint8_t *ref0, const uint8_t *inp0,
+		  const uint8_t *inp_max, usize_t cmp_len)
+{
+  int i;
+
+  for (i = 0; i < cmp_len; i += 1)
+    {
+      XD3_ASSERT (ref0[i] == inp0[i]);
+    }
+
+  if (inp0 + cmp_len < inp_max)
+    {
+      XD3_ASSERT (inp0[i] != ref0[i]);
+    }
+
+  return 1;
+}
+#endif /* XD3_DEBUG */
+
+/* When the hash table indicates a possible small string match, it
+ * calls this routine to find the best match.  The first matching
+ * position is taken from the small_table, HASH_CKOFFSET is subtracted
+ * to get the actual position.  After checking that match, if previous
+ * linked lists are in use (because stream->smatcher.small_chain > 1),
+ * previous matches are tested searching for the longest match.  If
+ * (stream->min_match > MIN_MATCH) then a lazy match is in effect.
+ *
+ * TODO: This is the second most-expensive function, after
+ * xd3_srcwin_move_point().
+ */
+static usize_t
+xd3_smatch (xd3_stream *stream,
+	    usize_t base,
+	    usize_t scksum,
+	    usize_t *match_offset)
+{
+  usize_t         cmp_len;
+  usize_t         match_length = 0;
+  usize_t         chain        = (stream->min_match == MIN_MATCH ?
+				  stream->smatcher.small_chain :
+				  stream->smatcher.small_lchain);
+  const uint8_t *inp_max      = stream->next_in + stream->avail_in;
+  const uint8_t *inp;
+  const uint8_t *ref;
+
+  SMALL_HASH_DEBUG1 (stream, stream->next_in + stream->input_position);
+
+  XD3_ASSERT (stream->min_match + stream->input_position <= stream->avail_in);
+
+  base -= HASH_CKOFFSET;
+
+ again:
+
+  /* For small matches, we can always go to the end-of-input because
+   * the matching position must be less than the input position. */
+  XD3_ASSERT (base < stream->input_position);
+
+  ref = stream->next_in + base;
+  inp = stream->next_in + stream->input_position;
+
+  SMALL_HASH_DEBUG2 (stream, ref);
+
+  /* Expand potential match forward. */
+  while (inp < inp_max && *inp == *ref)
+    {
+      ++inp;
+      ++ref;
+    }
+
+  cmp_len = inp - (stream->next_in + stream->input_position);
+
+  /* Verify correctness */
+  XD3_ASSERT (xd3_check_smatch (stream->next_in + base,
+				stream->next_in + stream->input_position,
+				inp_max, cmp_len));
+
+  /* Update longest match */
+  if (cmp_len > match_length)
+    {
+      ( match_length) = cmp_len;
+      (*match_offset) = base;
+
+      /* Stop if we match the entire input or have a long_enough match. */
+      if (inp == inp_max || cmp_len >= stream->smatcher.long_enough)
+	{
+	  goto done;
+	}
+    }
+
+  /* If we have not reached the chain limit, see if there is another
+     previous position. */
+  while (--chain != 0)
+    {
+      /* Calculate the previous offset. */
+      usize_t last_pos = stream->small_prev[base & stream->sprevmask].last_pos;
+
+      if (last_pos == 0)
+	{
+	  break;
+	}
+
+      last_pos -= HASH_CKOFFSET;
+      base = last_pos;
+
+      /* Stop if the position is wrong (because the lists are not
+       * re-initialized across input windows). */
+      if (base < stream->input_position)
+	{
+	  goto again;
+	}
+
+      break;
+    }
+
+ done:
+  return match_length;
+}
+
+#if XD3_DEBUG
+static void
+xd3_verify_small_state (xd3_stream    *stream,
+			const uint8_t *inp,
+			uint32_t          x_cksum)
+{
+  uint32_t cksum = xd3_scksum (inp, stream->smatcher.small_look);
+
+  XD3_ASSERT (cksum == x_cksum);
+}
+
+static void
+xd3_verify_large_state (xd3_stream    *stream,
+			const uint8_t *inp,
+			uint32_t          x_cksum)
+{
+  uint32_t cksum = xd3_lcksum (inp, stream->smatcher.large_look);
+
+  XD3_ASSERT (cksum == x_cksum);
+}
+
+static void
+xd3_verify_run_state (xd3_stream    *stream,
+		      const uint8_t *inp,
+		      int            x_run_l,
+		      uint8_t        x_run_c)
+{
+  int     slook = stream->smatcher.small_look;
+  uint8_t run_c;
+  int     run_l = xd3_comprun (inp, slook, &run_c);
+
+  XD3_ASSERT (run_l == 0 || run_c == x_run_c);
+  XD3_ASSERT (x_run_l > slook || run_l == x_run_l);
+}
+#endif /* XD3_DEBUG */
+#endif /* XD3_ENCODER */
+
+/******************************************************************************************
+ TEMPLATE pass
+ ******************************************************************************************/
+
+#endif /* __XDELTA3_C_INLINE_PASS__ */
+#ifdef __XDELTA3_C_TEMPLATE_PASS__
+
+#if XD3_ENCODER
+
+/******************************************************************************************
+ Templates
+ ******************************************************************************************/
+
+/* Template macros */
+#define XD3_TEMPLATE(x)      XD3_TEMPLATE2(x,TEMPLATE)
+#define XD3_TEMPLATE2(x,n)   XD3_TEMPLATE3(x,n)
+#define XD3_TEMPLATE3(x,n)   x ## n
+#define XD3_STRINGIFY(x)     XD3_STRINGIFY2(x)
+#define XD3_STRINGIFY2(x)    #x
+
+static int XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream);
+
+static const xd3_smatcher XD3_TEMPLATE(__smatcher_) =
+{
+  XD3_STRINGIFY(TEMPLATE),
+  XD3_TEMPLATE(xd3_string_match_),
+#if SOFTCFG == 1
+  0, 0, 0, 0, 0, 0, 0
+#else
+  LLOOK, LSTEP, SLOOK, SCHAIN, SLCHAIN, MAXLAZY, LONGENOUGH
+#endif
+};
+
+static int
+XD3_TEMPLATE(xd3_string_match_) (xd3_stream *stream)
+{
+  /* TODO config: These next three variables should be statically compliled in various
+   * scan_cfg configurations? */
+  const int      DO_SMALL = ! (stream->flags & XD3_NOCOMPRESS);
+  const int      DO_LARGE = (stream->src != NULL);
+  const int      DO_RUN   = (1);
+
+  const uint8_t *inp;
+  uint32_t       scksum = 0;
+  uint32_t       lcksum = 0;
+  usize_t         sinx;
+  usize_t         linx;
+  uint8_t        run_c;
+  int            run_l;
+  int            ret;
+  usize_t         match_length;
+  usize_t         match_offset;  /* "may be unused" warnings are bogus (due to min_match test) */
+  usize_t         next_move_point;
+
+  /* If there will be no compression due to settings or short input, skip it entirely. */
+  if (! (DO_SMALL || DO_LARGE || DO_RUN) ||
+      stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; }
+
+  if ((ret = xd3_string_match_init (stream))) { return ret; }
+
+  /* The restartloop label is reached when the incremental loop state needs to be
+   * reset. */
+ restartloop:
+
+  /* If there is not enough input remaining for any kind of match, skip it. */
+  if (stream->input_position + SLOOK > stream->avail_in) { goto loopnomore; }
+
+  /* Now reset the incremental loop state: */
+
+  /* The min_match variable is updated to avoid matching the same lazy match over and over
+   * again.  For example, if you find a (small) match of length 9 at one position, you
+   * will likely find a match of length 8 at the next position. */
+  stream->min_match = MIN_MATCH;
+
+  /* The current input byte. */
+  inp = stream->next_in + stream->input_position;
+
+  /* Small match state. */
+  if (DO_SMALL)
+    {
+      scksum = xd3_scksum (inp, SLOOK);
+    }
+
+  /* Run state. */
+  if (DO_RUN)
+    {
+      run_l = xd3_comprun (inp, SLOOK, & run_c);
+    }
+
+  /* Large match state.  We continue the loop even after not enough bytes for LLOOK
+   * remain, so always check stream->input_position in DO_LARGE code. */
+  if (DO_LARGE && (stream->input_position + LLOOK <= stream->avail_in))
+    {
+      /* Source window: next_move_point is the point that stream->input_position must reach before
+       * computing more source checksum. */
+      if ((ret = xd3_srcwin_move_point (stream, & next_move_point)))
+	{
+	  return ret;
+	}
+
+      lcksum = xd3_lcksum (inp, LLOOK);
+    }
+
+  /* TRYLAZYLEN: True if a certain length match should be followed by lazy search.  This
+   * checks that LEN is shorter than MAXLAZY and that there is enough leftover data to
+   * consider lazy matching.  "Enough" is set to 2 since the next match will start at the
+   * next offset, it must match two extra characters. */
+#define TRYLAZYLEN(LEN,POS,MAX) ((MAXLAZY) > 0 && (LEN) < (MAXLAZY) && (POS) + (LEN) <= (MAX) - 2)
+
+  /* HANDLELAZY: This statement is called each time an instruciton is emitted (three
+   * cases).  If the instruction is large enough, the loop is restarted, otherwise lazy
+   * matching may ensue. */
+#define HANDLELAZY(mlen) \
+  if (TRYLAZYLEN ((mlen), (stream->input_position), (stream->avail_in))) \
+    { stream->min_match = (mlen) + LEAST_MATCH_INCR; goto updateone; } \
+  else \
+    { stream->input_position += (mlen); goto restartloop; }
+
+  /* Now loop over one input byte at a time until a match is found... */
+  for (;; inp += 1, stream->input_position += 1)
+    {
+      /* Now we try three kinds of string match in order of expense:
+       * run, large match, small match. */
+
+      /* Expand the start of a RUN.  The test for (run_l == SLOOK) avoids repeating this
+       * check when we pass through a run area performing lazy matching.  The run is only
+       * expanded once when the min_match is first reached.  If lazy matching is
+       * performed, the run_l variable will remain inconsistent until the first
+       * non-running input character is reached, at which time the run_l may then again
+       * grow to SLOOK. */
+      if (DO_RUN && run_l == SLOOK)
+	{
+	  usize_t max_len = stream->avail_in - stream->input_position;
+
+	  IF_DEBUG (xd3_verify_run_state (stream, inp, run_l, run_c));
+
+	  while (run_l < max_len && inp[run_l] == run_c) { run_l += 1; }
+
+	  /* Output a RUN instruction. */
+	  if (run_l >= stream->min_match && run_l >= MIN_RUN)
+	    {
+	      if ((ret = xd3_emit_run (stream, stream->input_position, run_l, run_c))) { return ret; }
+
+	      HANDLELAZY (run_l);
+	    }
+	}
+
+      /* If there is enough input remaining. */
+      if (DO_LARGE && (stream->input_position + LLOOK <= stream->avail_in))
+	{
+	  if ((stream->input_position >= next_move_point) &&
+	      (ret = xd3_srcwin_move_point (stream, & next_move_point)))
+	    {
+	      return ret;
+	    }
+
+	  linx = xd3_checksum_hash (& stream->large_hash, lcksum);
+
+	  IF_DEBUG (xd3_verify_large_state (stream, inp, lcksum));
+
+	  /* Note: To handle large checksum duplicates, this code should be rearranged to
+	   * resemble the small_match case more.  But how much of the code can be truly
+	   * shared?  The main difference is the need for xd3_source_extend_match to work
+	   * outside of xd3_string_match, in the case where inputs are identical. */
+	  if (unlikely (stream->large_table[linx] != 0))
+	    {
+	      /* the match_setup will fail if the source window has been decided and the
+	       * match lies outside it.  You could consider forcing a window at this point
+	       * to permit a new source window. */
+	      xoff_t adj_offset =
+		xd3_source_cksum_offset(stream,
+					stream->large_table[linx] - HASH_CKOFFSET);
+	      if (xd3_source_match_setup (stream, adj_offset) == 0)
+		{
+		  if ((ret = xd3_source_extend_match (stream)))
+		    {
+		      return ret;
+		    }
+
+		  /* Update stream position.  match_fwd is zero if no match. */
+		  if (stream->match_fwd > 0)
+		    {
+		      HANDLELAZY (stream->match_fwd);
+		    }
+		}
+	    }
+	}
+
+      /* Small matches. */
+      if (DO_SMALL)
+	{
+	  sinx = xd3_checksum_hash (& stream->small_hash, scksum);
+
+	  /* Verify incremental state in debugging mode. */
+	  IF_DEBUG (xd3_verify_small_state (stream, inp, scksum));
+
+	  /* Search for the longest match */
+	  if (unlikely (stream->small_table[sinx] != 0))
+	    {
+	      match_length = xd3_smatch (stream,
+					 stream->small_table[sinx],
+					 scksum,
+					 & match_offset);
+	    }
+	  else
+	    {
+	      match_length = 0;
+	    }
+
+	  /* Insert a hash for this string. */
+	  xd3_scksum_insert (stream, sinx, scksum, stream->input_position);
+
+	  /* Maybe output a COPY instruction */
+	  if (unlikely (match_length >= stream->min_match))
+	    {
+	      IF_DEBUG1 ({
+		static int x = 0;
+		DP(RINT "[target match:%d] <inp %u %u>  <cpy %u %u> (-%d) [ %u bytes ]\n",
+		   x++,
+		   stream->input_position,
+		   stream->input_position + match_length,
+		   match_offset,
+		   match_offset + match_length,
+		   stream->input_position - match_offset,
+		   match_length);
+	      });
+
+	      if ((ret = xd3_found_match (stream,
+					/* decoder position */ stream->input_position,
+					/* length */ match_length,
+					/* address */ match_offset,
+					/* is_source */ 0))) { return ret; }
+
+	      /* Copy instruction. */
+	      HANDLELAZY (match_length);
+	    }
+	}
+
+      /* The logic above prevents excess work during lazy matching by increasing min_match
+       * to avoid smaller matches.  Each time we advance stream->input_position by one, the minimum match
+       * shortens as well.  */
+      if (stream->min_match > MIN_MATCH)
+	{
+	  stream->min_match -= 1;
+	}
+
+    updateone:
+
+      /* See if there are no more incremental cksums to compute. */
+      if (stream->input_position + SLOOK == stream->avail_in)
+	{
+	  goto loopnomore;
+	}
+
+      /* Compute next RUN, CKSUM */
+      if (DO_RUN)   { NEXTRUN (inp[SLOOK]); }
+      if (DO_SMALL) { SMALL_CKSUM_UPDATE (scksum, inp, SLOOK); }
+      if (DO_LARGE && (stream->input_position + LLOOK < stream->avail_in)) { LARGE_CKSUM_UPDATE (lcksum, inp, LLOOK); }
+    }
+
+ loopnomore:
+  return 0;
+}
+#endif /* XD3_ENCODER */
+#endif /* __XDELTA3_C_TEMPLATE_PASS__ */
Index: /nikanabo/current/xdelta/diy/xdelta3.h
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3.h	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3.h	(revision 185)
@@ -0,0 +1,1055 @@
+/* xdelta 3 - delta compression tools and library
+ * Copyright (C) 2001, 2003, 2004, 2005, 2006.  Joshua P. MacDonald
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Welcome to Xdelta.  If you want to know more about Xdelta, start by reading xdelta3.c.
+ * If you are ready to use the API, continue reading here.  There are two interfaces --
+ * xd3_encode_input and xd3_decode_input -- plus a dozen or so related calls.  This
+ * interface is styled after Zlib. */
+
+#ifndef _XDELTA3_H_
+#define _XDELTA3_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+/**********************************************************************/
+
+/* Default configured value of stream->winsize.  If the program supplies
+ * xd3_encode_input() with data smaller than winsize the stream will
+ * automatically buffer the input, otherwise the input buffer is used directly.
+ */
+#ifndef XD3_DEFAULT_WINSIZE
+#define XD3_DEFAULT_WINSIZE (1U << 23)
+#endif
+
+/* Default total size of the source window used in xdelta3-main.h */
+#ifndef XD3_DEFAULT_SRCWINSZ
+#define XD3_DEFAULT_SRCWINSZ (1U << 26)
+#endif
+
+/* When Xdelta requests a memory allocation for certain buffers, it rounds up to units of
+ * at least this size.  The code assumes (and asserts) that this is a power-of-two. */
+#ifndef XD3_ALLOCSIZE
+#define XD3_ALLOCSIZE (1U<<14)
+#endif
+
+/* The XD3_HARDMAXWINSIZE parameter is a safety mechanism to protect decoders against
+ * malicious files.  The decoder will never decode a window larger than this.  If the file
+ * specifies VCD_TARGET the decoder may require two buffers of this size.
+ *
+ * 8-16MB is reasonable, probably don't need to go larger. */
+#ifndef XD3_HARDMAXWINSIZE
+#define XD3_HARDMAXWINSIZE (1U<<24)
+#endif
+
+/* The XD3_NODECOMPRESSSIZE parameter tells the xdelta main routine not to try to
+ * externally-decompress source inputs that are too large.  Since these files must be
+ * seekable, they are decompressed to a temporary file location and the user may not wish
+ * for this. */
+#ifndef XD3_NODECOMPRESSSIZE
+#define XD3_NODECOMPRESSSIZE (1U<<28)
+#endif
+
+/* The IOPT_SIZE value sets the size of a buffer used to batch overlapping copy
+ * instructions before they are optimized by picking the best non-overlapping ranges.  The
+ * larger this buffer, the longer a forced xd3_srcwin_setup() decision is held off.
+ * Setting this value to 0 causes an unlimited buffer to be used. */
+#ifndef XD3_DEFAULT_IOPT_SIZE
+#define XD3_DEFAULT_IOPT_SIZE    (1U<<15)
+#endif
+
+/* The maximum distance backward to search for small matches */
+#ifndef XD3_DEFAULT_SPREVSZ
+#define XD3_DEFAULT_SPREVSZ (1U<<18)
+#endif
+
+/* The default compression level
+ */
+#ifndef XD3_DEFAULT_LEVEL
+#define XD3_DEFAULT_LEVEL 1
+#endif
+
+/* Sizes and addresses within VCDIFF windows are represented as usize_t
+ *
+ * For source-file offsets and total file sizes, total input and output counts, the xoff_t
+ * type is used.  The decoder and encoder generally check for overflow of the xoff_t size,
+ * and this is tested at the 32bit boundary [xdelta3-test.h].
+ */
+#ifndef _WIN32
+typedef unsigned int    usize_t;
+typedef u_int8_t        uint8_t;
+typedef u_int16_t       uint16_t;
+
+#ifndef __uint32_t_defined  /* Note: Cygwin compat */
+typedef u_int32_t       uint32_t;
+#endif
+
+typedef u_int64_t       uint64_t;
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#define inline
+typedef unsigned int   uint;
+typedef signed int     ssize_t;
+typedef unsigned int   usize_t;
+typedef unsigned char  uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long  uint32_t;
+typedef ULONGLONG      uint64_t;
+#endif
+
+#define SIZEOF_USIZE_T 4
+
+#ifndef XD3_USE_LARGEFILE64
+#define XD3_USE_LARGEFILE64 1
+#endif
+
+#if XD3_USE_LARGEFILE64
+#define __USE_FILE_OFFSET64 1 /* GLIBC: for 64bit fileops, ... ? */
+typedef uint64_t xoff_t;
+#define SIZEOF_XOFF_T 8
+#else
+typedef uint32_t xoff_t;
+#define SIZEOF_XOFF_T 4
+#endif
+
+#define USE_UINT32 (SIZEOF_USIZE_T == 4 || SIZEOF_XOFF_T == 4 || REGRESSION_TEST)
+#define USE_UINT64 (SIZEOF_USIZE_T == 8 || SIZEOF_XOFF_T == 8 || REGRESSION_TEST)
+
+/**********************************************************************/
+
+#ifndef INLINE
+#define INLINE inline
+#endif
+
+/* Whether to build the encoder, otherwise only build the decoder. */
+#ifndef XD3_ENCODER
+#define XD3_ENCODER 1
+#endif
+
+/* The code returned when main() fails, also defined in system includes. */
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* REGRESSION TEST enables the "xdelta3 test" command, which runs a series of self-tests. */
+#ifndef REGRESSION_TEST
+#define REGRESSION_TEST 0
+#endif
+
+/* XD3_DEBUG=1 enables assertions and various statistics.  Levels > 1 enable some
+ * additional output only useful during development and debugging. */
+#ifndef XD3_DEBUG
+#define XD3_DEBUG 0
+#endif
+
+#ifndef PYTHON_MODULE
+#define PYTHON_MODULE 0
+#endif
+
+#ifndef SWIG_MODULE
+#define SWIG_MODULE 0
+#endif
+
+/* There are three string matching functions supplied: one fast, one slow (default), and
+ * one soft-configurable.  To disable any of these, use the following definitions. */
+#ifndef XD3_BUILD_SLOW
+#define XD3_BUILD_SLOW 1
+#endif
+#ifndef XD3_BUILD_FAST
+#define XD3_BUILD_FAST 1
+#endif
+#ifndef XD3_BUILD_FASTEST
+#define XD3_BUILD_FASTEST 1
+#endif
+#ifndef XD3_BUILD_SOFT
+#define XD3_BUILD_SOFT 1
+#endif
+#ifndef XD3_BUILD_DEFAULT
+#define XD3_BUILD_DEFAULT 1
+#endif
+
+#if XD3_DEBUG
+#include <stdio.h>
+#endif
+
+/* XPRINT.  Debug output and VCDIFF_TOOLS functions report to stderr.  I have used an
+ * irregular style to abbreviate [fprintf(stderr, "] as [DP(RINT "]. */
+#define DP   fprintf
+#define RINT stderr,
+
+typedef struct _xd3_stream             xd3_stream;
+typedef struct _xd3_source             xd3_source;
+typedef struct _xd3_hash_cfg           xd3_hash_cfg;
+typedef struct _xd3_smatcher           xd3_smatcher;
+typedef struct _xd3_rinst              xd3_rinst;
+typedef struct _xd3_dinst              xd3_dinst;
+typedef struct _xd3_hinst              xd3_hinst;
+typedef struct _xd3_rpage              xd3_rpage;
+typedef struct _xd3_addr_cache         xd3_addr_cache;
+typedef struct _xd3_output             xd3_output;
+typedef struct _xd3_desect             xd3_desect;
+typedef struct _xd3_iopt_buflist       xd3_iopt_buflist;
+typedef struct _xd3_rlist              xd3_rlist;
+typedef struct _xd3_sec_type           xd3_sec_type;
+typedef struct _xd3_sec_cfg            xd3_sec_cfg;
+typedef struct _xd3_sec_stream         xd3_sec_stream;
+typedef struct _xd3_config             xd3_config;
+typedef struct _xd3_code_table_desc    xd3_code_table_desc;
+typedef struct _xd3_code_table_sizes   xd3_code_table_sizes;
+typedef struct _xd3_slist              xd3_slist;
+
+/* The stream configuration has three callbacks functions, all of which may be supplied
+ * with NULL values.  If config->getblk is provided as NULL, the stream returns
+ * XD3_GETSRCBLK. */
+
+typedef void*  (xd3_alloc_func)    (void       *opaque,
+				    usize_t      items,
+				    usize_t      size);
+typedef void   (xd3_free_func)     (void       *opaque,
+				    void       *address);
+
+typedef int    (xd3_getblk_func)   (xd3_stream *stream,
+				    xd3_source *source,
+				    xoff_t      blkno);
+
+/* These are internal functions to delay construction of encoding tables and support
+ * alternate code tables.  See the comments & code enabled by GENERIC_ENCODE_TABLES. */
+
+typedef const xd3_dinst* (xd3_code_table_func) (void);
+typedef int              (xd3_comp_table_func) (xd3_stream *stream,
+						const uint8_t **data,
+						usize_t *size);
+
+
+/* Some junk. */
+
+#ifndef XD3_ASSERT
+#if XD3_DEBUG
+#define XD3_ASSERT(x) \
+    do { if (! (x)) { DP(RINT "%s:%d: XD3 assertion failed: %s\n", __FILE__, __LINE__, #x); \
+    abort (); } } while (0)
+#else
+#define XD3_ASSERT(x) (void)0
+#endif
+#endif
+
+#ifdef __GNUC__
+/* As seen on linux-kernel. */
+#ifndef max
+#define max(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x > _y ? _x : _y; })
+#endif
+
+#ifndef min
+#define min(x,y) ({ \
+	const typeof(x) _x = (x);	\
+	const typeof(y) _y = (y);	\
+	(void) (&_x == &_y);		\
+	_x < _y ? _x : _y; })
+#endif
+#else
+#ifndef max
+#define max(x,y) ((x) < (y) ? (y) : (x))
+#endif
+#ifndef min
+#define min(x,y) ((x) < (y) ? (x) : (y))
+#endif
+#endif
+
+/******************************************************************************************
+ PUBLIC ENUMS
+ ******************************************************************************************/
+
+/* These are the five ordinary status codes returned by the xd3_encode_input() and
+ * xd3_decode_input() state machines. */
+typedef enum {
+
+  /* An application must be prepared to handle these five return values from either
+   * xd3_encode_input or xd3_decode_input, except in the case of no-source compression, in
+   * which case XD3_GETSRCBLK is never returned.  More detailed comments for these are
+   * given in xd3_encode_input and xd3_decode_input comments, below. */
+  XD3_INPUT     = -17703, /* need input */
+  XD3_OUTPUT    = -17704, /* have output */
+  XD3_GETSRCBLK = -17705, /* need a block of source input (with no xd3_getblk function),
+			   * a chance to do non-blocking read. */
+  XD3_GOTHEADER = -17706, /* (decode-only) after the initial VCDIFF & first window header */
+  XD3_WINSTART  = -17707, /* notification: returned before a window is processed, giving a
+			   * chance to XD3_SKIP_WINDOW or not XD3_SKIP_EMIT that window. */
+  XD3_WINFINISH  = -17708, /* notification: returned after encode/decode & output for a window */
+  XD3_TOOFARBACK = -17709, /* (encoder only) may be returned by getblk() if the block is too old */
+  XD3_INTERNAL   = -17710, /* internal error */
+  XD3_INVALID    = -17711, /* invalid config */
+  XD3_INVALID_INPUT = -17712, /* invalid input/decoder error */
+
+} xd3_rvalues;
+
+/* special values in config->flags */
+typedef enum
+{
+  XD3_JUST_HDR       = (1 << 1),   /* used by VCDIFF tools, see xdelta3-main.h. */
+  XD3_SKIP_WINDOW    = (1 << 2),   /* used by VCDIFF tools, see xdelta3-main.h. */
+  XD3_SKIP_EMIT      = (1 << 3),   /* used by VCDIFF tools, see xdelta3-main.h. */
+  XD3_FLUSH          = (1 << 4),   /* flush the stream buffer to prepare for xd3_stream_close(). */
+
+  XD3_SEC_DJW        = (1 << 5),   /* use DJW static huffman */
+  XD3_SEC_FGK        = (1 << 6),   /* use FGK adaptive huffman */
+  XD3_SEC_TYPE       = (XD3_SEC_DJW | XD3_SEC_FGK),
+
+  XD3_SEC_NODATA     = (1 << 7),   /* disable secondary compression of the data section. */
+  XD3_SEC_NOINST     = (1 << 8),   /* disable secondary compression of the inst section. */
+  XD3_SEC_NOADDR     = (1 << 9),   /* disable secondary compression of the addr section. */
+
+  XD3_SEC_OTHER      = (XD3_SEC_NODATA | XD3_SEC_NOINST | XD3_SEC_NOADDR),
+
+  XD3_ADLER32        = (1 << 10),  /* enable checksum computation in the encoder. */
+  XD3_ADLER32_NOVER  = (1 << 11),  /* disable checksum verification in the decoder. */
+
+  XD3_ALT_CODE_TABLE = (1 << 12),  /* for testing the alternate code table encoding. */
+
+  XD3_NOCOMPRESS     = (1 << 13),  /* disable ordinary data compression feature,
+				    * only search the source, not the target. */
+  XD3_BEGREEDY       = (1 << 14),  /* disable the "1.5-pass algorithm", instead use
+				    * greedy matching.  Greedy is off by default. */
+
+  /* 4 bits to set the compression level the same as the command-line
+   * setting -1 through -9 (-0 corresponds to the XD3_NOCOMPRESS flag,
+   * and is independent of compression level).  This is for
+   * convenience, especially with xd3_encode_memory(). */
+
+  XD3_COMPLEVEL_SHIFT = 20,  /* 20 - 24 */
+  XD3_COMPLEVEL_MASK = (0xF << XD3_COMPLEVEL_SHIFT),
+  XD3_COMPLEVEL_1 = (1 << XD3_COMPLEVEL_SHIFT),
+  XD3_COMPLEVEL_3 = (3 << XD3_COMPLEVEL_SHIFT),
+  XD3_COMPLEVEL_6 = (6 << XD3_COMPLEVEL_SHIFT),
+  XD3_COMPLEVEL_9 = (9 << XD3_COMPLEVEL_SHIFT),
+
+} xd3_flags;
+
+/* The values of this enumeration are set in xd3_config using the
+ * smatch_cfg variable.  It can be set to default, slow, fast, etc.,
+ * and soft. */
+typedef enum
+{
+  XD3_SMATCH_DEFAULT = 0, /* Flags may contain XD3_COMPLEVEL bits, else default. */
+  XD3_SMATCH_SLOW    = 1,
+  XD3_SMATCH_FAST    = 2,
+  XD3_SMATCH_FASTEST = 3,
+  XD3_SMATCH_SOFT    = 4,
+} xd3_smatch_cfg;
+
+/******************************************************************************************
+ PRIVATE ENUMS
+ ******************************************************************************************/
+
+/* stream->match_state is part of the xd3_encode_input state machine for source matching:
+ *
+ *  1. the XD3_GETSRCBLK block-read mechanism means reentrant matching
+ *  2. this state spans encoder windows: a match and end-of-window will continue in the next
+ *  3. the initial target byte and source byte are a presumed match, to avoid some computation
+ *  in case the inputs are identical.
+ */
+typedef enum {
+
+  MATCH_TARGET    = 0, /* in this state, attempt to match the start of the target with the
+			* previously set source address (initially 0). */
+  MATCH_BACKWARD  = 1, /* currently expanding a match backward in the source/target. */
+  MATCH_FORWARD   = 2, /* currently expanding a match forward in the source/target. */
+  MATCH_SEARCHING = 3, /* currently searching for a match. */
+
+} xd3_match_state;
+
+/* The xd3_encode_input state machine steps through these states in the following order.
+ * The matcher is reentrant and returns XD3_INPUT whenever it requires more data.  After
+ * receiving XD3_INPUT, if the application reads EOF it should call xd3_stream_close().
+ */
+typedef enum {
+
+  ENC_INIT      = 0, /* xd3_encode_input has never been called. */
+  ENC_INPUT     = 1, /* waiting for xd3_avail_input () to be called. */
+  ENC_SEARCH    = 2, /* currently searching for matches. */
+  ENC_FLUSH     = 3, /* currently emitting output. */
+  ENC_POSTOUT   = 4, /* after an output section. */
+  ENC_POSTWIN   = 5, /* after all output sections. */
+  ENC_ABORTED   = 6, /* abort. */
+} xd3_encode_state;
+
+/* The xd3_decode_input state machine steps through these states in the following order.
+ * The matcher is reentrant and returns XD3_INPUT whenever it requires more data.  After
+ * receiving XD3_INPUT, if the application reads EOF it should call xd3_stream_close().
+ *
+ * 0-8:   the VCDIFF header
+ * 9-18:  the VCDIFF window header
+ * 19-21: the three primary sections: data (which I think should have gone last), inst, addr
+ * 22:    producing output: returns XD3_OUTPUT, possibly XD3_GETSRCBLK,
+ * 23:    return XD3_WINFINISH, set state=9 to decode more input
+ */
+typedef enum {
+
+  DEC_VCHEAD   = 0, /* VCDIFF header */
+  DEC_HDRIND   = 1, /* header indicator */
+
+  DEC_SECONDID = 2, /* secondary compressor ID */
+
+  DEC_TABLEN   = 3, /* code table length */
+  DEC_NEAR     = 4, /* code table near */
+  DEC_SAME     = 5, /* code table same */
+  DEC_TABDAT   = 6, /* code table data */
+
+  DEC_APPLEN   = 7, /* application data length */
+  DEC_APPDAT   = 8, /* application data */
+
+  DEC_WININD   = 9, /* window indicator */
+
+  DEC_CPYLEN   = 10, /* copy window length */
+  DEC_CPYOFF   = 11, /* copy window offset */
+
+  DEC_ENCLEN   = 12, /* length of delta encoding */
+  DEC_TGTLEN   = 13, /* length of target window */
+  DEC_DELIND   = 14, /* delta indicator */
+
+  DEC_DATALEN  = 15, /* length of ADD+RUN data */
+  DEC_INSTLEN  = 16, /* length of instruction data */
+  DEC_ADDRLEN  = 17, /* length of address data */
+
+  DEC_CKSUM    = 18, /* window checksum */
+
+  DEC_DATA     = 19, /* data section */
+  DEC_INST     = 20, /* instruction section */
+  DEC_ADDR     = 21, /* address section */
+
+  DEC_EMIT     = 22, /* producing data */
+
+  DEC_FINISH   = 23, /* window finished */
+
+  DEC_ABORTED  = 24, /* xd3_abort_stream */
+} xd3_decode_state;
+
+/* An application never sees these internal codes: */  
+typedef enum {
+  XD3_NOSECOND  = -17708, /* when secondary compression finds no improvement. */
+} xd3_pvalues;
+
+/******************************************************************************************
+ internal types
+ ******************************************************************************************/
+
+/* instruction lists used in the IOPT buffer */
+struct _xd3_rlist
+{
+  xd3_rlist  *next;
+  xd3_rlist  *prev;
+};
+
+/* the raw encoding of an instruction used in the IOPT buffer */
+struct _xd3_rinst
+{
+  uint8_t     type;
+  uint8_t     xtra;
+  uint8_t     code1;
+  uint8_t     code2;
+  usize_t      pos;
+  usize_t      size;
+  xoff_t      addr;
+  xd3_rlist   link;
+};
+
+/* the code-table form of an single- or double-instruction */
+struct _xd3_dinst
+{
+  uint8_t     type1;
+  uint8_t     size1;
+  uint8_t     type2;
+  uint8_t     size2;
+};
+
+/* the decoded form of a single (half) instruction. */
+struct _xd3_hinst
+{
+  uint8_t     type;
+  uint32_t    size;
+  uint32_t    addr;
+};
+
+/* used by the encoder to buffer output in sections.  list of blocks. */
+struct _xd3_output
+{
+  uint8_t    *base;
+  usize_t      next;
+  usize_t      avail;
+  xd3_output *next_page;
+};
+
+/* the VCDIFF address cache, see the RFC */
+struct _xd3_addr_cache
+{
+  uint     s_near;
+  uint     s_same;
+  usize_t  next_slot;  /* the circular index for near */
+  usize_t *near_array; /* array of size s_near        */
+  usize_t *same_array; /* array of size s_same*256    */
+};
+
+/* the IOPT buffer list is just a list of buffers, which may be allocated
+ * during encode when using an unlimited buffer. */
+struct _xd3_iopt_buflist
+{
+  xd3_rinst *buffer;
+  xd3_iopt_buflist *next;
+};
+
+/* This is the record of a pre-compiled configuration, a subset of xd3_config. */
+struct _xd3_smatcher
+{
+  const char        *name;
+  int             (*string_match) (xd3_stream  *stream);
+  uint               large_look;
+  uint               large_step;
+  uint               small_look;
+  uint               small_chain;
+  uint               small_lchain;
+  uint               max_lazy;
+  uint               long_enough;
+};
+
+/* hash table size & power-of-two hash function. */
+struct _xd3_hash_cfg
+{
+  usize_t           size;
+  usize_t           shift;
+  usize_t           mask;
+};
+
+/* the sprev list */
+struct _xd3_slist
+{
+  usize_t     last_pos;
+};
+
+/* a decoder section (data, inst, or addr).  there is an optimization to avoid copying
+ * these sections if all the input is available, related to the copied field below.
+ * secondation compression uses the copied2 field. */
+struct _xd3_desect
+{
+  const uint8_t *buf;
+  const uint8_t *buf_max;
+  uint32_t       size;
+  usize_t        pos;
+  uint8_t       *copied1;
+  usize_t        alloc1;
+  uint8_t       *copied2;
+  usize_t        alloc2;
+};
+
+/******************************************************************************************
+ public types
+ ******************************************************************************************/
+
+/* Settings for the secondary compressor. */
+struct _xd3_sec_cfg
+{
+  int                data_type;     /* Which section. (set automatically) */
+  int                ngroups;       /* Number of DJW Huffman groups. */
+  int                sector_size;   /* Sector size. */
+  int                inefficient;   /* If true, ignore efficiency check [avoid XD3_NOSECOND]. */
+};
+
+/* This is the user-visible stream configuration. */
+struct _xd3_config
+{
+  usize_t             winsize;       /* The encoder window size. */
+  usize_t             sprevsz;       /* How far back small string matching goes */
+  usize_t             iopt_size;     /* entries in the instruction-optimizing buffer */
+  usize_t             srcwin_maxsz;  /* srcwin_size grows by a factor of 2 when no matches are found */
+
+  xd3_getblk_func   *getblk;        /* The three callbacks. */
+  xd3_alloc_func    *alloc;
+  xd3_free_func     *freef;
+  void              *opaque;        /* Not used. */
+  int                flags;         /* stream->flags are initialized from xd3_config &
+				     * never modified by the library.  Use xd3_set_flags
+				     * to modify flags settings mid-stream. */
+
+  xd3_sec_cfg       sec_data;       /* Secondary compressor config: data */
+  xd3_sec_cfg       sec_inst;       /* Secondary compressor config: inst */
+  xd3_sec_cfg       sec_addr;       /* Secondary compressor config: addr */
+
+  xd3_smatch_cfg     smatch_cfg;    /* See enum: use fields below for soft config */
+  xd3_smatcher       smatcher_soft;
+};
+
+/* The primary source file object. You create one of these objects and initialize the
+ * first four fields.  This library maintains the next 5 fields.  The configured getblk
+ * implementation is responsible for setting the final 3 fields when called (and/or when
+ * XD3_GETSRCBLK is returned).
+ */
+struct _xd3_source
+{
+  /* you set */
+  xoff_t              size;          /* size of this source */
+  usize_t             blksize;       /* block size */
+  const char         *name;          /* its name, for debug/print purposes */
+  void               *ioh;           /* opaque handle */
+
+  /* getblk sets */
+  xoff_t              curblkno;      /* current block number: client sets after getblk request */
+  usize_t             onblk;         /* number of bytes on current block: client sets, xd3 verifies */
+  const uint8_t      *curblk;        /* current block array: client sets after getblk request */
+
+  /* xd3 sets */
+  usize_t             srclen;        /* length of this source window */
+  xoff_t              srcbase;       /* offset of this source window in the source itself */
+  xoff_t              blocks;        /* the total number of blocks in this source */
+  usize_t             cpyoff_blocks; /* offset of copy window in blocks */
+  usize_t             cpyoff_blkoff; /* offset of copy window in blocks, remainder */
+  xoff_t              getblkno;      /* request block number: xd3 sets current getblk request */
+};
+
+/* The primary xd3_stream object, used for encoding and decoding.  You may access only two
+ * fields: avail_out, next_out.  Use the methods above to operate on xd3_stream. */
+struct _xd3_stream
+{
+  /* input state */
+  const uint8_t    *next_in;          /* next input byte */
+  usize_t           avail_in;         /* number of bytes available at next_in */
+  xoff_t            total_in;         /* how many bytes in */
+
+  /* output state */
+  uint8_t          *next_out;         /* next output byte */
+  usize_t           avail_out;        /* number of bytes available at next_out */
+  usize_t           space_out;        /* total out space */
+  xoff_t            current_window;   /* number of windows encoded/decoded */
+  xoff_t            total_out;        /* how many bytes out */
+
+  /* to indicate an error, xd3 sets */
+  const char       *msg;              /* last error message, NULL if no error */
+
+  /* source configuration */
+  xd3_source       *src;              /* source array */
+
+  /* encoder memory configuration */
+  usize_t           winsize;          /* suggested window size */
+  usize_t           sprevsz;          /* small string, previous window size (power of 2) */
+  usize_t           sprevmask;        /* small string, previous window size mask */
+  uint              iopt_size;
+  uint              iopt_unlimited;
+  uint              srcwin_maxsz;
+
+  /* general configuration */
+  xd3_getblk_func  *getblk;           /* set nxtblk, nxtblkno to scanblkno */
+  xd3_alloc_func   *alloc;            /* malloc function */
+  xd3_free_func    *free;             /* free function */
+  void*             opaque;           /* private data object passed to alloc, free, and getblk */
+  int               flags;            /* various options */
+  
+  /* secondary compressor configuration */
+  xd3_sec_cfg       sec_data;         /* Secondary compressor config: data */
+  xd3_sec_cfg       sec_inst;         /* Secondary compressor config: inst */
+  xd3_sec_cfg       sec_addr;         /* Secondary compressor config: addr */
+
+  xd3_smatcher      smatcher;
+
+  usize_t           *large_table;      /* table of large checksums */
+  xd3_hash_cfg       large_hash;       /* large hash config */
+
+  usize_t           *small_table;      /* table of small checksums */
+  xd3_slist         *small_prev;       /* table of previous offsets, circular linked list */
+  int                small_reset;      /* true if small table should be reset */
+
+  xd3_hash_cfg       small_hash;       /* small hash config */
+  xd3_addr_cache     acache;           /* the vcdiff address cache */
+  xd3_encode_state   enc_state;        /* state of the encoder */
+
+  usize_t            taroff;           /* base offset of the target input */
+  usize_t            input_position;   /* current input position */
+  usize_t            min_match;        /* current minimum match length, avoids redundent matches */
+  usize_t            unencoded_offset; /* current input, first unencoded offset. this value is <= the first
+				       * instruction's position in the iopt buffer, if there is at least one
+				       * match in the buffer. */
+
+  // SRCWIN
+  // these variables plus srcwin_maxsz above (set by config)
+  int                srcwin_decided;    /* boolean: true if the srclen,srcbase have been decided. */
+  xoff_t             srcwin_cksum_pos;  /* Source checksum position */
+
+  // MATCH
+  xd3_match_state    match_state;      /* encoder match state */
+  xoff_t             match_srcpos;     /* current match source position relative to srcbase */
+  xoff_t             match_minaddr;    /* smallest matching address to set window params
+				       * (reset each window xd3_encode_reset) */
+  xoff_t             match_maxaddr;    /* largest matching address to set window params
+				       * (reset each window xd3_encode_reset) */
+  usize_t            match_back;       /* match extends back so far */
+  usize_t            match_maxback;    /* match extends back maximum */
+  usize_t            match_fwd;        /* match extends forward so far */
+  usize_t            match_maxfwd;     /* match extends forward maximum */
+
+  xoff_t             maxsrcaddr;      /* address of the last source match (across windows) */
+
+  uint8_t          *buf_in;           /* for saving buffered input */
+  usize_t            buf_avail;        /* amount of saved input */
+  const uint8_t    *buf_leftover;     /* leftover content of next_in (i.e., user's buffer) */
+  usize_t            buf_leftavail;    /* amount of leftover content */
+
+  xd3_output       *enc_current;      /* current output buffer */
+  xd3_output       *enc_free;         /* free output buffers */
+  xd3_output       *enc_heads[4];     /* array of encoded outputs: head of chain */
+  xd3_output       *enc_tails[4];     /* array of encoded outputs: tail of chain */
+
+  xd3_rlist         iopt_used;        /* instruction optimizing buffer */
+  xd3_rlist         iopt_free;
+  xd3_rinst        *iout;             /* next single instruction */
+  xd3_iopt_buflist *iopt_alloc;
+
+  const uint8_t    *enc_appheader;    /* application header to encode */
+  usize_t            enc_appheadsz;    /* application header size */
+
+  /* decoder stuff */
+  xd3_decode_state  dec_state;        /* current DEC_XXX value */
+  uint              dec_hdr_ind;      /* VCDIFF header indicator */
+  uint              dec_win_ind;      /* VCDIFF window indicator */
+  uint              dec_del_ind;      /* VCDIFF delta indicator */
+
+  uint8_t           dec_magic[4];     /* First four bytes */
+  usize_t           dec_magicbytes;   /* Magic position. */
+
+  uint              dec_secondid;     /* Optional secondary compressor ID. */
+
+  uint32_t          dec_codetblsz;    /* Optional code table: length. */
+  uint8_t          *dec_codetbl;      /* Optional code table: storage. */
+  usize_t           dec_codetblbytes; /* Optional code table: position. */
+
+  uint32_t          dec_appheadsz;    /* Optional application header: size. */
+  uint8_t          *dec_appheader;    /* Optional application header: storage */
+  usize_t           dec_appheadbytes; /* Optional application header: position. */
+
+  usize_t            dec_cksumbytes;   /* Optional checksum: position. */
+  uint8_t           dec_cksum[4];     /* Optional checksum: storage. */
+  uint32_t          dec_adler32;      /* Optional checksum: value. */
+
+  uint32_t           dec_cpylen;       /* length of copy window (VCD_SOURCE or VCD_TARGET) */
+  xoff_t             dec_cpyoff;       /* offset of copy window (VCD_SOURCE or VCD_TARGET)  */
+  uint32_t           dec_enclen;       /* length of delta encoding */
+  uint32_t           dec_tgtlen;       /* length of target window */
+
+#if USE_UINT64
+  uint64_t          dec_64part;       /* part of a decoded uint64_t */
+#endif
+#if USE_UINT32
+  uint32_t          dec_32part;       /* part of a decoded uint32_t */
+#endif
+
+  xoff_t            dec_winstart;     /* offset of the start of current target window */
+  xoff_t            dec_window_count; /* == current_window + 1 in DEC_FINISH */
+  usize_t            dec_winbytes;     /* bytes of the three sections so far consumed */
+  usize_t            dec_hdrsize;      /* VCDIFF + app header size */
+
+  const uint8_t    *dec_tgtaddrbase;  /* Base of decoded target addresses (addr >= dec_cpylen). */
+  const uint8_t    *dec_cpyaddrbase;  /* Base of decoded copy addresses (addr < dec_cpylen). */
+
+  usize_t            dec_position;     /* current decoder position counting the cpylen offset */
+  usize_t            dec_maxpos;       /* maximum decoder position counting the cpylen offset */
+  xd3_hinst         dec_current1;     /* current instruction */
+  xd3_hinst         dec_current2;     /* current instruction */
+
+  uint8_t          *dec_buffer;       /* Decode buffer */
+  uint8_t          *dec_lastwin;      /* In case of VCD_TARGET, the last target window. */
+  usize_t            dec_lastlen;      /* length of the last target window */
+  xoff_t            dec_laststart;    /* offset of the start of last target window */
+  usize_t            dec_lastspace;    /* allocated space of last target window, for reuse */
+
+  xd3_desect        inst_sect;        /* staging area for decoding window sections */
+  xd3_desect        addr_sect;
+  xd3_desect        data_sect;
+
+  xd3_code_table_func       *code_table_func;
+  xd3_comp_table_func       *comp_table_func;
+  const xd3_dinst           *code_table;
+  const xd3_code_table_desc *code_table_desc;
+  xd3_dinst                 *code_table_alloc;
+
+  /* secondary compression */
+  const xd3_sec_type *sec_type;
+  xd3_sec_stream     *sec_stream_d;
+  xd3_sec_stream     *sec_stream_i;
+  xd3_sec_stream     *sec_stream_a;
+
+  /* statistics */
+  xoff_t            n_scpy;
+  xoff_t            n_tcpy;
+  xoff_t            n_add;
+  xoff_t            n_run;
+
+  xoff_t            l_scpy;
+  xoff_t            l_tcpy;
+  xoff_t            l_add;
+  xoff_t            l_run;
+
+  usize_t           i_slots_used;
+
+#if XD3_DEBUG
+  usize_t            large_ckcnt;
+
+  /* memory usage */
+  usize_t            alloc_cnt;
+  usize_t            free_cnt;
+
+  xoff_t            n_emit;
+#endif
+};
+
+/******************************************************************************************
+ PUBLIC FUNCTIONS
+ ******************************************************************************************/
+
+/* This function configures an xd3_stream using the provided in-memory input buffer,
+ * source buffer, output buffer, and flags.  The output array must be large enough or else
+ * ENOSPC will be returned.  This is the simplest in-memory encoding interface. */
+int     xd3_encode_memory (const uint8_t *input,
+			   usize_t        input_size,
+			   const uint8_t *source,
+			   usize_t        source_size,
+			   uint8_t       *output_buffer,
+			   usize_t       *output_size,
+			   usize_t        avail_output,
+			   int            flags);
+
+/* The reverse of xd3_encode_memory. */
+int     xd3_decode_memory (const uint8_t *input,
+			   usize_t        input_size,
+			   const uint8_t *source,
+			   usize_t        source_size,
+			   uint8_t       *output_buf,
+			   usize_t       *output_size,
+			   usize_t        avail_output,
+			   int            flags);
+
+/* This function encodes an in-memory input.  Everything else about the xd3_stream is
+ * configurable.  The output array must be large enough to hold the output or else ENOSPC
+ * is returned.  The source (if any) should be set using xd3_set_source() with a
+ * single-block xd3_source.  This calls the underlying non-blocking interface,
+ * xd3_encode_input(), handling the necessary input/output states.  This method be
+ * considered a reference for any application using xd3_encode_input() directly.
+ *
+ *   xd3_stream stream;
+ *   xd3_config config;
+ *   xd3_source src;
+ * 
+ *   memset (& src, 0, sizeof (src));
+ *   memset (& stream, 0, sizeof (stream));
+ *   memset (& config, 0, sizeof (config));
+ *
+ *   if (source != NULL)
+ *     {
+ *       src.size = source_size;
+ *       src.blksize = source_size;
+ *       src.curblkno = 0;
+ *       src.onblk = source_size;
+ *       src.curblk = source;
+ *       xd3_set_source(&stream, &src);
+ *     }
+ *
+ *   config.flags = flags;
+ *   config.srcwin_maxsz = source_size;
+ *   config.winsize = input_size;
+ *
+ *   ... set smatcher, appheader, encoding-table, compression-level, etc.
+ *
+ *   xd3_config_stream(&stream, &config);
+ *   xd3_encode_stream(&stream, ...);
+ *   xd3_free_stream(&stream);
+ *
+ * DO NOT USE except for testing. These methods are allocate bad buffer sizes.
+ */
+int     xd3_encode_stream (xd3_stream    *stream,
+			   const uint8_t *input,
+			   usize_t         input_size,
+			   uint8_t       *output,
+			   usize_t        *output_size,
+			   usize_t         avail_output);
+
+/* The reverse of xd3_encode_stream. */
+int     xd3_decode_stream (xd3_stream    *stream,
+			   const uint8_t *input,
+			   usize_t        input_size,
+			   uint8_t       *output,
+			   usize_t       *output_size,
+			   usize_t        avail_size);
+
+/* This is the non-blocking interface.
+ *
+ * Handling input and output states is the same for encoding or decoding using the
+ * xd3_avail_input() and xd3_consume_output() routines, inlined below.
+ *
+ * Return values:
+ *
+ *   XD3_INPUT:  the process requires more input: call xd3_avail_input() then repeat
+ *   XD3_OUTPUT: the process has more output: read stream->next_out, stream->avail_out,
+ *               then call xd3_consume_output(), then repeat
+ *   XD3_GOTHEADER: (decoder-only) notification returned following the VCDIFF header and
+ *               first window header.  the decoder may use the header to configure itself.
+ *   XD3_WINSTART: a general notification returned once for each window except the 0-th
+ *               window, which is implied by XD3_GOTHEADER.  It is recommended to
+ *               use a switch-stmt such as:
+ *                 ...
+ *               again:
+ *                 switch ((ret = xd3_decode_input (stream))) {
+ *                    case XD3_GOTHEADER: {
+ *                      assert(stream->current_window == 0);
+ *                      stuff;
+ *                    }
+ *                    // fallthrough 
+ *                    case XD3_WINSTART: {
+ *                      something(stream->current_window);
+ *                      goto again;
+ *                    }
+ *                    ...
+ *   XD3_WINFINISH: a general notification, following the complete input & output of a
+ *               window.  at this point, stream->total_in and stream->total_out are
+ *               consistent for either encoding or decoding.
+ *   XD3_GETSRCBLK: If the xd3_getblk() callback is NULL, this value is returned to
+ *               initiate a non-blocking source read.
+ */
+int     xd3_decode_input  (xd3_stream    *stream);
+int     xd3_encode_input  (xd3_stream    *stream);
+
+/* The xd3_config structure is used to initialize a stream - all data is copied into
+ * stream so config may be a temporary variable.  See the [documentation] or comments on
+ * the xd3_config structure. */
+int     xd3_config_stream (xd3_stream    *stream,
+			   xd3_config    *config);
+
+/* Since Xdelta3 doesn't open any files, xd3_close_stream is just an error check that the
+ * stream is in a proper state to be closed: this means the encoder is flushed and the
+ * decoder is at a window boundary.  The application is responsible for freeing any of the
+ * resources it supplied. */
+int     xd3_close_stream (xd3_stream    *stream);
+
+/* This unconditionally closes/frees the stream, future close() will succeed. */
+void    xd3_abort_stream (xd3_stream    *stream);
+
+/* xd3_free_stream frees all memory allocated for the stream.  The application is
+ * responsible for freeing any of the resources it supplied. */
+void    xd3_free_stream   (xd3_stream    *stream);
+
+/* This function informs the encoder or decoder that source matching (i.e.,
+ * delta-compression) is possible.  For encoding, this should be called before the first
+ * xd3_encode_input.  A NULL source is ignored.  For decoding, this should be called
+ * before the first window is decoded, but the appheader may be read first
+ * (XD3_GOTHEADER).  At this point, consult xd3_decoder_needs_source(), inlined below, to
+ * determine if a source is expected by the decoder. */
+int     xd3_set_source    (xd3_stream    *stream,
+			   xd3_source    *source);
+
+/* This should be called before the first call to xd3_encode_input() to include
+ * application-specific data in the VCDIFF header. */
+void    xd3_set_appheader (xd3_stream    *stream,
+			   const uint8_t *data,
+			   usize_t        size);
+
+/* xd3_get_appheader may be called in the decoder after XD3_GOTHEADER.  For convenience,
+ * the decoder always adds a single byte padding to the end of the application header,
+ * which is set to zero in case the application header is a string. */
+int     xd3_get_appheader (xd3_stream     *stream,
+			   uint8_t       **data,
+			   usize_t        *size);
+
+/* After receiving XD3_GOTHEADER, the decoder should check this function which returns 1
+ * if the decoder will require source data. */
+int     xd3_decoder_needs_source (xd3_stream *stream);
+
+/* Gives an error string for xdelta3-speficic errors, returns NULL for system errors */
+const char* xd3_strerror (int ret);
+
+/* For convenience, zero & initialize the xd3_config structure with specified flags. */
+static inline
+void    xd3_init_config (xd3_config *config,
+			 int         flags)
+{
+  memset (config, 0, sizeof (*config));
+  config->flags = flags;
+}
+
+/* This supplies some input to the stream. */
+static inline
+void    xd3_avail_input  (xd3_stream    *stream,
+			  const uint8_t *idata,
+			  usize_t         isize)
+{
+  /* Even if isize is zero, the code expects a non-NULL idata.  Why?  It uses this value
+   * to determine whether xd3_avail_input has ever been called.  If xd3_encode_input is
+   * called before xd3_avail_input it will return XD3_INPUT right away without allocating
+   * a stream->winsize buffer.  This is to avoid an unwanted allocation. */
+  XD3_ASSERT (idata != NULL);
+
+  stream->next_in  = idata;
+  stream->avail_in = isize;
+}
+
+/* This acknowledges receipt of output data, must be called after any XD3_OUTPUT
+ * return. */
+static inline
+void xd3_consume_output (xd3_stream  *stream)
+{
+  stream->avail_out  = 0;
+}
+
+/* These are set for each XD3_WINFINISH return. */
+static inline
+int     xd3_encoder_used_source (xd3_stream *stream) { return stream->src != NULL && stream->src->srclen > 0; }
+static inline
+xoff_t  xd3_encoder_srcbase (xd3_stream *stream) { return stream->src->srcbase; }
+static inline
+usize_t  xd3_encoder_srclen (xd3_stream *stream) { return stream->src->srclen; }
+
+/* Checks for legal flag changes. */
+static inline
+void xd3_set_flags (xd3_stream *stream, int flags)
+{
+  /* The bitwise difference should contain only XD3_FLUSH or XD3_SKIP_WINDOW */
+  XD3_ASSERT(((flags ^ stream->flags) & ~(XD3_FLUSH | XD3_SKIP_WINDOW)) == 0);
+  stream->flags = flags;
+}
+
+/* Gives some extra information about the latest library error, if any is known. */
+static inline
+const char* xd3_errstring (xd3_stream  *stream)
+{
+  return stream->msg ? stream->msg : "";
+}
+
+/* This function tells the number of bytes expected to be set in source->onblk after a
+ * getblk request.  This is for convenience of handling a partial last block. */
+static inline
+usize_t xd3_bytes_on_srcblk (xd3_source *source, xoff_t blkno)
+{
+  XD3_ASSERT (blkno < source->blocks);
+
+  if (blkno != source->blocks - 1)
+    {
+      return source->blksize;
+    }
+
+  return (usize_t)((source->size - 1) % source->blksize) + 1;
+}
+
+#endif /* _XDELTA3_H_ */
Index: /nikanabo/current/xdelta/diy/xdelta3.py
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3.py	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3.py	(revision 185)
@@ -0,0 +1,61 @@
+# This file was created automatically by SWIG.
+# Don't modify this file, modify the SWIG interface instead.
+# This file is compatible with both classic and new-style classes.
+
+import _xdelta3
+
+def _swig_setattr_nondynamic(self,class_type,name,value,static=1):
+    if (name == "this"):
+        if isinstance(value, class_type):
+            self.__dict__[name] = value.this
+            if hasattr(value,"thisown"): self.__dict__["thisown"] = value.thisown
+            del value.thisown
+            return
+    method = class_type.__swig_setmethods__.get(name,None)
+    if method: return method(self,value)
+    if (not static) or hasattr(self,name) or (name == "thisown"):
+        self.__dict__[name] = value
+    else:
+        raise AttributeError("You cannot add attributes to %s" % self)
+
+def _swig_setattr(self,class_type,name,value):
+    return _swig_setattr_nondynamic(self,class_type,name,value,0)
+
+def _swig_getattr(self,class_type,name):
+    method = class_type.__swig_getmethods__.get(name,None)
+    if method: return method(self)
+    raise AttributeError,name
+
+import types
+try:
+    _object = types.ObjectType
+    _newclass = 1
+except AttributeError:
+    class _object : pass
+    _newclass = 0
+del types
+
+
+
+xd3_encode_memory = _xdelta3.xd3_encode_memory
+
+xd3_decode_memory = _xdelta3.xd3_decode_memory
+
+xd3_main_cmdline = _xdelta3.xd3_main_cmdline
+XD3_SEC_DJW = _xdelta3.XD3_SEC_DJW
+XD3_SEC_FGK = _xdelta3.XD3_SEC_FGK
+XD3_SEC_NODATA = _xdelta3.XD3_SEC_NODATA
+XD3_SEC_NOINST = _xdelta3.XD3_SEC_NOINST
+XD3_SEC_NOADDR = _xdelta3.XD3_SEC_NOADDR
+XD3_ADLER32 = _xdelta3.XD3_ADLER32
+XD3_ADLER32_NOVER = _xdelta3.XD3_ADLER32_NOVER
+XD3_ALT_CODE_TABLE = _xdelta3.XD3_ALT_CODE_TABLE
+XD3_NOCOMPRESS = _xdelta3.XD3_NOCOMPRESS
+XD3_BEGREEDY = _xdelta3.XD3_BEGREEDY
+XD3_COMPLEVEL_SHIFT = _xdelta3.XD3_COMPLEVEL_SHIFT
+XD3_COMPLEVEL_MASK = _xdelta3.XD3_COMPLEVEL_MASK
+XD3_COMPLEVEL_1 = _xdelta3.XD3_COMPLEVEL_1
+XD3_COMPLEVEL_3 = _xdelta3.XD3_COMPLEVEL_3
+XD3_COMPLEVEL_6 = _xdelta3.XD3_COMPLEVEL_6
+XD3_COMPLEVEL_9 = _xdelta3.XD3_COMPLEVEL_9
+
Index: /nikanabo/current/xdelta/diy/xdelta3.swig
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3.swig	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3.swig	(revision 185)
@@ -0,0 +1,93 @@
+%module xdelta3
+%import cstring.i
+%import argcargv.i
+%{
+#include "xdelta3.h"
+
+int xd3_main_cmdline (int ARGC, char **ARGV);
+
+#undef SWIG_init
+#undef SWIG_name
+
+#define SWIG_init    initxdelta3
+#define SWIG_name    "xdelta3"
+
+%}
+
+%cstring_input_binary(const char *input, unsigned int input_size);
+%cstring_input_binary(const char *source, unsigned int source_size);
+
+%define %max_output_withsize(TYPEMAP, SIZE, MAXSIZE)
+%typemap(in) MAXSIZE (unsigned int alloc_size) {
+  $1 = alloc_size = PyInt_AsLong(obj2);
+}
+%typemap(in,numinputs=0) (TYPEMAP, SIZE) {
+}
+%typemap(check) (TYPEMAP, SIZE) {
+  // alloc_size input is #7th position in xd3_xxcode_memory()
+  $1 = malloc(alloc_size7);
+  $2 = &alloc_size7;
+}
+%typemap(argout,fragment="t_output_helper") (TYPEMAP, SIZE) {
+  if (result == 0) {
+    PyObject *o;
+    // alloc_size7 now carries actual size
+    o = PyString_FromStringAndSize($1,alloc_size7);
+    $result = t_output_helper($result,o);
+  } else {
+    $result = t_output_helper($result,Py_None);
+  }
+  free($1);
+}
+%typemap(default) int flags {
+  $1 = 0;
+}
+%enddef
+
+%max_output_withsize(char *output_buf, unsigned int *output_size, unsigned int max_output);
+
+int     xd3_encode_memory (const char   *input,
+			   unsigned int  input_size,
+			   const char   *source,
+			   unsigned int  source_size,
+			   char         *output_buf,
+			   unsigned int *output_size,
+			   unsigned int  max_output,
+			   int           flags);
+
+int     xd3_decode_memory (const char   *input,
+			   unsigned int  input_size,
+			   const char   *source,
+			   unsigned int  source_size,
+			   char         *output_buf,
+			   unsigned int *output_size,
+			   unsigned int  max_output,
+			   int           flags);
+
+int     xd3_main_cmdline (int ARGC, char **ARGV);
+
+/* Is this the right way? */
+enum {
+  /*XD3_JUST_HDR,*/
+  /*XD3_SKIP_WINDOW,*/
+  /*XD3_SKIP_EMIT,*/
+  /*XD3_FLUSH,*/
+  XD3_SEC_DJW,
+  XD3_SEC_FGK,
+  /*XD3_SEC_TYPE,*/
+  XD3_SEC_NODATA,
+  XD3_SEC_NOINST,
+  XD3_SEC_NOADDR,
+  /*XD3_SEC_OTHER,*/
+  XD3_ADLER32,
+  XD3_ADLER32_NOVER,
+  XD3_ALT_CODE_TABLE,
+  XD3_NOCOMPRESS,
+  XD3_BEGREEDY,
+  XD3_COMPLEVEL_SHIFT,
+  XD3_COMPLEVEL_MASK,
+  XD3_COMPLEVEL_1,
+  XD3_COMPLEVEL_3,
+  XD3_COMPLEVEL_6,
+  XD3_COMPLEVEL_9,
+};
Index: /nikanabo/current/xdelta/diy/xdelta3.vcproj
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3.vcproj	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3.vcproj	(revision 185)
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="xdelta3"
+	ProjectGUID="{7F30EDF1-4493-4E47-8664-0661516BC9E4}"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0 /D_CRT_SECURE_NO_DEPRECATE"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/DXD3_DEBUG=0 /DXD3_USE_LARGEFILE64=1 /DREGRESSION_TEST=1 /DSECONDARY_DJW=1 /DSECONDARY_FGK=1 /DXD3_MAIN=1 /DXD3_WIN32=1 /DEXTERNAL_COMPRESSION=0 /DXD3_STDIO=0 /DXD3_POSIX=0  /D_CRT_SECURE_NO_DEPRECATE"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\xdelta3-cfgs.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-decode.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-djw.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-fgk.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-list.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-main.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-python.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-second.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3-test.h"
+				>
+			</File>
+			<File
+				RelativePath=".\xdelta3.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\xdelta3.c"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: /nikanabo/current/xdelta/diy/xdelta3_wrap.c
===================================================================
--- /nikanabo/current/xdelta/diy/xdelta3_wrap.c	(revision 185)
+++ /nikanabo/current/xdelta/diy/xdelta3_wrap.c	(revision 185)
@@ -0,0 +1,2433 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 1.3.25
+ * 
+ * This file is not intended to be easily readable and contains a number of 
+ * coding conventions designed to improve portability and efficiency. Do not make
+ * changes to this file unless you know what you are doing--modify the SWIG 
+ * interface file instead. 
+ * ----------------------------------------------------------------------------- */
+
+#define SWIGPYTHON
+/***********************************************************************
+ *
+ *  This section contains generic SWIG labels for method/variable
+ *  declarations/attributes, and other compiler dependent labels.
+ *
+ ************************************************************************/
+
+/* template workaround for compilers that cannot correctly implement the C++ standard */
+#ifndef SWIGTEMPLATEDISAMBIGUATOR
+#  if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560)
+#    define SWIGTEMPLATEDISAMBIGUATOR template
+#  else
+#    define SWIGTEMPLATEDISAMBIGUATOR 
+#  endif
+#endif
+
+/* inline attribute */
+#ifndef SWIGINLINE
+# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__))
+#   define SWIGINLINE inline
+# else
+#   define SWIGINLINE
+# endif
+#endif
+
+/* attribute recognised by some compilers to avoid 'unused' warnings */
+#ifndef SWIGUNUSED
+# if defined(__GNUC__) || defined(__ICC)
+#   define SWIGUNUSED __attribute__ ((unused)) 
+# else
+#   define SWIGUNUSED 
+# endif
+#endif
+
+/* internal SWIG method */
+#ifndef SWIGINTERN
+# define SWIGINTERN static SWIGUNUSED
+#endif
+
+/* internal inline SWIG method */
+#ifndef SWIGINTERNINLINE
+# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/* exporting methods for Windows DLLs */
+#ifndef SWIGEXPORT
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   if defined(STATIC_LINKED)
+#     define SWIGEXPORT
+#   else
+#     define SWIGEXPORT __declspec(dllexport)
+#   endif
+# else
+#   define SWIGEXPORT
+# endif
+#endif
+
+/* calling conventions for Windows */
+#ifndef SWIGSTDCALL
+# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+#   define SWIGSTDCALL __stdcall
+# else
+#   define SWIGSTDCALL
+# endif 
+#endif
+
+
+
+#include <Python.h>
+
+/***********************************************************************
+ * swigrun.swg
+ *
+ *     This file contains generic CAPI SWIG runtime support for pointer
+ *     type checking.
+ *
+ ************************************************************************/
+
+/* This should only be incremented when either the layout of swig_type_info changes,
+   or for whatever reason, the runtime changes incompatibly */
+#define SWIG_RUNTIME_VERSION "2"
+
+/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */
+#ifdef SWIG_TYPE_TABLE
+# define SWIG_QUOTE_STRING(x) #x
+# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x)
+# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE)
+#else
+# define SWIG_TYPE_TABLE_NAME
+#endif
+
+/*
+  You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for
+  creating a static or dynamic library from the swig runtime code.
+  In 99.9% of the cases, swig just needs to declare them as 'static'.
+  
+  But only do this if is strictly necessary, ie, if you have problems
+  with your compiler or so.
+*/
+
+#ifndef SWIGRUNTIME
+# define SWIGRUNTIME SWIGINTERN
+#endif
+
+#ifndef SWIGRUNTIMEINLINE
+# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE
+#endif
+
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *(*swig_converter_func)(void *);
+typedef struct swig_type_info *(*swig_dycast_func)(void **);
+
+/* Structure to store inforomation on one type */
+typedef struct swig_type_info {
+  const char             *name;			/* mangled name of this type */
+  const char             *str;			/* human readable name of this type */
+  swig_dycast_func        dcast;		/* dynamic cast function down a hierarchy */
+  struct swig_cast_info  *cast;			/* linked list of types that can cast into this type */
+  void                   *clientdata;		/* language specific type data */
+} swig_type_info;
+
+/* Structure to store a type and conversion function used for casting */
+typedef struct swig_cast_info {
+  swig_type_info         *type;			/* pointer to type that is equivalent to this type */
+  swig_converter_func     converter;		/* function to cast the void pointers */
+  struct swig_cast_info  *next;			/* pointer to next cast in linked list */
+  struct swig_cast_info  *prev;			/* pointer to the previous cast */
+} swig_cast_info;
+
+/* Structure used to store module information
+ * Each module generates one structure like this, and the runtime collects
+ * all of these structures and stores them in a circularly linked list.*/
+typedef struct swig_module_info {
+  swig_type_info         **types;		/* Array of pointers to swig_type_info structures that are in this module */
+  size_t                 size;		        /* Number of types in this module */
+  struct swig_module_info *next;		/* Pointer to next element in circularly linked list */
+  swig_type_info         **type_initial;	/* Array of initially generated type structures */
+  swig_cast_info         **cast_initial;	/* Array of initially generated casting structures */
+  void                    *clientdata;		/* Language specific module data */
+} swig_module_info;
+
+
+/* 
+  Compare two type names skipping the space characters, therefore
+  "char*" == "char *" and "Class<int>" == "Class<int >", etc.
+
+  Return 0 when the two name types are equivalent, as in
+  strncmp, but skipping ' '.
+*/
+SWIGRUNTIME int
+SWIG_TypeNameComp(const char *f1, const char *l1,
+		  const char *f2, const char *l2) {
+  for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) {
+    while ((*f1 == ' ') && (f1 != l1)) ++f1;
+    while ((*f2 == ' ') && (f2 != l2)) ++f2;
+    if (*f1 != *f2) return (int)(*f1 - *f2);
+  }
+  return (l1 - f1) - (l2 - f2);
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if not equal, 1 if equal
+*/
+SWIGRUNTIME int
+SWIG_TypeEquiv(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+/*
+  Check type equivalence in a name list like <name1>|<name2>|...
+  Return 0 if equal, -1 if nb < tb, 1 if nb > tb
+*/
+SWIGRUNTIME int
+SWIG_TypeCompare(const char *nb, const char *tb) {
+  int equiv = 0;
+  const char* te = tb + strlen(tb);
+  const char* ne = nb;
+  while (!equiv && *ne) {
+    for (nb = ne; *ne; ++ne) {
+      if (*ne == '|') break;
+    }
+    equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0;
+    if (*ne) ++ne;
+  }
+  return equiv;
+}
+
+
+/* think of this as a c++ template<> or a scheme macro */
+#define SWIG_TypeCheck_Template(comparison, ty)         \
+  if (ty) {                                             \
+    swig_cast_info *iter = ty->cast;                    \
+    while (iter) {                                      \
+      if (comparison) {                                 \
+        if (iter == ty->cast) return iter;              \
+        /* Move iter to the top of the linked list */   \
+        iter->prev->next = iter->next;                  \
+        if (iter->next)                                 \
+          iter->next->prev = iter->prev;                \
+        iter->next = ty->cast;                          \
+        iter->prev = 0;                                 \
+        if (ty->cast) ty->cast->prev = iter;            \
+        ty->cast = iter;                                \
+        return iter;                                    \
+      }                                                 \
+      iter = iter->next;                                \
+    }                                                   \
+  }                                                     \
+  return 0
+
+/*
+  Check the typename
+*/
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheck(const char *c, swig_type_info *ty) {
+  SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty);
+}
+
+/* Same as previous function, except strcmp is replaced with a pointer comparison */
+SWIGRUNTIME swig_cast_info *
+SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) {
+  SWIG_TypeCheck_Template(iter->type == from, into);
+}
+
+/*
+  Cast a pointer up an inheritance hierarchy
+*/
+SWIGRUNTIMEINLINE void *
+SWIG_TypeCast(swig_cast_info *ty, void *ptr) {
+  return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr);
+}
+
+/* 
+   Dynamic pointer casting. Down an inheritance hierarchy
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) {
+  swig_type_info *lastty = ty;
+  if (!ty || !ty->dcast) return ty;
+  while (ty && (ty->dcast)) {
+    ty = (*ty->dcast)(ptr);
+    if (ty) lastty = ty;
+  }
+  return lastty;
+}
+
+/*
+  Return the name associated with this type
+*/
+SWIGRUNTIMEINLINE const char *
+SWIG_TypeName(const swig_type_info *ty) {
+  return ty->name;
+}
+
+/*
+  Return the pretty name associated with this type,
+  that is an unmangled type name in a form presentable to the user.
+*/
+SWIGRUNTIME const char *
+SWIG_TypePrettyName(const swig_type_info *type) {
+  /* The "str" field contains the equivalent pretty names of the
+     type, separated by vertical-bar characters.  We choose
+     to print the last name, as it is often (?) the most
+     specific. */
+  if (type->str != NULL) {
+    const char *last_name = type->str;
+    const char *s;
+    for (s = type->str; *s; s++)
+      if (*s == '|') last_name = s+1;
+    return last_name;
+  }
+  else
+    return type->name;
+}
+
+/* 
+   Set the clientdata field for a type
+*/
+SWIGRUNTIME void
+SWIG_TypeClientData(swig_type_info *ti, void *clientdata) {
+  if (!ti->clientdata) {
+    swig_cast_info *cast = ti->cast;
+    /* if (ti->clientdata == clientdata) return; */
+    ti->clientdata = clientdata;
+    
+    while (cast) {
+      if (!cast->converter)
+	SWIG_TypeClientData(cast->type, clientdata);
+      cast = cast->next;
+    }
+  }
+}
+
+/*
+  Search for a swig_type_info structure only by mangled name
+  Search is a O(log #types)
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_MangledTypeQueryModule(swig_module_info *start, 
+                            swig_module_info *end, 
+		            const char *name) {
+  swig_module_info *iter = start;
+  do {
+    if (iter->size) {
+      register size_t l = 0;
+      register size_t r = iter->size - 1;
+      do {
+	/* since l+r >= 0, we can (>> 1) instead (/ 2) */
+	register size_t i = (l + r) >> 1; 
+	const char *iname = iter->types[i]->name;
+	if (iname) {
+	  register int compare = strcmp(name, iname);
+	  if (compare == 0) {	    
+	    return iter->types[i];
+	  } else if (compare < 0) {
+	    if (i) {
+	      r = i - 1;
+	    } else {
+	      break;
+	    }
+	  } else if (compare > 0) {
+	    l = i + 1;
+	  }
+	} else {
+	  break; /* should never happen */
+	}
+      } while (l <= r);
+    }
+    iter = iter->next;
+  } while (iter != end);
+  return 0;
+}
+
+/*
+  Search for a swig_type_info structure for either a mangled name or a human readable name.
+  It first searches the mangled names of the types, which is a O(log #types)
+  If a type is not found it then searches the human readable names, which is O(#types).
+  
+  We start searching at module start, and finish searching when start == end.  
+  Note: if start == end at the beginning of the function, we go all the way around
+  the circular list.
+*/
+SWIGRUNTIME swig_type_info *
+SWIG_TypeQueryModule(swig_module_info *start, 
+                     swig_module_info *end, 
+		     const char *name) {
+  /* STEP 1: Search the name field using binary search */
+  swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name);
+  if (ret) {
+    return ret;
+  } else {
+    /* STEP 2: If the type hasn't been found, do a complete search
+       of the str field (the human readable name) */
+    swig_module_info *iter = start;
+    do {
+      register size_t i = 0;
+      for (; i < iter->size; ++i) {
+	if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name)))
+	  return iter->types[i];
+      }
+      iter = iter->next;
+    } while (iter != end);
+  }
+  
+  /* neither found a match */
+  return 0;
+}
+
+
+/* 
+   Pack binary data into a string
+*/
+SWIGRUNTIME char *
+SWIG_PackData(char *c, void *ptr, size_t sz) {
+  static const char hex[17] = "0123456789abcdef";
+  register const unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu =  u + sz;
+  for (; u != eu; ++u) {
+    register unsigned char uu = *u;
+    *(c++) = hex[(uu & 0xf0) >> 4];
+    *(c++) = hex[uu & 0xf];
+  }
+  return c;
+}
+
+/* 
+   Unpack binary data from a string
+*/
+SWIGRUNTIME const char *
+SWIG_UnpackData(const char *c, void *ptr, size_t sz) {
+  register unsigned char *u = (unsigned char *) ptr;
+  register const unsigned char *eu = u + sz;
+  for (; u != eu; ++u) {
+    register char d = *(c++);
+    register unsigned char uu = 0;
+    if ((d >= '0') && (d <= '9'))
+      uu = ((d - '0') << 4);
+    else if ((d >= 'a') && (d <= 'f'))
+      uu = ((d - ('a'-10)) << 4);
+    else 
+      return (char *) 0;
+    d = *(c++);
+    if ((d >= '0') && (d <= '9'))
+      uu |= (d - '0');
+    else if ((d >= 'a') && (d <= 'f'))
+      uu |= (d - ('a'-10));
+    else 
+      return (char *) 0;
+    *u = uu;
+  }
+  return c;
+}
+
+/* 
+   Pack 'void *' into a string buffer.
+*/
+SWIGRUNTIME char *
+SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) {
+  char *r = buff;
+  if ((2*sizeof(void *) + 2) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,&ptr,sizeof(void *));
+  if (strlen(name) + 1 > (bsz - (r - buff))) return 0;
+  strcpy(r,name);
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      *ptr = (void *) 0;
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sizeof(void *));
+}
+
+SWIGRUNTIME char *
+SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) {
+  char *r = buff;
+  size_t lname = (name ? strlen(name) : 0);
+  if ((2*sz + 2 + lname) > bsz) return 0;
+  *(r++) = '_';
+  r = SWIG_PackData(r,ptr,sz);
+  if (lname) {
+    strncpy(r,name,lname+1);
+  } else {
+    *r = 0;
+  }
+  return buff;
+}
+
+SWIGRUNTIME const char *
+SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) {
+  if (*c != '_') {
+    if (strcmp(c,"NULL") == 0) {
+      memset(ptr,0,sz);
+      return name;
+    } else {
+      return 0;
+    }
+  }
+  return SWIG_UnpackData(++c,ptr,sz);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------
+ * SWIG API. Portion that goes into the runtime
+ * ----------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* -----------------------------------------------------------------------------
+ * for internal method declarations
+ * ----------------------------------------------------------------------------- */
+
+#ifndef SWIGINTERN
+#  define SWIGINTERN static SWIGUNUSED
+#endif
+
+#ifndef SWIGINTERNINLINE
+#  define SWIGINTERNINLINE SWIGINTERN SWIGINLINE
+#endif
+
+/*
+  Exception handling in wrappers
+*/
+#define SWIG_fail                goto fail
+#define SWIG_arg_fail(arg)       SWIG_Python_ArgFail(arg)
+#define SWIG_append_errmsg(msg)   SWIG_Python_AddErrMesg(msg,0)
+#define SWIG_preppend_errmsg(msg) SWIG_Python_AddErrMesg(msg,1)
+#define SWIG_type_error(type,obj) SWIG_Python_TypeError(type,obj)
+#define SWIG_null_ref(type)       SWIG_Python_NullRef(type)
+
+/*
+  Contract support
+*/
+#define SWIG_contract_assert(expr, msg) \
+ if (!(expr)) { PyErr_SetString(PyExc_RuntimeError, (char *) msg ); goto fail; } else
+
+/* -----------------------------------------------------------------------------
+ * Constant declarations
+ * ----------------------------------------------------------------------------- */
+
+/* Constant Types */
+#define SWIG_PY_INT     1
+#define SWIG_PY_FLOAT   2
+#define SWIG_PY_STRING  3
+#define SWIG_PY_POINTER 4
+#define SWIG_PY_BINARY  5
+
+/* Constant information structure */
+typedef struct swig_const_info {
+    int type;
+    char *name;
+    long lvalue;
+    double dvalue;
+    void   *pvalue;
+    swig_type_info **ptype;
+} swig_const_info;
+
+
+/* -----------------------------------------------------------------------------
+ * Alloc. memory flags
+ * ----------------------------------------------------------------------------- */
+#define SWIG_OLDOBJ  1
+#define SWIG_NEWOBJ  SWIG_OLDOBJ + 1
+#define SWIG_PYSTR   SWIG_NEWOBJ + 1
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/***********************************************************************
+ * pyrun.swg
+ *
+ *     This file contains the runtime support for Python modules
+ *     and includes code for managing global variables and pointer
+ *     type checking.
+ *
+ * Author : David Beazley (beazley@cs.uchicago.edu)
+ ************************************************************************/
+
+/* Common SWIG API */
+#define SWIG_ConvertPtr(obj, pp, type, flags)    SWIG_Python_ConvertPtr(obj, pp, type, flags)
+#define SWIG_NewPointerObj(p, type, flags)       SWIG_Python_NewPointerObj(p, type, flags)
+#define SWIG_MustGetPtr(p, type, argnum, flags)  SWIG_Python_MustGetPtr(p, type, argnum, flags)
+ 
+
+/* Python-specific SWIG API */
+#define SWIG_ConvertPacked(obj, ptr, sz, ty, flags)   SWIG_Python_ConvertPacked(obj, ptr, sz, ty, flags)
+#define SWIG_NewPackedObj(ptr, sz, type)              SWIG_Python_NewPackedObj(ptr, sz, type)
+
+/* Runtime API */
+#define SWIG_GetModule(clientdata) SWIG_Python_GetModule()
+#define SWIG_SetModule(clientdata, pointer) SWIG_Python_SetModule(pointer)
+
+/* -----------------------------------------------------------------------------
+ * Pointer declarations
+ * ----------------------------------------------------------------------------- */
+/*
+  Use SWIG_NO_COBJECT_TYPES to force the use of strings to represent
+  C/C++ pointers in the python side. Very useful for debugging, but
+  not always safe.
+*/
+#if !defined(SWIG_NO_COBJECT_TYPES) && !defined(SWIG_COBJECT_TYPES)
+#  define SWIG_COBJECT_TYPES
+#endif
+
+/* Flags for pointer conversion */
+#define SWIG_POINTER_EXCEPTION     0x1
+#define SWIG_POINTER_DISOWN        0x2
+
+
+/* Add PyOS_snprintf for old Pythons */
+#if PY_VERSION_HEX < 0x02020000
+#define PyOS_snprintf snprintf
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Create a new pointer string 
+ * ----------------------------------------------------------------------------- */
+#ifndef SWIG_BUFFER_SIZE
+#define SWIG_BUFFER_SIZE 1024
+#endif
+
+#if defined(SWIG_COBJECT_TYPES)
+#if !defined(SWIG_COBJECT_PYTHON)
+/* -----------------------------------------------------------------------------
+ * Implements a simple Swig Object type, and use it instead of PyCObject
+ * ----------------------------------------------------------------------------- */
+
+typedef struct {
+  PyObject_HEAD
+  void *ptr;
+  const char *desc;
+} PySwigObject;
+
+/* Declarations for objects of type PySwigObject */
+
+SWIGRUNTIME int
+PySwigObject_print(PySwigObject *v, FILE *fp, int flags)
+{
+  char result[SWIG_BUFFER_SIZE];
+  flags = flags;
+  if (SWIG_PackVoidPtr(result, v->ptr, v->desc, sizeof(result))) {
+    fputs("<Swig Object at ", fp); fputs(result, fp); fputs(">", fp);
+    return 0; 
+  } else {
+    return 1; 
+  }
+}
+  
+SWIGRUNTIME PyObject *
+PySwigObject_repr(PySwigObject *v)
+{
+  char result[SWIG_BUFFER_SIZE];
+  return SWIG_PackVoidPtr(result, v->ptr, v->desc, sizeof(result)) ?
+    PyString_FromFormat("<Swig Object at %s>", result) : 0;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_str(PySwigObject *v)
+{
+  char result[SWIG_BUFFER_SIZE];
+  return SWIG_PackVoidPtr(result, v->ptr, v->desc, sizeof(result)) ?
+    PyString_FromString(result) : 0;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_long(PySwigObject *v)
+{
+  return PyLong_FromVoidPtr(v->ptr);
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_format(const char* fmt, PySwigObject *v)
+{
+  PyObject *res = NULL;
+  PyObject *args = PyTuple_New(1);
+  if (args && (PyTuple_SetItem(args, 0, PySwigObject_long(v)) == 0)) {
+    PyObject *ofmt = PyString_FromString(fmt);
+    if (ofmt) {
+      res = PyString_Format(ofmt,args);
+      Py_DECREF(ofmt);
+    }
+    Py_DECREF(args);
+  }  
+  return res;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_oct(PySwigObject *v)
+{
+  return PySwigObject_format("%o",v);
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_hex(PySwigObject *v)
+{
+  return PySwigObject_format("%x",v);
+}
+
+SWIGRUNTIME int
+PySwigObject_compare(PySwigObject *v, PySwigObject *w)
+{
+  int c = strcmp(v->desc, w->desc);
+  if (c) {
+    return (c > 0) ? 1 : -1;
+  } else {
+    void *i = v->ptr;
+    void *j = w->ptr;
+    return (i < j) ? -1 : ((i > j) ? 1 : 0);
+  }
+}
+
+SWIGRUNTIME void
+PySwigObject_dealloc(PySwigObject *self)
+{
+  PyObject_DEL(self);
+}
+
+SWIGRUNTIME PyTypeObject*
+PySwigObject_type(void) {
+  static char pyswigobject_type__doc__[] = 
+    "Swig object carries a C/C++ instance pointer";
+  
+  static PyNumberMethods PySwigObject_as_number = {
+    (binaryfunc)0, /*nb_add*/
+    (binaryfunc)0, /*nb_subtract*/
+    (binaryfunc)0, /*nb_multiply*/
+    (binaryfunc)0, /*nb_divide*/
+    (binaryfunc)0, /*nb_remainder*/
+    (binaryfunc)0, /*nb_divmod*/
+    (ternaryfunc)0,/*nb_power*/
+    (unaryfunc)0,  /*nb_negative*/
+    (unaryfunc)0,  /*nb_positive*/
+    (unaryfunc)0,  /*nb_absolute*/
+    (inquiry)0,    /*nb_nonzero*/
+    0,		   /*nb_invert*/
+    0,		   /*nb_lshift*/
+    0,		   /*nb_rshift*/
+    0,		   /*nb_and*/
+    0,		   /*nb_xor*/
+    0,		   /*nb_or*/
+    (coercion)0,   /*nb_coerce*/
+    (unaryfunc)PySwigObject_long, /*nb_int*/
+    (unaryfunc)PySwigObject_long, /*nb_long*/
+    (unaryfunc)0,                 /*nb_float*/
+    (unaryfunc)PySwigObject_oct,  /*nb_oct*/
+    (unaryfunc)PySwigObject_hex,  /*nb_hex*/
+#if PY_VERSION_HEX >= 0x02000000
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* nb_inplace_add -> nb_inplace_true_divide */ 
+#endif
+  };
+
+  static PyTypeObject pyswigobject_type
+#if !defined(__cplusplus)
+  ;  
+  static int type_init = 0;
+  if (!type_init) {
+    PyTypeObject tmp
+#endif
+    = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,					/*ob_size*/
+    (char *)"PySwigObject",		/*tp_name*/
+    sizeof(PySwigObject),		/*tp_basicsize*/
+    0,					/*tp_itemsize*/
+    /* methods */
+    (destructor)PySwigObject_dealloc,	/*tp_dealloc*/
+    (printfunc)PySwigObject_print,	/*tp_print*/
+    (getattrfunc)0,			/*tp_getattr*/
+    (setattrfunc)0,			/*tp_setattr*/
+    (cmpfunc)PySwigObject_compare,	/*tp_compare*/
+    (reprfunc)PySwigObject_repr,	/*tp_repr*/
+    &PySwigObject_as_number,	        /*tp_as_number*/
+    0,					/*tp_as_sequence*/
+    0,					/*tp_as_mapping*/
+    (hashfunc)0,			/*tp_hash*/
+    (ternaryfunc)0,			/*tp_call*/
+    (reprfunc)PySwigObject_str,		/*tp_str*/
+    /* Space for future expansion */
+    0,0,0,0,
+    pyswigobject_type__doc__, 	        /* Documentation string */
+#if PY_VERSION_HEX >= 0x02000000
+    0,                                  /* tp_traverse */
+    0,                                  /* tp_clear */
+#endif
+#if PY_VERSION_HEX >= 0x02010000
+    0,                                  /* tp_richcompare */
+    0,                                  /* tp_weaklistoffset */
+#endif
+#if PY_VERSION_HEX >= 0x02020000
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+    0,                                  /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+    0,0,0,0                             /* tp_alloc -> tp_next */
+#endif
+    };
+#if !defined(__cplusplus)
+    pyswigobject_type = tmp;
+    type_init = 1;
+  }
+#endif
+  return &pyswigobject_type;
+}
+
+SWIGRUNTIME PyObject *
+PySwigObject_FromVoidPtrAndDesc(void *ptr, const char *desc)
+{
+  PySwigObject *self = PyObject_NEW(PySwigObject, PySwigObject_type());
+  if (self) {
+    self->ptr = ptr;
+    self->desc = desc;
+  }
+  return (PyObject *)self;
+}
+
+SWIGRUNTIMEINLINE void *
+PySwigObject_AsVoidPtr(PyObject *self)
+{
+  return ((PySwigObject *)self)->ptr;
+}
+
+SWIGRUNTIMEINLINE const char *
+PySwigObject_GetDesc(PyObject *self)
+{
+  return ((PySwigObject *)self)->desc;
+}
+
+SWIGRUNTIMEINLINE int
+PySwigObject_Check(PyObject *op) {
+  return ((op)->ob_type == PySwigObject_type()) 
+    || (strcmp((op)->ob_type->tp_name,"PySwigObject") == 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Implements a simple Swig Packed type, and use it instead of string
+ * ----------------------------------------------------------------------------- */
+
+typedef struct {
+  PyObject_HEAD
+  void *pack;
+  const char *desc;
+  size_t size;
+} PySwigPacked;
+
+SWIGRUNTIME int
+PySwigPacked_print(PySwigPacked *v, FILE *fp, int flags)
+{
+  char result[SWIG_BUFFER_SIZE];
+  flags = flags;
+  fputs("<Swig Packed ", fp); 
+  if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+    fputs("at ", fp); 
+    fputs(result, fp); 
+  }
+  fputs(v->desc,fp); 
+  fputs(">", fp);
+  return 0; 
+}
+  
+SWIGRUNTIME PyObject *
+PySwigPacked_repr(PySwigPacked *v)
+{
+  char result[SWIG_BUFFER_SIZE];
+  if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))) {
+    return PyString_FromFormat("<Swig Packed at %s%s>", result, v->desc);
+  } else {
+    return PyString_FromFormat("<Swig Packed %s>", v->desc);
+  }  
+}
+
+SWIGRUNTIME PyObject *
+PySwigPacked_str(PySwigPacked *v)
+{
+  char result[SWIG_BUFFER_SIZE];
+  if (SWIG_PackDataName(result, v->pack, v->size, 0, sizeof(result))){
+    return PyString_FromFormat("%s%s", result, v->desc);
+  } else {
+    return PyString_FromFormat("%s", v->desc);
+  }  
+}
+
+SWIGRUNTIME int
+PySwigPacked_compare(PySwigPacked *v, PySwigPacked *w)
+{
+  int c = strcmp(v->desc, w->desc);
+  if (c) {
+    return (c > 0) ? 1 : -1;
+  } else {
+    size_t i = v->size;
+    size_t j = w->size;
+    int s = (i < j) ? -1 : ((i > j) ? 1 : 0);
+    return s ? s : strncmp((char *)v->pack, (char *)w->pack, 2*v->size);
+  }
+}
+
+SWIGRUNTIME void
+PySwigPacked_dealloc(PySwigPacked *self)
+{
+  free(self->pack);
+  PyObject_DEL(self);
+}
+
+SWIGRUNTIME PyTypeObject*
+PySwigPacked_type(void) {
+  static char pyswigpacked_type__doc__[] = 
+    "Swig object carries a C/C++ instance pointer";
+  static PyTypeObject pyswigpacked_type
+#if !defined(__cplusplus)
+  ;
+  static int type_init = 0;  
+  if (!type_init) {
+    PyTypeObject tmp
+#endif
+    = {
+    PyObject_HEAD_INIT(&PyType_Type)
+    0,					/*ob_size*/
+    (char *)"PySwigPacked",		/*tp_name*/
+    sizeof(PySwigPacked),		/*tp_basicsize*/
+    0,					/*tp_itemsize*/
+    /* methods */
+    (destructor)PySwigPacked_dealloc,	/*tp_dealloc*/
+    (printfunc)PySwigPacked_print,	/*tp_print*/
+    (getattrfunc)0,			/*tp_getattr*/
+    (setattrfunc)0,			/*tp_setattr*/
+    (cmpfunc)PySwigPacked_compare,	/*tp_compare*/
+    (reprfunc)PySwigPacked_repr,	/*tp_repr*/
+    0,	                                /*tp_as_number*/
+    0,					/*tp_as_sequence*/
+    0,					/*tp_as_mapping*/
+    (hashfunc)0,			/*tp_hash*/
+    (ternaryfunc)0,			/*tp_call*/
+    (reprfunc)PySwigPacked_str,		/*tp_str*/
+    /* Space for future expansion */
+    0,0,0,0,
+    pyswigpacked_type__doc__, 	        /* Documentation string */
+#if PY_VERSION_HEX >= 0x02000000
+    0,                                  /* tp_traverse */
+    0,                                  /* tp_clear */
+#endif
+#if PY_VERSION_HEX >= 0x02010000
+    0,                                  /* tp_richcompare */
+    0,                                  /* tp_weaklistoffset */
+#endif
+#if PY_VERSION_HEX >= 0x02020000         
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+    0,                                  /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+    0,0,0,0                             /* tp_alloc -> tp_next */
+#endif
+    };
+#if !defined(__cplusplus)
+    pyswigpacked_type = tmp;
+    type_init = 1;
+  }
+#endif
+  return &pyswigpacked_type;
+}
+
+SWIGRUNTIME PyObject *
+PySwigPacked_FromDataAndDesc(void *ptr, size_t size, const char *desc)
+{
+  PySwigPacked *self = PyObject_NEW(PySwigPacked, PySwigPacked_type());
+  if (self == NULL) {
+    return NULL;
+  } else {
+    void *pack = malloc(size);
+    if (pack) {
+      memcpy(pack, ptr, size);
+      self->pack = pack;
+      self->desc = desc;
+      self->size = size;
+      return (PyObject *) self;
+    }
+    return NULL;
+  }
+}
+
+SWIGRUNTIMEINLINE const char *
+PySwigPacked_UnpackData(PyObject *obj, void *ptr, size_t size)
+{
+  PySwigPacked *self = (PySwigPacked *)obj;
+  if (self->size != size) return 0;
+  memcpy(ptr, self->pack, size);
+  return self->desc;
+}
+
+SWIGRUNTIMEINLINE const char *
+PySwigPacked_GetDesc(PyObject *self)
+{
+  return ((PySwigPacked *)self)->desc;
+}
+
+SWIGRUNTIMEINLINE int
+PySwigPacked_Check(PyObject *op) {
+  return ((op)->ob_type == PySwigPacked_type()) 
+    || (strcmp((op)->ob_type->tp_name,"PySwigPacked") == 0);
+}
+
+#else
+/* -----------------------------------------------------------------------------
+ * Use the old Python PyCObject instead of PySwigObject
+ * ----------------------------------------------------------------------------- */
+
+#define PySwigObject_GetDesc(obj)	           PyCObject_GetDesc(obj)
+#define PySwigObject_Check(obj)	           PyCObject_Check(obj)
+#define PySwigObject_AsVoidPtr(obj)	   PyCObject_AsVoidPtr(obj)
+#define PySwigObject_FromVoidPtrAndDesc(p, d)  PyCObject_FromVoidPtrAndDesc(p, d, NULL)
+
+#endif
+
+#endif
+
+/* -----------------------------------------------------------------------------
+ * errors manipulation
+ * ----------------------------------------------------------------------------- */
+
+SWIGRUNTIME void
+SWIG_Python_TypeError(const char *type, PyObject *obj)
+{
+  if (type) {
+#if defined(SWIG_COBJECT_TYPES)
+    if (obj && PySwigObject_Check(obj)) {
+      const char *otype = (const char *) PySwigObject_GetDesc(obj);
+      if (otype) {
+	PyErr_Format(PyExc_TypeError, "a '%s' is expected, 'PySwigObject(%s)' is received",
+		     type, otype);
+	return;
+      }
+    } else 
+#endif      
+    {
+      const char *otype = (obj ? obj->ob_type->tp_name : 0); 
+      if (otype) {
+	PyObject *str = PyObject_Str(obj);
+	const char *cstr = str ? PyString_AsString(str) : 0;
+	if (cstr) {
+	  PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s(%s)' is received",
+		       type, otype, cstr);
+	} else {
+	  PyErr_Format(PyExc_TypeError, "a '%s' is expected, '%s' is received",
+		       type, otype);
+	}
+	Py_XDECREF(str);
+	return;
+      }
+    }   
+    PyErr_Format(PyExc_TypeError, "a '%s' is expected", type);
+  } else {
+    PyErr_Format(PyExc_TypeError, "unexpected type is received");
+  }
+}
+
+SWIGRUNTIMEINLINE void
+SWIG_Python_NullRef(const char *type)
+{
+  if (type) {
+    PyErr_Format(PyExc_TypeError, "null reference of type '%s' was received",type);
+  } else {
+    PyErr_Format(PyExc_TypeError, "null reference was received");
+  }
+}
+
+SWIGRUNTIME int
+SWIG_Python_AddErrMesg(const char* mesg, int infront)
+{
+  if (PyErr_Occurred()) {
+    PyObject *type = 0;
+    PyObject *value = 0;
+    PyObject *traceback = 0;
+    PyErr_Fetch(&type, &value, &traceback);
+    if (value) {
+      PyObject *old_str = PyObject_Str(value);
+      Py_XINCREF(type);
+      PyErr_Clear();
+      if (infront) {
+	PyErr_Format(type, "%s %s", mesg, PyString_AsString(old_str));
+      } else {
+	PyErr_Format(type, "%s %s", PyString_AsString(old_str), mesg);
+      }
+      Py_DECREF(old_str);
+    }
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
+SWIGRUNTIME int
+SWIG_Python_ArgFail(int argnum)
+{
+  if (PyErr_Occurred()) {
+    /* add information about failing argument */
+    char mesg[256];
+    PyOS_snprintf(mesg, sizeof(mesg), "argument number %d:", argnum);
+    return SWIG_Python_AddErrMesg(mesg, 1);
+  } else {
+    return 0;
+  }
+}
+
+
+/* -----------------------------------------------------------------------------
+ * pointers/data manipulation
+ * ----------------------------------------------------------------------------- */
+
+/* Convert a pointer value */
+SWIGRUNTIME int
+SWIG_Python_ConvertPtr(PyObject *obj, void **ptr, swig_type_info *ty, int flags) {
+  swig_cast_info *tc;
+  const char *c = 0;
+  static PyObject *SWIG_this = 0;
+  int    newref = 0;
+  PyObject  *pyobj = 0;
+  void *vptr;
+  
+  if (!obj) return 0;
+  if (obj == Py_None) {
+    *ptr = 0;
+    return 0;
+  }
+
+#ifdef SWIG_COBJECT_TYPES
+  if (!(PySwigObject_Check(obj))) {
+    if (!SWIG_this)
+      SWIG_this = PyString_FromString("this");
+    pyobj = obj;
+    obj = PyObject_GetAttr(obj,SWIG_this);
+    newref = 1;
+    if (!obj) goto type_error;
+    if (!PySwigObject_Check(obj)) {
+      Py_DECREF(obj);
+      goto type_error;
+    }
+  }  
+  vptr = PySwigObject_AsVoidPtr(obj);
+  c = (const char *) PySwigObject_GetDesc(obj);
+  if (newref) { Py_DECREF(obj); }
+  goto type_check;
+#else
+  if (!(PyString_Check(obj))) {
+    if (!SWIG_this)
+      SWIG_this = PyString_FromString("this");
+    pyobj = obj;
+    obj = PyObject_GetAttr(obj,SWIG_this);
+    newref = 1;
+    if (!obj) goto type_error;
+    if (!PyString_Check(obj)) {
+      Py_DECREF(obj);
+      goto type_error;
+    }
+  } 
+  c = PyString_AS_STRING(obj);
+  /* Pointer values must start with leading underscore */
+  c = SWIG_UnpackVoidPtr(c, &vptr, ty->name);
+  if (newref) { Py_DECREF(obj); }
+  if (!c) goto type_error;
+#endif
+
+type_check:
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) goto type_error;
+    *ptr = SWIG_TypeCast(tc,vptr);
+  } else {
+    *ptr = vptr;
+  }
+  if ((pyobj) && (flags & SWIG_POINTER_DISOWN)) {
+    PyObject_SetAttrString(pyobj,(char*)"thisown",Py_False);
+  }
+  return 0;
+
+type_error:
+  PyErr_Clear();
+  if (pyobj && !obj) {    
+    obj = pyobj;
+    if (PyCFunction_Check(obj)) {
+      /* here we get the method pointer for callbacks */
+      char *doc = (((PyCFunctionObject *)obj) -> m_ml -> ml_doc);
+      c = doc ? strstr(doc, "swig_ptr: ") : 0;
+      if (c) {
+	c = ty ? SWIG_UnpackVoidPtr(c + 10, &vptr, ty->name) : 0;
+	if (!c) goto type_error;
+	goto type_check;
+      }
+    }
+  }
+  if (flags & SWIG_POINTER_EXCEPTION) {
+    if (ty) {
+      SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj);
+    } else {
+      SWIG_Python_TypeError("C/C++ pointer", obj);
+    }
+  }
+  return -1;
+}
+
+/* Convert a pointer value, signal an exception on a type mismatch */
+SWIGRUNTIME void *
+SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) {
+  void *result;
+  if (SWIG_Python_ConvertPtr(obj, &result, ty, flags) == -1) {
+    PyErr_Clear();
+    if (flags & SWIG_POINTER_EXCEPTION) {
+      SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj);
+      SWIG_Python_ArgFail(argnum);
+    }
+  }
+  return result;
+}
+
+/* Convert a packed value value */
+SWIGRUNTIME int
+SWIG_Python_ConvertPacked(PyObject *obj, void *ptr, size_t sz, swig_type_info *ty, int flags) {
+  swig_cast_info *tc;
+  const char *c = 0;
+
+#if defined(SWIG_COBJECT_TYPES) && !defined(SWIG_COBJECT_PYTHON)
+  c = PySwigPacked_UnpackData(obj, ptr, sz);
+#else
+  if ((!obj) || (!PyString_Check(obj))) goto type_error;
+  c = PyString_AS_STRING(obj);
+  /* Pointer values must start with leading underscore */
+  c = SWIG_UnpackDataName(c, ptr, sz, ty->name);
+#endif
+  if (!c) goto type_error;
+  if (ty) {
+    tc = SWIG_TypeCheck(c,ty);
+    if (!tc) goto type_error;
+  }
+  return 0;
+
+type_error:
+  PyErr_Clear();
+  if (flags & SWIG_POINTER_EXCEPTION) {
+    if (ty) {
+      SWIG_Python_TypeError(SWIG_TypePrettyName(ty), obj);
+    } else {
+      SWIG_Python_TypeError("C/C++ packed data", obj);
+    }
+  }
+  return -1;
+}  
+
+/* Create a new array object */
+SWIGRUNTIME PyObject *
+SWIG_Python_NewPointerObj(void *ptr, swig_type_info *type, int own) {
+  PyObject *robj = 0;
+  if (!type) {
+    if (!PyErr_Occurred()) {
+      PyErr_Format(PyExc_TypeError, "Swig: null type passed to NewPointerObj");
+    }
+    return robj;
+  }
+  if (!ptr) {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+#ifdef SWIG_COBJECT_TYPES
+  robj = PySwigObject_FromVoidPtrAndDesc((void *) ptr, (char *)type->name);
+#else
+  {
+    char result[SWIG_BUFFER_SIZE];
+    robj = SWIG_PackVoidPtr(result, ptr, type->name, sizeof(result)) ?
+      PyString_FromString(result) : 0;
+  }
+#endif
+  if (!robj || (robj == Py_None)) return robj;
+  if (type->clientdata) {
+    PyObject *inst;
+    PyObject *args = Py_BuildValue((char*)"(O)", robj);
+    Py_DECREF(robj);
+    inst = PyObject_CallObject((PyObject *) type->clientdata, args);
+    Py_DECREF(args);
+    if (inst) {
+      if (own) {
+        PyObject_SetAttrString(inst,(char*)"thisown",Py_True);
+      }
+      robj = inst;
+    }
+  }
+  return robj;
+}
+
+SWIGRUNTIME PyObject *
+SWIG_Python_NewPackedObj(void *ptr, size_t sz, swig_type_info *type) {
+  PyObject *robj = 0;
+  if (!ptr) {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+#if defined(SWIG_COBJECT_TYPES) && !defined(SWIG_COBJECT_PYTHON)
+  robj = PySwigPacked_FromDataAndDesc((void *) ptr, sz, (char *)type->name);
+#else
+  {
+    char result[SWIG_BUFFER_SIZE];
+    robj = SWIG_PackDataName(result, ptr, sz, type->name, sizeof(result)) ?
+      PyString_FromString(result) : 0;
+  }
+#endif
+  return robj;
+}
+
+/* -----------------------------------------------------------------------------*
+ *  Get type list 
+ * -----------------------------------------------------------------------------*/
+
+#ifdef SWIG_LINK_RUNTIME
+void *SWIG_ReturnGlobalTypeList(void *);
+#endif
+
+SWIGRUNTIME swig_module_info *
+SWIG_Python_GetModule(void) {
+  static void *type_pointer = (void *)0;
+  /* first check if module already created */
+  if (!type_pointer) {
+#ifdef SWIG_LINK_RUNTIME
+    type_pointer = SWIG_ReturnGlobalTypeList((void *)0);
+#else
+    type_pointer = PyCObject_Import((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION,
+				    (char*)"type_pointer" SWIG_TYPE_TABLE_NAME);
+    if (PyErr_Occurred()) {
+      PyErr_Clear();
+      type_pointer = (void *)0;
+    }
+  }
+#endif
+  return (swig_module_info *) type_pointer;
+}
+
+SWIGRUNTIME void
+SWIG_Python_SetModule(swig_module_info *swig_module) {
+  static PyMethodDef swig_empty_runtime_method_table[] = { {NULL, NULL, 0, NULL} };/* Sentinel */
+
+  PyObject *module = Py_InitModule((char*)"swig_runtime_data" SWIG_RUNTIME_VERSION,
+				   swig_empty_runtime_method_table);
+  PyObject *pointer = PyCObject_FromVoidPtr((void *) swig_module, NULL);
+  if (pointer && module) {
+    PyModule_AddObject(module, (char*)"type_pointer" SWIG_TYPE_TABLE_NAME, pointer);
+  }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/* -------- TYPES TABLE (BEGIN) -------- */
+
+#define SWIGTYPE_p_char swig_types[0]
+#define SWIGTYPE_p_p_char swig_types[1]
+#define SWIGTYPE_p_unsigned_int swig_types[2]
+#define SWIGTYPE_ptrdiff_t swig_types[3]
+#define SWIGTYPE_size_t swig_types[4]
+static swig_type_info *swig_types[5];
+static swig_module_info swig_module = {swig_types, 5, 0, 0, 0, 0};
+#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
+#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
+
+/* -------- TYPES TABLE (END) -------- */
+
+
+/*-----------------------------------------------
+              @(target):= _xdelta3.so
+  ------------------------------------------------*/
+#define SWIG_init    init_xdelta3
+
+#define SWIG_name    "_xdelta3"
+
+#include "xdelta3.h"
+
+int xd3_main_cmdline (int ARGC, char **ARGV);
+
+#undef SWIG_init
+#undef SWIG_name
+
+#define SWIG_init    initxdelta3
+#define SWIG_name    "xdelta3"
+
+
+
+/* returns SWIG_OLDOBJ if the input is a raw char*, SWIG_PYSTR if is a PyString */
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize)
+{
+  static swig_type_info* pchar_info = 0;
+  char* vptr = 0;
+  if (!pchar_info) pchar_info = SWIG_TypeQuery("char *");
+  if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_info, 0) != -1) {
+    if (cptr) *cptr = vptr;
+    if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0;
+    return SWIG_OLDOBJ;
+  } else {
+    PyErr_Clear();
+    if (PyString_Check(obj)) {
+      if (cptr) {
+	*cptr = PyString_AS_STRING(obj);
+	if (psize) {
+	  *psize = PyString_GET_SIZE(obj) + 1;
+	}
+      }
+      return SWIG_PYSTR;
+    }
+  }
+  if (cptr) {
+    SWIG_type_error("char *", obj);
+  }
+  return 0;
+}
+
+
+#include <limits.h>
+
+
+SWIGINTERN int
+  SWIG_CheckLongInRange(long value, long min_value, long max_value,
+			const char *errmsg)
+{
+  if (value < min_value) {
+    if (errmsg) {
+      PyErr_Format(PyExc_OverflowError, 
+		   "value %ld is less than '%s' minimum %ld", 
+		   value, errmsg, min_value);
+    }
+    return 0;    
+  } else if (value > max_value) {
+    if (errmsg) {
+      PyErr_Format(PyExc_OverflowError,
+		   "value %ld is greater than '%s' maximum %ld", 
+		   value, errmsg, max_value);
+    }
+    return 0;
+  }
+  return 1;
+}
+
+
+SWIGINTERN int
+  SWIG_AsVal_long(PyObject * obj, long* val)
+{
+  if (PyInt_Check(obj)) {
+    if (val) *val = PyInt_AS_LONG(obj);
+    return 1;
+  }
+  if (PyLong_Check(obj)) {
+    long v = PyLong_AsLong(obj);
+    if (!PyErr_Occurred()) {
+      if (val) *val = v;
+      return 1;
+    } else {
+      if (!val) PyErr_Clear();
+      return 0;
+    }
+  }
+  if (val) {
+    SWIG_type_error("long", obj);
+  }
+  return 0;
+ }
+
+
+#if INT_MAX != LONG_MAX
+SWIGINTERN int
+  SWIG_AsVal_int(PyObject *obj, int *val)
+{ 
+  const char* errmsg = val ? "int" : (char*)0;
+  long v;
+  if (SWIG_AsVal_long(obj, &v)) {
+    if (SWIG_CheckLongInRange(v, INT_MIN,INT_MAX, errmsg)) {
+      if (val) *val = (int)(v);
+      return 1;
+    } else {
+      return 0;
+    }
+  } else {
+    PyErr_Clear();
+  }
+  if (val) {
+    SWIG_type_error(errmsg, obj);
+  }
+  return 0;    
+}
+#else
+SWIGINTERNINLINE int
+  SWIG_AsVal_int(PyObject *obj, int *val)
+{
+  return SWIG_AsVal_long(obj,(long*)val);
+}
+#endif
+
+
+SWIGINTERNINLINE int
+SWIG_As_int(PyObject* obj)
+{
+  int v;
+  if (!SWIG_AsVal_int(obj, &v)) {
+    /*
+      this is needed to make valgrind/purify happier. 
+     */
+    memset((void*)&v, 0, sizeof(int));
+  }
+  return v;
+}
+
+
+SWIGINTERNINLINE int
+SWIG_AsCharPtr(PyObject *obj, char **val)
+{
+  if (SWIG_AsCharPtrAndSize(obj, val, (size_t*)(0))) {
+    return 1;
+  }
+  if (val) {
+    PyErr_Clear();
+    SWIG_type_error("char *", obj);
+  }
+  return 0;
+}
+
+
+SWIGINTERNINLINE int
+  SWIG_CheckUnsignedLongInRange(unsigned long value,
+				unsigned long max_value,
+				const char *errmsg) 
+{
+  if (value > max_value) {
+    if (errmsg) {
+      PyErr_Format(PyExc_OverflowError,
+		   "value %lu is greater than '%s' minimum %lu",
+		   value, errmsg, max_value);
+    }
+    return 0;
+  }
+  return 1;
+ }
+
+
+SWIGINTERN int
+  SWIG_AsVal_unsigned_SS_long(PyObject *obj, unsigned long *val) 
+{
+  if (PyInt_Check(obj)) {
+    long v = PyInt_AS_LONG(obj);
+    if (v >= 0) {
+      if (val) *val = v;
+      return 1;
+    }   
+  }
+  if (PyLong_Check(obj)) {
+    unsigned long v = PyLong_AsUnsignedLong(obj);
+    if (!PyErr_Occurred()) {
+      if (val) *val = v;
+      return 1;
+    } else {
+      if (!val) PyErr_Clear();
+      return 0;
+    }
+  } 
+  if (val) {
+    SWIG_type_error("unsigned long", obj);
+  }
+  return 0;
+}
+
+
+#if UINT_MAX != ULONG_MAX
+SWIGINTERN int
+  SWIG_AsVal_unsigned_SS_int(PyObject *obj, unsigned int *val)
+{ 
+  const char* errmsg = val ? "unsigned int" : (char*)0;
+  unsigned long v;
+  if (SWIG_AsVal_unsigned_SS_long(obj, &v)) {
+    if (SWIG_CheckUnsignedLongInRange(v, INT_MAX, errmsg)) {
+      if (val) *val = (unsigned int)(v);
+      return 1;
+    }
+  } else {
+    PyErr_Clear();
+  }
+  if (val) {
+    SWIG_type_error(errmsg, obj);
+  }
+  return 0;    
+}
+#else
+SWIGINTERNINLINE unsigned int
+  SWIG_AsVal_unsigned_SS_int(PyObject *obj, unsigned int *val)
+{
+  return SWIG_AsVal_unsigned_SS_long(obj,(unsigned long *)val);
+}
+#endif
+
+  
+SWIGINTERNINLINE int
+SWIG_Check_unsigned_SS_int(PyObject* obj)
+{
+  return SWIG_AsVal_unsigned_SS_int(obj, (unsigned int*)0);
+}
+
+  
+SWIGINTERNINLINE int
+SWIG_Check_int(PyObject* obj)
+{
+  return SWIG_AsVal_int(obj, (int*)0);
+}
+
+
+SWIGINTERN PyObject*
+t_output_helper(PyObject* target, PyObject* o) {
+  if (!target) {
+    target = o;
+  } else if (target == Py_None) {  
+    Py_DECREF(target);
+    target = o;
+  } else {
+    if (!PyList_Check(target)) {
+      PyObject *o2 = target;
+      target = PyList_New(1);
+      PyList_SetItem(target, 0, o2);
+    }
+    PyList_Append(target,o);
+    Py_DECREF(o);
+    }
+  return target;
+}
+
+
+  /*@/usr/share/swig/1.3.25/python/pymacros.swg,66,SWIG_define@*/
+#define SWIG_From_int PyInt_FromLong
+/*@@*/
+
+
+SWIGINTERN char**
+  SWIG_AsArgcArgv(PyObject* input,
+		  swig_type_info* ppchar_info,
+		  size_t* argc, int* owner)
+{  
+  char **argv = 0;
+  size_t i = 0;
+  if (SWIG_ConvertPtr(input, (void **)&argv, ppchar_info, 0) == -1) {
+    PyErr_Clear();
+    int list = PyList_Check(input);
+    if (list || PyTuple_Check(input)) {
+      *argc = list ? PyList_Size(input) : PyTuple_Size(input);
+      argv = ((char**) malloc((*argc + 1)*sizeof(char*)));
+      *owner = 1;
+      for (; i < *argc; ++i) {
+	PyObject *obj = list ? PyList_GetItem(input,i) : PyTuple_GetItem(input,i);
+	if (!SWIG_AsCharPtr(obj, &(argv[i]))) {
+	  PyErr_Clear();
+	  PyErr_SetString(PyExc_TypeError,"list or tuple must contain strings only");
+	}
+      }
+      argv[i] = 0;
+      return argv;
+    } else {
+      *argc = 0;
+      PyErr_SetString(PyExc_TypeError,"a list or tuple is expected");
+      return 0;
+    }
+  } else {
+    /* seems dangerous, but the user asked for it... */
+    while (argv[i] != 0) ++i;
+    *argc = i;
+    owner = 0;
+    return argv;
+  }
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+static PyObject *_wrap_xd3_encode_memory(PyObject *self, PyObject *args) {
+    PyObject *resultobj = NULL;
+    char *arg1 = (char *) 0 ;
+    unsigned int arg2 ;
+    char *arg3 = (char *) 0 ;
+    unsigned int arg4 ;
+    char *arg5 = (char *) 0 ;
+    unsigned int *arg6 = (unsigned int *) 0 ;
+    unsigned int arg7 ;
+    int arg8 ;
+    int result;
+    char *buf1 ;
+    size_t size1 ;
+    char *buf3 ;
+    size_t size3 ;
+    unsigned int alloc_size7 ;
+    PyObject * obj0 = 0 ;
+    PyObject * obj1 = 0 ;
+    PyObject * obj2 = 0 ;
+    PyObject * obj3 = 0 ;
+    
+    {
+        arg8 = 0;
+    }
+    {
+        
+    }
+    if(!PyArg_ParseTuple(args,(char *)"OOO|O:xd3_encode_memory",&obj0,&obj1,&obj2,&obj3)) goto fail;
+    {
+        int res = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1);
+        if (!res) {
+            SWIG_arg_fail(1);SWIG_fail;
+        }
+        arg1 = (char *) buf1;
+        arg2 = (unsigned int) size1 - 1;
+    }
+    {
+        int res = SWIG_AsCharPtrAndSize(obj1, &buf3, &size3);
+        if (!res) {
+            SWIG_arg_fail(3);SWIG_fail;
+        }
+        arg3 = (char *) buf3;
+        arg4 = (unsigned int) size3 - 1;
+    }
+    {
+        arg7 = alloc_size7 = PyInt_AsLong(obj2);
+    }
+    if (obj3) {
+        {
+            arg8 = (int)(SWIG_As_int(obj3)); 
+            if (SWIG_arg_fail(8)) SWIG_fail;
+        }
+    }
+    {
+        // alloc_size input is #7th position in xd3_xxcode_memory()
+        arg5 = malloc(alloc_size7);
+        arg6 = &alloc_size7;
+    }
+    result = (int)xd3_encode_memory((char const *)arg1,arg2,(char const *)arg3,arg4,arg5,arg6,arg7,arg8);
+    
+    {
+        resultobj = SWIG_From_int((int)(result)); 
+    }
+    {
+        if (result == 0) {
+            PyObject *o;
+            // alloc_size7 now carries actual size
+            o = PyString_FromStringAndSize(arg5,alloc_size7);
+            resultobj = t_output_helper(resultobj,o);
+        } else {
+            resultobj = t_output_helper(resultobj,Py_None);
+        }
+        free(arg5);
+    }
+    return resultobj;
+    fail:
+    return NULL;
+}
+
+
+static PyObject *_wrap_xd3_decode_memory(PyObject *self, PyObject *args) {
+    PyObject *resultobj = NULL;
+    char *arg1 = (char *) 0 ;
+    unsigned int arg2 ;
+    char *arg3 = (char *) 0 ;
+    unsigned int arg4 ;
+    char *arg5 = (char *) 0 ;
+    unsigned int *arg6 = (unsigned int *) 0 ;
+    unsigned int arg7 ;
+    int arg8 ;
+    int result;
+    char *buf1 ;
+    size_t size1 ;
+    char *buf3 ;
+    size_t size3 ;
+    unsigned int alloc_size7 ;
+    PyObject * obj0 = 0 ;
+    PyObject * obj1 = 0 ;
+    PyObject * obj2 = 0 ;
+    PyObject * obj3 = 0 ;
+    
+    {
+        arg8 = 0;
+    }
+    {
+        
+    }
+    if(!PyArg_ParseTuple(args,(char *)"OOO|O:xd3_decode_memory",&obj0,&obj1,&obj2,&obj3)) goto fail;
+    {
+        int res = SWIG_AsCharPtrAndSize(obj0, &buf1, &size1);
+        if (!res) {
+            SWIG_arg_fail(1);SWIG_fail;
+        }
+        arg1 = (char *) buf1;
+        arg2 = (unsigned int) size1 - 1;
+    }
+    {
+        int res = SWIG_AsCharPtrAndSize(obj1, &buf3, &size3);
+        if (!res) {
+            SWIG_arg_fail(3);SWIG_fail;
+        }
+        arg3 = (char *) buf3;
+        arg4 = (unsigned int) size3 - 1;
+    }
+    {
+        arg7 = alloc_size7 = PyInt_AsLong(obj2);
+    }
+    if (obj3) {
+        {
+            arg8 = (int)(SWIG_As_int(obj3)); 
+            if (SWIG_arg_fail(8)) SWIG_fail;
+        }
+    }
+    {
+        // alloc_size input is #7th position in xd3_xxcode_memory()
+        arg5 = malloc(alloc_size7);
+        arg6 = &alloc_size7;
+    }
+    result = (int)xd3_decode_memory((char const *)arg1,arg2,(char const *)arg3,arg4,arg5,arg6,arg7,arg8);
+    
+    {
+        resultobj = SWIG_From_int((int)(result)); 
+    }
+    {
+        if (result == 0) {
+            PyObject *o;
+            // alloc_size7 now carries actual size
+            o = PyString_FromStringAndSize(arg5,alloc_size7);
+            resultobj = t_output_helper(resultobj,o);
+        } else {
+            resultobj = t_output_helper(resultobj,Py_None);
+        }
+        free(arg5);
+    }
+    return resultobj;
+    fail:
+    return NULL;
+}
+
+
+static PyObject *_wrap_xd3_main_cmdline(PyObject *self, PyObject *args) {
+    PyObject *resultobj = NULL;
+    int arg1 ;
+    char **arg2 = (char **) 0 ;
+    int result;
+    int owner1 ;
+    PyObject * obj0 = 0 ;
+    
+    if(!PyArg_ParseTuple(args,(char *)"O:xd3_main_cmdline",&obj0)) goto fail;
+    {
+        size_t argc = 0;
+        char **argv = SWIG_AsArgcArgv(obj0, SWIGTYPE_p_p_char, &argc, &owner1);
+        if (PyErr_Occurred()) {
+            arg1 = 0; arg2 = 0;
+            if (SWIG_arg_fail(1)) SWIG_fail;
+        } else {
+            arg1 = (int) argc;
+            arg2 = (char **) argv;
+        }
+    }
+    result = (int)xd3_main_cmdline(arg1,arg2);
+    
+    {
+        resultobj = SWIG_From_int((int)(result)); 
+    }
+    {
+        if (owner1) free((char*)arg2);
+    }
+    return resultobj;
+    fail:
+    {
+        if (owner1) free((char*)arg2);
+    }
+    return NULL;
+}
+
+
+static PyMethodDef SwigMethods[] = {
+	 { (char *)"xd3_encode_memory", _wrap_xd3_encode_memory, METH_VARARGS, NULL},
+	 { (char *)"xd3_decode_memory", _wrap_xd3_decode_memory, METH_VARARGS, NULL},
+	 { (char *)"xd3_main_cmdline", _wrap_xd3_main_cmdline, METH_VARARGS, NULL},
+	 { NULL, NULL, 0, NULL }
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
+
+static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, 0};
+static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, 0};
+static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "unsigned int *", 0, 0, 0};
+static swig_type_info _swigt__ptrdiff_t = {"_ptrdiff_t", "ptrdiff_t", 0, 0, 0};
+static swig_type_info _swigt__size_t = {"_size_t", "size_t", 0, 0, 0};
+
+static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_char,
+  &_swigt__p_p_char,
+  &_swigt__p_unsigned_int,
+  &_swigt__ptrdiff_t,
+  &_swigt__size_t,
+};
+
+static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_unsigned_int[] = {  {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__ptrdiff_t[] = {  {&_swigt__ptrdiff_t, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__size_t[] = {  {&_swigt__size_t, 0, 0, 0},{0, 0, 0, 0}};
+
+static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_char,
+  _swigc__p_p_char,
+  _swigc__p_unsigned_int,
+  _swigc__ptrdiff_t,
+  _swigc__size_t,
+};
+
+
+/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
+
+static swig_const_info swig_const_table[] = {
+{0, 0, 0, 0.0, 0, 0}};
+
+#ifdef __cplusplus
+}
+#endif
+/*************************************************************************
+ * Type initialization:
+ * This problem is tough by the requirement that no dynamic 
+ * memory is used. Also, since swig_type_info structures store pointers to 
+ * swig_cast_info structures and swig_cast_info structures store pointers back
+ * to swig_type_info structures, we need some lookup code at initialization. 
+ * The idea is that swig generates all the structures that are needed. 
+ * The runtime then collects these partially filled structures. 
+ * The SWIG_InitializeModule function takes these initial arrays out of 
+ * swig_module, and does all the lookup, filling in the swig_module.types
+ * array with the correct data and linking the correct swig_cast_info
+ * structures together.
+
+ * The generated swig_type_info structures are assigned staticly to an initial 
+ * array. We just loop though that array, and handle each type individually.
+ * First we lookup if this type has been already loaded, and if so, use the
+ * loaded structure instead of the generated one. Then we have to fill in the
+ * cast linked list. The cast data is initially stored in something like a
+ * two-dimensional array. Each row corresponds to a type (there are the same
+ * number of rows as there are in the swig_type_initial array). Each entry in
+ * a column is one of the swig_cast_info structures for that type.
+ * The cast_initial array is actually an array of arrays, because each row has
+ * a variable number of columns. So to actually build the cast linked list,
+ * we find the array of casts associated with the type, and loop through it 
+ * adding the casts to the list. The one last trick we need to do is making
+ * sure the type pointer in the swig_cast_info struct is correct.
+
+ * First off, we lookup the cast->type name to see if it is already loaded. 
+ * There are three cases to handle:
+ *  1) If the cast->type has already been loaded AND the type we are adding
+ *     casting info to has not been loaded (it is in this module), THEN we
+ *     replace the cast->type pointer with the type pointer that has already
+ *     been loaded.
+ *  2) If BOTH types (the one we are adding casting info to, and the 
+ *     cast->type) are loaded, THEN the cast info has already been loaded by
+ *     the previous module so we just ignore it.
+ *  3) Finally, if cast->type has not already been loaded, then we add that
+ *     swig_cast_info to the linked list (because the cast->type) pointer will
+ *     be correct.
+**/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+    SWIGRUNTIME void
+    SWIG_InitializeModule(void *clientdata) {
+        swig_type_info *type, *ret;
+        swig_cast_info *cast;
+        size_t i;
+        swig_module_info *module_head;
+        static int init_run = 0;
+        
+        clientdata = clientdata;
+        
+        if (init_run) return;
+        init_run = 1;
+        
+        /* Initialize the swig_module */
+        swig_module.type_initial = swig_type_initial;
+        swig_module.cast_initial = swig_cast_initial;
+        
+        /* Try and load any already created modules */
+        module_head = SWIG_GetModule(clientdata);
+        if (module_head) {
+            swig_module.next = module_head->next;
+            module_head->next = &swig_module;
+        } else {
+            /* This is the first module loaded */
+            swig_module.next = &swig_module;
+            SWIG_SetModule(clientdata, &swig_module);
+        }
+        
+        /* Now work on filling in swig_module.types */
+        for (i = 0; i < swig_module.size; ++i) {
+            type = 0;
+            
+            /* if there is another module already loaded */
+            if (swig_module.next != &swig_module) {
+                type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name);
+            }
+            if (type) {
+                /* Overwrite clientdata field */
+                if (swig_module.type_initial[i]->clientdata) type->clientdata = swig_module.type_initial[i]->clientdata;
+            } else {
+                type = swig_module.type_initial[i];
+            }
+            
+            /* Insert casting types */
+            cast = swig_module.cast_initial[i];
+            while (cast->type) {
+                /* Don't need to add information already in the list */
+                ret = 0;
+                if (swig_module.next != &swig_module) {
+                    ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name);
+                }
+                if (ret && type == swig_module.type_initial[i]) {
+                    cast->type = ret;
+                    ret = 0;
+                }
+                
+                if (!ret) {
+                    if (type->cast) {
+                        type->cast->prev = cast;
+                        cast->next = type->cast;
+                    }
+                    type->cast = cast;
+                }
+                
+                cast++;
+            }
+            
+            /* Set entry in modules->types array equal to the type */
+            swig_module.types[i] = type;
+        }
+    }
+    
+    /* This function will propagate the clientdata field of type to
+    * any new swig_type_info structures that have been added into the list
+    * of equivalent types.  It is like calling
+    * SWIG_TypeClientData(type, clientdata) a second time.
+    */
+    SWIGRUNTIME void
+    SWIG_PropagateClientData(void) {
+        size_t i;
+        swig_cast_info *equiv;
+        static int init_run = 0;
+        
+        if (init_run) return;
+        init_run = 1;
+        
+        for (i = 0; i < swig_module.size; i++) {
+            if (swig_module.types[i]->clientdata) {
+                equiv = swig_module.types[i]->cast;
+                while (equiv) {
+                    if (!equiv->converter) {
+                        if (equiv->type && !equiv->type->clientdata)
+                        SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata);
+                    }
+                    equiv = equiv->next;
+                }
+            }
+        }
+    }
+    
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+    /* Python-specific SWIG API */
+#define SWIG_newvarlink()                             SWIG_Python_newvarlink()
+#define SWIG_addvarlink(p, name, get_attr, set_attr)  SWIG_Python_addvarlink(p, name, get_attr, set_attr)
+#define SWIG_InstallConstants(d, constants)           SWIG_Python_InstallConstants(d, constants)
+    
+    /* -----------------------------------------------------------------------------
+     * global variable support code.
+     * ----------------------------------------------------------------------------- */
+    
+    typedef struct swig_globalvar {
+        char       *name;                  /* Name of global variable */
+        PyObject *(*get_attr)(void);       /* Return the current value */
+        int       (*set_attr)(PyObject *); /* Set the value */
+        struct swig_globalvar *next;
+    } swig_globalvar;
+    
+    typedef struct swig_varlinkobject {
+        PyObject_HEAD
+        swig_globalvar *vars;
+    } swig_varlinkobject;
+    
+    SWIGINTERN PyObject *
+    swig_varlink_repr(swig_varlinkobject *v) {
+        v = v;
+        return PyString_FromString("<Swig global variables>");
+    }
+    
+    SWIGINTERN int
+    swig_varlink_print(swig_varlinkobject *v, FILE *fp, int flags) {
+        swig_globalvar  *var;
+        flags = flags;
+        fprintf(fp,"Swig global variables { ");
+        for (var = v->vars; var; var=var->next) {
+            fprintf(fp,"%s", var->name);
+            if (var->next) fprintf(fp,", ");
+        }
+        fprintf(fp," }\n");
+        return 0;
+    }
+    
+    SWIGINTERN PyObject *
+    swig_varlink_getattr(swig_varlinkobject *v, char *n) {
+        swig_globalvar *var = v->vars;
+        while (var) {
+            if (strcmp(var->name,n) == 0) {
+                return (*var->get_attr)();
+            }
+            var = var->next;
+        }
+        PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+        return NULL;
+    }
+    
+    SWIGINTERN int
+    swig_varlink_setattr(swig_varlinkobject *v, char *n, PyObject *p) {
+        swig_globalvar *var = v->vars;
+        while (var) {
+            if (strcmp(var->name,n) == 0) {
+                return (*var->set_attr)(p);
+            }
+            var = var->next;
+        }
+        PyErr_SetString(PyExc_NameError,"Unknown C global variable");
+        return 1;
+    }
+    
+    SWIGINTERN PyTypeObject*
+    swig_varlink_type(void) {
+        static char varlink__doc__[] = "Swig var link object";
+        static PyTypeObject varlink_type
+#if !defined(__cplusplus)
+        ;
+        static int type_init = 0;  
+        if (!type_init) {
+            PyTypeObject tmp
+#endif
+            = {
+                PyObject_HEAD_INIT(&PyType_Type)
+                0,                                  /* Number of items in variable part (ob_size) */
+                (char *)"swigvarlink",              /* Type name (tp_name) */
+                sizeof(swig_varlinkobject),         /* Basic size (tp_basicsize) */
+                0,                                  /* Itemsize (tp_itemsize) */
+                0,                                  /* Deallocator (tp_dealloc) */ 
+                (printfunc) swig_varlink_print,     /* Print (tp_print) */
+                (getattrfunc) swig_varlink_getattr, /* get attr (tp_getattr) */
+                (setattrfunc) swig_varlink_setattr, /* Set attr (tp_setattr) */
+                0,                                  /* tp_compare */
+                (reprfunc) swig_varlink_repr,       /* tp_repr */
+                0,                                  /* tp_as_number */
+                0,                                  /* tp_as_sequence */
+                0,                                  /* tp_as_mapping */
+                0,                                  /* tp_hash */
+                0,                                  /* tp_call */
+                0,                                  /* tp_str */
+                0,                                  /* tp_getattro */
+                0,                                  /* tp_setattro */
+                0,                                  /* tp_as_buffer */
+                0,                                  /* tp_flags */
+                varlink__doc__,                     /* tp_doc */
+#if PY_VERSION_HEX >= 0x02000000
+                0,                                  /* tp_traverse */
+                0,                                  /* tp_clear */
+#endif
+#if PY_VERSION_HEX >= 0x02010000
+                0,                                  /* tp_richcompare */
+                0,                                  /* tp_weaklistoffset */
+#endif
+#if PY_VERSION_HEX >= 0x02020000
+                0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_iter -> tp_weaklist */
+#endif
+#if PY_VERSION_HEX >= 0x02030000
+                0,                                  /* tp_del */
+#endif
+#ifdef COUNT_ALLOCS
+                0,0,0,0                             /* tp_alloc -> tp_next */
+#endif
+            };
+#if !defined(__cplusplus)
+            varlink_type = tmp;
+            type_init = 1;
+        }
+#endif
+        return &varlink_type;
+    }
+    
+    /* Create a variable linking object for use later */
+    SWIGINTERN PyObject *
+    SWIG_Python_newvarlink(void) {
+        swig_varlinkobject *result = PyObject_NEW(swig_varlinkobject, swig_varlink_type());
+        if (result) {
+            result->vars = 0;
+        }
+        return ((PyObject*) result);
+    }
+    
+    SWIGINTERN void 
+    SWIG_Python_addvarlink(PyObject *p, char *name, PyObject *(*get_attr)(void), int (*set_attr)(PyObject *p)) {
+        swig_varlinkobject *v = (swig_varlinkobject *) p;
+        swig_globalvar *gv = (swig_globalvar *) malloc(sizeof(swig_globalvar));
+        if (gv) {
+            size_t size = strlen(name)+1;
+            gv->name = (char *)malloc(size);
+            if (gv->name) {
+                strncpy(gv->name,name,size);
+                gv->get_attr = get_attr;
+                gv->set_attr = set_attr;
+                gv->next = v->vars;
+            }
+        }
+        v->vars = gv;
+    }
+    
+    /* -----------------------------------------------------------------------------
+     * constants/methods manipulation
+     * ----------------------------------------------------------------------------- */
+    
+    /* Install Constants */
+    SWIGINTERN void
+    SWIG_Python_InstallConstants(PyObject *d, swig_const_info constants[]) {
+        PyObject *obj = 0;
+        size_t i;
+        for (i = 0; constants[i].type; ++i) {
+            switch(constants[i].type) {
+                case SWIG_PY_INT:
+                obj = PyInt_FromLong(constants[i].lvalue);
+                break;
+                case SWIG_PY_FLOAT:
+                obj = PyFloat_FromDouble(constants[i].dvalue);
+                break;
+                case SWIG_PY_STRING:
+                if (constants[i].pvalue) {
+                    obj = PyString_FromString((char *) constants[i].pvalue);
+                } else {
+                    Py_INCREF(Py_None);
+                    obj = Py_None;
+                }
+                break;
+                case SWIG_PY_POINTER:
+                obj = SWIG_NewPointerObj(constants[i].pvalue, *(constants[i]).ptype,0);
+                break;
+                case SWIG_PY_BINARY:
+                obj = SWIG_NewPackedObj(constants[i].pvalue, constants[i].lvalue, *(constants[i].ptype));
+                break;
+                default:
+                obj = 0;
+                break;
+            }
+            if (obj) {
+                PyDict_SetItemString(d,constants[i].name,obj);
+                Py_DECREF(obj);
+            }
+        }
+    }
+    
+    /* -----------------------------------------------------------------------------*/
+    /* Fix SwigMethods to carry the callback ptrs when needed */
+    /* -----------------------------------------------------------------------------*/
+    
+    SWIGINTERN void
+    SWIG_Python_FixMethods(PyMethodDef *methods,
+    swig_const_info *const_table,
+    swig_type_info **types,
+    swig_type_info **types_initial) {
+        size_t i;
+        for (i = 0; methods[i].ml_name; ++i) {
+            char *c = methods[i].ml_doc;
+            if (c && (c = strstr(c, "swig_ptr: "))) {
+                int j;
+                swig_const_info *ci = 0;
+                char *name = c + 10;
+                for (j = 0; const_table[j].type; ++j) {
+                    if (strncmp(const_table[j].name, name, 
+                    strlen(const_table[j].name)) == 0) {
+                        ci = &(const_table[j]);
+                        break;
+                    }
+                }
+                if (ci) {
+                    size_t shift = (ci->ptype) - types;
+                    swig_type_info *ty = types_initial[shift];
+                    size_t ldoc = (c - methods[i].ml_doc);
+                    size_t lptr = strlen(ty->name)+2*sizeof(void*)+2;
+                    char *ndoc = (char*)malloc(ldoc + lptr + 10);
+                    if (ndoc) {
+                        char *buff = ndoc;
+                        void *ptr = (ci->type == SWIG_PY_POINTER) ? ci->pvalue : 0;
+                        if (ptr) {
+                            strncpy(buff, methods[i].ml_doc, ldoc);
+                            buff += ldoc;
+                            strncpy(buff, "swig_ptr: ", 10);
+                            buff += 10;
+                            SWIG_PackVoidPtr(buff, ptr, ty->name, lptr);
+                            methods[i].ml_doc = ndoc;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    /* -----------------------------------------------------------------------------*
+     *  Initialize type list
+     * -----------------------------------------------------------------------------*/
+    
+#if PY_MAJOR_VERSION < 2
+    /* PyModule_AddObject function was introduced in Python 2.0.  The following function
+    is copied out of Python/modsupport.c in python version 2.3.4 */
+    SWIGINTERN int
+    PyModule_AddObject(PyObject *m, char *name, PyObject *o)
+    {
+        PyObject *dict;
+        if (!PyModule_Check(m)) {
+            PyErr_SetString(PyExc_TypeError,
+            "PyModule_AddObject() needs module as first arg");
+            return -1;
+        }
+        if (!o) {
+            PyErr_SetString(PyExc_TypeError,
+            "PyModule_AddObject() needs non-NULL value");
+            return -1;
+        }
+        
+        dict = PyModule_GetDict(m);
+        if (dict == NULL) {
+            /* Internal error -- modules must have a dict! */
+            PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__",
+            PyModule_GetName(m));
+            return -1;
+        }
+        if (PyDict_SetItemString(dict, name, o))
+        return -1;
+        Py_DECREF(o);
+        return 0;
+    }
+#endif
+    
+#ifdef __cplusplus
+}
+#endif
+
+/* -----------------------------------------------------------------------------*
+ *  Partial Init method
+ * -----------------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C"
+#endif
+SWIGEXPORT void SWIG_init(void) {
+    static PyObject *SWIG_globals = 0; 
+    PyObject *m, *d;
+    if (!SWIG_globals) SWIG_globals = SWIG_newvarlink();
+    
+    /* Fix SwigMethods to carry the callback ptrs when needed */
+    SWIG_Python_FixMethods(SwigMethods, swig_const_table, swig_types, swig_type_initial);
+    
+    m = Py_InitModule((char *) SWIG_name, SwigMethods);
+    d = PyModule_GetDict(m);
+    
+    SWIG_InitializeModule(0);
+    SWIG_InstallConstants(d,swig_const_table);
+    
+    {
+        PyDict_SetItemString(d,"XD3_SEC_DJW", SWIG_From_int((int)(XD3_SEC_DJW))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_SEC_FGK", SWIG_From_int((int)(XD3_SEC_FGK))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_SEC_NODATA", SWIG_From_int((int)(XD3_SEC_NODATA))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_SEC_NOINST", SWIG_From_int((int)(XD3_SEC_NOINST))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_SEC_NOADDR", SWIG_From_int((int)(XD3_SEC_NOADDR))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_ADLER32", SWIG_From_int((int)(XD3_ADLER32))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_ADLER32_NOVER", SWIG_From_int((int)(XD3_ADLER32_NOVER))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_ALT_CODE_TABLE", SWIG_From_int((int)(XD3_ALT_CODE_TABLE))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_NOCOMPRESS", SWIG_From_int((int)(XD3_NOCOMPRESS))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_BEGREEDY", SWIG_From_int((int)(XD3_BEGREEDY))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_SHIFT", SWIG_From_int((int)(XD3_COMPLEVEL_SHIFT))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_MASK", SWIG_From_int((int)(XD3_COMPLEVEL_MASK))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_1", SWIG_From_int((int)(XD3_COMPLEVEL_1))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_3", SWIG_From_int((int)(XD3_COMPLEVEL_3))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_6", SWIG_From_int((int)(XD3_COMPLEVEL_6))); 
+    }
+    {
+        PyDict_SetItemString(d,"XD3_COMPLEVEL_9", SWIG_From_int((int)(XD3_COMPLEVEL_9))); 
+    }
+}
+
Index: /nikanabo/current/xdelta/linuxdiy.sh
===================================================================
--- /nikanabo/current/xdelta/linuxdiy.sh	(revision 185)
+++ /nikanabo/current/xdelta/linuxdiy.sh	(revision 185)
@@ -0,0 +1,5 @@
+#!/bin/sh
+cd diy
+make all
+cd ..
+cp diy/xdelta3.exe .
Index: /nikanabo/current/xdelta/macintel.sh
===================================================================
--- /nikanabo/current/xdelta/macintel.sh	(revision 185)
+++ /nikanabo/current/xdelta/macintel.sh	(revision 185)
@@ -0,0 +1,2 @@
+#!/bin/sh
+cp i386/xdelta3.exe .
Index: /nikanabo/current/xdelta/macpowpc.sh
===================================================================
--- /nikanabo/current/xdelta/macpowpc.sh	(revision 185)
+++ /nikanabo/current/xdelta/macpowpc.sh	(revision 185)
@@ -0,0 +1,2 @@
+#!/bin/sh
+cp ppc/xdelta3.exe .
Index: /nikanabo/current/xdelta/pcwin32.bat
===================================================================
--- /nikanabo/current/xdelta/pcwin32.bat	(revision 185)
+++ /nikanabo/current/xdelta/pcwin32.bat	(revision 185)
@@ -0,0 +1,2 @@
+echo off
+copy win32\xdelta3.exe .
Index: /nikanabo/current/xdelta/readme.txt
===================================================================
--- /nikanabo/current/xdelta/readme.txt	(revision 185)
+++ /nikanabo/current/xdelta/readme.txt	(revision 185)
@@ -0,0 +1,19 @@
+Xdelta is a popular binary diff-patcher.
+
+It's a reasonable alternative to OUP 
+as long as the patched version is known 
+by the modder (e.g., the Mac or PC demo)
+
+Before you can install a binary mod 
+(that relies on xdelta for installation)
+you'll have to set up Xdelta here.
+
+Please run the installer for your platform:
+	pcwin32.bat	Windows
+	macintel.sh	Intel Mac
+	macpowpc.sh	Power PC Mac
+	linuxdiy.sh	Do It Yourself ^^
+
+The result of the installation is that 
+xdelta3.exe will appear in this folder.
+(It will be called when installing mods)
