@@ -170,6 +170,16 @@ function PART:SetEvent(event)
170170 if (owner == pac .LocalPlayer ) and (not pace .processing ) then
171171 if event == " command" then owner .pac_command_events = owner .pac_command_events or {} end
172172 if not self .Events [event ] then -- invalid event? try another event
173+ if # string .Split (event , " " ) == 2 then -- timerx2
174+ local strs = string .Split (event , " " )
175+ timer .Simple (0.2 , function ()
176+ if not self .pace_properties or self ~= pace .current_part then return end
177+ self :SetEvent (" timerx2" )
178+ self :SetArguments (strs [1 ] .. " @@" .. strs [2 ] .. " @@1@@0" )
179+ pace .PopulateProperties (self )
180+ end )
181+ return
182+ end
173183 if isnumber (tonumber (event )) then -- timerx
174184 timer .Simple (0.2 , function ()
175185 if not self .pace_properties or self ~= pace .current_part then return end
@@ -220,7 +230,36 @@ function PART:SetEvent(event)
220230 end
221231end
222232
233+ function PART :SetProperty (key , val )
234+ if self [" Set" .. key ] ~= nil then
235+ if self [" Get" .. key ](self ) ~= val then
236+ self [" Set" .. key ](self , val )
237+ end
238+ elseif self .GetDynamicProperties then
239+ local info = self :GetDynamicProperties ()[key ]
240+ if info and info then
241+ if isnumber (val ) then
242+ val = math .Round (val , 7 )
243+ end
244+ info .set (val )
245+ if self :GetPlayerOwner () ~= pac .LocalPlayer then return end
246+ if pace .IsActive () then
247+ self .pace_properties [" Arguments" ]:SetText (" " .. self .Arguments )
248+ self .pace_properties [" Arguments" ].original_str = self .Arguments
249+ end
250+ end
251+ end
252+ end
253+
254+ function PART :SetArguments (str )
255+ self .Arguments = str
256+ if pace .IsActive () and pac .LocalPlayer == self :GetPlayerOwner () then
257+ pace .PopulateProperties (self )
258+ end
259+ end
260+
223261function PART :Initialize ()
262+ self .found_cached_parts = {}
224263 self .specialtrackedparts = {}
225264 self .ExtraHermites = {}
226265 if self :GetPlayerOwner () == LocalPlayer () then
@@ -234,13 +273,21 @@ function PART:Initialize()
234273 end
235274 end )
236275 end
276+ -- force refresh
277+ timer .Simple (10 , function ()
278+ self .found_cached_parts = {}
279+ end )
237280
238281end
239282
240283function PART :GetOrFindCachedPart (uid_or_name )
241284 local part = nil
242- self .found_cached_parts = self .found_cached_parts or {}
243- if self .found_cached_parts [uid_or_name ] then return self .found_cached_parts [uid_or_name ] end
285+ local existing_part = self .found_cached_parts [uid_or_name ]
286+ if existing_part then
287+ if existing_part ~= NULL and existing_part :IsValid () then
288+ return existing_part
289+ end
290+ end
244291
245292 local owner = self :GetPlayerOwner ()
246293 part = pac .GetPartFromUniqueID (pac .Hash (owner ), uid_or_name ) or pac .FindPartByPartialUniqueID (pac .Hash (owner ), uid_or_name )
@@ -577,6 +624,36 @@ PART.OldEvents = {
577624 end ,
578625 },
579626
627+ timerx2 = {
628+ operator_type = " none" ,
629+ tutorial_explanation = " timerx2 is a dual timerx, a stopwatch that counts time since it's shown and determines whether it fits within the window defined by StartTime and EndTime" ,
630+ arguments = {{StartTime = " number" }, {EndTime = " number" }, {reset_on_hide = " boolean" }, {synced_time = " boolean" }},
631+ userdata = {
632+ {default = 0.5 , timerx_property = " StartTime" },
633+ {default = 1 , timerx_property = " EndTime" },
634+ {default = true , timerx_property = " reset_on_hide" }
635+ },
636+ nice = function (self , ent , seconds , seconds2 )
637+ return " timerx2: " .. (" %.2f" ):format (self .number or 0 , 2 ) .. " between " .. seconds .. " and " .. seconds2 .. " seconds"
638+ end ,
639+ callback = function (self , ent , StartTime , EndTime , reset_on_hide , synced_time )
640+
641+ local time = synced_time and CurTime () or RealTime ()
642+
643+ self .time = self .time or time
644+ self .timerx_reset = reset_on_hide
645+
646+ if self .AffectChildrenOnly and self :IsHiddenBySomethingElse () then
647+ return false
648+ end
649+ self .number = time - self .time
650+
651+ return self .number > StartTime and self .number < EndTime
652+
653+ -- return self:NumberOperator(self.number, seconds)
654+ end ,
655+ },
656+
580657 timersys = {
581658 operator_type = " number" , preferred_operator = " above" ,
582659 tutorial_explanation = " like timerx, timersys is a stopwatch that counts time (it uses SysTime()) since it's shown (hiding and re-showing is an important resetting condition).\n it takes that time and compares it with the duration defined in seconds.\n meaning it can show things after(above) a delay or until(below) a certain amount of time passes" ,
@@ -1549,9 +1626,32 @@ PART.OldEvents = {
15491626 end ,
15501627 },
15511628
1629+ ratio_timer = {
1630+ operator_type = " none" ,
1631+ arguments = {{interval = " number" }, {offset = " number" }, {ratio = " number" }, {reset_on_hide = " boolean" }},
1632+ userdata = {{default = 1 }, {default = 0 }, {default = 0.5 }, {default = false }},
1633+ callback = function (self , ent , interval , offset , ratio , reset_on_hide )
1634+ interval = interval or 1
1635+ offset = offset or 0
1636+ final_offset = offset
1637+ ratio = math .Clamp (math.abs (ratio or 0.5 ), 0 , 1 )
1638+
1639+ if interval == 0 or interval < FrameTime () then
1640+ self .timer_hack = not self .timer_hack
1641+ return self .timer_hack
1642+ end
1643+
1644+ if reset_on_hide then
1645+ final_offset = - self .showtime + offset
1646+ end
1647+ return (CurTime () + final_offset ) % interval < (interval * ratio )
1648+ end ,
1649+ },
1650+
15521651 timer = {
15531652 operator_type = " none" ,
15541653 arguments = {{interval = " number" }, {offset = " number" }},
1654+ userdata = {{default = 1 }, {default = 0 }},
15551655 callback = function (self , ent , interval , offset )
15561656 interval = interval or 1
15571657 offset = offset or 0
@@ -2358,7 +2458,7 @@ PART.OldEvents = {
23582458 damage_zone_hit = {
23592459 operator_type = " number" , preferred_operator = " above" ,
23602460 arguments = {{time = " number" }, {damage = " number" }, {uid = " string" }},
2361- userdata = {{default = 1 }, {default = 0 }, {enums = function (part )
2461+ userdata = {{default = 1 }, {default = 0 }, {default = " " , enums = function (part )
23622462 local output = {}
23632463 local parts = pac .GetLocalParts ()
23642464
@@ -2408,7 +2508,7 @@ PART.OldEvents = {
24082508 damage_zone_kill = {
24092509 operator_type = " mixed" , preferred_operator = " above" ,
24102510 arguments = {{time = " number" }, {uid = " string" }},
2411- userdata = {{default = 1 }, {enums = function (part )
2511+ userdata = {{default = 1 }, {default = " " , enums = function (part )
24122512 local output = {}
24132513 local parts = pac .GetLocalParts ()
24142514
@@ -2635,8 +2735,8 @@ PART.OldEvents = {
26352735 or_gate = {
26362736 operator_type = " none" , preferred_operator = " find simple" ,
26372737 tutorial_explanation = " combines multiple events into an OR gate, the event will activate as soon as one of the events listed is activated (taking inverts into account)" ,
2638- arguments = {{uids = " string" }},
2639- userdata = {{enums = function (part )
2738+ arguments = {{uids = " string" }, { ignore_inverts = " boolean " } },
2739+ userdata = {{default = " " , enums = function (part )
26402740 local output = {}
26412741 local parts = pac .GetLocalParts ()
26422742 for i , part in pairs (parts ) do
@@ -2646,20 +2746,108 @@ PART.OldEvents = {
26462746 end
26472747 return output
26482748 end }},
2649- callback = function (self , ent , uids )
2749+ callback = function (self , ent , uids , ignore_inverts )
26502750 if uids == " " then return false end
26512751 local uid_splits = string .Split (uids , " ;" )
2752+ local true_count = 0
26522753 for i ,uid in ipairs (uid_splits ) do
26532754 local part = self :GetOrFindCachedPart (uid )
2654- if part then
2655- local b = part .event_triggered
2656- if part .Invert then b = not b end
2755+ if part :IsValid () then
2756+ local raw = part .raw_event_condition
2757+ local b = false
2758+ if ignore_inverts then
2759+ b = raw
2760+ else
2761+ b = not part .event_triggered
2762+ end
26572763 if b then
2658- return true
2764+ true_count = true_count + 1
26592765 end
26602766 end
26612767 end
2662- return false
2768+ return true_count > 0
2769+ end ,
2770+ },
2771+ xor_gate = {
2772+ operator_type = " none" , preferred_operator = " find simple" ,
2773+ tutorial_explanation = " combines multiple events into an XOR gate, the event will activate if one (and only one) of the two events is activated (taking inverts into account)" ,
2774+ arguments = {{uid1 = " string" },{uid2 = " string" }},
2775+ userdata = {
2776+ {default = " " , enums = function (part )
2777+ local output = {}
2778+ local parts = pac .GetLocalParts ()
2779+ for i , part in pairs (parts ) do
2780+ if part .ClassName == " event" then
2781+ output [" [UID:" .. string.sub (i ,1 ,16 ) .. " ...] " .. part :GetName () .. " ; in " .. part :GetParent ().ClassName .. " " .. part :GetParent ():GetName ()] = part .UniqueID
2782+ end
2783+ end
2784+ return output
2785+ end },
2786+ {default = " " , enums = function (part )
2787+ local output = {}
2788+ local parts = pac .GetLocalParts ()
2789+ for i , part in pairs (parts ) do
2790+ if part .ClassName == " event" then
2791+ output [" [UID:" .. string.sub (i ,1 ,16 ) .. " ...] " .. part :GetName () .. " ; in " .. part :GetParent ().ClassName .. " " .. part :GetParent ():GetName ()] = part .UniqueID
2792+ end
2793+ end
2794+ return output
2795+ end }
2796+ },
2797+ callback = function (self , ent , uid1 , uid2 )
2798+ if uid1 == " " then return false end
2799+ if uid2 == " " then return false end
2800+ local part1 = self :GetOrFindCachedPart (uid1 )
2801+ local part2 = self :GetOrFindCachedPart (uid2 )
2802+ if not IsValid (part1 ) or not IsValid (part2 ) then return false end
2803+ local b1 = part1 .event_triggered if part1 .Invert then b1 = not b1 end
2804+ local b2 = part2 .event_triggered if part2 .Invert then b2 = not b2 end
2805+ return ((b1 and not b2 ) or (b2 and not b1 )) and not (b1 and b2 )
2806+ end ,
2807+ nice = function (self , ent , uid1 , uid2 )
2808+ local part1 = self :GetOrFindCachedPart (uid1 )
2809+ local part2 = self :GetOrFindCachedPart (uid2 )
2810+ if not IsValid (part1 ) or not IsValid (part2 ) then return " xor_gate : [" .. uid1 .. " , " .. uid2 .. " ] <ERROR>" end
2811+ local str = " xor_gate : [" .. part1 :GetName () .. " , " .. part2 :GetName () .. " ]"
2812+ return str
2813+ end
2814+ },
2815+ and_gate = {
2816+ operator_type = " none" , preferred_operator = " find simple" ,
2817+ tutorial_explanation = " combines multiple events into an AND gate, the event will activate when all the events listed are activated (taking inverts into account)" ,
2818+ arguments = {{uids = " string" }, {ignore_inverts = " boolean" }},
2819+ userdata = {{default = " " , enums = function (part )
2820+ local output = {}
2821+ local parts = pac .GetLocalParts ()
2822+ for i , part in pairs (parts ) do
2823+ if part .ClassName == " event" then
2824+ output [" [UID:" .. string.sub (i ,1 ,16 ) .. " ...] " .. part :GetName () .. " ; in " .. part :GetParent ().ClassName .. " " .. part :GetParent ():GetName ()] = part .UniqueID
2825+ end
2826+ end
2827+ return output
2828+ end }},
2829+ callback = function (self , ent , uids , ignore_inverts )
2830+ if uids == " " then return false end
2831+ local uid_splits = string .Split (uids , " ;" )
2832+ for i ,uid in ipairs (uid_splits ) do
2833+ local part = self :GetOrFindCachedPart (uid )
2834+ if part :IsValid () then
2835+ local raw = part .raw_event_condition
2836+ local b = false
2837+ if ignore_inverts then
2838+ b = raw
2839+ else
2840+ b = not part .event_triggered
2841+ end
2842+
2843+ if not b then
2844+ return false
2845+ end
2846+ else
2847+ return false
2848+ end
2849+ end
2850+ return true
26632851 end ,
26642852 }
26652853
@@ -3263,6 +3451,7 @@ local function should_trigger(self, ent, eventObject)
32633451 else
32643452 b = eventObject :Think (self , ent , self :GetParsedArgumentsForObject (eventObject )) or false
32653453 end
3454+ self .raw_event_condition = b
32663455
32673456 if self .Invert then
32683457 b = not b
0 commit comments