2016-07-06 05:03:02 +00:00
/* User action execution handler */
// Handles actions set in editor e.g. for dialogues, switches, etc.
// An object is sometimes needed to show a menu or start a timer, so this definition is created whenever a user action is run
local Name = " UserAction " ;
local Plane = 0 ;
2016-07-21 04:22:53 +00:00
/* UserAction definition */
2016-07-06 05:03:02 +00:00
// Base classes for EditorProps using actions
local Evaluator ;
// EditorProps for generic user action callbacks
local Prop , PropProgressMode , PropParallel ;
// Base props for action execution conditions
local ActionEvaluation ;
// Proplist containing callback function. Indexed by option names.
local EvaluatorCallbacks ;
2016-07-10 18:11:23 +00:00
// Proplist containing option definitions. Indexed by option names.
local EvaluatorDefs ;
2016-07-06 05:03:02 +00:00
// Call this definition early (but after EditorBase) to allow EditorProp initialization
local DefinitionPriority = 99 ;
2016-07-30 17:21:38 +00:00
// Localized group names
local GroupNames = { Structure = " $Structure$ " } ;
2016-07-06 05:03:02 +00:00
func Definition ( def )
{
// Typed evaluator base definitions
Evaluator = { } ;
2016-07-21 04:47:43 +00:00
Evaluator . Action = { Name = " $UserAction$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $None$ " } ] } ;
Evaluator . Object = { Name = " $UserObject$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $None$ " } ] } ;
2016-07-29 05:43:35 +00:00
Evaluator . Definition = { Name = " $UserDefinition$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $None$ " } ] } ;
2016-07-21 04:47:43 +00:00
Evaluator . Player = { Name = " $UserPlayer$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $Noone$ " } ] } ;
Evaluator . PlayerList = { Name = " $UserPlayerList$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $Noone$ " } ] } ;
Evaluator . Boolean = { Name = " $UserBoolean$ " , Type = " enum " , OptionKey = " Function " , Options = [ ] } ;
2016-07-30 06:06:54 +00:00
Evaluator . Integer = { Name = " $UserInteger$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " 0 " } ] } ;
2016-07-21 04:47:43 +00:00
Evaluator . Condition = { Name = " $UserCondition$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $None$ " } ] } ;
2016-07-29 05:43:35 +00:00
Evaluator . Position = { Name = " $UserPosition$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $Here$ " } ] } ;
2016-07-30 06:06:54 +00:00
Evaluator . Offset = { Name = " $UserOffset$ " , Type = " enum " , OptionKey = " Function " , Options = [ { Name = " $None$ " } ] } ;
2016-07-06 05:03:02 +00:00
// Action evaluators
EvaluatorCallbacks = { } ;
2016-07-10 18:11:23 +00:00
EvaluatorDefs = { } ;
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Action " , " $Sequence$ " , " $Sequence$ " , " $SequenceHelp$ " , " sequence " , [ def , def . EvalAct_Sequence ] , { Actions = [ ] } , { Type = " proplist " , DescendPath = " Actions " , Display = " {{Actions}} " , EditorProps = {
2016-07-13 21:18:08 +00:00
Actions = { Name = " $Actions$ " , Type = " array " , Elements = Evaluator . Action } ,
2016-07-06 05:03:02 +00:00
} } ) ;
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Action " , " $Sequence$ " , " $Goto$ " , " $GotoHelp$ " , " goto " , [ def , def . EvalAct_Goto ] , { Index = 0 } , { Type = " proplist " , Display = " {{Index}} " , EditorProps = {
2016-07-13 21:18:08 +00:00
Index = { Name = " $Index$ " , Type = " int " , Min = 0 }
2016-07-06 05:03:02 +00:00
} } ) ;
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Action " , " $Sequence$ " , " $StopSequence$ " , " $StopSequenceHelp$ " , " stop_sequence " , [ def , def . EvalAct_StopSequence ] ) ;
AddEvaluator ( " Action " , " $Sequence$ " , " $SuspendSequence$ " , " $SuspendSequenceHelp$ " , " suspend_sequence " , [ def , def . EvalAct_SuspendSequence ] ) ;
AddEvaluator ( " Action " , " $Sequence$ " , " $Wait$ " , " $WaitHelp$ " , " wait " , [ def , def . EvalAct_Wait ] , { Time = 60 } , { Type = " proplist " , Display = " {{Time}} " , EditorProps = {
2016-07-13 21:18:08 +00:00
Time = { Name = " $Time$ " , Type = " int " , Min = 1 }
2016-07-06 05:03:02 +00:00
} } ) ;
2016-07-29 03:44:10 +00:00
AddEvaluator ( " Action " , " $Ambience$ " , " $Sound$ " , " $SoundHelp$ " , " sound " , [ def , def . EvalAct_Sound ] , { Pitch = { Function = " int_constant " , Value = 0 } , Volume = { Function = " int_constant " , Value = 100 } , TargetPlayers = { Function = " all_players " } } , { Type = " proplist " , Display = " {{Sound}} " , EditorProps = {
Sound = { Name = " $SoundName$ " , EditorHelp = " $SoundNameHelp$ " , Type = " sound " , AllowEditing = true } ,
Pitch = new Evaluator . Integer { Name = " $SoundPitch$ " , EditorHelp = " $SoundPitchHelp$ " } ,
Volume = new Evaluator . Integer { Name = " $SoundVolume$ " , EditorHelp = " $SoundVolumeHelp$ " } ,
Loop = { Name = " $SoundLoop$ " , EditorHelp = " $SoundLoopHelp$ " , Type = " enum " , Options = [
{ Name = " $SoundLoopNone$ " } ,
{ Name = " $SoundLoopOn$ " , Value = + 1 } ,
{ Name = " $SoundLoopOff$ " , Value = - 1 }
] } ,
TargetPlayers = new Evaluator . PlayerList { EditorHelp = " $SoundTargetPlayersHelp$ " } ,
SourceObject = new Evaluator . Object { Name = " $SoundSourceObject$ " , EditorHelp = " $SoundSourceObjectHelp$ " }
} } ) ;
2016-07-29 05:43:35 +00:00
AddEvaluator ( " Action " , " $Object$ " , " $CreateObject$ " , " $CreateObjectHelp$ " , " create_object " , [ def , def . EvalAct_CreateObject ] , { SpeedX = { Function = " int_constant " , Value = 0 } , SpeedY = { Function = " int_constant " , Value = 0 } } , { Type = " proplist " , Display = " {{ID}} " , EditorProps = {
ID = new Evaluator . Definition { EditorHelp = " $CreateObjectDefinitionHelp$ " } ,
Position = new Evaluator . Position { EditorHelp = " $CreateObjectPositionHelp$ " } ,
CreateAbove = { Name = " $CreateObjectCreationOffset$ " , EditorHelp = " $CreateObjectCreationOffsetHelp$ " , Type = " enum " , Options = [
{ Name = " $Center$ " } ,
{ Name = " $Bottom$ " , Value = true }
] } ,
Owner = new Evaluator . Player { Name = " $Owner$ " , EditorHelp = " $CreateObjectOwnerHelp$ " } ,
Container = new Evaluator . Object { Name = " $Container$ " , EditorHelp = " $CreateObjectContainerHelp$ " } ,
SpeedX = new Evaluator . Integer { Name = " $SpeedX$ " , EditorHelp = " $CreateObjectSpeedXHelp$ " } ,
SpeedY = new Evaluator . Integer { Name = " $SpeedY$ " , EditorHelp = " $CreateObjectSpeedYHelp$ " }
} } ) ;
2016-07-29 06:06:20 +00:00
AddEvaluator ( " Action " , " $Object$ " , " $RemoveObject$ " , " $RemoveObjectHelp$ " , " remove_object " , [ def , def . EvalAct_RemoveObject ] , { } , { Type = " proplist " , Display = " {{Object}} " , EditorProps = {
Object = new Evaluator . Object { EditorHelp = " $RemoveObjectObject$ " } ,
EjectContents = { Name = " $EjectContents$ " , EditorHelp = " $EjectContentsHelp$ " , Type = " enum " , Options = [
{ Name = " $EjectContentsNo$ " } ,
{ Name = " $EjectContentsYes$ " , Value = true }
] } ,
} } ) ;
2016-07-06 05:03:02 +00:00
// Object evaluators
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Object " , nil , " $ActionObject$ " , " $ActionObjectHelp$ " , " action_object " , [ def , def . EvalObj_ActionObject ] ) ;
AddEvaluator ( " Object " , nil , " $TriggerClonk$ " , " $TriggerClonkHelp$ " , " triggering_clonk " , [ def , def . EvalObj_TriggeringClonk ] ) ;
AddEvaluator ( " Object " , nil , " $TriggerObject$ " , " $TriggerObjectHelp$ " , " triggering_object " , [ def , def . EvalObj_TriggeringObject ] ) ;
AddEvaluator ( " Object " , nil , " $ConstantObject$ " , " $ConstantObjectHelp$ " , " object_constant " , [ def , def . EvalConstant ] , { Value = nil } , { Type = " object " , Name = " $Value$ " } ) ;
2016-07-29 05:43:35 +00:00
AddEvaluator ( " Object " , nil , " $LastCreatedObject$ " , " $LastCreatedObjectHelp$ " , " last_created_object " , [ def , def . EvalObj_LastCreatedObject ] ) ;
// Definition evaluators
AddEvaluator ( " Definition " , nil , " $Constant$ " , " $ConstantHelp$ " , " def_constant " , [ def , def . EvalConstant ] , { Value = nil } , { Type = " def " , Name = " $Value$ " } ) ;
2016-07-06 05:03:02 +00:00
// Player evaluators
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Player " , nil , " $TriggeringPlayer$ " , " $TriggeringPlayerHelp$ " , " triggering_player " , [ def , def . EvalPlr_Trigger ] ) ;
AddEvaluator ( " PlayerList " , nil , " $TriggeringPlayer$ " , " $TriggeringPlayerHelp$ " , " triggering_player_list " , [ def , def . EvalPlrList_Single , def . EvalPlr_Trigger ] ) ;
AddEvaluator ( " PlayerList " , nil , " $AllPlayers$ " , " $AllPlayersHelp$ " , " all_players " , [ def , def . EvalPlrList_All ] ) ;
2016-07-13 06:17:12 +00:00
// Boolean (condition) evaluators
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Boolean " , nil , " $Constant$ " , " $ConstantHelp$ " , " bool_constant " , [ def , def . EvalConstant ] , { Value = true } , { Type = " bool " , Name = " $Value$ " } ) ;
2016-07-29 03:44:10 +00:00
// Integer evaluators
AddEvaluator ( " Integer " , nil , " $Constant$ " , " $ConstantHelp$ " , " int_constant " , [ def , def . EvalConstant ] , { Value = 0 } , { Type = " int " , Name = " $Value$ " } ) ;
2016-07-30 16:29:35 +00:00
AddEvaluator ( " Integer " , nil , " $Random$ " , " $RandomIntHelp$ " , " int_random " , [ def , def . EvalIntRandom ] , { Min = { Function = " int_constant " , Value = 0 } , Max = { Function = " int_constant " , Value = 99 } } , { Type = " proplist " , Display = " {{Min}}-{{Max}} " , EditorProps = {
2016-07-30 15:03:26 +00:00
Min = new Evaluator . Integer { Name = " $Min$ " , EditorHelp = " $RandomMinHelp$ " } ,
Max = new Evaluator . Integer { Name = " $Max$ " , EditorHelp = " $RandomMaxHelp$ " }
} } ) ;
2016-07-30 05:06:21 +00:00
// Position evaluators
AddEvaluator ( " Position " , nil , " $ConstantPositionAbsolute$ " , " $ConstantPositionAbsoluteHelp$ " , " position_constant " , [ def , def . EvalConstant ] , def . GetDefaultPosition , { Type = " point " , Name = " $Position$ " , Relative = false , Color = 0xff2000 } ) ;
AddEvaluator ( " Position " , nil , " $ConstantPositionRelative$ " , " $ConstantPositionRelativeHelp$ " , " position_constant_rel " , [ def , def . EvalPositionRelative ] , { Value = [ 0 , 0 ] } , { Type = " point " , Name = " $Position$ " , Relative = true , Color = 0xff0050 } ) ;
2016-07-30 06:06:54 +00:00
AddEvaluator ( " Position " , nil , " $Coordinates$ " , " $CoordinatesHelp$ " , " position_coordinates " , [ def , def . EvalCoordinates ] , def . GetDefaultCoordinates , { Type = " proplist " , Display = " ({{X}},{{Y}}) " , EditorProps = {
X = new Evaluator . Integer { Name = " X " , EditorHelp = " $PosXHelp$ " } ,
Y = new Evaluator . Integer { Name = " Y " , EditorHelp = " $PosYHelp$ " }
} } ) ;
AddEvaluator ( " Position " , nil , " $PositionOffset$ " , " $PositionOffsetHelp$ " , " position_offset " , [ def , def . EvalPositionOffset ] , { } , { Type = " proplist " , Display = " {{Position}}+{{Offset}} " , EditorProps = {
Position = new Evaluator . Position { EditorHelp = " $PositionOffsetPositionHelp$ " } ,
Offset = new Evaluator . Offset { EditorHelp = " $PositionOffsetOffsetHelp$ " }
} } ) ;
2016-07-30 15:14:12 +00:00
AddEvaluator ( " Position " , nil , " $ObjectPosition$ " , " $ObjectPositionHelp$ " , " object_position " , [ def , def . EvalPositionObject ] , { Object = { Function = " triggering_object " } } , new Evaluator . Object { EditorHelp = " $ObjectPositionObjectHelp$ " } , " Object " ) ;
2016-07-30 16:29:35 +00:00
AddEvaluator ( " Position " , " $RandomPosition$ " , " $RandomRectAbs$ " , " $RandomRectAbsHelp$ " , " random_pos_rect_abs " , [ def , def . EvalPos_RandomRect , false ] , def . GetDefaultRect , { Type = " rect " , Name = " $Rectangle$ " , Relative = false , Color = 0xffff00 } , " Area " ) ;
AddEvaluator ( " Position " , " $RandomPosition$ " , " $RandomRectRel$ " , " $RandomRectRelHelp$ " , " random_pos_rect_rel " , [ def , def . EvalPos_RandomRect , true ] , { Area = [ - 30 , - 30 , 60 , 60 ] } , { Type = " rect " , Name = " $Rectangle$ " , Relative = true , Color = 0x00ffff } , " Area " ) ;
AddEvaluator ( " Position " , " $RandomPosition$ " , " $RandomCircleAbs$ " , " $RandomCircleAbsHelp$ " , " random_pos_circle_abs " , [ def , def . EvalPos_RandomCircle , false ] , def . GetDefaultCircle , { Type = " circle " , Name = " $Circle$ " , Relative = false , CanMoveCenter = true , Color = 0xff00ff } , " Area " ) ;
AddEvaluator ( " Position " , " $RandomPosition$ " , " $RandomCircleRel$ " , " $RandomCircleRelHelp$ " , " random_pos_circle_rel " , [ def , def . EvalPos_RandomCircle , true ] , { Area = [ 50 , 0 , 0 ] } , { Type = " circle " , Name = " $Circle$ " , Relative = true , CanMoveCenter = true , Color = 0xa000a0 } , " Area " ) ;
2016-07-30 06:06:54 +00:00
// Offset evaluators
AddEvaluator ( " Offset " , nil , " $ConstantOffsetRelative$ " , " $ConstantOffsetRelativeHelp$ " , " offset_constant " , [ def , def . EvalConstant ] , { Value = [ 0 , 0 ] } , { Type = " point " , Name = " $Position$ " , Relative = true , Color = 0xff30ff } ) ;
AddEvaluator ( " Offset " , nil , " $Coordinates$ " , " $CoordinatesHelp$ " , " offset_coordinates " , [ def , def . EvalCoordinates ] , { Value = { X = 0 , Y = 0 } } , { Type = " proplist " , Display = " ({{X}},{{Y}}) " , EditorProps = {
X = new Evaluator . Integer { Name = " X " , EditorHelp = " $OffXHelp$ " } ,
Y = new Evaluator . Integer { Name = " Y " , EditorHelp = " $OffYHelp$ " } ,
} } ) ;
2016-07-30 15:26:34 +00:00
AddEvaluator ( " Offset " , nil , " $AddOffsets$ " , " $AddOffsetsHelp$ " , " add_offsets " , [ def , def . EvalOffsetAdd ] , { } , { Type = " proplist " , Display = " {{Offset1}}+{{Offset2}} " , EditorProps = {
Offset1 = new Evaluator . Offset { EditorHelp = " $AddOffsetOffsetHelp$ " } ,
Offset2 = new Evaluator . Offset { EditorHelp = " $AddOffsetOffsetHelp$ " }
} } ) ;
AddEvaluator ( " Offset " , nil , " $DiffPositions$ " , " $DiffPositionsHelp$ " , " diff_positions " , [ def , def . EvalOffsetDiff ] , { } , { Type = " proplist " , Display = " {{PositionB}}-{{PositionA}} " , EditorProps = {
PositionA = new Evaluator . Position { Name = " $PositionA$ " , EditorHelp = " $PositionAHelp$ " } ,
PositionB = new Evaluator . Position { Name = " $PositionB$ " , EditorHelp = " $PositionBHelp$ " }
2016-07-30 06:06:54 +00:00
} } ) ;
2016-07-30 16:29:35 +00:00
AddEvaluator ( " Offset " , nil , " $RandomOffRectRel$ " , " $RandomRectRelHelp$ " , " random_off_rect_rel " , [ def , def . EvalPos_RandomRect , " rect " , false ] , { Area = [ - 30 , - 30 , 60 , 60 ] } , { Type = " rect " , Name = " $Rectangle$ " , Relative = true , Color = 0x00ffff } , " Area " ) ;
AddEvaluator ( " Offset " , nil , " $RandomOffCircleRel$ " , " $RandomCircleRelHelp$ " , " random_off_circle_rel " , [ def , def . EvalPos_RandomCircle , " circle " , false ] , { Area = [ 0 , 0 , 50 ] } , { Type = " circle " , Name = " $Circle$ " , Relative = true , CanMoveCenter = true , Color = 0xa000a0 } , " Area " ) ;
2016-07-06 05:03:02 +00:00
// User action editor props
Prop = Evaluator . Action ;
2016-07-25 05:42:23 +00:00
PropProgressMode = { Name = " $UserActionProgressMode$ " , EditorHelp = " $UserActionProgressModeHelp$ " , Type = " enum " , Options = [ { Name = " $Session$ " , Value = " session " } , { Name = " $Player$ " , Value = " player " } , { Name = " $Global$ " } ] } ;
PropParallel = { Name = " $ParallelAction$ " , EditorHelp = " $ParallelActionHelp$ " , Type = " bool " } ;
2016-07-06 05:03:02 +00:00
return true ;
}
2016-07-30 17:21:38 +00:00
public func GetObjectEvaluator ( filter_def , name , help )
2016-07-13 06:17:12 +00:00
{
// Create copy of the Evaluator.Object delegate, but with the object_constant proplist replaced by a version with filter_def
var object_options = Evaluator . Object . Options [ : ] ;
var const_option = new EvaluatorDefs [ " object_constant " ] { } ;
const_option . Delegate = new const_option . Delegate { Filter = filter_def } ;
object_options [ const_option . OptionIndex ] = const_option ;
2016-07-30 17:21:38 +00:00
return new Evaluator . Object { Name = name , Options = object_options , EditorHelp = help } ;
2016-07-13 06:17:12 +00:00
}
2016-07-30 15:14:12 +00:00
public func AddEvaluator ( string eval_type , string group , string name , string help , string identifier , callback_data , default_val , proplist delegate , string delegate_storage_key )
2016-07-06 05:03:02 +00:00
{
2016-07-13 06:17:12 +00:00
// Add an evaluator for one of the data types. Evaluators allow users to write small action sequences and scripts in the editor using dropdown lists.
// eval_type: Return type of the evaluator (Action, Object, Boolean, Player, etc. as defined in UserAction.Evaluator)
// group [optional] Localized name of sub-group for larger enums (i.e. actions)
// name: Localized name as it appears in the dropdown list of evaluators
// identifier: Unique identifier that is used to store this action in savegames and look up the action def. Identifiers must be unique among all data types.
// callback_data: Array of [definition, definition.Function, parameter (optional)]. Function to be called when this evaluator is called
// default_val [optional]: Default value to be set when this evaluator is selected. Must be a proplist. Should contain values for all properties in the delegate
// delegate: Parameters for this evaluator
2016-07-30 17:21:38 +00:00
if ( group ) group = GroupNames [ group ] ? ? group ; // resolve localized group name
2016-07-06 05:03:02 +00:00
if ( ! default_val ) default_val = { } ;
var default_get ;
if ( GetType ( default_val ) = = C4V_Function )
{
default_get = default_val ;
default_val = Call ( default_get ) ;
}
2016-07-21 04:47:43 +00:00
default_val . Function = identifier ;
2016-07-25 05:42:23 +00:00
var action_def = { Name = name , EditorHelp = help , Group = group , Value = default_val , OptionKey = " Function " , Delegate = delegate , Get = default_get } , n ;
2016-07-13 06:17:12 +00:00
if ( delegate )
2016-07-06 05:03:02 +00:00
{
2016-07-25 05:42:23 +00:00
if ( delegate . EditorProps | | delegate . Elements )
2016-07-13 06:17:12 +00:00
{
// Proplist of array parameter for this evaluator: Descend path title should be name
2016-07-13 21:18:08 +00:00
delegate . Name = name ;
2016-07-25 05:42:23 +00:00
var child_delegate = delegate ;
if ( delegate . DescendPath ) child_delegate = delegate . EditorProps [ delegate . DescendPath ] ;
if ( ! child_delegate . EditorHelp ) child_delegate . EditorHelp = help ;
2016-07-13 06:17:12 +00:00
}
else
{
// Any other parameter type: Store in value
2016-07-30 15:14:12 +00:00
action_def . ValueKey = delegate_storage_key ? ? " Value " ;
2016-07-13 06:17:12 +00:00
}
2016-07-06 05:03:02 +00:00
}
2016-07-13 06:17:12 +00:00
Evaluator [ eval_type ] . Options [ n = GetLength ( Evaluator [ eval_type ] . Options ) ] = action_def ;
action_def . OptionIndex = n ;
2016-07-06 05:03:02 +00:00
EvaluatorCallbacks [ identifier ] = callback_data ;
2016-07-10 18:11:23 +00:00
EvaluatorDefs [ identifier ] = action_def ;
2016-07-21 04:22:53 +00:00
// Copy most boolean props to condition prop
if ( eval_type = = " Boolean " & & identifier ! = " bool_constant " )
2016-07-25 05:42:23 +00:00
AddEvaluator ( " Condition " , group , name , help , identifier , callback_data , default_val , delegate ) ;
2016-07-06 05:03:02 +00:00
return action_def ;
}
public func EvaluateValue ( string eval_type , proplist props , proplist context )
{
//Log("EvaluateValue %v %v %v", eval_type, props, context);
if ( ! props ) return nil ;
// Finish any hold-action
if ( context . hold = = props )
{
context . hold = nil ;
return context . hold_result ;
}
// Not on hold: Perform evaluation
2016-07-21 04:47:43 +00:00
var cb = EvaluatorCallbacks [ props . Function ] ;
2016-07-30 15:03:26 +00:00
/*var rval = cb[0]->Call(cb[1], props, context, cb[2]);
Log ( " %v <- EvaluateValue %v %v %v " , rval , eval_type , props , context ) ;
return rval ; */
2016-07-06 05:03:02 +00:00
return cb [ 0 ] - > Call ( cb [ 1 ] , props , context , cb [ 2 ] ) ;
}
2016-07-21 04:22:53 +00:00
public func EvaluateAction ( proplist props , object action_object , object triggering_object , int triggering_player , string progress_mode , bool allow_parallel , finish_callback )
2016-07-06 05:03:02 +00:00
{
2016-07-24 14:50:39 +00:00
// No action
if ( ! props ) if ( finish_callback ) return action_object - > Call ( finish_callback ) ; else return ;
2016-07-06 05:03:02 +00:00
// Determine context
var context ;
if ( ! progress_mode )
{
2016-07-21 04:22:53 +00:00
if ( ! ( context = props . _context ) )
props . _context = context = CreateObject ( UserAction ) ;
2016-07-06 05:03:02 +00:00
}
else if ( progress_mode = = " player " )
{
2016-07-21 04:22:53 +00:00
if ( ! props . _contexts ) props . _contexts = [ ] ;
2016-07-06 05:03:02 +00:00
var plr_id ;
if ( action_object ) plr_id = GetPlayerID ( action_object - > GetOwner ( ) ) ;
2016-07-21 04:22:53 +00:00
if ( ! ( context = props . _contexts [ plr_id ] ) )
props . _contexts [ plr_id ] = context = CreateObject ( UserAction ) ;
2016-07-06 05:03:02 +00:00
}
else // if (progress_mode == "session")
{
// Temporary context
context = CreateObject ( UserAction ) ;
context . temp = true ;
}
// Prevent duplicate parallel execution
2016-07-22 05:51:29 +00:00
if ( ! allow_parallel & & ( context . hold & & ! context . suspended ) ) return false ;
2016-07-06 05:03:02 +00:00
// Init context settings
2016-07-21 04:22:53 +00:00
context - > InitContext ( action_object , triggering_player , triggering_object , props ) ;
2016-07-06 05:03:02 +00:00
// Execute action
EvaluateValue ( " Action " , props , context ) ;
FinishAction ( context ) ;
2016-07-22 05:51:29 +00:00
return true ;
2016-07-06 05:03:02 +00:00
}
2016-07-21 04:22:53 +00:00
public func EvaluateCondition ( proplist props , object action_object , object triggering_object , int triggering_player )
{
// Build temp context
var context = CreateObject ( UserAction ) ;
context . temp = true ;
// Init context settings
context - > InitContext ( action_object , triggering_player , triggering_object , props ) ;
// Execute condition evaluator
var result = EvaluateValue ( " Condition " , props , context ) ;
// Cleanup
if ( context ) context - > RemoveObject ( ) ;
// Done
return result ;
}
2016-07-29 05:43:35 +00:00
private func EvaluatePosition ( proplist props , object context )
{
// Execute position evaluator; fall back to position of action object
var position = EvaluateValue ( " Position " , props , context ) ;
if ( ! position )
{
if ( context . action_object ) position = [ context . action_object - > GetX ( ) , context . action_object - > GetY ( ) ] ;
else position = [ 0 , 0 ] ;
}
return position ;
}
2016-07-30 06:06:54 +00:00
private func EvaluateOffset ( proplist props , object context )
{
// Execute offset evaluator; fall back to [0, 0]
return EvaluateValue ( " Offset " , props , context ) ? ? [ 0 , 0 ] ;
}
2016-07-06 05:03:02 +00:00
private func ResumeAction ( proplist context , proplist resume_props )
{
//Log("ResumeAction %v %v", context, resume_props);
// Resume only if on hold for the same entry
if ( context . hold ! = resume_props ) return ;
2016-07-29 05:43:35 +00:00
// Not if owning object is dead
if ( ! context . action_object ) return ;
2016-07-06 05:03:02 +00:00
// Resume action
EvaluateValue ( " Action " , context . root_action , context ) ;
// Cleanup action object (unless it ran into another hold)
FinishAction ( context ) ;
}
private func FinishAction ( proplist context )
{
// Cleanup action object (unless it's kept around for callbacks or to store sequence progress)
// Note that context.root_action.contexts is checked to kill session-contexts that try to suspend
// There would be no way to resume so just kill the context
2016-07-21 04:22:53 +00:00
if ( ! context . hold | | context . temp )
{
if ( context . action_object & & context . finish_callback ) context . action_object - > Call ( context . finish_callback , context ) ;
context - > RemoveObject ( ) ;
}
2016-07-06 05:03:02 +00:00
}
2016-07-13 06:17:12 +00:00
private func EvalConstant ( proplist props , proplist context ) { return props . Value ; }
2016-07-06 05:03:02 +00:00
private func EvalObj_ActionObject ( proplist props , proplist context ) { return context . action_object ; }
private func EvalObj_TriggeringObject ( proplist props , proplist context ) { return context . triggering_object ; }
2016-07-24 14:50:39 +00:00
private func EvalObj_TriggeringClonk ( proplist props , proplist context ) { return context . triggering_clonk ; }
2016-07-29 05:43:35 +00:00
private func EvalObj_LastCreatedObject ( proplist props , proplist context ) { return context . last_created_object ; }
2016-07-21 04:22:53 +00:00
private func EvalPlr_Trigger ( proplist props , proplist context ) { return context . triggering_player ; }
2016-07-06 05:03:02 +00:00
private func EvalPlrList_Single ( proplist props , proplist context , fn ) { return [ Call ( fn , props , context ) ] ; }
private func EvalPlrList_All ( proplist props , proplist context , fn )
{
var n = GetPlayerCount ( C4PT_User ) ;
var result = CreateArray ( n ) ;
for ( var i = 0 ; i < n ; + + i ) result [ i ] = GetPlayerByIndex ( i ) ;
return result ;
}
private func EvalAct_Sequence ( proplist props , proplist context )
{
// Sequence execution: Iterate over actions until one action puts the context on hold
2016-07-13 21:39:36 +00:00
var n = GetLength ( props . Actions ) , sid = props . _sequence_id ;
if ( ! sid ) sid = props . _sequence_id = Format ( " %d " , + + UserAction_SequenceIDs ) ;
for ( var progress = context . sequence_progress [ sid ] ? ? 0 ; progress < n ; + + progress )
2016-07-06 05:03:02 +00:00
{
//Log("Sequence progress exec %v %v", progress, context.hold);
// goto preparations
context . sequence_had_goto [ sid ] = false ;
context . last_sequence = props ;
// Evaluate next sequence step
EvaluateValue ( " Action " , props . Actions [ progress ] , context ) ;
if ( context . hold | | context . suspended )
{
// Execution on hold (i.e. wait action). Stop execution for now
if ( ! context . hold ) progress = 0 ; // No hold specified: Stop with sequence reset
context . sequence_progress [ sid ] = progress ;
return ;
}
// Apply jump in the sequence
if ( context . sequence_had_goto [ sid ] ) progress = context . sequence_progress [ sid ] - 1 ;
}
// Sequence finished
context . last_sequence = nil ;
// Reset for next execution.
2016-07-13 21:39:36 +00:00
context . sequence_progress [ sid ] = 0 ;
2016-07-06 05:03:02 +00:00
}
private func EvalAct_Goto ( proplist props , proplist context )
{
// Apply goto by jumping in most recently executed sequence
if ( context . last_sequence )
{
2016-07-24 14:50:39 +00:00
context . sequence_progress [ context . last_sequence . _sequence_id ] = props . Index ;
context . sequence_had_goto [ context . last_sequence . _sequence_id ] = true ;
2016-07-06 05:03:02 +00:00
}
}
private func EvalAct_StopSequence ( proplist props , proplist context )
{
// Stop: Suspend without hold props, which causes all sequences to reset
context . hold = nil ;
context . suspended = true ;
}
private func EvalAct_SuspendSequence ( proplist props , proplist context )
{
// Suspend: Remember hold position and stop action execution
context . hold = props ;
context . suspended = true ;
}
private func EvalAct_Wait ( proplist props , proplist context )
{
// Wait for specified number of frames
context . hold = props ;
ScheduleCall ( context , UserAction . ResumeAction , props . Time , 1 , context , props ) ;
}
2016-07-29 03:44:10 +00:00
private func EvalAct_Sound ( proplist props , proplist context )
{
if ( ! props . Sound ) return ;
var sound_context = props . SourceObject ? ? Global ;
var volume = EvaluateValue ( " Integer " , props . Volume , context ) ;
var pitch = EvaluateValue ( " Integer " , props . Pitch , context ) ;
if ( props . TargetPlayers = = " all_players " )
{
sound_context - > Sound ( props . Sound , true , volume , nil , props . Loop , nil , pitch ) ;
}
else
{
for ( var plr in EvaluateValue ( " PlayerList " , props . TargetPlayers , context ) )
{
sound_context - > Sound ( props . Sound , false , volume , plr , props . Loop , nil , pitch ) ;
}
}
}
2016-07-29 05:43:35 +00:00
private func EvalAct_CreateObject ( proplist props , proplist context )
{
// Create a new object
var create_id = EvaluateValue ( " Definition " , props . ID , context ) ;
if ( ! create_id ) return ;
var owner = EvaluateValue ( " Player " , props . Owner , context ) ;
var container = EvaluateValue ( " Object " , props . Container , context ) ;
var obj ;
if ( container )
{
// Contained object
obj = container - > CreateContents ( create_id ) ;
if ( obj ) obj - > SetOwner ( owner ) ;
}
else
{
// Uncontained object
var position = EvaluatePosition ( props . Position , context ) ;
var speed_x = EvaluateValue ( " Integer " , props . SpeedX , context ) ;
var speed_y = EvaluateValue ( " Integer " , props . SpeedY , context ) ;
if ( props . CreateAbove )
obj = Global - > CreateObjectAbove ( create_id , position [ 0 ] , position [ 1 ] , owner ) ;
else
obj = Global - > CreateObject ( create_id , position [ 0 ] , position [ 1 ] , owner ) ;
// Default speed
if ( obj ) obj - > SetXDir ( speed_x , 100 ) ;
if ( obj ) obj - > SetYDir ( speed_y , 100 ) ;
}
// Remember object for later access
context . last_created_object = obj ;
}
2016-07-29 06:06:20 +00:00
private func EvalAct_RemoveObject ( proplist props , proplist context )
{
var obj = EvaluateValue ( " Object " , props . Object , context ) ;
if ( ! obj ) return ;
obj - > RemoveObject ( props . EjectContents ) ;
}
2016-07-30 05:06:21 +00:00
private func GetDefaultPosition ( object target_object )
{
// Default position for constant absolute position evaluator: Use selected object position
var value ;
if ( target_object )
value = [ target_object - > GetX ( ) , target_object - > GetY ( ) ] ;
else
value = [ 0 , 0 ] ;
return { Function = " position_constant " , Value = value } ;
}
2016-07-30 06:06:54 +00:00
private func GetDefaultCoordinates ( object target_object )
{
// Default position for constant absolute position evaluator: Use selected object position
var value ;
if ( target_object )
value = { X = { Function = " int_constant " , Value = target_object - > GetX ( ) } , Y = { Function = " int_constant " , Value = target_object - > GetY ( ) } } ;
else
value = { X = 0 , Y = 0 } ;
value . Function = " position_coordinates " ;
return value ;
}
2016-07-30 16:29:35 +00:00
private func GetDefaultRect ( object target_object )
{
// Default rectangle around target object
var r ;
if ( target_object ) r = [ target_object - > GetX ( ) - 30 , target_object - > GetY ( ) - 30 , 60 , 60 ] ; else r = [ 100 , 100 , 100 , 100 ] ;
return { Function = " random_pos_rect_abs " , Area = r } ;
}
private func GetDefaultCircle ( object target_object )
{
// Default circle around target object
var r ;
if ( target_object ) r = [ 50 , target_object - > GetX ( ) , target_object - > GetY ( ) ] ; else r = [ 50 , 100 , 100 ] ;
return { Function = " random_pos_circle_abs " , Area = r } ;
}
private func EvalIntRandom ( proplist props , proplist context )
2016-07-30 15:03:26 +00:00
{
// Random value between min and max. Also allow them to be swapped.
var min = EvaluateValue ( " Integer " , props . Min , context ) ;
var max = EvaluateValue ( " Integer " , props . Max , context ) ;
var rmin = Min ( min , max ) ;
return Random ( Max ( max , min ) - rmin ) + rmin ;
}
2016-07-30 05:06:21 +00:00
private func EvalPositionRelative ( proplist props , proplist context )
{
// Return position relative to action_object
if ( context . action_object )
return [ props . Value [ 0 ] + context . action_object - > GetX ( ) , props . Value [ 1 ] + context . action_object - > GetY ( ) ] ;
else
return props . Value ;
}
2016-07-30 06:06:54 +00:00
private func EvalCoordinates ( proplist props , proplist context )
{
// Coordinate evaluation: Make array [X, Y]
return [ EvaluateValue ( " Integer " , props . X , context ) , EvaluateValue ( " Integer " , props . Y , context ) ] ;
}
private func EvalPositionOffset ( proplist props , proplist context )
{
var p = EvaluatePosition ( props . Position , context ) ;
var o = EvaluateOffset ( props . Offset , context ) ;
return [ p [ 0 ] + o [ 0 ] , p [ 1 ] + o [ 1 ] ] ;
}
2016-07-30 15:14:12 +00:00
private func EvalPositionObject ( proplist props , proplist context )
{
var obj = EvaluateValue ( " Object " , props . Object , context ) ;
if ( obj ) return [ obj - > GetX ( ) , obj - > GetY ( ) ] ;
return [ 0 , 0 ] ; // undefined object: Position is 0/0 default
}
2016-07-30 16:29:35 +00:00
private func EvalPos_RandomRect ( proplist props , proplist context , bool relative )
{
// Constant random distribution in rectangle
var a = props . Area ;
var rval = [ a [ 0 ] + Random ( a [ 2 ] ) , a [ 1 ] + Random ( a [ 3 ] ) ] ;
// Apply relative offset
if ( relative & & context . action_object )
{
rval [ 0 ] + = context . action_object - > GetX ( ) ;
rval [ 1 ] + = context . action_object - > GetY ( ) ;
}
return rval ;
}
private func EvalPos_RandomCircle ( proplist props , proplist context , bool relative )
{
// Constant random distribution in circle
var a = props . Area ;
var r = a [ 0 ] ;
r = Sqrt ( Random ( r * r ) ) ;
var ang = Random ( 360 ) ;
var x = Sin ( ang , r ) , y = Cos ( ang , r ) ;
var rval = [ a [ 1 ] + x , a [ 2 ] + y ] ;
// Apply relative offset
if ( relative & & context . action_object )
{
rval [ 0 ] + = context . action_object - > GetX ( ) ;
rval [ 1 ] + = context . action_object - > GetY ( ) ;
}
return rval ;
}
2016-07-30 15:26:34 +00:00
private func EvalOffsetAdd ( proplist props , proplist context )
2016-07-30 06:06:54 +00:00
{
var o1 = EvaluateOffset ( props . Offset1 , context ) ;
var o2 = EvaluateOffset ( props . Offset2 , context ) ;
return [ o1 [ 0 ] + o2 [ 0 ] , o1 [ 1 ] + o2 [ 1 ] ] ;
}
2016-07-30 15:26:34 +00:00
private func EvalOffsetDiff ( proplist props , proplist context )
{
var pA = EvaluatePosition ( props . PositionA , context ) ;
var pB = EvaluatePosition ( props . PositionB , context ) ;
return [ pB [ 0 ] - pA [ 0 ] , pB [ 1 ] - pA [ 1 ] ] ;
}
2016-07-21 04:22:53 +00:00
/* Context instance */
// Proplist holding progress in each sequence
local sequence_progress , sequence_had_goto ;
static UserAction_SequenceIDs ;
// Set to innermost sequence (for goto)
local last_sequence ;
// If this action is paused and will be resumed by a callback or by re-execution of the action, this property is set to the props of the holding action
local hold ;
// Set to true if action is on hold but waiting for re-execution
local suspended ;
// Return value if a value-providing evaluator is held
local hold_result ;
public func Initialize ( )
{
sequence_progress = { } ;
sequence_had_goto = { } ;
return true ;
}
public func InitContext ( object action_object , int triggering_player , object triggering_object , proplist props )
{
2016-07-24 14:50:39 +00:00
// Determine triggering player+objects
var triggering_clonk ;
// Triggering player unknown? Try fallback to the controller of the triggering object
if ( ! GetType ( triggering_player ) & & triggering_object )
2016-07-21 04:22:53 +00:00
{
2016-07-24 14:50:39 +00:00
triggering_player = triggering_object - > GetController ( ) ;
2016-07-21 04:22:53 +00:00
}
2016-07-24 14:50:39 +00:00
// Triggering clonk is the selected clonk of the triggering player
if ( GetType ( triggering_player ) )
2016-07-21 04:22:53 +00:00
{
2016-07-24 14:50:39 +00:00
triggering_clonk = GetCursor ( triggering_player ) ; ;
if ( ! triggering_clonk ) triggering_clonk = GetCrew ( triggering_player ) ;
2016-07-21 04:22:53 +00:00
}
2016-07-24 14:50:39 +00:00
// Triggering object: Fallback to triggering player clonk
if ( ! triggering_object ) triggering_object = triggering_clonk ;
2016-07-21 04:22:53 +00:00
// Init context settings
this . action_object = action_object ;
this . triggering_object = triggering_object ;
2016-07-24 14:50:39 +00:00
this . triggering_clonk = triggering_clonk ;
2016-07-21 04:22:53 +00:00
this . triggering_player = triggering_player ;
this . root_action = props ;
this . suspended = false ;
return true ;
}
2016-07-06 05:03:02 +00:00
public func MenuOK ( proplist menu_id , object clonk )
{
// Pressed 'Next' in dialogue: Resume in user action
UserAction - > ResumeAction ( this , this . hold ) ;
}
public func MenuSelectOption ( int index )
{
// Selected an option in dialogue: Resume at specified position in innermost sequence
if ( ! hold | | ! hold . Options ) return ;
var opt = this . hold . Options [ index ] ;
if ( opt & & last_sequence )
{
2016-07-24 14:50:39 +00:00
sequence_progress [ last_sequence . _sequence_id ] = opt . Goto ;
2016-07-06 05:03:02 +00:00
hold = nil ;
}
UserAction - > ResumeAction ( this , hold ) ;
}
2016-07-21 04:22:53 +00:00
public func SaveScenarioObject ( props ) { return false ; } // temp. don't save.