Crossfire Server, Trunk
roll-o-matic.py
Go to the documentation of this file.
1 # Script for the roll-o-matic.
2 # Idea courtesy Alex Schultz.
3 #
4 # Copyright 2007 Nicolas Weeger
5 # Released as GPL
6 #
7 # This script makes its item move following tiles, in direction specified by a player
8 
9 """
10 Using this script:
11 
12 1. Create a transport object in the map editor. Ensure that its type is actually TRANSPORT.
13 
14 2. Add Python events that trigger this script. Transports require at least two events:
15 
16  - event_time, which periodically calls this script to move the transport along
17 
18  - event_apply and/or event_say, to start and stop the transport
19 
20  In practice, each event has fields:
21 
22  title Python
23  slaying /python/items/roll-o-matic.py
24 
25  Optionally, add:
26 
27  name ship_mode
28 
29  Which makes roll-o-matic work for ships.
30 """
31 
32 import Crossfire
33 
34 key_direction = 'rom_dir'
35 key_follow = 'rom_follow'
36 
37 dir_x = [ 0, 0, 1, 1, 1, 0, -1, -1, -1 ]
38 dir_y = [ 0, -1, -1, 0, 1, 1, 1, 0, -1 ]
39 
40 ship_mode = False
41 
42 def is_floor(ob):
43  if ship_mode:
44  return ob.ArchName in {'sea_route', 'sea_route_2', 'sea_route_3', 'sea_route_4'}
45  else:
46  return ob.Floor == 1
47 
48 def find_floor(x, y):
49  """Find all objects satisfying is_floor() at the given location."""
50  obj = me.Map.ObjectAt(x, y)
51  while obj != None:
52  if is_floor(obj):
53  yield obj
54  obj = obj.Above
55 
57  obj = me.Map.ObjectAt(me.X, me.Y)
58  while obj != None:
59  if obj.Type == Crossfire.Type.PLAYER:
60  return obj
61  obj = obj.Above
62  return None
63 
64 def has_floor(x, y, name):
65  """Check whether one floor at the given location matches the given 'name'."""
66  for ob in find_floor(x, y):
67  if ob.Name == name:
68  return True
69  return False
70 
71 def abs_dir(d):
72  while d < 1:
73  d = d + 8
74  while d > 8:
75  d = d - 8
76  return d
77 
78 def stop():
79  me.WriteKey(key_direction, '', 1)
80  me.WriteKey(key_follow, '', 1)
81  me.Map.Print('The %s stops moving.'%me.Name)
82 
83 def try_move(check_directions, want_dir):
84  floor = me.ReadKey(key_follow)
85  x = me.X
86  y = me.Y
87  done = False
88  for check in check_directions:
89  d = abs_dir(want_dir + check)
90  if has_floor(x + dir_x[d], y + dir_y[d], floor):
91  # Next time, move in the direction we last moved in.
92  # This heuristic helps follow the roads better.
93  me.WriteKey(key_direction, str(d))
94  if me.Move(d) == 0:
95  continue
96 
97  if pl != None:
98  pl.Move(d)
99  done = True
100  break
101 
102  if not done:
103  stop()
104 
105 def do_shipwreck(me):
106  stop()
107 
109  want_dir = me.ReadKey(key_direction)
110  floor = me.ReadKey(key_follow)
111  if want_dir == '' or floor == '':
112  return
113 # me.Map.Print('roll')
114  pl = find_player()
115  want_dir = int(want_dir)
116  if ship_mode:
117  # For ship routes, check all candidate directions except the opposite-direction one.
118  check_directions = [0, 1, -1, 2, -2, 3, -3]
119 
120  curr_tile = me.Map.ObjectAt(me.X, me.Y)
121  while curr_tile != None:
122  if curr_tile.Name == 'shipwreck':
123  do_shipwreck(me)
124  return
125  curr_tile = curr_tile.Above
126  else:
127  # For roads, only check the routes that make progress in the right direction.
128  check_directions = [0, 1, -1]
129  try_move(check_directions, want_dir)
130 
131 def start_move(want_dir):
132  floors = list(find_floor(me.X, me.Y))
133  if len(floors) < 1:
134  return
135  floor = floors[0].Name
136 
137  if me.ReadKey(key_direction) == '':
138  me.Map.Print('The %s starts moving!' % me.Name)
139 
140  me.WriteKey(key_direction, str(want_dir), 1)
141  me.WriteKey(key_follow, floor, 1)
142 
144  msg = Crossfire.WhatIsMessage()
145  if msg == 'stop':
146  if me.ReadKey(key_direction) != '':
147  stop()
148  return
149 
150  want_dir = -1
151 
152  for d in Crossfire.DirectionName.keys():
153  if msg == Crossfire.DirectionName[d].lower():
154  want_dir = d
155  break
156 
157  if want_dir == -1:
158  return
159 
160  start_move(want_dir)
161 
163  if pl.Transport != None:
164  # Stop if already moving.
165  stop()
166  else:
167  # When applied, we don't know initial direction. Try to find one.
168  start_move(0)
169  try_move([0, 1, 2, 3, 4, 5, 6, 7], 0)
170  Crossfire.SetReturnValue(0)
171 
172 def do_handle():
173  if me.Map == None:
174  return
175 
176  if "ship_mode" in params:
177  global ship_mode
178  ship_mode = True
179 
180  Crossfire.SetReturnValue(1)
181 
182  if evt.Subtype == Crossfire.EventType.SAY:
183  handle_say()
184  elif evt.Subtype == Crossfire.EventType.APPLY:
185  handle_apply()
186  elif evt.Subtype == Crossfire.EventType.TIME:
187  handle_move()
188 
189 
190 evt = Crossfire.WhatIsEvent()
191 me = Crossfire.WhoAmI()
192 pl = Crossfire.WhoIsActivator()
193 params = Crossfire.ScriptParameters()
194 
195 do_handle()
roll-o-matic.handle_say
def handle_say()
Definition: roll-o-matic.py:143
roll-o-matic.is_floor
def is_floor(ob)
Definition: roll-o-matic.py:42
guildoracle.list
list
Definition: guildoracle.py:87
roll-o-matic.find_player
def find_player()
Definition: roll-o-matic.py:56
roll-o-matic.abs_dir
def abs_dir(d)
Definition: roll-o-matic.py:71
roll-o-matic.has_floor
def has_floor(x, y, name)
Definition: roll-o-matic.py:64
roll-o-matic.start_move
def start_move(want_dir)
Definition: roll-o-matic.py:131
make_face_from_files.str
str
Definition: make_face_from_files.py:30
roll-o-matic.do_shipwreck
def do_shipwreck(me)
Definition: roll-o-matic.py:105
roll-o-matic.try_move
def try_move(check_directions, want_dir)
Definition: roll-o-matic.py:83
roll-o-matic.find_floor
def find_floor(x, y)
Definition: roll-o-matic.py:48
roll-o-matic.stop
def stop()
Definition: roll-o-matic.py:78
roll-o-matic.do_handle
def do_handle()
Definition: roll-o-matic.py:172
roll-o-matic.handle_apply
def handle_apply()
Definition: roll-o-matic.py:162
make_face_from_files.int
int
Definition: make_face_from_files.py:32
roll-o-matic.handle_move
def handle_move()
Definition: roll-o-matic.py:108