The older CandleLight Sims DigiDec unit was, in essense, an alarm clock with a hacked init BHAV (so that it would hang on the wall) and a graphics-swapping routine built in. This time, I started with a basic painting, stripped all of the BHAVs and built the object from the ground up. The goal was to create an object that could be set to ring at any specific time of day or relative to the sim's work schedule (being from one to five hours before the start time of the sim's job). It can also have its display color set between blue, red and green.

To begin, here's a brief explanation of the Stack Obj's Attribute values at play:

0: This Attribute is in charge of keeping up with the DigiDec's display color. 0=Blue, 1=Red and 2=Green. The Attribute is set by the "Change Color To" BHAVs and is read by the "Update Graphic" BHAV.
1: When the alarm is set, this Attribute is assigned the proper value. If the alarm is set for 11:00 PM, then Stack Obj's Attribute 1 will be set to "23."
2: Though the user needn't be aware, the DigiDec alarm has three different "modes." One of the modes is "off," and that is the default mode set at purchase time when Stack Obj's Attribute 2 is set at "0." When a specific time is chosen for the alarm setting, the value is set to "6," which indicates that the alarm is in "manual" mode. However, if the alarm is set to ring a certain number of hours before work time, then Stack Obj's Attribute 2 is set for a value between "1" and "5," all of which indicate "automatic" mode. An explanation will follow in the BHAV section.

Don't be intimidated by the number of BHAVs! It may look like a long list, but it's mostly comprised of Interaction BHAVs and their Test BHAVs, all of which are so similar and simple that they need very little explanation.

Once Per Hour
True to its name, this BHAV works once per hour. Actually, it works every loop, but returns "True" immediately if the "minute" value of the game clock is not "zero." Otherwise, the BHAV first checks to make sure that the alarm isn't supposed to start ringing (by checking Stack Obj's Attribute 1 against the "hour" value of the game clock), and then runs the "Update Graphics" BHAV if the alarm isn't supposed to ring yet.
Update Graphics
The basic function of this BHAV is to make sure that the clock displays the correct hour in the correct color. To this end, it first collects the game clock's "hour" value in Local Variable 0. Next, it checks to see whether or not the time is past noon. If so, we'll need to subtract "12" from Local Variable 0 because the DigiDec is a twelve-hour clock, not a military clock; it doesn't display 13:00, for instance. If, on the other hand, the time is 0:00, we go ahead and change Local Variable 0 to "12."

We would almost be finished at this point, but the design is slightly complicated by the fact that the DigiDec has two more optional colors. While the drawgroups were being created, care was taken to ensure that the graphics for the time display would be consistent. The graphic for "12:00" blue is exactly twelve drawgroups behind "12:00" red, which is exactly 12 drawgroups behind "12:00" green. Therefore, all we have to do is test the value of Stack Obj's Attribute 0, and if it is "1" or "2" we simply add "12" or "24" to the value of Local Variable 0 accordingly.

Now we're almost finished. We can go ahead and tell the BHAV to assign the value of "stack object's graphic" to Local Variable 0, but keep in mind that the drawgroup for "1:00" blue is actually at index 0, (and all of the other drawgroups are one index below the time represented by their graphic), so we simply subtract "1" from the value now stored in "stack object's graphic" before refreshing the graphic and moving on.
Update Alarm Time
This BHAV will immediately return "True" unless the alarm is in "automatic" mode, which (you'll recall from the "Attributes" table above) means that Stack Obj's Attribute 2 is set to a value from "1" to "5."

The reason for separating a "manual" mode from an "automatic" mode in the first place is that if the alarm is set to go off a certain amount of time before the carpool arrives, then the actual alarm hour is not set in stone; it's relative and must be updated regularly in case the sim gets a promotion and his or her work schedule changes. That's where this BHAV comes into play. Using a method which was largely stolen from the Maxis alarm clock, it gathers the "job type" in Temporary Storage 0 and the "job promotion" in Temporary Storage 1. Then, it uses those two values to store the sim's job start time into a variable of our choosing. Since we first have to set Stack Obj ID to "Next Person" before grabbing any info from the sim, we can't directly adjust the DigiDec's Stack Obj's Attributes until setting Stack Obj ID back to "my obj id." For that reason, I just used Local Variable 1 and Local Variable 2 as proxies for Stack Obj's Attribute 1 and Stack Obj's Attribute 2 respectively.

As for the math, that starts out with the act of setting Local Variable 1 to the sim's start job. Since the goal is to eventually set Stack Obj's Attribute 1 a certain number of hours before the sim's job starts, we need to subtract. Back in the Interaction BHAVs used to set the alarm for work, Stack Obj's Attribute 2 was set to the appropriate number, and since Local Variable 2 is now set to Stack Obj's Attribute 2, all we have to do is subtract Local Variable 2 from Local Variable 1.

However, we still have to account for the possibility that our sim's job starts in the wee hours of the morning, which would cause Local Variable 1 to end up being negative if we subracted a large enough number. There's an easy fix for this; all we need to do is check to see whether Local Variable 1 is less than "0" and then add "24" if it is.

Now we can be confident that Local Variable 1 is currently the value that we want Stack Obj's Attribute 1 to be, so it's time to return the Stack Obj ID to "my obj id" and assign Stack Obj's Attribute 1 to Local Variable 1's value.
Set For Work -1
This is merely the first of the five "Set For Work" BHAVs. It simply uses a standard "Go To" function and then sets Stack Obj's Attribute 2 to "1." The other four "Set For Work" BHAVs set Stack Obj's Attribute 1 to "2," "3," "4" and "5" accordingly.
Set For 0:00
This particular BHAV sets Stack Obj's Attribute 1 to "0," which means that it sets the alarm to go off at midnight. It also sets Stack Obj's Attribute 2 to "6" because we want the clock to be in neither "off" mode nor "automatic" mode, and "6" is the number chosen specifically for "manual" mode. This BHAV has twenty-three near-identical copies, but each of them sets Stack Obj's Attribute 1 to a different value from "1" to "23" accordingly.
Change to Blue
This BHAV runs "Go To" and then changes Stack Obj's Attribute 0 to "0." "Change to Red" and "Change to Green" change Stack Obj's Attribute 0 to "1" and "2," of course. After setting the attritube, there's also a call to the "Update Graphics" BHAV because it's normally only run from the "init tree" or "Once Per Hour" BHAVs, but we don't want to wait until the time changes to see the color update.
It doesn't get much simpler than this one. All it does is "Go To" the unit and set Stack Obj's Attribute 2 to "0," which is the "off" state. It doesn't even make a change to Stack Obj's Attribute 1 because no matter what time the alarm is technically still set for, it won't ring if the clock is in "off" mode.
Not surprisingly, this BHAV calls for the alarm clock's "ringing" sound. When it is first called, it handles a few preliminary steps before trapping the object in a loop; the most important of these steps is setting Local Variable 3 to "10." This is important because after the object has entered the loop, each iteration will decrease Local Variable 3 until it reaches zero, at which point the object will escape the loop. During the loop in question, the object switches between the two "ringing" drawgroups, refreshes itself and idles for a moment. Idling is important because the object can't get back to its "main" BHAV and idle from there, and if the object isn't allowed to idle at all, it will cause everything in the game, including the sims, to freeze.

Even though the DigiDec appears to have four rotations, please note that it actually only uses "front" and "back." I was able to keep the numbers in the display from appearing backwards in the "flipped" rotation because I kept them as seperate sprites. When the DigiDec's frame is flipped, the sprite index used for the display is actually the "back" graphic. When the frame's back is showing, the display isn't visible, so it's not even referenced in those drawgroups.

The complexity might have been overkill, but it did manage to save a great deal of unnecessary SPR2 bloat, which can quickly increase file sizes. It's a good technique to keep in mind for larger objects that would accumulate a lot of bloat quickly.

Thanks for reading!
~ Candall