Crossfire Server, Trunk
lockable_doors.py
Go to the documentation of this file.
1 # Script for the lockable door and key.
2 # Ideas courtesy Yann Chachkoff.
3 #
4 # Copyright 2012 Nicolas Weeger
5 # Released as GPL
6 #
7 # Lockable doors have 2 components:
8 # - doors, which have the 'lockable 1' attribute
9 # - locking keys, which have a apply handler pointing to this script
10 #
11 # Rules are as follow:
12 # - the 'slaying' field is used to match doors and keys
13 # - locking keys start blank (empty slaying)
14 # - applying a blank key to an unlocked door locks the door and assigns the door to the key,
15 # the key gets a '(used)' appended to its name
16 # - applying a valid key to a locked/unlocked door unlocks/locks
17 # - locked doors must be alive, unlocked mustn't be
18 # - the 'other_arch' field is used to link locked and unlocked variants
19 # - the following fields are changed when un/locking takes place: name, move_block,
20 # move_allow, face. This allows customization of the doors (prevent walk but not fly, for instance)
21 #
22 # Right now, the following archetypes use this system:
23 # lockable_vdoor, lockable_vdoor_locked, lockable_hdoor, lockable_hdoor_locked, locking_key
24 #
25 # Feel free to use those as a base.
26 #
27 # Note: using a DOOR (type 23) instead of a LOCKED_DOOR (type 20) doesn't seem to
28 # work, since any key can remove the door - not the desired behaviour.
29 #
30 # If the lockable door has the correct 'trigger' hook (case for the previous archetypes),
31 # then the door can be picked, depending on the player's lockpicking level.
32 # Experience is awarded for the first successful pick only. Failures decrease the
33 # chance to succeed, and increase the chance of leaving traces.
34 
35 import Crossfire
36 import random
37 
38 def get_door(me, direction):
39  '''Find the first item in the specified direction'''
40  map = me.Map
41  x = me.X
42  y = me.Y
43 
44  if direction==2:
45  ob = map.ObjectAt(x+1, y-1)
46  elif direction==3:
47  ob = map.ObjectAt(x+1, y)
48  elif direction==4:
49  ob = map.ObjectAt(x+1, y+1)
50  elif direction==5:
51  ob = map.ObjectAt(x, y+1)
52  elif direction==6:
53  ob = map.ObjectAt(x-1, y+1)
54  elif direction==7:
55  ob = map.ObjectAt(x-1, y)
56  elif direction==8:
57  ob = map.ObjectAt(x-1, y-1)
58  else:
59  ob = map.ObjectAt(x, y-1)
60  return ob
61 
62 def give_properties(who, lock):
63  '''Give properties from either the archetype or the other archetype.'''
64  if lock == who.Archetype.Clone.Alive:
65  arch = who.Archetype
66  else:
67  arch = who.OtherArchetype
68  who.MoveType = arch.Clone.MoveType
69  who.MoveBlock = arch.Clone.MoveBlock
70  who.MoveAllow = arch.Clone.MoveAllow
71  who.Alive = arch.Clone.Alive
72  who.Name = arch.Clone.Name
73  who.Face = arch.Clone.Face
74 
75 def check_picked(door, who):
76  '''Check if the lock was picked, and inform the player if this is the case.'''
77  if door.ReadKey('door_picked') == '1':
78  who.Write('You notice some suspicious traces on the lock.')
79  door.WriteKey('door_picked', '')
80 
81 def handle_key():
82  '''Handle applying a locking key.'''
83  Crossfire.SetReturnValue(1)
84 
85  key = Crossfire.WhoAmI()
86  who = Crossfire.WhoIsActivator()
87 
88  door = get_door(who, who.Facing)
89 
90  while door != None:
91  if door.ReadKey('lockable') == '1':
92  break
93  door = door.Above
94 
95  if door == None:
96  who.Write('There is no lock here')
97  else:
98  if door.Alive:
99  # door is locked, check if key matches
100  if door.Slaying != key.Slaying:
101  who.Write("You can't use this %s on this %s"%(key.Name, door.Name))
102  else:
103  who.Write('You unlock the %s'%(door.Name))
104  give_properties(door, 0)
105  check_picked(door, who)
106  else:
107  # door is unlocked, a key can lock if blank or matching
108  if key.Slaying == '' or key.Slaying == None or key.Slaying == door.Slaying:
109  if key.Slaying == '' or key.Slaying == None:
110  key.Slaying = door.Slaying
111  key.Name = key.Name + " (used)"
112  who.Write('You lock the %s'%(door.Name))
113  give_properties(door, 1)
114  check_picked(door, who)
115  else:
116  who.Write("You can't use this %s on this %s"%(key.Name, door.Name))
117 
118 def get_attempts(door, who):
119  '''Get how many attempts to pick a lock a player did'''
120  s = door.ReadKey('attempts_' + who.Name)
121  if s == '':
122  return 0
123  return int(s)
124 
125 def get_success_chance(door, who, level):
126  '''Return the chance of successfully picking the lock for the player'''
127  if door.ReadKey('was_picked_' + who.Name) != '':
128  return 100
129  attempts = min(get_attempts(door, who), 5)
130  diff = level - door.Level - attempts
131  #who.Write('chance: %d'%(max(25, min(90, 50 + diff * 5))))
132  return max(25, min(90, 50 + diff * 5))
133 
134 def get_exp(door, who):
135  '''Return the experience for lockpicking the door'''
136  if door.ReadKey('was_picked_' + who.Name) != '':
137  return 0
138  attempts = get_attempts(door, who)
139  #who.Write('exp: %d'%(round((door.Exp * (100. - min(100., attempts * 20.))) / 100.)))
140  return round((door.Exp * (100. - min(100., attempts * 20.))) / 100.)
141 
143  '''Handle lockpicking a door.'''
144  Crossfire.SetReturnValue(1)
145 
146  door = Crossfire.WhoAmI()
147  who = Crossfire.WhoIsActivator()
148 
149  if who == None:
150  return
151 
152  if door.Alive == 0:
153  who.Write("This %s is unlocked."%(door.Name))
154  return
155 
156  chance = get_success_chance(door, who, Crossfire.WhoIsOther().Level)
157  # chance to leave traces on the lock
158  if random.randint(0, 100) < 100 - chance:
159  door.WriteKey('door_picked', '1', 1)
160 
161  # attempt to unlock
162  if random.randint(0, 100) < chance:
163  who.Write('You successfully pick the lock.')
164  give_properties(door, 0)
165  who.AddExp(get_exp(door, who), Crossfire.WhoIsOther().Name)
166  door.WriteKey('was_picked_' + who.Name, '1', 1)
167  else:
168  who.Write('You fail to pick the lock.')
169  door.WriteKey('attempts_' + who.Name, str(get_attempts(door, who) + 1), 1)
170 
171 event = Crossfire.WhatIsEvent()
172 if event.Subtype == Crossfire.EventType.APPLY:
173  handle_key()
174 elif event.Subtype == Crossfire.EventType.TRIGGER:
lockable_doors.get_door
def get_door(me, direction)
Definition: lockable_doors.py:38
lockable_doors.get_attempts
def get_attempts(door, who)
Definition: lockable_doors.py:118
lockable_doors.check_picked
def check_picked(door, who)
Definition: lockable_doors.py:75
lockable_doors.handle_key
def handle_key()
Definition: lockable_doors.py:81
lockable_doors.handle_lockpick
def handle_lockpick()
Definition: lockable_doors.py:142
make_face_from_files.str
str
Definition: make_face_from_files.py:30
say.max
dictionary max
Definition: say.py:148
lockable_doors.get_success_chance
def get_success_chance(door, who, level)
Definition: lockable_doors.py:125
lockable_doors.give_properties
def give_properties(who, lock)
Definition: lockable_doors.py:62
make_face_from_files.int
int
Definition: make_face_from_files.py:32
lockable_doors.get_exp
def get_exp(door, who)
Definition: lockable_doors.py:134