[HD2 Windows Mobile 6.5 Themes and Apps] rat_2665:
Modifications of the lua script/functions

lua script 1EC5924B_manila (former 461d3306_manila)

This file is responsible for the animations of the analog clock. It's a HTC lua script. HTC's version of lua is not documented. So if you want to mod manila lua scripts you should have some basic knowledge in coding. I'm at best clumsy. I didn't find for example a solution to bring the numerical value of the calendar day to a string on the screen (EDIT: Problem solved with the help of co0kie). So I went around to the classical mechanical approach with two disks. So there is still room for some useful inventions. For start look at this general lua programming guide . Another good resource ist the source code of Co0kies Home Tab. It's published at the end of this post.

For compiling and decompiling I used m9editor. If you in the lower part of the editor click right at the lua script manila file, you can decompile the file and save it in the lua script subfolder of the editor. There you can change it with Notepad2 (by Florian Balmer, compiled by Co0kiemonster). It is part of this kitchen. But because m9editor sometimes had problems with decompiling I used essentially the homealarmclock.lua from co0kie's source. After that once more click right on the 1EC5924B_manila file in the m9editor and compile the manila file.

functions

For every function in lua there are three essential parts: the definition of the function, the calling of the function and the update of the calling. In the HTC lua scripts these parts are typically not in sucession for each function but combined in blocks for all functions (at first all definitions and so on).

Tourbillon Cage/ second hand

In the original file by co0kie the query of the position of minute and hour hand was triggered by a change of the value of the minute. So the minute hand jumps every minute, the hour hand moves continously. The position of the second hand was determind by an own function triggered by a timer every second.

For the Tourbillon it was necessary to use milliseconds. HTC ROMs don't work with milliseconds (although windows mobile provides it). So this has to be made by a timer function. Here a tip by Co0kie:

MyTimerName = timer(time_in_seconds) -- the time can be 0.1 seconds for example
-- after the timer is created it immediately starts ticking
MyTimerName.OnElapsed:connect(some_function) -- the name of the function that should be called after timeout - the timer runs in a loop so the function will be called every 0.1 seconds
MyTimerName:Stop() -- stops the timer
MyTimerName:Start() -- starts it again

In the new function "ClockSecond" the cage (secondHand) makes five steps every second. This factor five I defined as FinenessFactor, so it can be changed very simple. The distance is every step 12° (really depending on the FinenessFactor), so the Cage turns once every minute and can be used as second hand.

The ClockSecondTimer = timer(0.2) in line 192 determines the period between two steps. The function starts every second with the new position, so the timer value should be 1 second / FinenessFactor for continous moving

rotation is realized with the function XXX.Rotation.z =

360 - myHandsPosition in clockwise direction

myHandsPosition against clockwise direction

The value of myHandsPosition is the numerical value of the ° position

SecondsCheck = machineStatus.CurrentTime.Value.Second
Counter = 1

ClockSecond = function()
if secondHand._visible == true then
local FinenessFactor = 5
local globalsecond = machineStatus.CurrentTime.Value.Second
local myHandsPosition0 = globalsecond * FinenessFactor
if SecondsCheck == globalsecond then
myHandsPosition0 = globalsecond * FinenessFactor + Counter
Counter = Counter + 1
else
Counter = 1
end
local myHandsPosition = (myHandsPosition0 - (2 * FinenessFactor) + 1) / (60 * FinenessFactor) * 360
secondHand.Rotation.z = 360 - myHandsPosition
secondHand1.Rotation.z = 360 - myHandsPosition
secondHandnight.Rotation.z = 360 - myHandsPosition
SecondsCheck = globalsecond
minuteHand.Rotation.z = -((machineStatus.CurrentTime.Value.Minute / 60 * 360) + ((machineStatus.CurrentTime.Value.Second - 5) / 10))
minuteHandnight.Rotation.z = -((machineStatus.CurrentTime.Value.Minute / 60 * 360) + ((machineStatus.CurrentTime.Value.Second - 5) / 10))
else
ClockSecondTimer:Stop()
end
end

balance wheel (secondhand2)

function "ClockSecond2". The balance wheel has not the same behavior as the other "hands". It swings with 5 (= FinenessFactor2) frames 180° back and forth. Crucial for the speed (and the frequency of queries) is the ClockSecond2Timer = timer(0.04) in line 194. At present it realizes 25 frames per second, a value 0.1 is only 10 fps (I attached a 1EC5924B_manila/461d3306_manila with this value in post 30) . This is the most CPU power and energy consuming process in the clock, but also the most visible.

Counter2 = 0
turn2 = 0

ClockSecond2 = function()
if secondHand._visible == true then
local FinenessFactor2 = 5
local myHandsPosition2 = 360
if turn2 == 0 then
myHandsPosition2 = 360 - ((360 / FinenessFactor2) * Counter2)
if Counter2 == FinenessFactor2 then
turn2 = 1
Counter2 = 0
end
else
myHandsPosition2 = (360 / FinenessFactor2) * Counter2
if Counter2 == FinenessFactor2 then
turn2 = 0
Counter2 = 0
end
end
Counter2 = Counter2 + 1
secondHand2.Rotation.z = 360 - myHandsPosition2
secondHand2night.Rotation.z = 360 - myHandsPosition2
else
ClockSecond2Timer:Stop()
end
end

The calling of both functions for the tourbillon with update:

if ShowSecondHand then
secondHand._visible = true
ClockSecondTimer = timer(0.2)
ClockSecondTimer.OnElapsed:connect(ClockSecond)
ClockSecond2Timer = timer(0.04)
ClockSecond2Timer.OnElapsed:connect(ClockSecond2)
else
secondHand._visible = false
secondHand1._visible = false
secondHandnight._visible = false
secondHand2night._visible = false
end

second hand (secondHand3)

It is bound to the movement of the Tourbillon cage. See code above

minute hand

function "ClockMinute". For continous moving every second a 1/60 of a minute step is added.

minuteHand.Rotation.z = -((machineStatus.CurrentTime.Value.Minute / 60 * 360) + ((machineStatus.CurrentTime.Value.Second - 5) / 10))

calendar day by disks

The disk for the tens (DateDayTens) turns every ten days for 90°, the disk for the ones (DateDayOnes) every day for 36°. (Don't be afraid for month with days lower than 30, it is in the formula). It checks at the change of the current time value of windows mobile.

CalendarDate1 = function()
local locday = machineStatus.CurrentTime.Value.Day
local DayTens = 0
local DayOnes = 1
if locday < 10 then
DayTens = 0
else
if locday < 20 then
DayTens = 1
else
if locday < 30 then
DayTens = 2
else
DayTens = 3
end
end
end
DayOnes = locday - (DayTens * 10)
DateDayTens.Rotation.z = DayTens * 90
DateDayOnes.Rotation.z = DayOnes * 36
DateDayTensnight.Rotation.z = DayTens * 90
DateDayOnesnight.Rotation.z = DayOnes * 36
end

CalendarDate1()

machineStatus.CurrentTime.OnValueChanged:connect(CalendarDate1)

calendar day by text object

CalendarDate1 = function()
local locday = machineStatus.CurrentTime.Value.Day
DayDate.String = tostring(locday)
DayDate.Rotation.z = 330
local val = (AnalogAMPMColor / 10) * 255
DayDate.Color = Color(val, val, val, 255)
DayDatenight.String = tostring(locday)
DayDatenight.Rotation.z = 330
end

In this example the color of DayDate is bound to the color of AMPM. So you can set in CHT Editor also the color of the Date. The calling and the update is the same as above.

If you want a constant rotated position for an object simply add the line

XXX.Rotation.z = 360 - y

where XXX is the name of your object in the mode9 file and y the ° value ot the incline of your object

(example for AMPM in the above mentioned Hero clock "ShowAMPM.Rotation.z = 330")

moonphase

The mathematical formula for the moonphases is described at various astronomical websites. I took it from this Swiss site (at Berechnungen). The formula takes a date of a full moon and then counts the difference to the present day and divides this through the lunar month. The not integer part of the result describes the position of the moon.

local lochour = machineStatus.CurrentTime.Value.Hour
local locday = machineStatus.CurrentTime.Value.Day
local locmonth = machineStatus.CurrentTime.Value.Month
local locyear = machineStatus.CurrentTime.Value.Year

local valueYear = 365 * (locyear - 2010)
if locyear > 2011 then
if locyear > 2016 then
valueYear = valueYear + 2
else
valueYear = valueYear + 1
end
end

local valueMonth = 0
if locmonth == 2 then valueMonth = 31	end
if locmonth == 3 then valueMonth = 59	end
if locmonth == 4 then valueMonth = 90	end
if locmonth == 5 then valueMonth = 120	end
if locmonth == 6 then valueMonth = 151	end
if locmonth == 7 then valueMonth = 181	end
if locmonth == 8 then valueMonth = 212	end
if locmonth == 9 then valueMonth = 243	end
if locmonth == 10 then valueMonth = 273	end
if locmonth == 11 then valueMonth = 304	end
if locmonth == 12 then valueMonth = 334	end

if locyear == 2012 then
if locmonth > 2 then valueMonth = valueMonth + 1 end end
if locyear == 2016 then
if locmonth > 2 then valueMonth = valueMonth + 1 end end

local presentday = (lochour / 24) + locday + valueMonth + valueYear
local moonposition1 = (presentday - 30.25) / 29.530588
moonphase.Rotation.z = - ((moonposition1 - math.floor(moonposition1)) * 180)
moonphasenight.Rotation.z = - ((moonposition1 - math.floor(moonposition1)) * 180)
end

moonposition()

machineStatus.CurrentTime.OnValueChanged:connect(moonposition)

day of week

This function takes the first (here two letters) of your date string.

DayOfWeek1 = function()
local weekday1
weekday1 = machineStatus.CurrentTime.Value:GetDateString(Locale:GetString("IDS_DATEFORMAT"))
weekday1 = string.sub(weekday1, 1, 2)
weekday.String = tostring(weekday1)
weekdaynight.String = tostring(weekday1)
end

DayOfWeek1()

machineStatus.CurrentTime.OnValueChanged:connect(DayOfWeek1)

For another approach with three letters you have to subtitute the lines

weekday1 = machineStatus.CurrentTime.Value:GetDateString(Locale:GetString("IDS_DATEFORMAT"))
weekday1 = string.sub(weekday1, 1, 2)

with

weekday1 = machineStatus.CurrentTime.Value:GetDateString(Locale:GetString("dddd"))
weekday1 = string.sub(weekday1, 1, 3)

visibility

Visibility depends on the hour value of the clock. That's a problem with the 12h use in AMPM Regions. So you have to transform all values to 24h. This happends in the first part of the function. In the second part the opacity of the "night objects" is determined in a definite time intervall. A special case in this code example are objects which can be made unvisible by settings in CHT or Windows Mobile. For the animation functions I found some tips in the attached animation toolkit for CHT 1.6.1 by Co0kie.

switchvisibility = function()

local locAMPM = machineStatus.CurrentTime.Value:GetTimeString("tt")
local lochour = machineStatus.CurrentTime.Value.Hour

if locAMPM == "AM" then
ShowAMPMnight.String = "AM" else
ShowAMPMnight.String = "PM" end

if machineStatus.CurrentTime.Value.IsTwentyFourHour
then
local lochour = machineStatus.CurrentTime.Value.Hour
else
if locAMPM == "AM" then
if lochour == 12 then lochour = 0
end
else
if lochour ~= 12 then lochour = lochour + 12
end
end
end

if lochour > 7
then
if lochour < 20 then
minuteHandnight.Opacity:Interpolate(0,200, 0, Interpolate_Linear)
hourHandnight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
analogclocknight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
moonphasenight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
if secondHand._visible == true then
secondHandnight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
secondHand2night.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
end
if machineStatus.CurrentTime.Value.IsTwentyFourHour then
ShowAMPMnight._visible = false
else
ShowAMPMnight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
end
weekdaynight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
DayDatenight.Opacity:Interpolate(0, 200, 0, Interpolate_Linear)
else
minuteHandnight.Opacity:Interpolate(100,200, 0, Interpolate_Linear)
hourHandnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
analogclocknight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
moonphasenight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
if secondHand._visible == true then
secondHandnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
secondHand2night.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
if machineStatus.CurrentTime.Value.IsTwentyFourHour then
ShowAMPMnight._visible = false
else
ShowAMPMnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
weekdaynight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
DayDatenight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
else
minuteHandnight.Opacity:Interpolate(100,200, 0, Interpolate_Linear)
hourHandnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
analogclocknight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
moonphasenight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
if secondHand._visible == true then
secondHandnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
secondHand2night.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
if machineStatus.CurrentTime.Value.IsTwentyFourHour then
ShowAMPMnight._visible = false
else
ShowAMPMnight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
weekdaynight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
DayDatenight.Opacity:Interpolate(100, 200, 0, Interpolate_Linear)
end
end

switchvisibility()

machineStatus.CurrentTime.OnValueChanged:connect(switchvisibility)

I hope this description will help you to understand a little bit the modifications and maybe to make yourself some examples. You can also mod or delete the indivual modifications. I'm open for improvements and simplifications.