WTS/game/scripts/utility/updatechecker.rpy

592 lines
25 KiB
Plaintext

init python early:
import zipfile
import json
import os
import ctypes
import shutil
def is_admin():
try:
return bool(ctypes.windll.shell32.IsUserAnAdmin())
except:
return False
def ask_admin():
"""We only need admin privileges if we fail deleting a file."""
try:
ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(" ".join(sys.argv)), None, 1)
return True
except:
return False
def remove_file(f):
f = os.path.join(config.basedir, f)
if not os.path.isfile(f):
return 0
try:
os.remove(f)
except OSError as e:
print "Cannot delete '{}'".format(f)
print "Error: {}".format(e)
return 2
else:
print "'{}' deleted".format(f)
return 1
def copytree(src, dst, symlinks=False, ignore=None):
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dst, item)
if os.path.isdir(s):
shutil.copytree(s, d, symlinks, ignore)
else:
shutil.copy2(s, d)
def version_float():
control, major, minor = config.version.split(" ")[0].split(".")
return float("{}.{}{}".format(control, major, minor))
# This function is no longer being used to check for potential updates.
# def version_check():
# if config.developer:
# return False
# import urllib2
# request = urllib2.Request(binascii.unhexlify("68747470733a2f2f706173746562696e2e636f6d2f7261772f424e354261647639"))
# try:
# response = urllib2.urlopen(request)
# except URLError as e:
# if hasattr(e, "reason"):
# print "Cannot check for updates. Server cannot be reached."
# print "Reason: {}".format(e.reason)
# elif hasattr(e, "code"):
# print "Cannot check for updates. Server cannot fulfill the request."
# print "Error: {}".format(e.code)
# return False
# current = version_float()
# latest = response.read()
# return current >= float(latest)
def version_patch():
if renpy.is_init_phase():
# Don't update save files from when game recovers from a crash.
return
latest = version_float()
if not hasattr(renpy.store, "version"):
if hasattr(renpy.store, "save_internal_version"):
raise Exception("Loaded save file is incompatible. (Save Version: {}, Game Version: {})".format(getattr(renpy.store, "save_internal_version")), latest)
raise Exception("Loaded save file is incompatible. (Save Version: Unknown, Game Version: {})".format(latest))
current = version
if current > latest:
raise Exception("Loaded save file is incompatible. (Save Version: {}, Game Version: {})".format(current, latest))
if current < latest:
setattr(renpy.store, "version", latest)
message = "Have fun!"
achievements.attempt_repair()
if current < 1.401:
global inventory_mode, time_turner_ITEM, imagination, bdsm_imagination, cheat_reading, birthday_happened
inventory_mode=0
inventory.remove(time_turner_ITEM)
del time_turner_ITEM
del imagination
del bdsm_imagination
del cheat_reading
del birthday_happened
if renpy.get_screen("blkfade"):
renpy.hide_screen("blkfade")
if not ball_quest.E4_complete:
her_outfit_ball.price = 0
if current < 1.402:
global mr_ev_ADR, hg_pr_sex_skip
mirror.remove(mr_ev_ADR)
del mr_ev_ADR
ton_hat_classy.zorder=3
ton_hat_classy.set_layers()
tonks.rebuild()
del hg_pr_sex_skip
if renpy.music.get_playing(channel="bg_sounds") == "sounds/fire02.ogg":
renpy.music.stop(channel="bg_sounds")
if current < 1.41:
reset_variables("tutorial_dict")
cho_outfit_cheerleader.name = "Ravenclaw Cheerleader Uniform"
cho_outfit_party.name = "Clubslut Outfit"
cho_outfit_bikini.name = "Micro Bikini Set"
her_outfit_bikini2.name = "Leathered Bikini Set"
her_outfit_bikini3.name = "Sling Bikini Set"
her_outfit_witch.name = "16th Century Witch Costume"
her_outfit_slutty_schoolgirl.name = "Slutty Schoolgirl Outfit"
her_outfit_fishnet.name = "Fishnet Set"
her_outfit_cheerleader_1.name = "Gryffindor Cheerleader Uniform"
her_outfit_cheerleader_2.name = "Gryffindor Cheerleader Plus Uniform"
lun_outfit_bikini3.name = "Rave Bikini Set"
ton_outfit_bikini_1.name = "Simple Bikini set"
ton_outfit_bikini_2.name = "Striped Bikini set"
quidditchguide_ITEM.price = 100
for i in inventory.items:
if hasattr(i, "infinite"):
continue
setattr(i, "infinite", False)
i.infinite = False
### Start Update 'Admire Panties' event
# Store states
ev_tier = hg_pf_admire_panties.tier
ev_in_progress = hg_pf_admire_panties.inProgress
ev_counter = hg_pf_admire_panties.counter
# Remove old pointer from favour list
hg_favor_list.remove(hg_pf_admire_panties)
# Re-run default statement
reset_variables("hg_pf_admire_panties")
# Restore state
hg_pf_admire_panties.tier = ev_tier
hg_pf_admire_panties.inProgress = ev_in_progress
hg_pf_admire_panties.counter = ev_counter
# Mark events from tier below as completed
if ev_tier > 1:
for i in xrange(ev_tier):
for ev in hg_pf_admire_panties.events[i]:
ev[1] = True
# Add new pointer to favour list
hg_favor_list.append(hg_pf_admire_panties)
### End Update 'Admire Panties' event
leg2_scroll_ITEM.label = "leg2_scroll"
global sna_support, ton_support
del sna_support
del ton_support
preferences.renderer = "angle2" if renpy.windows else "gl2"
# Update tooltip scope
renpy.hide_screen("tooltip")
renpy.show_screen("tooltip")
# Reset house points (Required to ensure balance isn't affected)
global gryffindor, slytherin, ravenclaw, hufflepuff
gryffindor, slytherin, ravenclaw, hufflepuff = 400, 500, 500, 500
# Update Outfits Addons
her_outfit_pajama.group = [her_hair_base.clone(), her_top_pajama.clone(), her_bottom_pajama.clone()]
her_outfit_pajama.addons = [her_bottom_pajama2]
her_outfit_maid.group = [her_hair_base.clone(), her_top_maid1.clone(), her_stockings_maid1.clone(), her_hat_maid1.clone(), her_neckwear_maid1.clone(), her_gloves_maid1.clone(), her_panties_base1.clone(), her_bra_base1.clone()]
her_outfit_maid.addons = [her_neckwear_maid2]
her_outfit_xmas.group = [her_hair_base.clone(), her_hat_antlers.clone(), her_neckwear_bell1.clone(), her_top_xmas.clone(), her_bottom_xmas.clone(), her_gloves_xmas.clone(), her_stockings_xmas.clone(), her_panties_base1.clone()]
her_outfit_xmas.addons = [her_hat_elf]
ton_outfit_succubus.group = [ton_hair_base_new.clone(), ton_hat_succubus.clone(), ton_neckwear_succubus.clone(), ton_gloves_succubus.clone(), ton_top_succubus.clone(), ton_panties_succubus.clone(), ton_accessory0_succubus.clone(), ton_accessory1_succubus.clone()]
ton_outfit_succubus.addons = [ton_top_succubus2]
ton_outfit_xmas.group = [ton_hair_base_new.clone(), ton_hat_antlers.clone(), ton_earring_bells.clone(), ton_neckwear_bell1.clone(), ton_bra_pasties2.clone(), ton_bottom_xmas.clone(), ton_gloves_xmas.clone(), ton_stockings_xmas.clone()]
ton_outfit_xmas.addons = [ton_piercing1_nipple_bells, ton_bra_pasties2]
# Update tonks' bikini
ton_panties_base.color_default = [[228, 250, 255, 255], [228, 55, 20, 255]]
ton_bra_base.color_default = [[228, 250, 255, 255], [228, 55, 20, 255]]
ton_panties_base.set_layers()
ton_bra_base.set_layers()
for i in CHARACTERS:
char = getattr(renpy.store, i)
for outfit in char.outfits:
if hasattr(outfit, "addons"):
continue
setattr(outfit, "addons", [])
char.rebuild()
# Add new backside layer for Hermione, and update zorders
hermione.body.body.update({"backside": [None, 1],})
hermione.body.set_zorder(armright=-1, base=0)
# Update CG camera object
camera.min_zoom = 0.1
# Didn't we remove that in last patch?
if hasattr(renpy.store, "hg_pr_sex_skip"):
delattr(renpy.store, "hg_pr_sex_skip")
# Update room objects
fireplace_OBJ.tooltip = "Light/Extinguish"
trophy_OBJ.pos = (650, 120)
if current < 1.411:
ton_gloves_leather.armfix = True
ton_gloves_leather.set_layers()
for i in CHARACTERS:
char = getattr(renpy.store, i)
char.rebuild()
setattr(renpy.store, "inventory_mode", 0)
if ll_pf_inspect.is_event_complete(2, 3):
hair_luna_ITEM.owned = 1
if current < 1.412:
message = "Happy halloween!"
# Fix luna levels
setattr(cho_hat_catears, "level", 10)
setattr(lun_top_crop, "level", 7)
setattr(lun_panties_lace2, "level", 7)
setattr(lun_stockings_muggle_knee_socks, "categories", ("legwear", "stockings"))
for i in inventory.items:
# Fix general items
if not hasattr(i, "give_label"):
setattr(i, "give_label", None)
if not hasattr(i, "usable_on"):
setattr(i, "usable_on", [])
# Fix decorations
if i.type == "decoration":
if not hasattr(i, "replaces"):
setattr(i, "replaces", False)
if not hasattr(i, "use_action"):
setattr(i, "use_action", None)
if not hasattr(i, "replace_action"):
setattr(i, "replace_action", None)
if not hasattr(i, "room_image_hover"):
setattr(i, "room_image_hover", i.room_image)
elif i.type == "gift":
setattr(i, "usable_on", list(CHARACTERS))
setattr(collar_ITEM, "name", "Magic Collar")
setattr(collar_ITEM, "price", 500)
setattr(collar_ITEM, "givable", True)
setattr(collar_ITEM, "give_label", "collar_scene")
setattr(collar_ITEM, "caption", "Give")
setattr(collar_ITEM, "usable_on", ["hermione"])
setattr(collar_ITEM, "unlocked", True)
setattr(collar_ITEM, "label", None)
setattr(collar_ITEM, "usable", False)
setattr(collar_ITEM, "desc", "{size=-2}A collar made out of metal. It has an inscription on the back.\n\n{/size}{size=-2}{i}\"Transforms to show the wearers true self.\n WARNING: May cause harm to adjacent clothing during transformation.\"{/i}{/size}")
setattr(collar_ITEM, "limit", 100)
setattr(halloween_phoenix_ITEM, "name", "Phoenix Halloween Set")
setattr(halloween_phoenix_ITEM, "desc", "A Halloween themed set for your favourite bird!")
setattr(halloween_fireplace_ITEM, "desc", "Adds a spooky pumpkin near your fireplace!")
setattr(halloween_cupboard, "name", "Cupboard Pumpkin")
setattr(halloween_cupboard, "desc", "Get in the Halloween spirit with this pumpkin, nobody's eating them so might as well decorate with them!")
# Fix room objects
setattr(candleL_OBJ, "focus_mask", True)
setattr(candleR_OBJ, "focus_mask", True)
setattr(candleL_OBJ, "zorder", 3)
setattr(candleR_OBJ, "zorder", 3)
# Rebuild models
for i in CHARACTERS:
char = getattr(renpy.store, i)
char.rebuild()
if current < 1.413:
message = "Happy halloween!"
if getattr(renpy.store, "room_menu_active"):
renpy.hide_screen("with_snape")
renpy.hide_screen("with_tonks_animated")
renpy.hide_screen("tonks_sit_ani")
renpy.hide_screen("tonks_sit_ani")
renpy.hide_screen("snape_chibi")
if current < 1.414:
message = "Happy Holidays!"
for i in inventory.items:
if i.type == "decoration":
if not hasattr(i, "replace_anchor"):
setattr(i, "replace_anchor", None)
setattr(i, "replace_pos", None)
# To fix hover images we need to dive into children of the hover transform displayable,
# and see if the child is None, in which case it should be replaced with the base room image.
# Animations (blink) are added on show events so it's irrevelant.
if i.room_image_hover and i.room_image_hover.child is None:
i.room_image_hover = i.room_image
ton_panties_succubus.armfix = True
tonks.rebuild()
# Power saving results in flickering on Intel Xe graphics units and low performance on some android devices. (probably a symptom rather than a cause)
preferences.gl_powersave = False
if current < 1.42:
message = "Happy April 1st! \n{size=-4}Disclaimer: This update is no joke, it's totaly real!{/size}"
# Update Cho clothes
choq_cloth_robequidditch1.armfix = False
choq_cloth_robequidditch1.color_default = [[60, 78, 131, 255], [186, 141, 11, 255]]
choq_cloth_robequidditch1.reset_color()
choq_cloth_topsweater1.armfix = False
choq_cloth_topsweater1.color_default = [[60, 78, 131, 255], [186, 141, 11, 255]]
choq_cloth_topsweater1.reset_color()
choq_cloth_pantslong2.armfix = False
choq_cloth_pantsshort4.armfix = False
cho_outfit_quidditch.group = [choq_cloth_topsweater1, choq_cloth_pantslong2, choq_cloth_robequidditch1, choq_bra_sports1, choq_panties_sport1]
cho_outfit_quidditch_hufflepuff.group = [choq_cloth_topsweater1, choq_cloth_schoolskirt2, choq_cloth_robequidditch1, choq_accessory_protectors, choq_bra_sports1, choq_panties_sport1]
cho_outfit_quidditch_slytherin.group = [choq_cloth_topsweater1, choq_cloth_pantslong2, choq_accessory_protectors2, choq_bra_sports1, choq_panties_sport1]
cho_outfit_quidditch_gryffindor.group = [choq_cloth_topsweater1, choq_cloth_schoolskirt3, choq_accessory_protectors, choq_bra_sports1, choq_panties_sport1]
# Update chitchat states and delete old vars from memory.
setattr(renpy.store, "snape_chatted", chitchated_with_snape)
setattr(renpy.store, "tonks_chatted", chitchated_with_tonks)
setattr(renpy.store, "hermione_chatted", chitchated_with_hermione)
setattr(renpy.store, "luna_chatted", chitchated_with_luna)
setattr(renpy.store, "cho_chatted", chitchated_with_cho)
setattr(renpy.store, "astoria_chatted", chitchated_with_astoria)
setattr(renpy.store, "susan_chatted", chitchated_with_susan)
delattr(renpy.store, "chitchated_with_snape")
delattr(renpy.store, "chitchated_with_tonks")
delattr(renpy.store, "chitchated_with_hermione")
delattr(renpy.store, "chitchated_with_luna")
delattr(renpy.store, "chitchated_with_cho")
delattr(renpy.store, "chitchated_with_astoria")
delattr(renpy.store, "chitchated_with_susan")
# Quidditch
setattr(cho_quid, "E10_complete", False)
setattr(cho_quid, "E11_complete", False)
setattr(cho_quid, "E12_complete", False)
setattr(cho_quid, "E13_complete", False)
setattr(cho_quid, "gryffindor_failed", False)
setattr(cho_quid, "gryffindor_prepared", False)
setattr(cho_quid, "gryffindor_training", False)
setattr(cho_quid, "gryffindor_complete", False)
# Tonks
setattr(renpy.store, "tonks_wardrobe_unlocked", True)
### Start Update 'Talk To Me' events
# Store states
ev_tier = cc_pf_talk.tier
ev_in_progress = cc_pf_talk.inProgress
ev_counter = cc_pf_talk.counter
# Remove old pointer from favour list
cc_favor_list.remove(cc_pf_talk)
# Re-run default statement
reset_variables("cc_pf_talk")
# Restore state
cc_pf_talk.tier = ev_tier
cc_pf_talk.inProgress = ev_in_progress
cc_pf_talk.counter = ev_counter
# Mark events from tier below as completed
# TODO: This might cause some events from current tier to be skipped.
# It would be better to use deepcopy on the list instead.
if ev_tier > 1:
for i in xrange(ev_tier):
for ev in cc_pf_talk.events[i]:
ev[1] = True
# Add new pointer to favour list
cc_favor_list.append(cc_pf_talk)
cho.rebuild()
# Reverse whoring cheat, otherwise the player would be locked out of some paths.
if getattr(renpy.store, "cho_whoring") >= 12:
setattr(renpy.store, "cho_whoring", 12)
# Update camera
camera.max_zoom = 5.0
### End Update 'Talk To Me' event
if current < 1.421:
message = "Happy April 1st!"
hooch.equip(hoo_outfit_default)
cho_outfit_quidditch.group = [choq_cloth_topsweater1.clone(), choq_cloth_pantslong2.clone(), choq_cloth_robequidditch1.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_hufflepuff.group = [choq_cloth_topsweater1.clone(), choq_cloth_schoolskirt2.clone(), choq_cloth_robequidditch1.clone(), choq_accessory_protectors.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_slytherin.group = [choq_cloth_topsweater1.clone(), choq_cloth_pantslong2.clone(), choq_accessory_protectors2.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_gryffindor.group = [choq_cloth_topsweater1.clone(), choq_cloth_schoolskirt3.clone(), choq_accessory_protectors.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
if current < 1.422:
message = ""
hooch.equip(hoo_outfit_default)
cho_outfit_quidditch.group = [cho_hair_ponytail1.clone(), choq_cloth_topsweater1.clone(), choq_cloth_pantslong2.clone(), choq_cloth_robequidditch1.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_hufflepuff.group = [cho_hair_ponytail1.clone(), choq_cloth_topsweater1.clone(), choq_cloth_schoolskirt2.clone(), choq_cloth_robequidditch1.clone(), choq_accessory_protectors.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_slytherin.group = [cho_hair_ponytail1.clone(), choq_cloth_topsweater1.clone(), choq_cloth_pantslong2.clone(), choq_accessory_protectors2.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho_outfit_quidditch_gryffindor.group = [cho_hair_ponytail1.clone(), choq_cloth_topsweater1.clone(), choq_cloth_schoolskirt3.clone(), choq_accessory_protectors.clone(), choq_bra_sports1.clone(), choq_panties_sport1.clone()]
cho.rebuild()
renpy.call_in_new_context("modal_popup", "Update Successful", "\nYour save file has been successfully updated to version {{b}}{}{{/b}}.\n\n{}".format(config.version, message), None, "Hurray!")
renpy.block_rollback()
return
def version_upgrade():
if config.developer:
return
if renpy.mobile:
return
def get_patch(files, deep=False):
prefix = config.gamedir if deep else config.basedir
archives = [os.path.join(prefix, x) for x in files if x == "patch.zip"]
if not archives:
return None
file = max(archives, key=os.path.getmtime)
return file
def get_progress(files):
for i, _ in enumerate(files):
print i
print "Searching for an archive..."
# Base search
files = [x for x in os.listdir(config.basedir) if os.path.isfile(x)]
patch = get_patch(files)
# Deep search
if not patch:
files = renpy.list_files()
patch = get_patch(files, deep=True)
if not patch:
print "No update packages detected. Skipping."
return
print "Archive found.\n{}".format(patch)
with zipfile.ZipFile(patch, "r") as zip:
print "Testing archive..."
corrupted = zip.testzip()
if corrupted:
print "Cannot perform an upgrade. File is corrupted."
return
print "Checking manifest..."
contents = zip.namelist()
if not "manifest.json" in contents:
print "Cannot perform an upgrade. Manifest not found."
return
with zip.open("manifest.json") as manifest:
data = json.load(manifest)
target = data.get("Target", None)
if not target:
print "Cannot perform an upgrade. Manifest is missing a target."
return
current = version_float()
if current >= float(target):
print "Cannot perform an upgrade. Equal or higher version already installed."
return
delete = data.get("Delete", [])
for f in delete:
status = remove_file(f)
if status == 2:
# Lacking permissions
if renpy.windows and not is_admin():
ask_admin()
renpy.quit()
print "Backing up files..."
src = os.path.join(config.basedir, "game/scripts/")
dest = os.path.join(config.basedir, "old-game/scripts/")
if os.path.isdir(dest):
shutil.rmtree(dest)
copytree(src, dest)
print "Unpacking..."
zip.extractall(config.basedir, members=get_progress(contents))
remove_file("instructions.txt")
remove_file("DO NOT EXTRACT!")
remove_file("hotfix.zip")
src = patch
dest = os.path.join(config.basedir, "old_patch.zip")
if os.path.isfile(dest):
remove_file(dest)
os.rename(src, dest)
print "Done."
print "Restarting..."
renpy.quit(relaunch=True)
version_upgrade()
init python:
config.after_load_callbacks.append(version_patch)
label before_main_menu():
# Add screen
return