Crossfire Server, Trunk
dialog_check.py
Go to the documentation of this file.
1 # -*- coding: utf-8 -*-
2 # dialog_check.py
3 # This script is *not* intended to be used by the crossfire plugin, it is
4 # designed to verify the correctness of a dialog script -independantly of the crossfire server.
5 # Typically you will want to run this script against a single file, the one that you specify in
6 # the event_say, but if you want to check all of the .msg files in the map distribution, then
7 # you can run something like:
8 # for i in $(grep -h name.*msg ../../ -r | cut -d " " -f 2 | sort | uniq); do echo $i && python dialog_check.py "../../"$i; done
9 # from maps/python/dialog
10 
11 import cjson
12 import sys
13 import os
14 import re
15 
16 # There is an upper limit on the maximum message length the server can cope with, exceeding it throws out a warning.
17 MAX_MSG_LENGTH = 2048
18 
19 def checkactionfile(filename, condition):
20  args = condition[1:]
21  checkstatus = 0
22  if not os.path.isfile(filename):
23  print("Error: No script to support action: ", condition[0], "Expected: ", filename)
24  return False
25  else:
26  actf = open(filename,"r")
27  argnum = 0
28  for actline in actf.readlines():
29  if checkstatus == 0:
30  if actline.find("## DIALOGCHECK") != -1:
31  checkstatus = 1
32  elif checkstatus == 1:
33  if actline.find("## ENDDIALOGCHECK") != -1:
34  checkstatus = 2
35  elif actline.find("## MINARGS") != -1:
36  num = actline.split()[2]
37  if not num.isdigit():
38  print("ERROR: Action definition for script ", filename, " MINARGS not defined")
39  return False
40  else:
41  if len(args)<int(num):
42  print("ERROR: Insufficiant options passed to script ", filename, "expected ", int(num), " recieved ", len(args))
43  return False
44  elif actline.find("## MAXARGS") != -1:
45  num = actline.split()[2]
46  if not num.isdigit():
47  print("ERROR: Action definition for script ", filename, " MAXARGS not defined")
48  return False
49  elif int(num) == 0:
50  # zero means there is no upper limit to the number of arguments
51  pass
52  else:
53  if len(args)>int(num):
54  print("ERROR: Too many options passed to script ", filename, "expected ", int(num), " recieved ", len(args))
55  return False
56  elif actline.find("##") != 1:
57  # This is a regexp for one of the arguments
58  if argnum < len(args):
59  argmatch = re.compile(actline.split()[1])
60  if not argmatch.match(args[argnum]):
61  print("ERROR: Argument ", argnum+2, "of rule: ", condition, " doesn't match regexp ", actline.split()[1])
62  return False
63  argnum+=1
64  if checkstatus != 2:
65  print("Warning: No dialogcheck block for file ", filename, " Unable to check condition ", condition)
66  return True
67  return True
68 
69 def checkdialoguefile(msgfile, location):
70 
71  rulenumber = 0
72  errors = 0
73  warnings = 0
74  extrafiles =[]
75  params = {}
76  try:
77  f = open(msgfile,"rb")
78  except:
79  print("ERROR: Can't open file, ", msgfile)
80  errors +=1
81  else:
82  try:
83  params = cjson.decode(f.read())
84  except:
85  print("ERROR: Failed to parse file, ", msgfile, "not a valid json file")
86  errors +=1
87  f.close()
88  if "location" in params:
89  if not location == '':
90  print("Warning: Location defined multiple times in included files")
91  warnings+=1
92  location = params["location"]
93  if location =='':
94  print("Warning: no location was specified")
95  warnings +=1
96  rulenumber =0
97  for jsonRule in params["rules"]:
98  rulenumber +=1
99  include = 0
100  msg=0
101  post=0
102  match=0
103  pre =0
104  for action in jsonRule:
105  if action == "pre":
106  pre+=1
107  for condition in jsonRule["pre"]:
108  action = condition[0]
109  path = os.path.join("pre/", action + ".py")
110  if not checkactionfile(path, condition):
111  print("ERROR: verification of action file ", path, " failed for rule ", rulenumber, " condition ", condition)
112  errors+=1
113 
114  elif action == "msg":
115  for line in jsonRule["msg"]:
116  if len(line) > MAX_MSG_LENGTH:
117  # We won't print out the entire line, because it's very
118  # very long, but we'll print the first 70 characters in order to help identify it
119  print("WARNING: A Dialog Line for rule", rulenumber, "is too long. (", len(line), "characters, maximum is", MAX_MSG_LENGTH, ") \nLine begins:", line[:70])
120  warnings+=1
121  msg+=1
122  elif action == "post":
123  post+=1
124  for condition in jsonRule["post"]:
125  action = condition[0]
126  path = os.path.join("post/", action + ".py")
127  if not checkactionfile(path, condition):
128  print("ERROR: verification of action file ", path, " failed for rule ", rulenumber, " condition ", condition)
129  errors +=1
130 
131  elif action == "match":
132  match+=1
133  elif action == "replies":
134  pass
135  elif action == "comment":
136  pass
137  elif action == "include":
138  include+=1
139  for condition in jsonRule["include"]:
140  if condition[0] == "/":
141  inclname = os.path.join("../..", condition[1:])
142  else:
143  inclname = os.path.join(os.path.dirname(msgfile), condition)
144  extrafiles.append(inclname)
145  else:
146  print("Warning: Ignoring unknown rule:", action)
147  warnings+=1
148  if (include == 1 and msg+post+match == 0) or (msg == 1 and post == 1 and match ==1 and pre == 1):
149  pass
150  else:
151  print("ERROR: Rule created with an invalid combination of actions, actions are: ", list(jsonRule.keys()))
152  errors +=1
153  newfiles =0
154  newrules =0
155  newwarnings=0
156  newerrors=0
157  if len(extrafiles) > 0:
158  for extrapath in extrafiles:
159  newfiles, newrules, newwarnings, newerrors = checkdialoguefile(extrapath, location)
160  print("checked ", newrules, "rules from file", extrapath, "Found ", newerrors, " errors and ", newwarnings,"warnings")
161  warnings +=newwarnings
162  rulenumber+=newrules
163  errors+=newerrors
164  extrafiles = []
165  return (1+newfiles, rulenumber, warnings, errors)
166 
167 if len(sys.argv) < 2:
168  print("usage: python dialog_check.py path/to/dialogfile.msg")
169  exit()
170 for arg in sys.argv[1:]:
171  newfiles, rulecount, newwarnings, newerrors = checkdialoguefile(arg, '')
172  print("checked ", rulecount, "rules from file", arg, "Found ", newerrors, " errors and ", newwarnings,"warnings")
dialog_check.checkactionfile
def checkactionfile(filename, condition)
Definition: dialog_check.py:19
guildoracle.list
list
Definition: guildoracle.py:87
dialog_check.checkdialoguefile
def checkdialoguefile(msgfile, location)
Definition: dialog_check.py:69
exit
Install Bug reporting Credits but rather whatever guild name you are using *With the current map and server there are three they and GreenGoblin *Whatever name you give the folder should but it will still use GUILD_TEMPLATE *You can change what guild it uses by editing the map files Modify Map or objects if you want to use the optional Python based Guild Storage hall The first three are on the main the next two are in the guild_hq and the final one is in hallofjoining Withe the Storage three objects are found on the main floor and the last two are in the basement It s not that but you will need a map editor You find the object that has the click edit and change the line script options(which currently is "GUILD_TEMPALTE") to the guild you wish to use. And make sure you use the same one for all of them or it won 't work. Here 's a quick HOWTO for using the map editor to make these changes edit the mainfloor map exit(x15, y29 - set to/Edit/This/Exit/Path in the template) back to the world map as well. If you are using the Storage Hall map(storage_hall)
make_face_from_files.int
int
Definition: make_face_from_files.py:32
CFBank.open
def open()
Definition: CFBank.py:70