Python Extensions
From ManorManual
Contents |
[edit] Python Manual
This manual assumes you are already familiar with Python (www.python.org). If you aren’t already familiar with Python, no fear. If you have experience with other programming languages, it’s fairly easy to pick up the basics of Python programming from looking at code samples.
Each script that is loaded is placed in a separate Python module. The cyborg script is placed in a module named “cyborg”. Spot scripts are placed in modules named “spot_##” where ## is the ID of the spot. Spot scripts are also loaded in order, so later spots can import spot modules that have already been loaded.
In addition, all scripts that wish to make calls to The Manor client will need to import the manor module.
[edit] Entry Points
If these routines are present in your script, they will be called as detailed. If your script does not contain at least one of these entry points, it won’t be called by The Manor client software.
mnr_signon cyborg only | Called when a connection is established to a Manor server. | ||||||||||||||
mnr_enter(userID) | Called when a user enters the room. | ||||||||||||||
mnr_leave(userID) | Called when a user leaves the room. | ||||||||||||||
mnr_spothit(spotID) spot script only | This is only called for the spot script of the spot the user has clicked on. | ||||||||||||||
mnr_spothitex(spotID) spot script only | This is called when the user clicks on any spot in the room. | ||||||||||||||
chatText mnr_inchat(userID, chatText) | Called when chat text is received by the client, before it is displayed to the user.
Your script should do any processing desired on the text, and then return the chatText. Your script may modify the chatText if desired, or clear the text. | ||||||||||||||
chatText mnr_outchat(chatText) | Called when chat text is sent by the user, before the text is actually sent to the server. | ||||||||||||||
mnr_statechange(spotID, stateID) | Called when the state of a spot changes. | ||||||||||||||
handled mnr_render(gworld, layer) spot script only | Called during room rendering operations.
| ||||||||||||||
handled mnr_keydown(char, key) | Called when the user presses a key
| ||||||||||||||
handled mnr_mousedown(x, y) spot script only |
Called when the user presses the mouse button
|
[edit] Manor Calls
[edit] Output functions
say(chatText) | Send chatText |
whisper([userID, (userID...)], chatText) | Send chatText to the users indicated by userID list as a whisper |
logstr(text) | Places text in the log |
logErrStr(text) | Places text in the log as an error (red text) |
localMsg(msg) | Displays a system message balloon. Only the user sees this message, it is not transmitted to the server. |
statusMsg (msg, logit) | Set a status message |
dirtyRect(rect) | Marks a section of the room as needing to be rendered. |
[edit] User functions
isRegistered() | Returns 1 if user is registered |
myRegHash() | Returns the users reg hash, if registered |
userID myID | Returns this users ID |
name getUserName(userID) | Returns the name of the user indicated by userID |
count getRoomUserCount | Returns the number of users in the room |
x,y getUserPos(userID) | Returns the position of the user indicated by userID |
userID getIdxRoomUser(userIdx) | Returns the id for an indexed user. UserIdx is 0 <= userIdx < getRoomUserCount |
[edit] Spot functions
hitSpot(spotID) | Simulates user clicking a spot. Any smart spot actions will be taken after calling any spothit scripts | ||||||
setSpotState(spotID, stateID, global) | Sets the current state of a spot
NOTE: If the spot contains state images, the new state image will not be displayed until the next time the client cycles. | ||||||
stateID getSpotState(spotID) | Returns the current state of a spot | ||||||
title getSpotTitle(spotID) | Returns the title of a spot | ||||||
count getSpotCount | Returns the number of spots in the room | ||||||
spotID getIdxSpot(spotIdx) | Return the ID of the indexed spot. spotIdx is 0 <= spotIdx < getSpotCount | ||||||
roomID getSpotDest(spotID) | Returns spots destination room ID | ||||||
rect getSpotBounds(spotID) | Returns spots bounding rectangle | ||||||
inSpot(spotID) | Return true if user is within the bounds of spotID. | ||||||
isLocked(spotID) | Returns true if spotID is locked. If spotID does not exist or is not closable will return false. | ||||||
lock(spotID) | Locks a spot. If spotID does not exist or is not closable an exception will be set. | ||||||
unlock(spotID) | UnLocks a spot. If spotID does not exist or is not closable an exception will be set. |
[edit] Prop functions
setProp(propList) | Sets the current worn props to those in proplist. | ||||||
propID getTopPropID() | Returns the id of the top most prop | ||||||
putProp(propID, x, y) | Place a prop in the room
| ||||||
clearProps() | Remove all the worn props, i.e. naked | ||||||
dropProp(x, y) | Drop the top prop in the the room at the location indicated by x and y | ||||||
donProp(propID) | Put the prop on as the top most prop | ||||||
doffProp() | Remove the top most prop | ||||||
numProps() | Returns the number of currently worn props | ||||||
removeProp(propID) | Removes propID from currently worn props | ||||||
faceColor(r, g, b) | Change the face color to the rgb value in r, g, and b | ||||||
face(faceNum) | Change the face to faceNum. FaceNum must be 0 – 15. |
[edit] Navigation functions
gotoRoom(roomNum) | Change the current room to roomNum |
roomName getRoomName() | Returns the name of the current room |
roomNum getRoomNumber() | Returns the number of the current room |
siteName getSiteName() | Returns the name of the current Manor |
openConnection(url) | Open a url. If the url is a manor url, a connection will be opened to the manor server. Otherwise the appropriate application will be launched for the URL. |
setPos(x, y) | Set the users position |
x,y getMouseRmPos() | Returns the current mouse positions clipped to the bounds of the room. |
isDown stillDown() | Returns non-zero if the mouse button is still down. |
[edit] Misc functions
boolean isKeyDown(keyCode) | Returns 1 is the key is down. Note keycodes are different on Mac vs Windows systems. |
clientType getClientType() | Returns the client type. 0 = Mac OS9, 1 = Windows, 2 = Mac OSX |
mills milliseconds() | Returns the number of milliseconds (1000ths of a second) since system start |
ticks tickcount() | Returns the number of ticks (60ths of a second) since system start |
setTimer(ticks, function, params) | Sets a timer function.
ticks The tick time the timer should be triggered. function The function to be called when the timer triggers The function is of the form: func(param) params Parameters to pass to the trigger function. If you are calling this from a class, this must be “self”. |
playSound(sound) | Plays a sound file from the cache. If the sound file is not already in the cache an exception is raised and the call returns. "sound" can either be just the name of the file to play (i.e. "sound.wav") or it can be a full URL (i.e. "http://www.madwolfsw.com/sound.wav). In most cases you will just want to use the name of the file to use your sites sounds. |
fetchSound(sound, function, params) | Checks a sound is in the cache. If the sound is not in the cache, or is out of date, downloads the sound to the cache. "sound" can either be just the name of the file to play (i.e. "sound.wav") or it can be a full URL (i.e. "http://www.madwolfsw.com/sound.wav). In most cases you will just want to use the name of the file to use your sites sounds.
function The function to be called when the sound is downloaded. The function is of the form: func(param) params Parameters to pass to the completion function. If you are calling this from a class, this must be “self”. NOTE: If this is the first time the sound file has been used in a session it can take several seconds for the download to complete even if the sound is already cached. This is normal as it is the time it takes to verify the sound file is up to date. |
fetchSoundObject(sound, function, params) | Checks a sound is in the cache. If the sound is not in the cache, or is out of date, downloads the sound to the cache. "sound" can either be just the name of the file to load (i.e. "sound.wav") or it can be a full URL (i.e. "http://www.madwolfsw.com/sound.wav). In most cases you will just want to use the name of the file to use your sites sounds. Once the sound is available it will be passed as an object to your completion function.
function The function to be called when the sound is downloaded. The function is of the form: func(sound, params) params Parameters to pass to the completion function. If you are calling this from a class, this must be “self”. NOTE: If this is the first time the sound file has been used in a session it can take several seconds for the download to complete even if the sound is already cached. This is normal as it is the time it takes to verify the sound file is up to date. |
playSoundObject(soundObject, interupt, loop) | Plays a sound object. Sound objects should be kept small as they are kept in memory. They are intended for use of sound effects in games.
soundObject The sound object returned by fetchSoundObject interupt if not zero any other sound currently playing will be stopped loop if not zero this sound will be played until stopped |
stopSounds() | Stops any sounds that may be currently playing |
fetchImageObject(image, function, params, forceDownload) | Import a jpg or png file to an image object. This first checks the cache for the image file. If the file is not already cached, or is out of date, the image is downloaded. |
broadcastData(msgID, isGlobal, data) | Broadcasts data to all the users. Global broadcasting requires being authenticated to a group with global message permissions.
msgID 15 character string identifying the type of message isGlobal if not zero, message is to be broadcast server wide data any object to be sent |
sendData(msgID, [userID, (userID...)], data) | Sends data to specific users..
msgID 15 character string identifying the type of message userID list of users to send data to data any object to be sent |
regDataReceive(msgID, func, param) | Registers a function to receive message types
msgID 15 character string identifying the type of message func Function to be called when msgID is received. The function is of the form: func(userID, data, param) param parameter to pass to receive function |
fetchTextObject(filename, function, params)</td | |
post(cgi, postData, func, param)</td |
[edit] Drawing
[edit] Object Modules
[edit] rect
The rect object defines rectangles used by other graphics objects.
myRect = rect(left, top, right, bottom)
Function | Behavior |
offset(x, y) | Offset the rectangle by x, y pixels |
inset(x,y) | Inset the rectangle by x, y pixels |
t, l, b, r = bounds | returns the bounds of the rectangle |
Unary | Behavior |
| | Union |
& | Intersection |
= | Copy |
== | Equal to |
!= | Not equal |
> | Area greater than |
< | Area less than |
[edit] shape
shapes are predefined line drawings that can be manipulated as a single object. They also draw slightly faster than drawing a comparable image with the gworld move and line functions.
myShape = shape()
Function | Behavior |
move(x, y) | Add a move point to the shape. x and y are relative to shape center. |
line(x, y) | Add a line point to the shape. x and y are relative to shape center. |
draw(gworld, x, y) | Draw the shape |
rotate(a) | Rotate the image to angle in radians. Zero is straight up, angles proceeding clockwise. Rotation is always from the original shape definition. |
scale(percent) | Scale the shape |
rect = bounds() | Return the bounding rectangle |
[edit] gworld
gworlds are offscreen graphics worlds. This is the workhorse object for graphics operations.
myGworld = gworld(boundRect
Function | Behavior |
beginMultiDraw | Prepare the gworld for multiple draw calls |
endMultiDraw | End multiple draw sequence |
foreColor(a, r, g, b) | Set the foreground color to alpha, red, green, blue. Alpha values are ignored when working with opaque gworlds. |
drawString(string) | Draw a string at the current pen position |
stringWidth(string) | Returns the pixel width of the string |
setFont(string) | Set the font. String is a comma delimited string of font names. |
setFontSize(size) | Set the font size in points |
fontHeight() | Returns the pixel height of the font |
fontAscent() | Returns the ascent height of the font |
penSize(h, v) | Set the horizontal and vertical size of the pen |
moveTo(x, y) | Change the pen position |
lineTo(x, y) | Draw a line from the current pen position |
frameRect(rect) | Draw a frame around a rectangle |
fillRect(rect) | Fill a rectangle with the foreground color |
frameOval(rect) | Draw an oval within the bounds of a rectangle |
fillOval(rect) | Fill an oval within the bounds of a rectangle |
copyimage(imageObject, srcRect, destRect) | copy srcRect from imageObject to destRect in gworld |
copygworld(srcGWorld, srcRect, destRect) | Copy srcRect from srcGWorld to destRect in gworld |
[edit] SAMPLE CODE
[edit] Bouncing Text
This was the initial test script for very early gworld functionality
import manor global xpos, ypos, xdir, ydir xpos = 105 ypos = 112 xdir = 3 ydir = 3 def mover(param): global xpos, ypos, xdir, ydir manor.dirtyRect(rect(xpos - 50, ypos + 3, xpos + 50, ypos - 13)) xpos += xdir ypos += ydir if (xpos > 510): xdir = -3 if (xpos < 4): xdir = 3 if (ypos > 380): ydir = -3 if (ypos < 4): ydir = 3 manor.dirtyRect(rect(xpos - 50, ypos + 3, xpos + 50, ypos - 13)) manor.setTimer(manor.tickcount() +1, mover, 0) def mnr_render(gworld, layer): global xpos, ypos, xdir, ydir handled = 0 if layer == 1: gworld.moveTo(xpos, ypos) gworld.foreColor(0xFF, 0xFF, 0xFF, 0xFF) gworld.drawString("test") handled = 1 return handled def mnr_enter(userID): if userID == manor.myID() or manor.myID() == 0: manor.setTimer(manor.tickcount() + 1, mover, 0)
[edit] Bouncing Ball
A variation of the bouncing text to display a bouncing ball in response to the user saying "ball" or "no ball" to stop. Assumes a room of 750x384
import manor global xpos, ypos, xdir, ydir global ball_on xpos = 105 ypos = 112 xdir = 1 ydir = 1 ball_on = 0 def mover(param): global xpos, ypos, xdir, ydir, ball_on manor.dirtyRect(rect(xpos - 5, ypos - 5, xpos + 6, ypos + 6)) xpos += xdir ypos += ydir if (xpos > 740): xdir = -1 if (xpos < 5): xdir = 1 if (ypos > 379): ydir = -1 if (ypos < 5): ydir = 1 manor.dirtyRect(rect(xpos - 5, ypos - 5, xpos + 6, ypos + 6)) if ball_on != 0: manor.setTimer(0, mover, 0) def mnr_render(gworld, layer): global ball_on if (layer == 1) and (ball_on == 1): gworld.foreColor(0xFF, 0xFF, 0, 0) gworld.fillOval(rect(xpos - 5, ypos - 5, xpos + 5, ypos + 5)) return 0 def mnr_outchat(chatText): global ball_on if chatText == "ball": ball_on = 1 manor.setTimer(0, mover, 0) chatText = "" if chatText == "no ball": ball_on = 0 chatText = "" return chatText
[edit] StarHawk
This is a much more complex script to implement a live action, multiplayer video game. The script is not finished as it still needs functions for the player to change the control keys and some other niceties, but it does show what can be done and how to do it.
The script uses three spots in the room, Spot 1 contains the script itself and defines the location of the centeral "star". Spot 2 defines the playing field, and Spot 3 defines where the players stats should be displayed.
import manor import math import random global initialized, numPlayers, players, torps, lastPing, star_x, star_y, play_w, play_h initialized = 0 numPlayers = 0 lastPing = 0 players = [] torps = [] star_x = 256 star_y = 192 play_w = 512 play_h = 384 class spaceObject: global star_x, star_y, play_w, play_h xpos = 105 ypos = 150 course = 0 vel = 1.2 lastUpdate = 0 def calcPos(self): oldx = self.xpos oldy = self.ypos self.xpos += math.sin(math.radians(self.course)) * self.vel self.ypos += math.cos(math.radians(self.course)) * self.vel gravXDif = star_x - oldx gravYDif = star_y - oldy grav = 2 * self.vel / math.sqrt(gravXDif**2 + gravYDif**2) if gravYDif == 0: gravC = 90 if gravXDif < 0: gravC = 270 else: if gravYDif > 0: gravC = math.degrees(math.atan(gravXDif / gravYDif)) if gravC < 0: gravC += 360 else: gravC = math.degrees(math.atan(gravXDif / gravYDif)) + 180 self.xpos += math.sin(math.radians(gravC)) * grav self.ypos += math.cos(math.radians(gravC)) * grav def calcCourseSpd(self, xdif, ydif): self.vel = math.sqrt(xdif**2 + ydif**2) if ydif == 0: self.course = 90 if xdif < 0: self.course = 270 else: if ydif > 0: self.course = math.degrees(math.atan(xdif / ydif)) if self.course < 0: self.course += 360 else: self.course = math.degrees(math.atan(xdif / ydif)) + 180 if (self.xpos > play_w - 4): self.xpos = 4 if (self.xpos < 4): self.xpos = play_w - 4 if (self.ypos > play_h - 4): self.ypos = 4 if (self.ypos < 4): self.ypos = play_h - 4 class torpedo(spaceObject): def __init__(self, x, y, course, vel, orientation, owner, serial, launchTime): self.xpos = x self.ypos = y self.course = course self.vel = vel self.orientation = orientation self.lastUpdate = manor.tickcount() self.fuel = 500 self.owner = owner self.serial = serial self.launchTime = launchTime self.armed = 0 def calcPos(self): currTick = manor.tickcount() timeDisp = currTick - self.lastUpdate if timeDisp != 0: manor.dirtyRect(rect(int(self.xpos) - 3, int(self.ypos) - 3, int(self.xpos) + 3, int(self.ypos) + 3)) for time in range(timeDisp): oldx = self.xpos oldy = self.ypos spaceObject.calcPos(self) if self.fuel > 0: thrust = 0.05/2.0 self.fuel -= 3 self.xpos += math.sin(math.radians(self.orientation)) * thrust self.ypos += math.cos(math.radians(self.orientation)) * thrust spaceObject.calcCourseSpd(self, self.xpos - oldx, self.ypos - oldy) manor.dirtyRect(rect(int(self.xpos) - 3, int(self.ypos) - 3, int(self.xpos) + 3, int(self.ypos) + 3)) self.lastUpdate = currTick; def draw(self, gworld): ixpos = int(self.xpos) iypos = int(self.ypos) if self.fuel > 0: if self.armed: gworld.foreColor(0xFF, 0xFF, 0x80, 0x80) else: gworld.foreColor(0xFF, 0xFF, 0xFF, 0xFF) else: gworld.foreColor(0xFF, 0xFF, 0, 0) gworld.fillOval(rect(ixpos - 3, iypos - 3, ixpos + 3, iypos + 3)) class ship(spaceObject): def __init__(self, x, y): self.explodeLev = 0 self.shipOr = 180 self.eng_on = 0 self.thrst_lft = 0 self.thrst_rt = 0 self.thrst_brk = 0 self.thrst_fwd = 0 self.rotVel = 0 self.shipImg = shape() self.engineImg = shape() self.leftThrstImg = shape() self.rightThrstImg = shape() self.fwdThrstImg = shape() self.brkThrstImg = shape() self.fuel = 5000 self.torps = 10 self.xpos = x self.ypos = y self.lastUpdate = manor.tickcount() self.shipImg.move(-4, 0) self.shipImg.line(-13, -8) self.shipImg.line(-13, -4) self.shipImg.line(-4, 7) self.shipImg.line(4, 7) self.shipImg.line(13, -4) self.shipImg.line(13, -8) self.shipImg.line(4, 0) self.shipImg.line(1, -13) self.shipImg.line(-1, -13) self.shipImg.line(-4, 0) self.shipImg.move(-13, -8) self.shipImg.line(-13, -14) self.shipImg.move(13, -8) self.shipImg.line(13, -14) self.shipImg.move(-2, 0) self.shipImg.line(0, -6) self.shipImg.line(2, 0) self.shipImg.line(-2, 0) self.engineImg.move(-3, 7) self.engineImg.line(0, 14) self.engineImg.line(3, 7) self.leftThrstImg.move(-2, -12) self.leftThrstImg.line(-5, -12) self.leftThrstImg.move(4, 7) self.leftThrstImg.line(7, 7) self.rightThrstImg.move(2, -12) self.rightThrstImg.line(5, -12) self.rightThrstImg.move(-4, 7) self.rightThrstImg.line(-7, 7) self.fwdThrstImg.move(-4, 7) self.fwdThrstImg.line(-4, 10) self.fwdThrstImg.move(4, 7) self.fwdThrstImg.line(4, 10) self.brkThrstImg.move(-6, -1) self.brkThrstImg.line(-6, -4) self.brkThrstImg.move(6, -1) self.brkThrstImg.line(6, -4) def calcPos(self): manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) currTick = manor.tickcount() timeDisp = currTick - self.lastUpdate if timeDisp != 0: for time in range(timeDisp): oldx = self.xpos oldy = self.ypos spaceObject.calcPos(self) if self.rotVel != 0: self.shipOr += self.rotVel if self.shipOr < 0: self.shipOr += 360 if self.shipOr > 360: self.shipOr -= 360 if self.explodeLev == 0: if self.fuel > 0: if self.thrst_lft != 0: self.rotVel -= 0.05/5.0 self.fuel -= 3 if self.thrst_rt != 0: self.rotVel += 0.05/5.0 self.fuel -= 3 thrust = 0 if self.thrst_brk != 0: thrust -= 0.05/5.0 self.fuel -= 3 if self.thrst_fwd != 0: thrust += 0.05/5.0 self.fuel -= 3 if self.eng_on != 0: thrust += 0.08/5.0 self.fuel -= 6 if thrust != 0: self.xpos += math.sin(math.radians(self.shipOr)) * thrust self.ypos += math.cos(math.radians(self.shipOr)) * thrust if self.fuel < 0: self.fuel = 0 else: self.thrst_lft = 0 self.thrst_rt = 0 self.thrst_brk = 0 self.thrst_fwd = 0 self.eng_on = 0 else: if self.explodeLev > 0: self.explodeLev -= 1 if self.explodeLev == 0: self.explodeLev = -1 spaceObject.calcCourseSpd(self, self.xpos - oldx, self.ypos - oldy) self.shipImg.rotate(math.radians(self.shipOr)) self.engineImg.rotate(math.radians(self.shipOr)) self.leftThrstImg.rotate(math.radians(self.shipOr)) self.rightThrstImg.rotate(math.radians(self.shipOr)) self.fwdThrstImg.rotate(math.radians(self.shipOr)) self.brkThrstImg.rotate(math.radians(self.shipOr)) manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) self.lastUpdate = currTick def clean(self): manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) def draw(self, gworld): ixpos = int(self.xpos) iypos = int(self.ypos) if self.explodeLev > 0: color = 0xFF - (60 - self.explodeLev) * 4 gworld.foreColor(0xFF, color, color, color) gworld.fillOval(self.shipImg.bounds().offset(ixpos, iypos)) else: gworld.foreColor(0xFF, 0, 0xFF, 0) self.shipImg.draw(gworld, ixpos, iypos) if self.eng_on != 0: gworld.foreColor(0xFF, 0, 0xFF, 0xFF) self.engineImg.draw(gworld, ixpos, iypos) if self.thrst_lft != 0: gworld.foreColor(0xFF, 0, 0xFF, 0xFF) self.leftThrstImg.draw(gworld, ixpos, iypos) if self.thrst_rt != 0: gworld.foreColor(0xFF, 0, 0xFF, 0xFF) self.rightThrstImg.draw(gworld, ixpos, iypos) if self.thrst_fwd != 0: gworld.foreColor(0xFF, 0, 0xFF, 0xFF) self.fwdThrstImg.draw(gworld, ixpos, iypos) if self.thrst_brk != 0: gworld.foreColor(0xFF, 0, 0xFF, 0xFF) self.brkThrstImg.draw(gworld, ixpos, iypos) class player(ship): def __init__(self, userID, stats): self.userID = userID xpos, ypos, shipOr, course, vel, rotVel, thrst_lft, thrst_rt, thrst_brk, thrst_fwd, eng_on, fuel = stats ship.__init__(self, xpos, ypos) manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) self.shipOr = shipOr self.course = course self.vel = vel self.rotVel = rotVel self.thrst_lft = thrst_lft self.thrst_rt = thrst_rt self.thrst_brk = thrst_brk self.thrst_fwd = thrst_fwd self.eng_on = eng_on self.pingTime = 0 self.fuel = fuel self.shipImg.rotate(math.radians(self.shipOr)) self.engineImg.rotate(math.radians(self.shipOr)) self.leftThrstImg.rotate(math.radians(self.shipOr)) self.rightThrstImg.rotate(math.radians(self.shipOr)) manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) def update(self, stats): manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) self.xpos, self.ypos, self.shipOr, self.course, self.vel, self.rotVel, self.thrst_lft, self.thrst_rt, self.thrst_brk, self.thrst_fwd, self.eng_on, self.fuel = stats self.shipImg.rotate(math.radians(self.shipOr)) self.engineImg.rotate(math.radians(self.shipOr)) self.leftThrstImg.rotate(math.radians(self.shipOr)) self.rightThrstImg.rotate(math.radians(self.shipOr)) manor.dirtyRect(self.shipImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.engineImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.leftThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.rightThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.fwdThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(self.brkThrstImg.bounds().offset(int(self.xpos), int(self.ypos))) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) self.lastUpdate = manor.tickcount() - self.pingTime def calcPos(self): manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) ship.calcPos(self) manor.dirtyRect(rect(int(self.xpos) - 50, int(self.ypos) + 20, int(self.xpos) + 50, int(self.ypos) +36)) def draw(self, gworld): ixpos = int(self.xpos) iypos = int(self.ypos) ship.draw(self, gworld) gworld.foreColor(0xFF, 0xFF, 0xFF, 0xFF) gworld.moveTo(ixpos - 49, iypos + 30) gworld.drawString(manor.getUserName(int(self.userID))) #---------------------------------------------------------------------------- # sendPos # # Send my current position to the room # def sendPos(): global myship, lastSend parms = [myship.xpos, myship.ypos, myship.shipOr, myship.course, myship.vel, myship.rotVel, myship.thrst_lft, myship.thrst_rt, myship.thrst_brk, myship.thrst_fwd, myship.eng_on, myship.fuel] manor.broadcastData("mypos", 0, parms) lastSend = manor.tickcount() #---------------------------------------------------------------------------- # sendExplode # # Send I blew up # def sendExplode(): global myship parms = [myship.xpos, myship.ypos, myship.shipOr, myship.course, myship.vel, myship.rotVel] manor.broadcastData("idead", 0, parms) #---------------------------------------------------------------------------- # recvExplode # # Recv explode # def recvExplode(userID, data, parms): global players for i in players: if i.userID == userID: i.clean() i.lastUpdate = manor.tickcount() - i.pingTime i.xpos, i.ypos, i.shipOr, i.course, i.vel, i.rotVel = data if i.explodeLev == 0: i.explodeLev = 60 def sendTorp(): global myship parms = [myship.xpos, myship.ypos, myship.course, myship.vel, myship.shipOr, myship.torps] manor.broadcastData("torp", 0, parms) def torpRecv(userID, data, parms): global torps, players xpos, ypos, course, vel, shipOr, serial = data pingTime = 0 for i in players: if i.userID == userID: pingTime = i.pingTime torps.append(torpedo(xpos, ypos, course, vel, shipOr, userID, serial, manor.tickcount() - pingTime)) #---------------------------------------------------------------------------- # sendPing # # Send a timing ping # def sendPing(): manor.broadcastData("ping", 0, manor.tickcount()) #---------------------------------------------------------------------------- # pingRecv # # Respond to ping def pingRecv(userID, data, parms): manor.sendData("pong", [userID], data) #---------------------------------------------------------------------------- # pongRecv # # Receive a pong def pongRecv(userID, data, parms): global players, numPlayers if numPlayers != 0: for i in players: if i.userID == userID: i.pingTime = (manor.tickcount() - data) / 2 #print "pingtime ",i.pingTime #---------------------------------------------------------------------------- # mover # # Calculate all the movement # def mover(param): global myship, numPlayers, players, lastSend, lastPing, torps, star_x, star_y sendInfo = 0 if manor.tickcount() - lastPing > 300: sendPing() if myship.explodeLev == 0: statsRect = manor.getSpotBounds(3) if (manor.getClientType() == 1 and manor.isKeyDown(102)) or (manor.getClientType() != 1 and manor.isKeyDown(88)): if myship.thrst_lft == 0: sendInfo = 1 myship.thrst_lft = 1 manor.dirtyRect(statsRect) else: if myship.thrst_lft == 1: sendInfo = 1 myship.thrst_lft = 0 if (manor.getClientType() == 1 and manor.isKeyDown(100)) or (manor.getClientType() != 1 and manor.isKeyDown(86)): if myship.thrst_rt == 0: sendInfo = 1 myship.thrst_rt = 1 manor.dirtyRect(statsRect) else: if myship.thrst_rt == 1: sendInfo = 1 myship.thrst_rt = 0 if (manor.getClientType() == 1 and manor.isKeyDown(101)) or (manor.getClientType() != 1 and manor.isKeyDown(87)): if myship.thrst_fwd == 0: sendInfo = 1 myship.thrst_fwd = 1 manor.dirtyRect(statsRect) else: if myship.thrst_fwd == 1: sendInfo = 1 myship.thrst_fwd = 0 if (manor.getClientType() == 1 and manor.isKeyDown(98)) or (manor.getClientType() != 1 and manor.isKeyDown(84)): if myship.thrst_brk == 0: sendInfo = 1 myship.thrst_brk = 1 manor.dirtyRect(statsRect) else: if myship.thrst_brk == 1: sendInfo = 1 myship.thrst_brk = 0 if (manor.getClientType() == 1 and manor.isKeyDown(104)) or (manor.getClientType() != 1 and manor.isKeyDown(91)): if myship.eng_on == 0: sendInfo = 1 myship.eng_on = 1 manor.dirtyRect(statsRect) else: if myship.eng_on == 1: sendInfo = 1 myship.eng_on = 0 elif myship.explodeLev == -1: statsRect = manor.getSpotBounds(3) myship.clean() myship.xpos = random.random() * 7 * 32 myship.ypos = random.random() * 7 * 32 myship.vel = .1 myship.explodeLev = 0 myship.fuel = 5000 myship.torps = 10 myship.rotVel = 0 manor.dirtyRect(statsRect) sendInfo = 1 myship.calcPos() if math.sqrt((myship.xpos - star_x)**2 + (myship.ypos - star_y)**2) < 32 and myship.explodeLev == 0: myship.explodeLev = 60 sendExplode() if sendInfo == 1: sendPos() count = 0 for i in torps: i.calcPos() if math.sqrt((i.xpos - star_x)**2 + (i.ypos - star_y)**2) < 32: del torps[count] else: if i.launchTime + 60 <= manor.tickcount(): i.armed = 1 if i.launchTime + 300 <= manor.tickcount(): del torps[count] else: if i.armed: if math.sqrt((i.xpos - myship.xpos)**2 + (i.ypos - myship.ypos)**2) < 16: if myship.explodeLev == 0: myship.explodeLev = 60 sendExplode() del torps[count] for p in players: if math.sqrt((i.xpos - p.xpos)**2 + (i.ypos - p.ypos)**2) < 16: del torps[count] count += 1 if numPlayers != 0: for i in players: i.calcPos() if math.sqrt((i.xpos - star_x)**2 + (i.ypos - star_y)**2) < 32 and i.explodeLev == 0: i.explodeLev = 60 elif math.sqrt((i.xpos - myship.xpos)**2 + (i.ypos - myship.ypos)**2) < 25: if myship.explodeLev == 0: myship.explodeLev = 60 sendExplode() manor.setTimer(manor.tickcount() + 1, mover, 0) #---------------------------------------------------------------------------- # posRecv # # Receive player position update, add to player list if new def posRecv(userID, data, parms): global players, numPlayers if numPlayers == 0: players.append(player(userID, data)) sendPos() numPlayers += 1 else: found = 0 for i in players: if i.userID == userID: found = 1 i.update(data) i.explodeLev = 0 if found == 0: players.append(player(userID, data)) sendPos() numPlayers += 1 #---------------------------------------------------------------------------- # Render event # def mnr_render(gworld, layer): global myship, initialized, numPlayers, players, torps handled = 0 if layer == 2: if initialized == 1: myship.draw(gworld) top, left, bottom, right = (manor.getSpotBounds(3)).bounds() names = [["Fuel:", str(myship.fuel)], ["Torpedoes:", str(myship.torps)], ["Hull temp:", "0"]] currLine = top + gworld.fontAscent() for i in names: gworld.foreColor(0xFF, 0xFF, 0xFF, 0xFF) gworld.moveTo(left + 60 - gworld.stringWidth(i[0]), currLine) gworld.drawString(i[0]) gworld.foreColor(0xFF, 0, 0xFF, 0) gworld.moveTo(left + 65, currLine) gworld.drawString(i[1]) currLine += gworld.fontHeight() for i in torps: i.draw(gworld) if numPlayers != 0: for i in players: i.draw(gworld) handled = 1 return handled #---------------------------------------------------------------------------- # Enter event # def mnr_enter(userID): global myship, initialized, numPlayers, player, star_x, star_y, play_w, play_h if userID == manor.myID() or manor.myID() == 0: print("StarHawk Copyright ©2004 MadWolf Software"); print("This script may be freely redistributed provided this notice is kept intact"); myship = ship(115, 190) t, l, b, r = manor.getSpotBounds(1).bounds() star_x = l + (r - l) / 2 star_y = t + (b - t) / 2 t, l, b, r = manor.getSpotBounds(2).bounds() play_w = r - l play_h = b - t initialized = 1 manor.setTimer(manor.tickcount() + 1, mover, 0) manor.regDataReceive("mypos", posRecv, 0) manor.regDataReceive("idead", recvExplode, 0) manor.regDataReceive("ping", pingRecv, 0) manor.regDataReceive("pong", pongRecv, 0) manor.regDataReceive("torp", torpRecv, 0) sendPos() def mnr_leave(userID): global players, numPlayers count = 0 for i in players: if i.userID == userID: i.clean() del players[count] numPlayers -= 1 count += 1 def mnr_keydown(char, key): global myship, torps handled = 0 #print key if (manor.getClientType() == 1): if key == 100 or key == 102 or key == 104 or key == 101 or key == 98 or key == 103: handled = 1 elif key == 91 or key == 86 or key == 88 or key == 87 or key == 84 or key == 89: handled = 1 if ((manor.getClientType() != 1 and key == 89) or (manor.getClientType() == 1 and key == 103)) and myship.torps > 0 and myship.explodeLev == 0: torps.append(torpedo(myship.xpos, myship.ypos, myship.course, myship.vel, myship.shipOr, 0, myship.torps, manor.tickcount())) sendTorp() myship.torps -= 1 manor.dirtyRect(manor.getSpotBounds(3)) return handled