CampBuddy/Camp.Buddy v2.2.1/Camp_Buddy-2.2.1-pc/renpy/common/00achievement.rpy
2025-03-03 23:00:33 +01:00

377 lines
11 KiB
Text

# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
init -1500 python in achievement:
from store import persistent, renpy, config, Action
# A list of backends that have been registered.
backends = [ ]
class Backend(object):
"""
Achievement backends should inherit from this class, so new methods
will be ignored.
"""
def register(self, name, **kwargs):
"""
Called to register a new achievement.
"""
def grant(self, name):
"""
Grants the achievement with `name`, if it has not already been
granted.
"""
def clear(self, name):
"""
Clears the achievement with `name`, if it has been granted.
"""
def clear_all(self):
"""
Clears all achievements.
"""
def progress(self, name, complete):
"""
Reports progress towards the achievement with `name`.
"""
def has(self, name):
"""
Returns true if the achievement with `name` is unlocked.
"""
return False
class PersistentBackend(Backend):
"""
A backend that stores achievements in persistent._achievements.
"""
def __init__(self):
if persistent._achievements is None:
persistent._achievements = _set()
if persistent._achievement_progress is None:
persistent._achievement_progress = _dict()
def grant(self, name):
persistent._achievements.add(name)
def clear(self, name):
persistent._achievements.discard(name)
def clear_all(self):
persistent._achievements.clear()
def has(self, name):
return name in persistent._achievements
def progress(self, name, complete):
old = persistent._achievement_progress.get(name, 0)
persistent._achievement_progress[name] = max(complete, old)
def merge(old, new, current):
if old is None:
old = set()
if new is None:
new = set()
return old | new
def merge_progress(old, new, current):
if old is None:
old = { }
if new is None:
new = { }
rv = _dict()
rv.update(old)
for k in new:
if k not in rv:
rv[k] = new[k]
else:
rv[k] = max(new[k], rv[k])
return rv
renpy.register_persistent("_achievements", merge)
renpy.register_persistent("_achievement_progress", merge_progress)
backends.append(PersistentBackend())
steam_maximum_framerate = 15
# The position of the steam notification popup. One of "top left", "top right",
# "bottom left", or "bottom right".
steam_position = None
class SteamBackend(Backend):
"""
A backend that sends achievements to Steam. This is only used if steam
has loaded and initialized successfully.
"""
def __init__(self):
# A map from achievement name to steam name.
self.names = { }
self.stats = { }
steam.retrieve_stats()
renpy.maximum_framerate(steam_maximum_framerate)
def register(self, name, steam=None, steam_stat=None, stat_max=None, stat_modulo=1, **kwargs):
if steam is not None:
self.names[name] = steam
self.stats[name] = (steam_stat, stat_max, stat_modulo)
def grant(self, name):
name = self.names.get(name, name)
renpy.maximum_framerate(steam_maximum_framerate)
steam.grant_achievement(name)
steam.store_stats()
def clear(self, name):
name = self.names.get(name, name)
steam.clear_achievement(name)
steam.store_stats()
def clear_all(self):
for i in steam.list_achievements():
steam.clear_achievement(i)
steam.store_stats()
def progress(self, name, completed):
orig_name = name
completed = int(completed)
if name not in self.stats:
if config.developer:
raise Exception("To report progress, you must register {} with a stat_max.".format(name))
else:
return
current = persistent._achievement_progress.get(name, 0)
steam_stat, stat_max, stat_modulo = self.stats[name]
name = self.names.get(name, name)
if (current is not None) and (current >= completed):
return
renpy.maximum_framerate(steam_maximum_framerate)
if completed >= stat_max:
steam.grant_achievement(name)
else:
if (stat_modulo is None) or (completed % stat_modulo) == 0:
steam.indicate_achievement_progress(name, completed, stat_max)
steam.store_stats()
def has(self, name):
name = self.names.get(name, name)
return steam.get_achievement(name)
try:
import _renpysteam as steam
renpy.write_log("Imported steam.")
except Exception as e:
steam = None
renpy.write_log("Importing _renpysteam: %r", e)
if steam is not None:
want_version = 2
if steam.version < want_version:
raise Exception("_renpysteam module is too old. (want version %d, got %d)" % (steam.version, want_version))
if steam.init():
renpy.write_log("Initialized steam.")
backends.insert(0, SteamBackend())
else:
renpy.write_log("Failed to initialize steam.")
steam = None
def register(name, **kwargs):
"""
:doc: achievement
Registers an achievement. Achievements are not required to be
registered, but doing so allows one to pass information to the
backends.
`name`
The name of the achievement to register.
The following keyword parameters are optional.
`steam`
The name to use on steam. If not given, defaults to `name`.
`stat_max`
The integer value of the stat at which the achievement unlocks.
`stat_modulo`
If the progress modulo `stat_max` is 0, progress is displayed
to the user. For example, if stat_modulo is 10, progress will
be displayed to the user when it reaches 10, 20, 30, etc. If
not given, this defaults to 0.
"""
for i in backends:
i.register(name, **kwargs)
def grant(name):
"""
:doc: achievement
Grants the achievement with `name`, if it has not already been
granted.
"""
if not has(name):
for i in backends:
i.grant(name)
def clear(name):
"""
:doc: achievement
Clears the achievement with `name`.
"""
if has(name):
for i in backends:
i.clear(name)
def clear_all():
"""
:doc: achievement
Clears all achievements.
"""
for i in backends:
i.clear_all()
def progress(name, complete, total=None):
"""
:doc: achievement
:args: (name, complete)
Reports progress towards the achievement with `name`, if that
achievement has not been granted. The achievement must be defined
with a completion amount.
`name`
The name of the achievement. This should be the name of the
achievement, and not the stat.
`complete`
An integer giving the number of units completed towards the
achievement.
"""
if has(name):
return
for i in backends:
i.progress(name, complete)
def grant_progress(name, complete, total=None):
progress(name, complete)
def has(name):
"""
:doc: achievement
Returns true if the player has been granted the achievement with
`name`.
"""
for i in backends:
if i.has(name):
return True
return False
def sync():
"""
:doc: achievement
Synchronizes registered achievements between local storage and
other backends. (For example, Steam.)
"""
for a in persistent._achievements:
for i in backends:
if not i.has(a):
i.grant(a)
class Sync(Action):
"""
:doc: achievement
An action that calls achievement.sync(). This is only sensitive if
achievements are out of sync.
"""
def __call__(self):
sync()
def get_sensitive(self):
for a in persistent._achievements:
for i in backends:
if not i.has(a):
return True
return False
init 1500 python in achievement:
# Steam position.
if steam is not None:
if steam_position == "top left":
steam.set_overlay_notification_position(steam.POSITION_TOP_LEFT)
elif steam_position == "top right":
steam.set_overlay_notification_position(steam.POSITION_TOP_RIGHT)
elif steam_position == "bottom left":
steam.set_overlay_notification_position(steam.POSITION_BOTTOM_LEFT)
elif steam_position == "bottom right":
steam.set_overlay_notification_position(steam.POSITION_BOTTOM_RIGHT)