Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

How to restart a live macro

I'm trying to figure out how to build a simple "active battle system", with action bars.
(live: $e1_time)[
	(set: $e1_act_bar to it + (a:"█"))
	Count: $e1_count_bar;(set: $e1_count_bar to it + 1)
	Bar: (print: $e1_act_bar.slice(0,10).join(" "))
]
$e1_time is the enemy reaction time score, so if a character has good reaction, the live will be faster and his bar be plenty sooner.

$e1_act_bar is an empty array.
(set: $e1_act_bar to (a:))
$e1_count_bar is a simple counter, set to 0 outside the live.
(set: $e1_count_bar to 0)
The print will display, this way, a bar like █ █ █ █ █ █ █ █ █, sliced to the first 10 blocks.

The question is: how can I stop the macro of keep filling the array with █, since if the player didn't act, he/she will have a massive array, even if only 10 are visible? The obvious answer is (stop:), but I don't have idea how to do it and after the combat actions (when the bar reaches 10 and must be stopped), bring it back to work.

Comments

  • The following comment will be made up of two parts:

    1. A better way to limit the maximum size of the $e1_act_bar array.

    Instead of using a slice() method to only show the first ten element of the array, check the Harlowe Array's length property and only extend the array when needed.
    {
    (set: $e1_time to 1s)
    (set: $e1_act_bar to (a:))
    (set: $e1_count_bar to 0)
    
    }(live: $e1_time)[
    	(if: $e1_act_bar's length < 10)[\
    		(set: $e1_act_bar to it + (a:"█"))\
    	]\
    	Count: $e1_count_bar;(set: $e1_count_bar to it + 1)
    	Bar: (print: $e1_act_bar.join(" "))
    ]
    

    2. Some suggestions about using (live:) macros in general, and using them to update a User Interface (UI) in particular.

    Your original question does not actually state this but I am going to assume that you may be thinking about using more than a single (live:) macro within your 'active battle system' to update the UI. (the different action bars)

    There is a potential issue with doing this due to the fact that each (live;) macro creates a timer thread and the thread needs to briefly interrupt the user's ability to interact with the screen to do whatever is in the macro's associated hook, this interruption occurs at the rate you set for the (live:) macro's delay parameter.
    Depending the both the length of the delays and the number of (live:) macros used, this can have a serious effect on the user's ability to interact with the screen.

    One way to reduce this issue is to use a single (live:) macro to do all the timer based logic of a screen, this technique is commonly known as a Game Loop.

    note: The actual delay length used for the (live:) macro depends on how long it takes for the related logic to process, the following example will use one second. It is also common to track the number of times the timer has fired so that you can have logic that only occurs every so often, it is a good idea to reset this counter every so often so that it's value does not become too large.
    {
    (set: $e1_time to 1s)
    (set: $e1_act_bar to (a:))
    (set: $e1_count_bar to 0)
    
    <!-- A meaningless dummy variable. -->
    (set: $dummy to 1)
    
    (set: $ticks to 0)
    }(live: 1s)[{
    	(set: $ticks to it + 1)
    
    	<!-- Logic for first action, update some dummy variable. -->
    	(set: $dummy to ((it * 3) - 1))
    	
    	<!-- Logic for second action, increase bar every fifth tick. -->
    }	(if: $ticks % 5 is 0)[\
    		(if: $e1_act_bar's length < 10)[\
    			(set: $e1_act_bar to it + (a:"█"))\
    		]\
    		Count: $e1_count_bar;(set: $e1_count_bar to it + 1)
    		Bar: (print: $e1_act_bar.join(" "))
    	]\
    \
    	(if: $ticks is 100)[(set: $ticks to 0)]\
    ]
    

    The above example leads me to my second suggestion, which is to separate the displaying/positioning of the screen's UI elements out of the (live:) macro's hook by using techniques like combining named hooks with (replace: ) macros. This can help you create more complex UI's.
    {(set: $e1_time to 1s)
    (set: $e1_act_bar to (a:))
    (set: $e1_count_bar to 0)
    
    }Count: [$e1_count_bar]<count|;
    Bar: [(print: $e1_act_bar.join(" "))]<bar|
    
    (set: $ticks to 0)
    (live: 1s)[{
    	(set: $ticks to it + 1)
    
    	<!-- logic for count and bar. -->
    	(if: $e1_act_bar's length < 10)[\
    		(set: $e1_act_bar to it + (a:"█"))\
    	]
    	(set: $e1_count_bar to it + 1)
    	(replace: ?count)[$e1_count_bar]
    	(replace: ?bar)[(print: $e1_act_bar.join(" "))]
    
    	(if: $ticks is 100)[(set: $ticks to 0)]\
    }]
    
  • Wow, your answers are lessons, thank you.

    The length approach is simple and effective, I should have thought of that, since I use length in other places...

    The second is a new one for me. And I use (live:) all around, the little interruption was something I decided to live with =D Maybe I need to review all my code now.

    Anyway, I'd found other solution: convert the array to a fixed 10 blocks when it reaches the max size:
    (if: $e1_count_bar >= 10)[
         (set: $e1_act_bar to (a:
    	    "█","█","█","█","█","█","█","█","█","█"
         )
    )]
    

Sign In or Register to comment.