Talk:Full Moon Table

From A KoL Wiki

Do we want to add Mild Lycanthropy to the table? It's an awfully small effect (+1% Mus and -1% Mox per unit of light), so I'm not sure it's worth making the table bigger for it. Especially if more moon-related effects appear in the future.--Terion 09:29, 13 October 2007 (CDT)

  • Hm. I guess we could turn the Baio column to "light units." It's pretty easy to multiply by 1 and 10. --Bagatelle 11:14, 13 October 2007 (CDT)
    • Speaking of more effects: Lycanthropy, Eh? is also based on the moon, +2% Mus and -2% Mox per unit of light. --Terion 20:36, 13 October 2007 (CDT)
  • Uh, how does one update the table? --Mr Crac 08:10, 12 November 2007 (CST)
    • From now on, automajickally. I'll post some Python code below. In terms of QA of whether the program works, I ran through the old dates and noticed no egregious differences. I've also taken the liberty of changing the Talisman column to a Total Moonlight column as discussed above. --Bagatelle 14:50, 12 November 2007 (CST)
      • It seems the automatical update is not happening. :-( Or do you mean I'd have to install a Python compiler, run the program, and copy&paste its output to the Calendar page? --Mr Crac 14:57, 13 May 2008 (CDT)
        • The code indeed must be run manually. It's a little easier than compiling, as in Python, all one has to do is save the code file locally and run it through the interpreter. --Bagatelle 19:19, 13 May 2008 (CDT)
          • I have tried to run this Python code, this is what I get :-(
Traceback (most recent call last):
  File "D:\calendar.py", line 239, in <module>
    Table += Line
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 672: ordinal not in range(128)

--Mr Crac 01:10, 29 October 2008 (UTC)

            • Hah. The copy & paste converted the HTML elements to Unicode, which screwed up the HP/MP multipliers. Anyway, tweaked below and updated article for the next six months. Sometimes I wonder whether people actually use this page... --BagatelleT/C 18:43, 29 October 2008 (UTC)
              • Tried to do an update using Python 3.01. First it whines that the character encoding is not correct seemingly. Then it complains about syntax errors. Then I fix errors, then it still complains. This is silly. Can we somehow establish a working solution here? Also, I can now totally see why Python is supposed to be so completely awesome. :-/ --Mr Crac 14:58, 27 April 2009 (UTC)
                • After fixing the encoding errors for Labór Day and ×2 HP/MP (just changed them to something else and fixed the output by hand), it worked fine. --Quietust (t|c) 15:23, 27 April 2009 (UTC)
                • Srysry, I've got my editor set to read UTF by default. Escaping using HTML entities will probably work for Python installs out-of-the-box. --BagatelleT/C 22:33, 27 April 2009 (UTC)

This is just awesome. Scroll down slowly to see revolving spheres. Thanks Jick!--Eniteris 19:32, 20 December 2008 (UTC)

Code

This Python code outputs only the monthly links and the full moon table part of the article. i.e., do not overwrite any introductory content or notes, categories, etc when copy-pasting. A person wishing to update the article to a new 176-day cycle need only save the file onto their computer and run it through the Python interpreter after modifying the start date parameters. The output can then be pasted into the article. The code runs in versions 3.x.

# start the moon cycle on this date; end date is calculated automatically
# as a complete 176-day cycle
# starting year, month, day of the calendar
StartYear = 2009
StartMonth = 4
StartDay = 23

# do not edit below this line
################################################################################
# code
from datetime import *

# date format
StartDate = date(StartYear, StartMonth, StartDay)
EndDate = StartDate + timedelta(175)
EndYear = EndDate.year
EndMonth = EndDate.month

# use a base date of 2007-11-11
BaseDate = date(2007, 11, 11)
Days = (StartDate - BaseDate).days
# 2007-11-11 was 03-01 KoL month-day; or 16th day if 01-01 is considered day 0
KoLStartDate = (16 + Days) % 96
# eight days in a KoL month
KoLStartMonth = int(KoLStartDate / 8) + 1
KoLStartDay = KoLStartDate % 8 + 1
# initialise {{moon}}
# Ronald, Grimace, minimoon were all at position 1 on 2007-11-11
# Grimace was on its first day of its two-day increment
RonaldStart = Days % 8 + 1
GrimaceStart = int(Days / 2) % 8 + 1
GrimaceOffset = Days % 2
MinimoonStart = (Days * 2) % 11 + 1

# list of KoL months
KoLMonths = [
  "Jarlsuary", "Frankuary", "Starch", "April", "Martinus", "Bill", "Bor",
  "Petember", "Carlvember", "Porktober", "Boozember", "Dougtember"
]

# game holidays
KoLHolidays = {
  "0101": "The Festival of Jarlsberg",
  "0204": "Valentine's Day",
  "0303": "St. Sneaky Pete's Day",
  "0402": "Oyster Egg Day",
  "0502": "El Dia de Los Muertos Borrachos",
  "0603": "Generic Summer Holiday",
  "0704": "Dependence Day",
  "0804": "Arrrbor Day",
  "0906": "Labór Day",
  "1008": "Halloween",
  "1107": "Feast of Boris",
  "1204": "Yuletide"
}

# real holidays
RealHolidays = {
  "0101": "The Festival of Jarlsberg",
  "0202": "Groundhog Day",
  "0214": "Valentine's Day",
  "0317": "St. Sneaky Pete's Day",
  "0401": "April Fool's Day",
  "0704": "Dependence Day",
  "0919": "Talk Like a Pirate Day",
  "1031": "Halloween",
  "1225": "Crimbo"
}

# real Easter Sunday (Gregorian) falling in the two years of the starting date
def Easter(Y):
  a = Y % 19
  b = int(Y / 100)
  c = Y % 100
  d = int(b / 4)
  e = b % 4
  f = int((b + 8) / 25)
  g = int((b - f + 1) / 3)
  h = (19*a + b - d - g + 15) % 30
  i = int(c / 4)
  k = c % 4
  L = (32 + 2*e + 2*i - h - k) % 7
  m = int((a + 11*h + 22*L) / 451)
  return date(Y, int(((h + L - 7*m + 114) / 31)), (((h + L - 7*m + 114) % 31) + 1))

Easter = [
  Easter(StartYear), Easter(StartYear + 1)
]

# generate a list to use as anchors to link to each real month of the cycle
IDList = []
for Year in range(StartYear, EndYear + 1):
  for Month in range(1, 13):
    if [StartYear, StartMonth] <= [Year, Month] <= [EndYear, EndMonth]:
      IDList.append(date(Year, Month, 1))

# monthly links
Header = """<div style="border: 1px solid #666; background: #EEE; """ + \
         """text-align: left; margin: 0 auto 1em; padding: 0.5em">"""
for Pos in range(0, len(IDList)):
  if Pos != 0:
    Header += " | "
  Temp = IDList[Pos].strftime("%B %Y")
  Header += "[[#" + Temp  + "|" + Temp + "]]"
Header += """</div>"""

# head of table
Table = """{| cellpadding="1" cellspacing="0" border="1" """ + \
"""style="margin-left: auto; margin-right: auto; text-align: center"
|- style="text-align: center; background-color: #EEEEEE"
!  [[Calendar|Date]]
! style="width: 123px" | [[Moons]]
! [[Stat Days|Stat<br>Day]]
! [[Resting]]
! [[Temporary Lycanthropy|Temporary<br />Lycanthropy]]
! [[Grue]]
! [[Moons|Total<br />Moonlight]]
! [[Jekyllin hide belt|Jekyllin]]
! [[The Raffle House|Grimacite<br />Equipment]]<br />(latest generation gives half of listed stat)"""

# initialise variables for looping
Date = StartDate
CurrKoLMonth = KoLStartMonth
CurrKoLDay = KoLStartDay
Ronald = RonaldStart
Grimace = GrimaceStart
Offset = GrimaceOffset
Minimoon = MinimoonStart
CurrMonth = 0
while Date <= EndDate:
  # calculate total light, Grimace darkness
  Light = 8 - abs(5 - Ronald) - abs(5 - Grimace)
  GrimaceDark = abs(5 - Grimace)
  # calculate minimoon modifiers
  LeftLight = [2, 3, 4, 5]
  RightLight = [5, 6, 7, 8]
  RonaldLeftLight = Ronald in LeftLight
  RonaldRightLight = Ronald in RightLight
  GrimaceLeftLight = Grimace in LeftLight
  GrimaceRightLight = Grimace in RightLight
  LightMod = 0
  if Minimoon == 1:
    LightMod = RonaldLeftLight
  elif Minimoon == 2:
    LightMod = (Ronald not in LeftLight) - (Ronald in LeftLight)
  elif Minimoon == 3:
    LightMod = (Ronald not in RightLight) - (Ronald in RightLight)
  elif Minimoon == 4:
    LightMod = RonaldRightLight + GrimaceLeftLight
  elif Minimoon == 5:
    LightMod = (Grimace not in LeftLight) - (Grimace in LeftLight)
  elif Minimoon == 6:
    LightMod = (Grimace not in RightLight) - (Grimace in RightLight)
  elif Minimoon == 7:
    LightMod = GrimaceRightLight
  elif Minimoon == 9:
    LightMod = GrimaceLeftLight
  elif Minimoon == 10:
    LightMod = RonaldRightLight
  GrimaceDarkMod = not (LightMod > 0)
  # catch exceptions for behind-moon cases
  if Minimoon in [8, 11]:
    LightMod = 0
    GrimaceDarkMod = 0
  # catch exceptions for when mini is in front of Grimace
  elif Minimoon in [5, 6]:
    GrimaceDarkMod -= not GrimaceDarkMod
  Light += LightMod
  GrimaceDark += GrimaceDarkMod

  # date
  PrevMonth = CurrMonth
  CurrMonth = Date.month
  if CurrMonth != PrevMonth:
    Line = "\n|-id=\"" + Date.strftime("%B %Y") + "\""
  else:
    Line = "\n|-"
  Line += \
    "\n|" + Date.strftime("%A, %B %d, %Y") + \
    "<br />" + KoLMonths[CurrKoLMonth - 1] + " " + str(CurrKoLDay)
  # check if real holiday/recurring KoL holiday
  KoLKey = "%02d" % CurrKoLMonth + "%02d" % CurrKoLDay
  RealKey = Date.strftime("%Y%m%d")
  KoLHoliday = KoLHolidays.get(KoLKey, "")
  RealHoliday = RealHolidays.get(RealKey[-4:], "")
  if not RealHoliday and Date in Easter:
    RealHoliday = "Oyster Egg Day"
  # if by chance real & KoL are same holiday only, want to show it once
  # otherwise, show both
  if RealHoliday or KoLHoliday:
    if RealHoliday == KoLHoliday:
      Line += "<br />([[" + RealHoliday + "]])"
    elif RealHoliday and KoLHoliday:
      Line += "<br />([[" + KoLHoliday + "]] and [["  + RealHoliday + "]])"
    else:
      Line += "<br />([[" + (RealHoliday or KoLHoliday) + "]])"

  # moons
  Line += \
    "\n|{{moon|" + str(Ronald) + "|" + str(Grimace) + "|" + str(Minimoon) + "}}"
  # stat days/resting
  if Ronald == 5:
    Line += "\n|Mysticality||×2 MP"
  elif Grimace == 5:
    Line += "\n|Muscle||×2 HP"
  elif Grimace == Ronald:
    Line += "\n|Moxie|| "
  else:
    Line += "\n| || "
  # temporary lycanthrope
  Line += "|| +" + str(int(round(10 + (20 * (Light**0.5)), 0))) + "% Muscle"
  # Grue
  if Light <= 5:
    Line += "||Attacks"
  else:
    Line += "||No Attack"
  # total moonlight
  Line += "||" + str(Light)
  # Jekyll
  Line += \
    "|| +" + str(9 - Light) + " All Stats<br />+" + str(15 + 5 * Light) + \
    "% Item Drops"
  # Grimacite
  Line += "||''stat'' +" + str(10 * GrimaceDark) + "%"

  # increment counters
  CurrKoLDay = CurrKoLDay % 8 + 1
  if CurrKoLDay == 1:
    CurrKoLMonth = CurrKoLMonth % 12 + 1
  Ronald = Ronald % 8 + 1
  if GrimaceOffset == 1:
    Grimace = Grimace % 8 + 1
  GrimaceOffset = (GrimaceOffset + 1) % 2
  if Minimoon >= 10:
    Minimoon = (Minimoon + 2) % 11
  else:
    Minimoon += 2
  Date = Date + timedelta(1)
  Table += Line
Table += "\n|}"

print(Header)
print("")
print(Table)

Mutant Familiars?

Now that it is known that the mutant rafflehouse familiars are effected by the moons, shouldn't they go on the table? Imakuni 17:51, 15 April 2009 (UTC)

Updated page

I've page some big-ish updates to this page. First, I rewrote the opening paragraph; since there are a large number of things affected by the moons which weren't listed there, I gave some examples and linked back to the moons page (at least four times). Then, I updated the table, starting in February 2011. I converted the above Python code to Java - huge thanks to whoever wrote the original code! I checked my table against NO's calendar, and it seems to match up, but if I made an error, please let me know. Finally, I juggled some columns. Everything is driven by the two light values, so I moved the total light right after the basic info, and converted the "grimacite equipment" column to grimacite darkness and put it next to total light. I let the Grue and Wereturtle share a column, and put lycanthropy and jek at the end. I didn't add anything new, since I didn't want the table to get too huge, and everything other than lycanthropy varies linearly with one of the light totals anyway. Let me know what you think. --Johnny Treehugger 17:16, 16 February 2011 (UTC)