pykiss

Python Kisekae set viewer
git clone https://code.literati.org/pykiss.git
Log | Files | Refs | LICENSE

commit 528764063ab95c37b1dbf34d6c836f104164b314
parent 32606013e90cd2a512ec873de3c07d086954c8fe
Author: Sean Lynch <seanl@literati.org>
Date:   Tue,  8 Jun 2010 09:45:07 -0700

Newer version of kiss.py

Diffstat:
Mkiss.py | 882++++++++++++++++++++++++++++---------------------------------------------------
1 file changed, 306 insertions(+), 576 deletions(-)

diff --git a/kiss.py b/kiss.py @@ -1,22 +1,36 @@ #!/usr/bin/python -import re, sys, os, time, bisect, random, struct -from PIL import Image +# Copyright (C) 2003 Sean R. Lynch <seanl@chaosring.org> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import re, sys, os, time, bisect, random, struct, string from kissparser import KissParser - +from kisscompiler import EventCompiler +import Numeric class ParseError(Exception): pass class Variable: """A variable.""" - def __init__(self, name, value=0): + def __init__(self, compiler, name, value=0): + self.compiler = compiler self.name = name self.value = value - def __cmp__(self, other): - return cmp(self.value, int(other)) - - def __int__(self): - return self.value + def __str__(self): + return self.compiler.varname('var_', self.name, 0) class MovementHandler: @@ -36,17 +50,18 @@ class MovementHandler: def check(self): """Check the condition.""" result = self.test() + prev_result = self.prev_result + self.prev_result = result if result: - if self.prev_result: + if prev_result: if self.handler3 is not None: self.handler3() elif self.handler1 is not None: self.handler1() else: - if self.prev_result: + if prev_result: if self.handler2 is not None: self.handler2() elif self.handler0 is not None: self.handler0() - self.prev_result = result class Collider(MovementHandler): @@ -56,11 +71,14 @@ class Collider(MovementHandler): self.cel1 = cel1 self.cel2 = cel2 + def __repr__(self): + return 'Collider("%s", "%s")' % (self.cel1.name, self.cel2.name) + def test(self): #print "Checking for collision between %s and %s" % (self.cel1.name, self.cel2.name) # Only check if both cels are visible - if not (self.cel1.is_visible() and self.cel2.is_visible()): return + if not (self.cel1.is_visible() and self.cel2.is_visible()): return 0 return self.cel1.collide(self.cel2) @@ -72,7 +90,9 @@ class Inout(MovementHandler): self.obj2 = obj2 def test(self): - return self.obj1.rectcollide(self.obj2) + result = self.obj1.rectcollide(self.obj2) + #print self.obj1.num, self.obj2.num, result + return result class Object: @@ -80,28 +100,58 @@ class Object: self.kiss = kiss self.num = num self.pos = [(0, 0)] * 10 + self.cnfpos = [(0, 0)] * 10 # Configured position self.cels = [] self.fixval = fixval self.colliders = [] + # Handlers + self.unfix_handler = None + self.catch_handler = None + self.drop_handler = None + self.fixcatch_handler = None + self.fixdrop_handler = None + self.press_handler = None + self.release_handler = None + + def __repr__(self): + return '#%d' % self.num + def add_cel(self, cel): self.cels.append(cel) def map(self): for cel in self.cels: - cel.map() + cel.mapped = 1 + + self.check_collisions() def unmap(self): for cel in self.cels: - cel.unmap() + cel.mapped = 0 + + self.check_collisions() def altmap(self): for cel in self.cels: - cel.altmap() + cel.mapped = not cel.mapped + + self.check_collisions() def setfixval(self, fixval): self.fixval = fixval + def is_fixed(self): + return self.fixval > 0 + + def is_moved(self): + return self.pos[self.kiss.set] == self.cnfpos[self.kiss.set] + + def move(self, pos): + """Move the object to an absolute position and check collisions""" + self.set_pos(pos) + self.check_collisions() + def set_pos(self, (x, y)): w = self.kiss.width h = self.kiss.height @@ -130,21 +180,42 @@ class Object: def rectcollide(self, other): for cel1 in self.cels: if not cel1.is_visible(): continue - for cel2 in self.cels: + for cel2 in other.cels: + #print cel1, cel2 if cel2.is_visible(): if cel1.quick_collide(cel2): return 1 return 0 - + + def set_transparent(self, reloffset): + for cel in self.cels: cel.set_transparent(reloffset) + + def setup_collisions(self): + for collision in self.colliders: + collision.setup() + + def check_collisions(self): + for collision in self.colliders: + collision.check() + class Cel: - def __init__(self, name, obj, palfile, sets, trans): + def __init__(self, name, obj, palfile, sets): self.name = name self.obj = obj self.palfile = palfile - self.transparent = trans + self.transparent = 0 self.mapped = 1 + # Handlers + self.unfix_handler = None + self.catch_handler = None + self.drop_handler = None + self.fixcatch_handler = None + self.fixdrop_handler = None + self.press_handler = None + self.release_handler = None + if sets is None: self.visible = [1] * 10 else: self.visible = [0] * 10 @@ -153,6 +224,9 @@ class Cel: self.load() + #def __repr__(self): + # return '<%s "%s" in #%d>' % (self.__class__.__name__, self.name, self.obj.num) + def set_transparent(self, reloffset): # This may need to be overridden self.transparent += reloffset @@ -166,34 +240,9 @@ class Cel: l1, t1, r1, b1 = self.get_rect() l2, t2, r2, b2 = other.get_rect() l, t, r, b = rect - im1 = self.image - im2 = other.image - # Need to check nontransparent pixels now - # For now, we'll naively loop through all the pixels. - # x and y are in screen coordinates - # One loop for each possible combination of image types - if im1.mode == "RGBA": - if im2.mode == "RGBA": - for y in range(t, b): - for x in range(l, r): - if im1.getpixel((x-l1, y-t1))[3] and \ - im2.getpixel((x-l2, y-t2))[3]: return 1 - else: - for y in range(t, b): - for x in range(l, r): - if im1.getpixel((x-l1, y-t1))[3] and \ - im2.getpixel((x-l2, y-t2)): return 1 - else: - if im2.mode == "RGBA": - for y in range(t, b): - for x in range(l, r): - if im1.getpixel((x-l1, y-t1)) and \ - im2.getpixel((x-l2, y-t2))[3]: return 1 - else: - for y in range(t, b): - for x in range(l, r): - if im1.getpixel((x-l1, y-t1)) and \ - im2.getpixel((x-l2, y-t2)): return 1 + + # Use the GUI's pixel collision detection + return self.pixcollide(other, (l-l1, t-t1), (l-l2, t-t2), (r-l, b-t)) return 0 @@ -209,9 +258,10 @@ class Cel: return l, t, r, b def load(self): - self.image, (self.xoffset, self.yoffset) = load_cel(self.name) - self.width, self.height = self.image.size - self.convert() + mode, data, (self.width, self.height), (self.xoffset, self.yoffset) \ + = load_cel(self.name) + print len(data), self.width, self.height, mode + self.convert(mode, data) def get_rect(self): x, y = self.obj.get_pos() @@ -227,21 +277,31 @@ class Cel: def get_pos(self): pos = self.obj.get_pos() + #print pos if pos is not None: return pos[0] + self.xoffset, pos[1] + self.yoffset def map(self): self.mapped = 1 + self.obj.check_collisions() def unmap(self): self.mapped = 0 + self.obj.check_collisions() def altmap(self): self.mapped = not self.mapped + self.obj.check_collisions() def is_visible(self): return self.mapped and self.visible[self.obj.kiss.set] + def is_fixed(self): + return self.obj.is_fixed() + + def is_moved(self): + return self.obj.is_moved() + def load_cel(filename): f = open(filename) @@ -257,20 +317,31 @@ def load_cel(filename): data = header[4:] + f.read() f.close() - + if bpp == 4: - im = Image.fromstring("F", (width, height), data, - "bit", 4, 8, 0).convert("P") + mode = 'P' + data = Numeric.fromstring(data, Numeric.UInt8) + outdata = Numeric.zeros((width*height,), Numeric.UInt8) + step = (width+1)/2 + step1 = width/2 + for y in range(height): + outdata[y*width:y*width+width:2] = (data[y*step:y*step+step] >> 4).astype(Numeric.UInt8) + outdata[y*width+1:y*width+width:2] = (data[y*step:y*step+step1] & 15).astype(Numeric.UInt8) + + outdata = outdata.tostring() elif bpp == 8: - im = Image.fromstring("P", (width, height), data) + mode = 'P' + outdata = data elif bpp == 32: - # The R and B are swapped, probably because they're dealing with ints - im = Image.fromstring("RGBA", (width, height), data) - r, g, b, a = im.split() - im = Image.merge("RGBA", (b, g, r, a)) + mode = 'RGBA' + outdata = Numeric.fromstring(data, Numeric.UInt8) + r = outdata[::4].copy() + outdata[::4] = outdata[2::4].copy() + outdata[2::4] = r + outdata = outdata.tostring() else: raise ValueError, "Unimplemented bpp %d" % bpp - return im, (xoffset, yoffset) + return mode, outdata, (width, height), (xoffset, yoffset) def load_palette(filename): @@ -315,65 +386,9 @@ def load_palette(filename): return pal -class Event: - def __init__(self, kiss, name, args): - self.kiss = kiss - self.name = name - self.args = args - self.cmds = [] - self.ifblock = 0 # State variable. 1 means we're executing a block - # 2 means we're skipping to an else - - def __repr__(self): - return '<%s %s(%s) at %x>' % (self.__class__.__name__, self.name, ', '.join(map(repr, self.args)), id(self)) - - def __call__(self): - print "@", self.name, self.args - kiss = self.kiss - for cmd, args in self.cmds: - if self.ifblock == 0: - # Need to handle ifequal, ifgreaterthan, iflessthan, ifnotequal, - # else, endif specially - if cmd == "ifequal": - if int(args[1]) == int(args[2]): self.ifblock = 1 - else: self.ifblock = 2 - continue - elif cmd == "ifgreaterthan": - if int(args[1]) > int(args[2]): self.ifblock = 1 - else: self.ifblock = 2 - continue - elif cmd == "iflessthan": - if int(args[1]) < int(args[2]): self.ifblock = 1 - else: self.ifblock = 2 - continue - elif cmd == "ifnotequal": - if int(args[1]) != int(args[2]): self.ifblock = 1 - else: self.ifblock = 2 - continue - elif self.ifblock == 1: - # Executing an if or else block - if cmd in ("else", "endif"): - self.ifblock = 0 - continue - elif self.ifblock == 2: - # Skipping the block - if cmd == "else": self.ifblock = 1 - continue - - try: func = getattr(kiss, 'cmd_' + cmd) - except AttributeError: print >> sys.stderr, "Unimplemented:", cmd, args - else: - # A true return value means to stop processing - print cmd, args - if func(*args): break - - def append_cmd(self, cmd, args): - self.cmds.append((cmd, args)) - - class KiSS: def __init__(self, cnf, canvas=None, cel_class=Cel): - self.objs = [None] * 1024 + self.objs = {} # Cel names are per set self.cels = {} self.cellist = [[], [], [], [], [], [], [], [], [], []] @@ -383,17 +398,24 @@ class KiSS: self.height = 320 self.bordercol = 0 self.handlers = {} + self.alarms = {} self.timers = [] self.palgroup = [0] * 10 # The palette group for each set self.palettes = [] # My palettes - self.cnfpos = {} # The configured position of each object - + self.compiler = EventCompiler(self) parser = KissParser(self) parser.parse(os.path.basename(cnf)) + # Reverse the cel lists to make sure bottom cels are drawn first + for l in self.cellist: l.reverse() + # methods called by the parser + def is_action(self, name): + return self.compiler.cmds.has_key(name) + def get_obj(self, num): - return self.objs[num] + try: return self.objs[num] + except KeyError: return None def get_var(self, name): try: var = self.vars[name] @@ -403,23 +425,47 @@ class KiSS: return var - def is_action(self, name): - return hasattr(self, 'cmd_' + name) - def set_palette(self, set, palnum): self.palgroup[set] = palnum def add_event(self, name, args, actions): - handler = Event(self, name, args) - for action, aargs in actions: - handler.append_cmd(action, aargs) + handler = self.compiler.compile('%s%r' % (name, args), actions) + + if handler is None: + self.warn("Empty event: %s%r: %r" % (name, args, actions)) + return - if name in ("apart", "collide"): + if name == "label": + self.compiler.add_label(args[0], handler) + elif name == "alarm": + self.alarms[args[0]] = handler + elif name in ("unfix", "map", "unmap", "catch", "fixcatch", "drop", "fixdrop", "press", "release"): + what = args[0] + # There should be a list called blah_handlers on objects + attr = '%s_handler' % name + if isinstance(what, Object): + if getattr(what, attr) is not None: + self.warn("Multiple handlers for %s%r" % (name, args)) + else: setattr(what, attr, handler) + else: + try: what = self.cels[what] + except KeyError: self.warn("Unknown cel: %s" % what) + else: + if getattr(what.obj, attr) is not None: + self.warn("Multiple handlers for %s%r" % (name, args)) + else: setattr(what, attr, handler) + elif name in ("initialize", "set", "col", "begin", "end", "version"): + self.handlers[name, args] = handler + elif name in ("apart", "collide"): # Handle a collision event name1, name2 = args + name1 = name1.lower() + name2 = name2.lower() - cel1 = self.cels[name1] - cel2 = self.cels[name2] + try: + cel1 = self.cels[name1] + cel2 = self.cels[name2] + except KeyError: return obj1 = cel1.obj obj2 = cel2.obj @@ -443,28 +489,31 @@ class KiSS: raise ParseError, "Two collide handlers for %s and %s" % \ (cel1.name, cel2.name) collider.handler1 = handler - - return - if name in ("in", "out", "stillin", "stillout"): + print cel1.name, cel2.name + + elif name in ("in", "out", "stillin", "stillout"): obj1, obj2 = args for inout in obj1.colliders: if not isinstance(inout, Inout): continue if (inout.obj1 == obj1 and inout.obj2 == obj2) or \ (inout.obj2 == obj1 and inout.obj1 == obj2): break - else: inout = Inout(obj1, obj2) + else: + inout = Inout(obj1, obj2) + obj1.colliders.append(inout) + obj2.colliders.append(inout) if name == "in": if inout.handler1 is not None: raise ParseError, "Two in handlers for #%d and #%d" % \ - obj1.num, obj2.num + (obj1.num, obj2.num) inout.handler1 = handler elif name == "out": if inout.handler2 is not None: raise ParseError, "Two out handlers for #%d and #%d" % \ obj1.num, obj2.num - inout.handler1 = handler + inout.handler2 = handler elif name == "stillin": if inout.handler3 is not None: raise ParseError, "Two stillin handlers for #%d and #%d" % \ @@ -476,12 +525,9 @@ class KiSS: obj1.num, obj2.num inout.handler0 = handler - return - - - if self.handlers.has_key((name, args)): - self.handlers[(name, args)].cmds.extend(actions) - else: self.handlers[(name, args)] = handler + elif self.handlers.has_key((name, args)): + self.warn("Duplicate handler for %s%r" % (name, args)) + else: raise ValueError, "Unknown event: %s%r" % (name, args) def set_size(self, (width, height)): self.width = width @@ -496,26 +542,33 @@ class KiSS: def add_cel(self, name, objnum, fixval, palfile, groups, trans): if groups is None: groups = range(10) - obj = self.objs[objnum] - if obj is None: + try: obj = self.objs[objnum] + except KeyError: obj = Object(self, objnum, fixval) self.objs[objnum] = obj - cel = self.cel_class(name, obj, palfile, groups, trans) + try: + cel = self.cel_class(name, obj, palfile, groups) + except IOError: + self.warn("No such cel: %s" % name) + return + + if trans != 0: cel.set_transparent(trans) #print 'adding cel', cel.name if self.cels.has_key(name): print >> sys.stderr, "Ambiguous cel name: %s" % name - self.cels[name] = cel + else: + self.cels[name] = cel obj.add_cel(cel) for group in groups: self.cellist[group].append(cel) def set_objpos(self, objnum, set, pos): - obj = self.objs[objnum] - if obj is None: return + try: obj = self.objs[objnum] + except KeyError: return obj.pos[set] = pos - self.cnfpos[obj, set] = pos + obj.cnfpos[set] = pos # Methods called by the GUI def pulse(self): @@ -526,8 +579,11 @@ class KiSS: t, num = self.timers[0] if t > now: break del self.timers[0] - self.handle("alarm", num) - flag = 1 + try: alarm = self.alarms[num] + except KeyError: pass + else: + alarm() + flag = 1 if flag: self.draw() @@ -535,34 +591,45 @@ class KiSS: def start(self): self.set = 0 self.dragging = None + self.pressed = None self.change_palette(self.palgroup[self.set]) + for obj in self.objs.values(): + obj.setup_collisions() self.handle('initialize') self.handle('version', 1) self.handle('version', 2) self.handle('version', 3) - for obj in self.objs: - if obj is None: continue - for collider in obj.colliders: - collider.setup() self.handle('begin') + self.handle('set', 0) self.draw() def end(self): self.handle('end') def get_cel_at(self, (x, y)): - for cel in self.cellist[self.set]: + cellist = self.cellist[self.set] + for i in range(len(cellist)-1, -1, -1): + cel = cellist[i] if not cel.mapped: continue x1, y1 = cel.get_pos() - w, h = cel.image.size + w = cel.width + h = cel.height #print cel.name, x, y, x1, y1, w, h if x >= x1 and y >= y1 and x < x1+w and y < y1+h: - pixel = cel.image.getpixel((x-x1, y-y1)) - if type(pixel) == type(0): - if pixel: return cel - elif pixel[3]: return cel + if cel.is_pixel_set((x-x1, y-y1)): return cel else: return None + def unfix(self, pos): + cel = self.get_cel_at(pos) + cel.obj.fixval = 1 + self.press(pos) + + def make_transparent(self, pos): + cel = self.get_cel_at(pos) + if cel.transparent > 0: cel.set_transparent(-255) + else: cel.set_transparent(255) + self.draw() + def press(self, (x, y)): """Mouse button pressed""" @@ -573,54 +640,69 @@ class KiSS: print "#%d.%d %s" % (obj.num, obj.fixval, cel.name) if obj.fixval == 0: x1, y1 = obj.get_pos() - self.handle("catch", cel.name) - self.handle("catch", obj) + func = cel.catch_handler + if func is not None: func() + func = obj.catch_handler + if func is not None: func() # Store the object and the position offset - self.dragging = obj, cel, x1-x, y1-y + self.dragging = x1-x, y1-y self.canvas.start_drag() else: - self.handle("fixcatch", cel.name) - self.handle("fixcatch", obj) + func = cel.catch_handler + if func is not None: func() + func = obj.catch_handler + if func is not None: func() obj.fixval -= 1 if obj.fixval == 0: - self.handle("unfix", obj) + func = obj.unfix_handler + if func is not None: func() for cel in obj.cels: - if cel.is_visible(): - self.handle("unfix", cel.name) + func = cel.unfix_handler + if func is not None: func() - self.handle("press", cel.name) - self.handle("press", obj) + func = cel.press_handler + if func is not None: func() + func = obj.press_handler + if func is not None: func() - def release(self, pos): + self.draw() + + def release(self, (x, y)): """Mouse button released""" + cel = self.pressed + if cel is None: return + obj = cel.obj + # Generate events that don't care about fixval + func = cel.release_handler + if func is not None: func() + func = obj.release_handler + if func is not None: func() + self.pressed = None if self.dragging: self.canvas.end_drag() - obj, cel, xoff, yoff = self.dragging + xoff, yoff = self.dragging self.dragging = None - self.handle("drop", cel.name) - self.handle("drop", obj) - # Check for collide/apart events - for collider in obj.colliders: - #print collider - collider.check() - else: - # Just use the cel under the current position - cel = self.pressed - obj = cel.obj - if obj.fixval: - # Object is fixed - self.handle("fixdrop", cel.name) - self.handle("fixdrop", obj) - - # Generate events that don't care about fixval - self.handle("release", cel.name) - self.handle("release", obj) - self.pressed = None + obj.move((x+xoff, y+yoff)) + func = cel.drop_handler + if func is not None: + func() + func = obj.drop_handler + if func is not None: + func() + elif obj.fixval: + # Object is fixed + func = cel.fixdrop_handler + if func is not None: func() + func = obj.fixdrop_handler + if func is not None: func() + + self.draw() def drag(self, (x, y)): """Mouse drag""" - obj, cel, xoff, yoff = self.dragging - obj.set_pos((x+xoff, y+yoff)) + xoff, yoff = self.dragging + cel = self.pressed + cel.obj.set_pos((x+xoff, y+yoff)) self.draw() # Internal @@ -630,18 +712,17 @@ class KiSS: except KeyError: return handler() + self.draw() - def change_set(self, set): + def changeset(self, set): self.set = set self.change_palette(self.palgroup[set]) self.draw() # Reset all colliders - for obj in self.objs: - if obj is None: continue - for collider in obj.colliders: - collider.setup() + for obj in self.objs.values(): + obj.setup_collisions() self.handle("set", set) @@ -654,393 +735,42 @@ class KiSS: for cel in self.cellist[self.set]: cel.set_palette(self.palettes[cel.palfile*10+self.palgroup[palnum]]) - def draw(self): - self.canvas.clear(self.palettes[self.palgroup[self.set]][self.bordercol]) - cellist = self.cellist[self.set] - # Loop through backwards to make sure that the top cels are drawn last - for i in range(len(cellist)-1, -1, -1): - cel = cellist[i] - if cel.mapped: self.canvas.draw(cel, cel.get_pos()) - - self.canvas.update() - - # Commands - def cmd_altmap(self, what): - """altmap(#object) / altmap("celname.cel") - - Turns any mapped cels to unmapped and vice-versa. - """ - - if type(what) == type(""): - try: self.cels[what.lower()].altmap() - except KeyError: print >> sys.stderr, "Missing cel: %s" % what - else: what.altmap() - - def cmd_map(self, what): - """map(#object) / map("celname.cel") - - Maps all cels. - """ - - if type(what) == type(""): - try: self.cels[what.lower()].map() - except KeyError: print >> sys.stderr, "Missing cel: %s" % what - else: what.map() - - - def cmd_randomtimer(self, number, minimum, maximum): - self.cmd_timer(number, random.randint(int(minimum), int(maximum))) + def get_bordercol(self): + if self.palettes: + return self.palettes[self.palgroup[self.set]][self.bordercol] + return (0, 0, 0) - - def cmd_setfix(self, obj, fixval): - """setfix(#object,fixval) - - Manually sets the fix val for the object. If the value is 0, any unfix() events linked to this object will be triggered. Note: This is a proposed FKiSS2.1 command, and is not generally supported by other viewers. - """ - - obj.fixval = int(fixval) - if fixval == 0: - self.handle("unfix", obj) - for cel in obj.cels: - if cel.is_visible(): - self.handle("unfix", cel.name) + def draw(self): + self.canvas.draw(self.cellist[self.set]) - def cmd_timer(self, number, duration): - """timer(number,duration) - """ - + def timer(self, number, duration): + #print "timer(%d, %d)" % (number, duration) now = time.time() timers = self.timers for i in range(len(self.timers)): - if self.timers[i][1] == number: - del self.timers[i] + if timers[i][1] == number: + del timers[i] break - + if duration: bisect.insort(timers, (now + int(duration)/1000.0, number)) - - def cmd_unmap(self, what): - """unmap(#object) / unmap("celname.cel") - - First case, unmaps all cels belonging to object #object. Second case - unmaps a specific cel. - """ - - if type(what) == type(""): - try: self.cels[what.lower()].unmap() - except KeyError: pass - else: what.unmap() - - def cmd_move(self, obj, offsetx, offsety): - """move(#object,offsetx,offsety) - - Moves an object using the offsets specified. Note: PlayFKiSS will never move an object off-screen, even when "Enforce Boundaries" is turned off. - """ - - x, y = obj.get_pos() - obj.set_pos((x+int(offsetx), y+int(offsety))) - - def cmd_movebyx(self, obj1, obj2, offsetx): - """movebyx(#object,#object,offsetx) - - Moves an object using the offset from another object. Note: This is a proposed FKiSS2 command, and is not generally supported by other viewers. - """ - - x, y = obj1.get_pos() - x1, y1 = obj2.get_pos() - x = x1 + offsetx - obj1.set_pos((x, y)) - - - def cmd_movebyy(self, obj1, obj2, offsety): - """movebyy(#object,#object,offsety) - - Moves an object using the offset from another object. Note: This is a proposed FKiSS2 command, and is not generally supported by other viewers. - """ - - x, y = obj1.get_pos() - x1, y1 = obj2.get_pos() - y = y1 + offsety - obj1.set_pos((x, y)) - - def cmd_ifmapped(self, celname, timer, value): - """ifmapped("cel", timer, value) - - Sets timer if the cel specified by "cel" is mapped. Note: This is a proposed FKiSS2.1 event and is not generally supported by other viewers. - """ - - try: - if self.cels[celname.lower()].mapped: - self.cmd_timer(timer, value) - except KeyError: pass - - def cmd_ifnotmapped(self, celname, timer, value): - """ifnotmapped("cel", timer, value) - - Sets timer if the cel specified by "cel" is not mapped. Note: This is a proposed FKiSS2.1 event and is not generally supported by other viewers. - """ - - try: - if not self.cels[celname.lower()].mapped: - self.cmd_timer(timer, value) - except KeyError: pass - - def cmd_sound(self, filename): - """sound("filename.wav") / sound("filename.au") - - Plays a sound. Not all viewers support .au format and vice-versa. If possible, include 2 versions of your .cnf file and convert all sounds to both formats. - """ - - self.canvas.sound(filename) - - def cmd_moveto(self, object, x, y): - """moveto(#object,x,y) - - Moves an object to the absolute coordinates specified. Note: PlayFKiSS will never move an object off-screen, even when "Enforce Boundaries" is turned off. Note: This is a proposed FKiSS2 command, and is not generally supported by other viewers. - """ - - object.set_pos((int(x), int(y))) - - def cmd_moverandx(self, object, min, max): - """moverandx(#object,min,max) - - Moves an object using random values. The new coordinate is relative, based on the min and max values. Ex: If min is -1 and max is 1, the new location may be either 1 pixel less, one pixel more, or the same location. Note: This is a proposed FKiSS2.1 command, and is not generally supported by other viewers. - """ - - x, y = object.get_pos() - object.set_pos((random.randint(x+int(min), x+int(max)), y)) - - def cmd_moverandy(self, object, min, max): - """moverandy(#object,min,max) - - Moves an object using random values. The new coordinate is relative, based on the min and max values. Ex: If min is -1 and max is 1, the new location may be either 1 pixel less, one pixel more, or the same location. Note: This is a proposed FKiSS2.1 command, and is not generally supported by other viewers. - """ - - x, y = object.get_pos() - object.set_pos((x, random.randint(y+int(min), y+int(max)))) - - def cmd_movetorand(self): - """movetorand(#object) - - Moves an object to random coordinates. Note: PlayFKiSS will never move an object off-screen, even when "Enforce Boundaries" is turned off. Note: This is a proposed FKiSS2.1 command, and is not generally supported by other viewers. - """ - - object.set_pos((random.randint(self.width), random.randint(self.height))) - - def cmd_transparent(self, what, reloffset): - """transparent(#object, reloffset) / transparent("celname.cel", reloffset) - - Sets the transparency level of the cels/object. reloffset is the value to add to the current transparency level. The maximum range is from 0 (totally opaque) up to 255 (totally transparent). Note: This command is fairly recent and is not supported by a ll FKiSS viewers. Also, some viewers show cels dithered and other's change to true-color mode (16 million colors). - """ - - if type(what) == type(""): - try: cel = self.cels[what.lower()] - except KeyError: pass - else: cel.set_transparent(int(reloffset)) - else: - for cel in what.cels: cel.set_transparent(int(reloffset)) - - def cmd_viewport(self, x, y): - """viewport(x,y) - - Changes the viewport offset. Note: PlayFKiSS ignores this command, but will retain it when saving. - """ + def setfix(self, obj, fixval): + obj.fixval = fixval + if fixval == 0: + self.handle("unfix", obj) + for cel in obj.cels: + if cel.is_visible(): + self.handle("unfix", cel.name) - self.canvas.viewport((int(x), int(y))) - - def cmd_windowsize(self, w, h): - """windowsize(x,y) - - Changes the window size. Note: PlayFKiSS ignores this command, but will retain it when saving. - """ - - self.canvas.windowsize((int(w), int(h))) - - def cmd_changecol(self, palette): - """changecol(palette) - - Forces another palette group to become the active one. - """ - - #self.palette[self.set] = palette - self.change_palette(palette) + def changecol(self, palette): + self.change_palette(palette) self.handle("col", palette) - changecol = cmd_changecol - - def cmd_changeset(self, set): - """changeset(set) - - Forces another set to become the active one. - """ - - self.change_set(int(set)) - - def cmd_debug(self, messagestring): - """debug("messagestring") - - Displays a message. Each viewer may have a different method to display debug information. - """ - - print >> sys.stderr, "Debug:", messagestring - - def cmd_iffixed(self, obj, timer, duration): - """iffixed(#obj, timer, value) - - Sets timer if the object specified by #obj is fixed (fix value is - greater than zero). Note: This is a proposed FKiSS2.1 event and is - not generally supported by other viewers. - """ - - if obj.fixval > 0: self.cmd_timer(int(timer), int(duration)) - - def cmd_ifmoved(self, timer, duration): - """ifmoved (#obj, timer, value) - - Sets timer if the object specified by #obj has been moved. An object is defined as moved if it's coordinates are not equal to the coordinates specified in the .CNF file. Note: This is a proposed FKiSS2.1 event and is not generally supported by other viewers. - """ - - if obj.pos[self.set] != self.cnfpos[obj, self.set]: - self.cmd_timer(int(timer), int(duration)) - - def cmd_ifnotfixed(self, obj, timer, duration): - """ifnotfixed(#obj, timer, value) - - Sets timer if the object specified by #obj is not fixed (fix value is equal to zero). Note: This is a proposed FKiSS2.1 event and is not generally supported by other viewers. - """ - - if self.fixval == 0: self.cmd_timer(int(timer), int(duration)) - - def cmd_ifnotmoved(self, obj, timer, duration): - """ifnotmoved (#obj, timer, value) - - Sets timer if the object specified by #obj has not been moved. An object is defined as moved if it's coordinates are not equal to the coordinates specified in the .CNF file. Note: This is a proposed FKiSS2.1 event and is not generally supported by o ther viewers. - """ - - if self.cnfpos[obj, self.set] == obj.pos[self.set]: - self.cmd_timer(int(timer), int(duration)) - - def cmd_music(self, filename): - """music ("filename.mid") - - Plays a MIDI song. Note: This is a proposed FKiSS2 command, and is not generally supported by other viewers. - """ - - self.canvas.music(filename) - - def cmd_nop(self, *args): - """nop() - - Does nothing. NOP is short for "No Operation" in assembly language. - """ - - return - - def cmd_notify(self, messagestring): - """notify("message string") - - Currently a synonym for debug() Note: This is a proposed FKiSS2 command, and is not generally supported by other viewers. - """ - - print >> sys.stderr, "Notify:" , messagestring - - def cmd_quit(self): - """quit() - - Forces the viewer to exit. Note: PlayFKiSS retains this command when saving, but will not quit when issued. - """ - - self.canvas.quit() - - # KiSS 3 - def cmd_goto(self, label): - self.handle('label', label) - # Stop processing of this event - return 1 - - def cmd_gosub(self, label): - self.handle('label', label) - # Don't stop processing :) - - def cmd_gotorandom(self, percent, label1, label2): - if random.randrange(100) < percent: handle("label", label1) - else: handle("label", label2) - return 1 - - def cmd_gosubrandom(self, percent, label1, label2): - if random.randrange(100) < percent: handle("label", label1) - else: handle("label", label2) - - def cmd_exitevent(self): - """Stop processing of the current event""" - return 1 - - # FKiSS 3 commands - def cmd_let(self, var, value): - var.value = int(value) - - def cmd_add(self, var1, var2, var3): - var1.value = int(var2) + int(var3) - - def cmd_sub(self, var1, var2, var3): - var1.value = int(var2) - int(var3) - - def cmd_mul(self, var1, var2, var3): - var1.value = int(var2) * int(var3) - - def cmd_div(self, var1, var2, var3): - var1.value = int(var2) / int(var3) - - def cmd_mod(self, var1, var2, var3): - var1.value = int(var2) % int(var3) - - def cmd_random(self, var, min, max): - var.value = random.randint(int(min), int(max)) + def warn(self, message): + print >> sys.stderr, "Warning:", message - def cmd_letobjectx(self, var, obj): - var.value = obj.get_pos()[0] + def notify(self, message): + print >> sys.stderr, "Notify:", message - def cmd_letobjecty(self, var, obj): - var.value = obj.get_pos()[1] - - def cmd_letfix(self, var, obj): - var.value = obj.fixval - - def cmd_letmapped(self, var, celname): - try: var.value = self.cels[celname.lower()].mapped - except KeyError: pass - - def cmd_letset(self, var): - var.value = self.set - - def cmd_letpal(self, var): - var.value = self.palgroup[self.set] - - def cmd_letmousex(self, var): - var.value = self.canvas.get_mousepos()[0] - - def cmd_letmousey(self, var): - var.value = self.canvas.get_mousepos()[1] - - def cmd_letcatch(self, var): - if self.dragging is not None: - var.value = self.dragging[0].num - else: print >> sys.stderr, "Warning: attempted to letcatch without a caught object" - - def cmd_letcollide(self, var, cel1name, cel2name): - try: - cel1 = self.cels[cel1name.lower()] - cel2 = self.cels[cel2name.lower()] - except KeyError: pass - else: var.value = cel1.collide(cel2) - - def cmd_letinside(self, var, obj1, obj2): - var.value = obj1.rectcollide(obj2) - - def cmd_lettransparent(self, var, celname): - try: cel = self.cels[celname.lower()] - except KeyError: pass - else: var.value = cel.transparent - - def cmd_shell(self, *args): pass - + def debug(self, message): + print >> sys.stderr, "Debug:", message