--Scripts

--Scripts give event and time based control over all the objects and their properties in the 3d world. The 3d world is build from a set of objects. The main ones are models, shaders, textures, lights and cameras. Each of these objects has a set of properties. A position in space of a model, the diffuse color of a shader or the yon of a camera are all examples of properties. The 3d world is controlled by changing the value of these properties over time. Scripts give you the control to change the value of any property of any object when a specified event occurs. Not only that it can trigger a sequence of value changes over time. Or in other words animate the value of a property over time. For even more control states can be assigned to trigger different events based on the value of a state variable. There are three types of events. The first are predefined events that occur according to the state the world is in. For example the event for when the world becomes active is #on_enter_world. Secondly there are predefined events that work together with trigger models. For example the #on_collide_with_trigger event is executed when the camera collides with the trigger model. Lastly the user can define their own custom events that are triggered, with or without conditional states, by other events.  
--As a bonus scripts give not only full access to all properties of the 3dsprite but to all sprites and members (#sprite, #member). Sprites and members can be created from scratch, giving the potential of expanding the functionality of the frontend itself!


--Notes:

--List any number of scripts <script>, containing any number of events <event>, containing any number of segments <segment>.
--For events that are used to set one property once it is not necessary to specify a <segments></segments> section. I.e. with a values list with just one element that is just executed once.
--For events that are only used to evaluate states and set no values themselves the object_target, object_type, object_property and object_value properties do not have to be specified.
--If no target objects (object_target|[list]|) are specified in an event the script will look for target objects specified as the first item of <script>. If still no target is found then the target specified in the arcadecfg will be used. Keeping the targets out of <events> and <script> opens the possibility for re-usable scripts.
--The on_event_end property is optional. And can be overridden by state comparisons.
--The state properties and <states></states> section are optional.


--Event notes:

--predefined world events:
--#on_setup_world: The events of this type are executed before the 3d world becomes visible and continues with the fe while these events play.
--#on_enter_world: The events of this type are executed when the 3d world becomes visible and continues with the fe while these events play.
--#on_leave_world: The events of this type are executed when the 3d world becomes invisible and continues with the fe while these events play.
--#on_cleanup_world: The events of this type are executed before the 3d world is unloaded and continues with the fe while these events play.

--predefined events with trigger models:
--#on_focus_trigger: The events of this type are executed when the trigger model is selected and continues with the fe while these events play.
--#on_select_trigger: The events of this type are executed when the trigger model is selected and the start key is pressed (or mouse double-click) and continues with the fe while these events play.
--#on_collide_with_trigger: The events of this type are executed when the camera collides with the trigger model and continues with the fe while these events play.
--#on_over_trigger: The events of this type are executed when the trigger model is below the camera position and continues with the fe while these events play.

--custom event types:
--You can define your own events that are triggered by other events when they finish with the on_event_end|#newevent| property. Optionally conditional states can be assigned to trigger different on_event_end events depending on the state of the condition.

--the _wait extension of event names:
--Add _wait to any predefined event name will wait until all the events of this type have been finished. For example #on_setup_world_wait.

--event state notes:
--States can be assigned to trigger different events based on the value of a state variable. For example create a variable (state_variable) named lightswitch that has two states #on and #of. When a trigger model is selected with and #on_select_trigger event the script can then compare, with state_compare, if the state is #on or #of. See also example 1 (light switch) and 3 (basic elevator).


--Advanced notes (Ignore this to save yourself a headache ;)):
--Normally the object_value list changes an objects property value over time. It also possible to use the value list to set a lot of properties in one go. Ideal for initializing stuff. Two options:
--1. When object_property contains a list it's assumed that each element in the object_property list correspondents with the value at the same position in the object_value list.
--2. When object_type contains also a list. Then its assumed that the list items in object_target, object_type, object_property and object_value all correspond to each other directly.


--Shortcut notes:
--#game, any gamelist model triggers the event
--#xtra, any xtra model triggers the event
--#all = #game + #xtra


--Syntax notes:
object_type, object_property and object_value all use the exact lingo syntax with a few exceptions. For object_property the exception is that the sub properties dot syntax is replaced by _.  For example in lingo's transform.position becomes #transform_position. For object_value the pointat syntax needs an additional rotation x,y,z to work properly. See example 2.


--Additional functionality:
--To make life easier some common fe functions can be directly accessed by script. Functions that are not directly associated with existing objects are organized into a custom object called #generic:
--For object type #model these functions are #bone_animation, #create_model, #load_model, #remove_model
--#boneanimation, object_value|[[modelname, animation], etc.]| --see example 6
--#create_model, object_value|[[#modeltype, [list with options]], etc.]| --valid modeltypes are #plane, #box, #cylinder, #sphere, #cone and #particle
--#load_model, object_value|[tfolder, etc.]| --tfolder accepts @ as fe path. specify the name of the model to load in object_target
--#remove_model, object_value|[#dummy, etc.]| --the model specified in object_target will be removed from the world
--For object type #generic these functions are #do, #state_save More to come ;)
--#do, object_value|[[lingo string 1, lingo string 2, lingo string 3], etc.]| --execute any lingo code you want
--#state_save, object_value|[[variable_name, variable_value, etc.]| --create and change the value of state variables. see example 8


--Examples:

--1. Light switch
--2. Model looks always at the camera position
--3. Basic elevator behavior
--4. Texture transform animation
--5. Collide with example
--6. Trigger bone animation on another model
--7. Change the bithdepth of the glass reflection map from 16bit to 24bit to make it smoother
--8. Create a plane model in the upper left corner of the 3d world and show on it the marquee of the model that is in focus.
--7. Ride pinky :) (not yet)


--1. Light switch:

<script> --switch a light on and of with a button. The blend of one shader of the button is set to 50% when the light is on. And back to 100% when the light is off.

object_target|["my_light_1"]|  --optional, overrides arcade cfg setting


	<events>

		<event> --on setup world make sure the light is off and the state variable #mylight is defined.

		event_name|#on_setup_world_wait|		
		on_event_end|#set_light_color_to_red| --next make the light red

		state_variable|#my_light_1| --setup a variable to keep track of the state of the target light(s)
		state_event_start|#busy|
		state_event_end|#busy|

		object_type|#light| --event object; #shader, #model, #light, #texture, #camera, #modelresource, #sprite, #member or #generic
		object_property|#newlight| --property of the object to change
		object_value|[#spot]| --list of values to change a property over time. If a value contains more then one item, its also a list. ie [[1,2],[2,1], etc.]

		</event>

		<event> --make it red and then turn it off

		event_name|#set_light_color_to_red|		
		on_event_end|#turn_light_off| --next turn the light it off

		object_type|#light| --event object; #shader, #model, #light, #texture, #camera, #modelresource, #sprite, #member or #generic
		object_property|#color| --property of the object to change
		object_value|[rgb(255,0,0)]|

		</event>

		<event> --on select "button_lightswitch" turn the light off or on depending of the current state of the light

		event_name|#on_select_trigger| 
		event_trigger|"fpsxtramodel2"| --name of the model that triggers this event.

		state_variable|#my_light_1|
		state_event_start|#busy|
		state_event_end|#busy|

			<states>
				<state>
				state_compare|#on|
				on_event_end|#turn_light_off|		
				</state>

				<state>
				state_compare|#off|
				on_event_end|#turn_light_on|		
				</state>
			</states>

		</event>
		
		<event> --turn the light on and set the state variable #lightswitch to #on

		event_name|#turn_light_on| --event type; #load, #select, #start, #collide, #below or create your own to respond to fpsxtramodel arctrigger or		
		on_event_end|#blend_50|

		state_variable|#my_light_1|
		state_event_start|#busy|
		state_event_end|#on|

		object_type|#light| --event object; #shader, #model, #light, #texture or #camera
		object_property|#parent| --property of the object to change
		object_value|[scene.group("world")]|

		</event>

		<event> 

		event_name|#blend_50|		

		object_target|["prop-box-sides"]|
		object_type|#shader|
		object_property|#blend|
		object_value|[50]|
		
		</event>

		<event> --turn the light off and set the state variable #lightswitch to #off

		event_name|#turn_light_off|	
		on_event_end|#blend_100|

		state_variable|#my_light_1|
		state_event_start|#busy|
		state_event_end|#off|

		object_type|#light|
		object_property|#parent| --property of the object to change
		object_value|[0]|
		
		</event>

		<event> 

		event_name|#blend_100|		

		object_target|["prop-box-sides"]|
		object_type|#shader|
		object_property|#blend|
		object_value|[100]|
		
		</event>

		<event> --on cleanup world make sure the light is deleted.

		event_name|#on_cleanup_world_wait|		

		state_variable|#my_light_1| --setup a variable to keep track of the state of the target light(s)
		state_event_start|#busy|
		state_event_end|#busy|

		object_type|#light| --event object; #shader, #model, #light, #texture or #camera
		object_property|#deletelight| --property of the object to change
		object_value|[#dummy]| --list of values to change a property over time.

		</event>

	</events>

</script>


--2. Model looks always at the camera position

<script> --using point at gamelist model "cabn13" (=gamelist postion 4) always looks towards the camera position...scary...big cab is watching you ;)

object_target|["cabn13"]|  --optional, overrides arcade cfg setting

	<events>

		<event> 

		event_name|#on_enter_world| 
	
		object_type|#model|
		object_property|#pointat| 
		object_value|[[scene.model("mycyl"),0,-90,0,90,0,0]]|

		segment_order|#sequentional|
		segment_position|1|

   			<segments>
			
    				<segment>
				start|1|
				end|1|
				position|1|
				loop|0|
				frequency|100|
        			</segment>

			</segments>

		</event>

	</events>

</script>


--3. Basic elevator behavior

<script> --basic elevator behavior

object_target|["fpsxtramodel5"]|  --optional, overrides arcade cfg setting

	<events>

		<event> 

		event_name|#on_setup_world_wait|		

		state_variable|#elevator1|
		state_event_start|#busy|
		state_event_end|#down|

		</event>

		<event> 

		event_name|#on_select_trigger| 
		event_trigger|"fpsxtramodel3"| --name of the model that triggers this event.
		--on_event_end||

		state_variable|#elevator1|
		--state_event_start|#busy|
		--state_event_end|#busy|

			<states>
				<state>
				state_compare|#up|
				on_event_end|#move_elevator_down|		
				</state>
			</states>

		</event>

		<event> 

		event_name|#on_select_trigger| 
		event_trigger|"fpsxtramodel4"| --name of the model that triggers this event.
		--on_event_end||

		state_variable|#elevator1|
		state_event_start|#busy|
		state_event_end|#busy|

			<states>
				<state>
				state_compare|#down|
				on_event_end|#move_elevator_up|		
				</state>
			</states>

		</event>

		<event> 

		event_name|#move_elevator_down|		

		state_variable|#elevator1|
		state_event_start|#busy|
		state_event_end|#down|

		object_type|#model|
		object_property|#translate| --property of the object to change
		object_value|[[0,0,-5,#self]]|
		
		segment_order|#sequentional_once|
		segment_position|1|

   			<segments>
			
    				<segment>
				start|1|
				end|1|
				position|1|
				loop|20|
				frequency|10|
        			</segment>

			</segments>

		</event>

		<event> 

		event_name|#move_elevator_up|

		state_variable|#elevator1|
		state_event_start|#busy|
		state_event_end|#up|

		object_type|#model|
		object_property|#translate| --property of the object to change
		object_value|[[0,0,5,#self]]|
		
		segment_order|#sequentional_once|
		segment_position|1|

   			<segments>
			
    				<segment>
				start|1|
				end|1|
				position|1|
				loop|20|
				frequency|10|
        			</segment>

			</segments>

		</event>

	</events>

</script>


--4. Texture transform animation

<script> --move texture layer 1 of shaders listed in the target property in 16 steps

object_target|["ANIM_TESTshader1", "shd1cabn13"]|  --optional, overrides arcade cfg setting

	<events>

		<event> 

		event_name|#on_enter_world|

		object_type|#shader|
		object_layer|1| --only required for event object #shader and background and overlays of the #camera object
		object_property|#texturetransformlist_position| --property of the object to change
		object_value|[vector(0,0,0),vector(0,0.0625,0),vector(0,0.125,0),vector(0,0.1875,0),vector(0,0.25,0),vector(0,0.3125,0),vector(0,0.375,0),vector(0,0.4375,0),vector(0,0.5,0),vector(0,0.5625,0),vector(0,0.625,0),vector(0,0.6875,0),vector(0,0.75,0),vector(0,0.8125,0),vector(0,0.875,0),vector(0,0.9375,0)]|
		
		segment_order|#sequentional|
		segment_position|1|

   			<segments>
			
    				<segment>
				start|1|
				end|7|
				position|1|
				loop|1|
				frequency|100|
        			</segment>

				<segment>
				start|8|
				end|16|
				position|8|
				loop|1|
				frequency|100|
        			</segment>

			</segments>

		</event>

	</events>

</script>


--5. Collide with example

<script>

object_target|["cabn10"]|  --optional, overrides arcade cfg setting

	<events>

		<event> 

		event_name|#on_collide_with_trigger| 
		event_trigger|"cabn10"| --cabn10 is the name of the model that represents the first gamelist entry.

		object_type|#model|
		object_property|#rotate| 
		object_value|[[0,0,10,#self]]|

		</event>

	</events>

</script>


--6. trigger bone animation on another model

<script>

object_target|["fpsxtramodel6"]|  --optional, overrides arcade cfg setting

	<events>

		<event> 

		event_name|#on_collide_with_trigger| 
		event_trigger|"fpsxtramodel6"|

		object_type|#model|
		object_property|#bone_animation| 
		object_value|[["fpsxtramodel7", #animationselect]]| --As an alternative to pointing here to a user animaton user property inside the w3d you can also specify its value as a string. 

		</event>

	</events>

</script>



7. change the bithdepth of the glass reflection map from 16bit to 24bit to make it smoother

<script>
	<events>

		<event> 

		event_name|#on_setup_world_wait| 

		object_target|["pinball_generic_glassrefmap"]|
		object_type|#texture|
		object_property|#renderformat|
		object_value|[#rgba8888]|

		</event>

	</events>
</script>


8. Create a plane model in the upper left corner of the 3d world and show on it the marquee of the model that is in focus.

<script>
	<events>

		<event> 

		event_name|#on_enter_world_wait| --create a plane model named plane_me, make the fpsarcade camera its parent, place it in the upper left corner of the viewport and assign the marquee texture of the current gamelist model to its shader.
		object_layer|1|
		object_target|["plane_1_","plane_1_","plane_1_","plane_1_shd",#generic, "plane_1_shd"]|
		object_type|[#model,#model,#model,#shader,#generic, #shader]|
		object_property|[#create_model, #parent,#transform_position,#emissive,#state_save,#texturelist]|
		object_value|[[#plane,[2.5,10.0,rgb(0,0,0)]],scene.camera("fpsarcadecam"),vector(-8,6,-18), rgb(255,255,255),[#current_marquee,"scene.model(fpscablist.getpropat(fpscablist.getpos(glistpos))).shaderlist[1].texturelist[1]"],[#state_variable, #current_marquee]]|

		</event>

		<event> 

		event_name|#on_focus_trigger_wait| 
		event_trigger|#game| --the event will be triggered when any of the gamelist models gets focus.

		object_layer|1|
		object_target|[#generic,"plane_1_shd"]|
		object_type|[#generic,#shader]|
		object_property|[#state_save,#texturelist]|
		object_value|[[#current_marquee,"scene.model(fpscablist.getpropat(fpscablist.getpos(glistpos))).shaderlist[1].texturelist[1]"],[#state_variable, #current_marquee]]|

		</event>

		<event> 

		event_name|#on_leave_world_wait| --remove the plane model and its shaders and resource
		object_layer|1|
		object_target|["plane_1_", "plane_1_shd", "plane_1_res"]|
		object_type|[#model, #shader, #modelresource]|
		object_property|[#deletemodel,#deleteshader,#deletemodelresource]|
		object_value|["plane_1_", "plane_1_shd", "plane_1_res"]|

		</event>

	</events>
</script>