File: lockable_doors.py

package info (click to toggle)
crossfire-maps 1.75.0%2Bdfsg1-1
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 275,656 kB
  • sloc: python: 7,711; sql: 92; sh: 73; makefile: 7
file content (175 lines) | stat: -rw-r--r-- 5,915 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# Script for the lockable door and key.
# Ideas courtesy Yann Chachkoff.
#
# Copyright 2012 Nicolas Weeger
# Released as GPL
#
# Lockable doors have 2 components:
# - doors, which have the 'lockable 1' attribute
# - locking keys, which have a apply handler pointing to this script
#
# Rules are as follow:
# - the 'slaying' field is used to match doors and keys
# - locking keys start blank (empty slaying)
# - applying a blank key to an unlocked door locks the door and assigns the door to the key,
#  the key gets a '(used)' appended to its name
# - applying a valid key to a locked/unlocked door unlocks/locks
# - locked doors must be alive, unlocked mustn't be
# - the 'other_arch' field is used to link locked and unlocked variants
# - the following fields are changed when un/locking takes place: name, move_block,
#  move_allow, face. This allows customization of the doors (prevent walk but not fly, for instance)
#
# Right now, the following archetypes use this system:
# lockable_vdoor, lockable_vdoor_locked, lockable_hdoor, lockable_hdoor_locked, locking_key
#
# Feel free to use those as a base.
#
# Note: using a DOOR (type 23) instead of a LOCKED_DOOR (type 20) doesn't seem to
# work, since any key can remove the door - not the desired behaviour.
#
# If the lockable door has the correct 'trigger' hook (case for the previous archetypes),
# then the door can be picked, depending on the player's lockpicking level.
# Experience is awarded for the first successful pick only. Failures decrease the
# chance to succeed, and increase the chance of leaving traces.

import Crossfire
import random

def get_door(me, direction):
    '''Find the first item in the specified direction'''
    map = me.Map
    x = me.X
    y = me.Y

    if direction==2:
        ob = map.ObjectAt(x+1, y-1)
    elif direction==3:
        ob = map.ObjectAt(x+1, y)
    elif direction==4:
        ob = map.ObjectAt(x+1, y+1)
    elif direction==5:
        ob = map.ObjectAt(x, y+1)
    elif direction==6:
        ob = map.ObjectAt(x-1, y+1)
    elif direction==7:
        ob = map.ObjectAt(x-1, y)
    elif direction==8:
        ob = map.ObjectAt(x-1, y-1)
    else:
        ob = map.ObjectAt(x, y-1)
    return ob

def give_properties(who, lock):
  '''Give properties from either the archetype or the other archetype.'''
  if lock == who.Archetype.Clone.Alive:
    arch = who.Archetype
  else:
    arch = who.OtherArchetype
  who.MoveType = arch.Clone.MoveType
  who.MoveBlock = arch.Clone.MoveBlock
  who.MoveAllow = arch.Clone.MoveAllow
  who.Alive = arch.Clone.Alive
  who.Name = arch.Clone.Name
  who.Face = arch.Clone.Face

def check_picked(door, who):
  '''Check if the lock was picked, and inform the player if this is the case.'''
  if door.ReadKey('door_picked') == '1':
    who.Write('You notice some suspicious traces on the lock.')
    door.WriteKey('door_picked', '')

def handle_key():
  '''Handle applying a locking key.'''
  Crossfire.SetReturnValue(1)

  key = Crossfire.WhoAmI()
  who = Crossfire.WhoIsActivator()

  door = get_door(who, who.Facing)

  while door != None:
    if door.ReadKey('lockable') == '1':
      break
    door = door.Above

  if door == None:
    who.Write('There is no lock here')
  else:
    if door.Alive:
      # door is locked, check if key matches
      if door.Slaying != key.Slaying:
        who.Write("You can't use this %s on this %s"%(key.Name, door.Name))
      else:
        who.Write('You unlock the %s'%(door.Name))
        give_properties(door, 0)
        check_picked(door, who)
    else:
      # door is unlocked, a key can lock if blank or matching
      if key.Slaying == '' or key.Slaying == None or key.Slaying == door.Slaying:
        if key.Slaying == '' or key.Slaying == None:
          key.Slaying = door.Slaying
          key.Name = key.Name + " (used)"
        who.Write('You lock the %s'%(door.Name))
        give_properties(door, 1)
        check_picked(door, who)
      else:
        who.Write("You can't use this %s on this %s"%(key.Name, door.Name))

def get_attempts(door, who):
  '''Get how many attempts to pick a lock a player did'''
  s = door.ReadKey('attempts_' + who.Name)
  if s == '':
    return 0
  return int(s)

def get_success_chance(door, who, level):
  '''Return the chance of successfully picking the lock for the player'''
  if door.ReadKey('was_picked_' + who.Name) != '':
    return 100
  attempts = min(get_attempts(door, who), 5)
  diff = level - door.Level - attempts
  #who.Write('chance: %d'%(max(25, min(90, 50 + diff * 5))))
  return max(25, min(90, 50 + diff * 5))

def get_exp(door, who):
  '''Return the experience for lockpicking the door'''
  if door.ReadKey('was_picked_' + who.Name) != '':
    return 0
  attempts = get_attempts(door, who)
  #who.Write('exp: %d'%(round((door.Exp * (100. - min(100., attempts * 20.))) / 100.)))
  return round((door.Exp * (100. - min(100., attempts * 20.))) / 100.)

def handle_lockpick():
  '''Handle lockpicking a door.'''
  Crossfire.SetReturnValue(1)

  door = Crossfire.WhoAmI()
  who = Crossfire.WhoIsActivator()

  if who == None:
    return

  if door.Alive == 0:
    who.Write("This %s is unlocked."%(door.Name))
    return

  chance = get_success_chance(door, who, Crossfire.WhoIsOther().Level)
  # chance to leave traces on the lock
  if random.randint(0, 100) < 100 - chance:
    door.WriteKey('door_picked', '1', 1)

  # attempt to unlock
  if random.randint(0, 100) < chance:
    who.Write('You successfully pick the lock.')
    give_properties(door, 0)
    who.AddExp(get_exp(door, who), Crossfire.WhoIsOther().Name)
    door.WriteKey('was_picked_' + who.Name, '1', 1)
  else:
    who.Write('You fail to pick the lock.')
    door.WriteKey('attempts_' + who.Name, str(get_attempts(door, who) + 1), 1)

event = Crossfire.WhatIsEvent()
if event.Subtype == Crossfire.EventType.APPLY:
  handle_key()
elif event.Subtype == Crossfire.EventType.TRIGGER:
  handle_lockpick()