entries with values with comments
This commit is contained in:
parent
6b2edf8f56
commit
8a08425e09
@ -3,10 +3,11 @@ title: "#" /(?! ).+(?<! )/ _NL // not starting or ending with a
|
|||||||
|
|
||||||
property: "-" _key ":" _values _NL
|
property: "-" _key ":" _values _NL
|
||||||
_key : /(?! ).+?(?=:)(?<! )/ // key: everything until next ":", not beginning or ending with a space
|
_key : /(?! ).+?(?=:)(?<! )/ // key: everything until next ":", not beginning or ending with a space
|
||||||
_values : [_value ("," _value)*]
|
_values : [value ("," value)*]
|
||||||
_value : quoted_value | unquoted_value
|
value : (quoted_value comment_value?) | (unquoted_value comment_value?)
|
||||||
quoted_value : /\".+?\"/ // with quotation marks, can contain commas
|
quoted_value : /\".*?\"/
|
||||||
unquoted_value : /(?![ \"])[^,\n]+(?<![ \"])/ // cannot contain commas, cannot start or end with quotation mark
|
unquoted_value : /(?![ \"]).+?(?=,|\n| \()/
|
||||||
|
comment_value : /(?<= )\(.+?\)/
|
||||||
|
|
||||||
note: /(?![\-#]).*\n/+ // Unstructured text, not starting with - or #
|
note: /(?![\-#]).*\n/+ // Unstructured text, not starting with - or #
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
start: _COMMENT _HEADER entry*
|
start: _COMMENT _HEADER entry*
|
||||||
entry: "##" name "[" _NUMBER "]" _NL property+
|
entry: "##" name "[" _NUMBER "]" _NL property+
|
||||||
property: "-" _key ":" _values _NL
|
property: "-" _key ":" _values _NL
|
||||||
_key : /(?! ).+?(?=:)(?<! )/ // key: everything until next ":", not beginning or ending with a space
|
_key : /(?! ).+?(?= *:)/ // key: everything until next ":", not beginning or ending with a space
|
||||||
_values : [_value ("," _value)*]
|
_values : [_value ("," _value)*]
|
||||||
_value : quoted_value | unquoted_value
|
_value : quoted_value | unquoted_value
|
||||||
quoted_value : /\".+?\"/ // with quotation marks, can contain commas
|
quoted_value : /\".*?\"/ // with quotation marks, can contain commas
|
||||||
unquoted_value : /(?![ \"])[^,\n]+(?<![ \"])/ // cannot contain commas, cannot start or end with quotation mark
|
unquoted_value : /(?![ \"]).+?(?= *,| *\n)/
|
||||||
|
|
||||||
name: /(?! ).+?(?= \[)/ // developer name: everything until " ["
|
|
||||||
|
name: /(?! ).+?(?= +\[)/ // developer name: everything until " ["
|
||||||
|
|
||||||
_NUMBER: /[0-9]+/
|
_NUMBER: /[0-9]+/
|
||||||
|
|
||||||
@ -15,9 +16,9 @@ CR : /\r/
|
|||||||
LF : /\n/
|
LF : /\n/
|
||||||
_NL : CR? LF
|
_NL : CR? LF
|
||||||
WS : (" "|/\t/)+
|
WS : (" "|/\t/)+
|
||||||
_EL : /^$\n/m
|
_EL : /^$\n/m // empty new line
|
||||||
_COMMENT : /^\[comment\]: #.*$\n/m // [comment]: # xxx
|
_COMMENT : /^\[comment\]: #.*$\n/m // [comment]: # xxx
|
||||||
_HEADER : /^# .+$\n/m
|
_HEADER : /^# .+$\n/m // line staring with "# "
|
||||||
|
|
||||||
%ignore WS
|
%ignore WS
|
||||||
%ignore _EL
|
%ignore _EL
|
||||||
|
@ -33,11 +33,11 @@ def get_config(key):
|
|||||||
generic_comment_string = '[comment]: # (partly autogenerated content, edit with care, read the manual before)'
|
generic_comment_string = '[comment]: # (partly autogenerated content, edit with care, read the manual before)'
|
||||||
|
|
||||||
# these fields have to be present in each entry (in this order)
|
# these fields have to be present in each entry (in this order)
|
||||||
essential_fields = ('Title', 'Home', 'State', 'Keywords', 'Code repository', 'Code language', 'Code license')
|
essential_fields = ('File', 'Title', 'Home', 'State', 'Keywords', 'Code repository', 'Code language', 'Code license')
|
||||||
|
|
||||||
# only these fields can be used currently (in this order)
|
# only these fields can be used currently (in this order)
|
||||||
valid_fields = (
|
valid_fields = (
|
||||||
'Title', 'Home', 'Media', 'Inspirations', 'State', 'Play', 'Download', 'Platform', 'Keywords', 'Code repository', 'Code language',
|
'File', 'Title', 'Home', 'Media', 'Inspirations', 'State', 'Play', 'Download', 'Platform', 'Keywords', 'Code repository', 'Code language',
|
||||||
'Code license', 'Code dependencies', 'Assets license', 'Developer', 'Note', 'Building')
|
'Code license', 'Code dependencies', 'Assets license', 'Developer', 'Note', 'Building')
|
||||||
|
|
||||||
valid_building_fields = ('Build system', 'Build instructions')
|
valid_building_fields = ('Build system', 'Build instructions')
|
||||||
@ -93,7 +93,9 @@ general_code_dependencies_without_entry = {'OpenGL': 'https://www.opengl.org/',
|
|||||||
# developer information (in the file all fields will be capitalized)
|
# developer information (in the file all fields will be capitalized)
|
||||||
essential_developer_fields = ('Name', 'Games')
|
essential_developer_fields = ('Name', 'Games')
|
||||||
valid_developer_fields = essential_developer_fields + ('Contact', 'Home', 'Organization')
|
valid_developer_fields = essential_developer_fields + ('Contact', 'Home', 'Organization')
|
||||||
|
url_developer_fields = ('Home',)
|
||||||
|
|
||||||
# inspiration/original game information (in the file all fields will be capitalized)
|
# inspiration/original game information (in the file all fields will be capitalized)
|
||||||
essential_inspiration_fields = ('Name', 'Inspired entries')
|
essential_inspiration_fields = ('Name', 'Inspired entries')
|
||||||
valid_inspiration_fields = essential_inspiration_fields + ('Media',)
|
valid_inspiration_fields = essential_inspiration_fields + ('Media',)
|
||||||
|
url_inspiration_fields = ('Media',)
|
@ -300,28 +300,32 @@ def read_developers():
|
|||||||
grammar_file = os.path.join(code_path, 'grammar_listing.lark')
|
grammar_file = os.path.join(code_path, 'grammar_listing.lark')
|
||||||
developers = osg_parse.read_and_parse(developer_file, grammar_file, osg_parse.ListingTransformer)
|
developers = osg_parse.read_and_parse(developer_file, grammar_file, osg_parse.ListingTransformer)
|
||||||
|
|
||||||
# now transform a bit more
|
# now developers is a list of dictionaries for every entry with some properties
|
||||||
for index, dev in enumerate(developers):
|
|
||||||
# check for valid keys
|
|
||||||
for field in dev.keys():
|
|
||||||
if field not in valid_developer_fields:
|
|
||||||
raise RuntimeError('Unknown developer field "{}" for developer: {}.'.format(field, dev['Name']))
|
|
||||||
# strip from name or organization (just in case)
|
|
||||||
for field in ('Name', ):
|
|
||||||
if field in dev:
|
|
||||||
dev[field] = dev[field].strip()
|
|
||||||
# split games, contact (are lists)
|
|
||||||
for field in ('Games', 'Contact'):
|
|
||||||
if field in dev:
|
|
||||||
content = dev[field]
|
|
||||||
content = [x.strip() for x in content]
|
|
||||||
dev[field] = content
|
|
||||||
# check for duplicate names entries
|
# check for duplicate names entries
|
||||||
names = [dev['Name'] for dev in developers]
|
names = [dev['Name'] for dev in developers]
|
||||||
duplicate_names = (name for name in names if names.count(name) > 1)
|
duplicate_names = (name for name in names if names.count(name) > 1)
|
||||||
duplicate_names = set(duplicate_names) # to avoid duplicates in duplicate_names
|
duplicate_names = set(duplicate_names) # to avoid duplicates in duplicate_names
|
||||||
if duplicate_names:
|
if duplicate_names:
|
||||||
print('Warning: duplicate developer names: {}'.format(', '.join(duplicate_names)))
|
print('Warning: duplicate developer names: {}'.format(', '.join(duplicate_names)))
|
||||||
|
|
||||||
|
# check for essential, valid fields
|
||||||
|
for dev in developers:
|
||||||
|
# check that essential fields are existing
|
||||||
|
for field in essential_developer_fields:
|
||||||
|
if field not in dev:
|
||||||
|
raise RuntimeError('Essential field "{}" missing in developer {}'.format(field, dev['Name']))
|
||||||
|
# check that all fields are valid fields
|
||||||
|
for field in dev.keys():
|
||||||
|
if field not in valid_developer_fields:
|
||||||
|
raise RuntimeError('Invalid field "{}" in developer {}.'.format(field, dev['Name']))
|
||||||
|
# url fields
|
||||||
|
for field in url_developer_fields:
|
||||||
|
if field in dev:
|
||||||
|
content = dev[field]
|
||||||
|
if any(not (x.startswith('http://') or x.startswith('https://')) for x in content):
|
||||||
|
raise RuntimeError('Invalid URL in field "{}" in developer {}.'.format(field, dev['Name']))
|
||||||
|
|
||||||
return developers
|
return developers
|
||||||
|
|
||||||
|
|
||||||
@ -343,7 +347,7 @@ def write_developers(developers):
|
|||||||
for dev in developers:
|
for dev in developers:
|
||||||
keys = list(dev.keys())
|
keys = list(dev.keys())
|
||||||
# developer name
|
# developer name
|
||||||
content += '## {} [{}]\n\n'.format(dev['Name'], len(dev['games']))
|
content += '## {} [{}]\n\n'.format(dev['Name'], len(dev['Games']))
|
||||||
keys.remove('Name')
|
keys.remove('Name')
|
||||||
|
|
||||||
# all the remaining in alphabetical order, but 'games' first
|
# all the remaining in alphabetical order, but 'games' first
|
||||||
@ -352,7 +356,6 @@ def write_developers(developers):
|
|||||||
keys = ['Games'] + keys
|
keys = ['Games'] + keys
|
||||||
for field in keys:
|
for field in keys:
|
||||||
value = dev[field]
|
value = dev[field]
|
||||||
field = field.capitalize()
|
|
||||||
# lists get special treatment
|
# lists get special treatment
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
value.sort(key=str.casefold)
|
value.sort(key=str.casefold)
|
||||||
@ -377,20 +380,7 @@ def read_inspirations():
|
|||||||
grammar_file = os.path.join(code_path, 'grammar_listing.lark')
|
grammar_file = os.path.join(code_path, 'grammar_listing.lark')
|
||||||
inspirations = osg_parse.read_and_parse(inspirations_file, grammar_file, osg_parse.ListingTransformer)
|
inspirations = osg_parse.read_and_parse(inspirations_file, grammar_file, osg_parse.ListingTransformer)
|
||||||
|
|
||||||
# now inspirations is a list of dictionaries for every entry with keys (valid_developers_fields)
|
# now inspirations is a list of dictionaries for every entry with some properties
|
||||||
|
|
||||||
# now transform a bit more
|
|
||||||
for inspiration in inspirations:
|
|
||||||
# check that keys are valid keys
|
|
||||||
for field in inspiration.keys():
|
|
||||||
if field not in valid_inspiration_fields:
|
|
||||||
raise RuntimeError('Unknown field "{}" for inspiration: {}.'.format(field, inspiration['Name']))
|
|
||||||
# split lists
|
|
||||||
for field in ('Inspired entries',):
|
|
||||||
if field in inspiration:
|
|
||||||
content = inspiration[field]
|
|
||||||
content = [x.strip() for x in content]
|
|
||||||
inspiration[field] = content
|
|
||||||
|
|
||||||
# check for duplicate names entries
|
# check for duplicate names entries
|
||||||
names = [inspiration['Name'] for inspiration in inspirations]
|
names = [inspiration['Name'] for inspiration in inspirations]
|
||||||
@ -399,6 +389,23 @@ def read_inspirations():
|
|||||||
if duplicate_names:
|
if duplicate_names:
|
||||||
raise RuntimeError('Duplicate inspiration names: {}'.format(', '.join(duplicate_names)))
|
raise RuntimeError('Duplicate inspiration names: {}'.format(', '.join(duplicate_names)))
|
||||||
|
|
||||||
|
# check for essential, valid fields
|
||||||
|
for inspiration in inspirations:
|
||||||
|
# check that essential fields are existing
|
||||||
|
for field in essential_inspiration_fields:
|
||||||
|
if field not in inspiration:
|
||||||
|
raise RuntimeError('Essential field "{}" missing in inspiration {}'.format(field, inspiration['Name']))
|
||||||
|
# check that all fields are valid fields
|
||||||
|
for field in inspiration.keys():
|
||||||
|
if field not in valid_inspiration_fields:
|
||||||
|
raise RuntimeError('Invalid field "{}" in inspiration {}.'.format(field, inspiration['Name']))
|
||||||
|
# url fields
|
||||||
|
for field in url_inspiration_fields:
|
||||||
|
if field in inspiration:
|
||||||
|
content = inspiration[field]
|
||||||
|
if any(not (x.startswith('http://') or x.startswith('https://')) for x in content):
|
||||||
|
raise RuntimeError('Invalid URL in field "{}" in inspiration {}.'.format(field, inspiration['Name']))
|
||||||
|
|
||||||
# convert to dictionary
|
# convert to dictionary
|
||||||
inspirations = {x['Name']: x for x in inspirations}
|
inspirations = {x['Name']: x for x in inspirations}
|
||||||
|
|
||||||
@ -417,7 +424,7 @@ def write_inspirations(inspirations):
|
|||||||
# comment
|
# comment
|
||||||
content = '{}\n'.format(generic_comment_string)
|
content = '{}\n'.format(generic_comment_string)
|
||||||
|
|
||||||
# number of developer
|
# updated number of inspirations
|
||||||
content += '# Inspirations [{}]\n\n'.format(len(inspirations))
|
content += '# Inspirations [{}]\n\n'.format(len(inspirations))
|
||||||
|
|
||||||
# sort by name
|
# sort by name
|
||||||
@ -436,7 +443,6 @@ def write_inspirations(inspirations):
|
|||||||
keys = ['Inspired entries'] + keys
|
keys = ['Inspired entries'] + keys
|
||||||
for field in keys:
|
for field in keys:
|
||||||
value = inspiration[field]
|
value = inspiration[field]
|
||||||
field = field.capitalize()
|
|
||||||
# lists get special treatment
|
# lists get special treatment
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
value.sort(key=str.casefold) # sorted alphabetically
|
value.sort(key=str.casefold) # sorted alphabetically
|
||||||
@ -472,15 +478,12 @@ def read_entries():
|
|||||||
# parse and transform entry content
|
# parse and transform entry content
|
||||||
try:
|
try:
|
||||||
entry = parse(content)
|
entry = parse(content)
|
||||||
# add file information
|
entry = [('File', file),] + entry # add file information to the beginning
|
||||||
entry['File'] = file
|
entry = check_and_process_entry(entry)
|
||||||
|
|
||||||
check_entry(entry)
|
|
||||||
|
|
||||||
post_process(entry)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print('{} - {}'.format(file, e))
|
print('{} - {}'.format(file, e))
|
||||||
exception_happened = True
|
exception_happened = True
|
||||||
|
# raise RuntimeError(e)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# add to list
|
# add to list
|
||||||
@ -490,47 +493,44 @@ def read_entries():
|
|||||||
|
|
||||||
return entries
|
return entries
|
||||||
|
|
||||||
def post_process(entry):
|
|
||||||
"""
|
|
||||||
|
|
||||||
:param entry:
|
def check_and_process_entry(entry):
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# remove all parentheses from developers
|
|
||||||
if 'Developer' in entry:
|
|
||||||
devs = entry['Developer']
|
|
||||||
devs = [re.sub(r'\([^)]*\)', '', x).strip() for x in devs]
|
|
||||||
if any(not x for x in devs):
|
|
||||||
raise RuntimeError('Empty developer')
|
|
||||||
entry['Developer'] = devs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_entry(entry):
|
|
||||||
"""
|
|
||||||
|
|
||||||
:param entry:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
message = ''
|
message = ''
|
||||||
|
|
||||||
file = entry['File']
|
# check that all fields are valid fields and are existing in that order
|
||||||
|
index = 0
|
||||||
|
for e in entry:
|
||||||
|
field = e[0]
|
||||||
|
while index < len(valid_fields) and field != valid_fields[index]:
|
||||||
|
index += 1
|
||||||
|
if index == len(valid_fields): # must be valid fields and must be in the right order
|
||||||
|
message += 'Field "{}" either misspelled or in wrong order\n'.format(field)
|
||||||
|
|
||||||
# check canonical file name
|
# order is fine we can convert to dictionary
|
||||||
canonical_file_name = canonical_entry_name(entry['Title']) + '.md'
|
d = {}
|
||||||
# we also allow -X with X =2..9 as possible extension (because of duplicate canonical file names)
|
for field, value in entry:
|
||||||
if canonical_file_name != file and canonical_file_name != file[:-5] + '.md':
|
if field in d:
|
||||||
message += 'file name should be {}\n'.format(canonical_file_name)
|
message += 'Field "{}" appears twice\n'.format(field)
|
||||||
|
d[field] = value
|
||||||
|
entry = d
|
||||||
|
|
||||||
# check for essential fields
|
# check for essential fields
|
||||||
for field in essential_fields:
|
for field in essential_fields:
|
||||||
if field not in entry:
|
if field not in entry:
|
||||||
message += 'essential property "{}" missing\n'.format(field)
|
message += 'essential property "{}" missing\n'.format(field)
|
||||||
|
|
||||||
|
# check canonical file name
|
||||||
|
file = entry['File']
|
||||||
|
canonical_file_name = canonical_entry_name(entry['Title']) + '.md'
|
||||||
|
# we also allow -X with X =2..9 as possible extension (because of duplicate canonical file names)
|
||||||
|
if canonical_file_name != file and canonical_file_name != file[:-5] + '.md':
|
||||||
|
message += 'file name should be {}\n'.format(canonical_file_name)
|
||||||
|
|
||||||
if message:
|
if message:
|
||||||
raise RuntimeError(message)
|
raise RuntimeError(message)
|
||||||
|
|
||||||
|
return entry
|
||||||
|
|
||||||
|
|
||||||
def write_entries(entries):
|
def write_entries(entries):
|
||||||
"""
|
"""
|
||||||
|
@ -17,7 +17,7 @@ class ListingTransformer(lark.Transformer):
|
|||||||
return x[0].value
|
return x[0].value
|
||||||
|
|
||||||
def quoted_value(self, x):
|
def quoted_value(self, x):
|
||||||
return x[0].value[1:-1] # remove quotation marks
|
return x[0].value[1:-1].strip() # remove quotation marks and strip whitespaces
|
||||||
|
|
||||||
def property(self, x):
|
def property(self, x):
|
||||||
"""
|
"""
|
||||||
@ -61,13 +61,23 @@ class EntryTransformer(lark.Transformer):
|
|||||||
def quoted_value(self, x):
|
def quoted_value(self, x):
|
||||||
return x[0].value[1:-1] # remove quotation marks
|
return x[0].value[1:-1] # remove quotation marks
|
||||||
|
|
||||||
|
def comment_value(self, x):
|
||||||
|
return x[0].value[1:-1] # remove parenthesis
|
||||||
|
|
||||||
|
def value(self, x):
|
||||||
|
if len(x) == 1:
|
||||||
|
v = ValueWithComment(value=x[0])
|
||||||
|
else:
|
||||||
|
v = ValueWithComment(value=x[0], comment=x[1])
|
||||||
|
return v
|
||||||
|
|
||||||
def property(self, x):
|
def property(self, x):
|
||||||
"""
|
"""
|
||||||
The key of a property will be converted to lower case and the value part is the second part
|
The key of a property will be converted to lower case and the value part is the second part
|
||||||
:param x:
|
:param x:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return x[0], x[1:]
|
return x[0].value, x[1:]
|
||||||
|
|
||||||
def title(self, x):
|
def title(self, x):
|
||||||
return 'Title', x[0].value
|
return 'Title', x[0].value
|
||||||
@ -83,33 +93,33 @@ class EntryTransformer(lark.Transformer):
|
|||||||
return 'Note', ''.join((x.value for x in x))
|
return 'Note', ''.join((x.value for x in x))
|
||||||
|
|
||||||
def building(self, x):
|
def building(self, x):
|
||||||
d = {}
|
return 'Building', x
|
||||||
for key, value in x:
|
|
||||||
if key in d:
|
|
||||||
raise RuntimeError('Key in entry appears twice')
|
|
||||||
d[key] = value
|
|
||||||
return 'Building', d
|
|
||||||
|
|
||||||
def start(self, x):
|
def start(self, x):
|
||||||
# we do the essential fields and valid fields checks right here
|
return x
|
||||||
fields = [x[0] for x in x]
|
|
||||||
# check for essential fields
|
|
||||||
for field in c.essential_fields:
|
class ValueWithComment:
|
||||||
if field not in fields:
|
"""
|
||||||
raise RuntimeError('Essential field "{}" is missing'.format(field))
|
All our property values can have (optional) comments. This is the class that represents them to us and implements
|
||||||
# check for valid fields (in that order)
|
equality and 'in' operator functionality purely on the value.
|
||||||
index = 0
|
"""
|
||||||
for field in fields:
|
|
||||||
while index < len(c.valid_fields) and field != c.valid_fields[index]:
|
def __init__(self, value, comment=None):
|
||||||
index += 1
|
self.value = value
|
||||||
if index == len(c.valid_fields):
|
self.comment = comment
|
||||||
raise RuntimeError('Field "{}" either not valid or in wrong order'.format(field))
|
|
||||||
d = {}
|
def __contains__(self, item):
|
||||||
for key, value in x:
|
return item in self.value
|
||||||
if key in d:
|
|
||||||
raise RuntimeError('Key in entry appears twice')
|
def __eq__(self, other):
|
||||||
d[key] = value
|
return self.value == other
|
||||||
return d
|
|
||||||
|
def __repr__(self):
|
||||||
|
if self.comment:
|
||||||
|
return '{} ({})'.format(self.value, self.comment)
|
||||||
|
else:
|
||||||
|
return '{}'.format(self.value)
|
||||||
|
|
||||||
|
|
||||||
def parse(parser, transformer, content):
|
def parse(parser, transformer, content):
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
## Alex Margarit [1]
|
## Alex Margarit [1]
|
||||||
|
|
||||||
- Games: faur
|
- Games: Faur
|
||||||
|
|
||||||
## Alexander Lang [1]
|
## Alexander Lang [1]
|
||||||
|
|
||||||
@ -590,7 +590,7 @@
|
|||||||
|
|
||||||
- Games: Hack
|
- Games: Hack
|
||||||
|
|
||||||
## Jean-Baptiste Lamy / Nekeme Prod. [1]
|
## Jean-Baptiste "Jiba" Lamy [1]
|
||||||
|
|
||||||
- Games: Slune
|
- Games: Slune
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
- Inspirations: Ballerburg
|
- Inspirations: Ballerburg
|
||||||
- State: mature
|
- State: mature
|
||||||
- Keywords: action, artillery, remake
|
- Keywords: action, artillery, remake
|
||||||
- Code repository: https://git.tuxfamily.org/baller/baller.git, https://gitlab.com/osgames/ballerburg.git (+) (import of original source downloads)
|
- Code repository: https://git.tuxfamily.org/baller/baller.git, https://gitlab.com/osgames/ballerburg.git (@add, import of original source downloads)
|
||||||
- Code language: C
|
- Code language: C
|
||||||
- Code license: GPL-3.0
|
- Code license: GPL-3.0
|
||||||
- Code dependencies: SDL2
|
- Code dependencies: SDL2
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
- Code language: Python
|
- Code language: Python
|
||||||
- Code license: GPL-2.0
|
- Code license: GPL-2.0
|
||||||
- Code dependencies: pyglet
|
- Code dependencies: pyglet
|
||||||
- Assets license: CC (caprica-letters and all the music in the latest version
|
- Assets license: CC (caprica-letters and all the music in the latest version)
|
||||||
|
|
||||||
Dual n-back brain training exercise.
|
Dual n-back brain training exercise.
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
- State: mature, inactive since 2014
|
- State: mature, inactive since 2014
|
||||||
- Download: https://sourceforge.net/projects/e-adventure/files/
|
- Download: https://sourceforge.net/projects/e-adventure/files/
|
||||||
- Keywords: adventure, game engine
|
- Keywords: adventure, game engine
|
||||||
- Code repository: https://github.com/e-ucm/eAdventure-legacy.git, https://github.com/e-ucm/eAdventure.git (+), https://github.com/e-ucm/uAdventure.git (+), https://gitlab.com/osgames/e-adventure.git (+) (conversion of svn), https://svn.code.sf.net/p/e-adventure/code (svn)
|
- Code repository: https://github.com/e-ucm/eAdventure-legacy.git, https://github.com/e-ucm/eAdventure.git (+), https://github.com/e-ucm/uAdventure.git (+), https://gitlab.com/osgames/e-adventure.git (@add, conversion of svn), https://svn.code.sf.net/p/e-adventure/code (svn)
|
||||||
- Code language: Java
|
- Code language: Java
|
||||||
- Code license: GPL-3.0
|
- Code license: GPL-3.0
|
||||||
|
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
# Inexor
|
# Inexor
|
||||||
|
|
||||||
- Home: https://inexor.org/
|
- Home: https://inexor.org/
|
||||||
- Media: <https://en.wikipedia.org/wiki/Ace_of_Spades_(video_game)>
|
|
||||||
- Inspirations: Cube 2: Sauerbraten
|
- Inspirations: Cube 2: Sauerbraten
|
||||||
- State: beta, inactive since 2018
|
- State: beta, inactive since 2018
|
||||||
- Keywords: remake
|
- Keywords: remake, first person, shooter
|
||||||
- Code repository: https://github.com/inexorgame/vulkan-renderer.git, https://github.com/inexorgame/inexor-core.git (+) (archived)
|
- Code repository: https://github.com/inexorgame/vulkan-renderer.git, https://github.com/inexorgame/inexor-core.git (@add, @archived)
|
||||||
- Code language: C++, JavaScript
|
- Code language: C++, JavaScript
|
||||||
- Code license: zlib
|
- Code license: zlib
|
||||||
- Code dependencies: Cube 2
|
- Code dependencies: Cube 2
|
||||||
|
|
||||||
Remake of Cube 2: Sauerbraten.
|
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
- Code repository: https://github.com/miki151/keeperrl.git
|
- Code repository: https://github.com/miki151/keeperrl.git
|
||||||
- Code language: C, C++
|
- Code language: C, C++
|
||||||
- Code license: GPL-2.0
|
- Code license: GPL-2.0
|
||||||
- Assets license: Proprietary (partly), CC-BY (partly) (see https://github.com/miki151/keeperrl/blob/master/COPYING-MEDIA.txt)
|
- Assets license: Proprietary (@partly), CC-BY (@partly, see https://github.com/miki151/keeperrl/blob/master/COPYING-MEDIA.txt)
|
||||||
|
|
||||||
Bungeon builder.
|
Bungeon builder.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
- Code repository: https://github.com/lexica/lexica.git
|
- Code repository: https://github.com/lexica/lexica.git
|
||||||
- Code language: Java
|
- Code language: Java
|
||||||
- Code license: GPL-3.0
|
- Code license: GPL-3.0
|
||||||
- Assets license: Apache-2.0 (word lists), CC-BY-4.0 (icons) (see https://github.com/lexica/lexica/blob/master/LICENSES)
|
- Assets license: Apache-2.0 (word lists), CC-BY-4.0 (icons, see https://github.com/lexica/lexica/blob/master/LICENSES)
|
||||||
|
|
||||||
Find as many words as possible on a grid of random letters.
|
Find as many words as possible on a grid of random letters.
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
- State: beta, inactive since 2005
|
- State: beta, inactive since 2005
|
||||||
- Download: https://sourceforge.net/projects/microracers/files/microracers/
|
- Download: https://sourceforge.net/projects/microracers/files/microracers/
|
||||||
- Keywords: remake, 2D, racing
|
- Keywords: remake, 2D, racing
|
||||||
- Code repository: https://github.com/rpmcruz/microracers.git, https://gitlab.com/osgames/microracers.git (+) (conversion of cvs), http://microracers.cvs.sourceforge.net (cvs)
|
- Code repository: https://github.com/rpmcruz/microracers.git, https://gitlab.com/osgames/microracers.git (@add, conversion of cvs), http://microracers.cvs.sourceforge.net (cvs)
|
||||||
- Code language: C, C++
|
- Code language: C, C++
|
||||||
- Code license: GPL-2.0
|
- Code license: GPL-2.0
|
||||||
- Developer: Ricardo Cruz
|
- Developer: Ricardo Cruz
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
- State: mature
|
- State: mature
|
||||||
- Download: http://rpg.hamsterrepublic.com/ohrrpgce/Downloads
|
- Download: http://rpg.hamsterrepublic.com/ohrrpgce/Downloads
|
||||||
- Keywords: framework
|
- Keywords: framework
|
||||||
- Code repository: https://bitbucket.org/rbv/ohrrpgce-svn.git (mirror), https://github.com/ohrrpgce/ohrrpgce.git (+) (mirror), https://rpg.hamsterrepublic.com/source/wip (+) (svn)
|
- Code repository: https://bitbucket.org/rbv/ohrrpgce-svn.git (@mirror), https://github.com/ohrrpgce/ohrrpgce.git (@add, @mirror), https://rpg.hamsterrepublic.com/source/wip (@add, svn)
|
||||||
- Code language: Basic
|
- Code language: Basic
|
||||||
- Code license: GPL-2.0
|
- Code license: GPL-2.0
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
- Download: https://sourceforge.net/projects/osgg/files/
|
- Download: https://sourceforge.net/projects/osgg/files/
|
||||||
- Platform: Windows, Linux
|
- Platform: Windows, Linux
|
||||||
- Keywords: arcade, open content, side-scrolling
|
- Keywords: arcade, open content, side-scrolling
|
||||||
- Code repository: https://github.com/DusteDdk/osgg.git, https://gitlab.com/osgames/osgg.git (+) (conversion of svn), https://svn.code.sf.net/p/osgg/code (svn)
|
- Code repository: https://github.com/DusteDdk/osgg.git, https://gitlab.com/osgames/osgg.git (@add, conversion of svn), https://svn.code.sf.net/p/osgg/code (svn)
|
||||||
- Code language: C++
|
- Code language: C++
|
||||||
- Code license: GPL-3.0
|
- Code license: GPL-3.0
|
||||||
- Code dependencies: OpenGL, SDL
|
- Code dependencies: OpenGL, SDL
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
- Code language: Python
|
- Code language: Python
|
||||||
- Code license: GPL-2.0
|
- Code license: GPL-2.0
|
||||||
- Code dependencies: Cal3D, GLEW, OpenGL, Py2Play, SDL
|
- Code dependencies: Cal3D, GLEW, OpenGL, Py2Play, SDL
|
||||||
- Developer: Jean-Baptiste Lamy (Jiba) / Nekeme Prod.
|
- Developer: Jean-Baptiste "Jiba" Lamy (Nekeme Prod.)
|
||||||
|
|
||||||
Action game.
|
Action game.
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
## Abuse [1]
|
## Abuse [1]
|
||||||
|
|
||||||
- Inspired entries: Abuse
|
- Inspired entries: Abuse
|
||||||
- Media: <https://en.wikipedia.org/wiki/Abuse_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Abuse_(video_game)
|
||||||
|
|
||||||
## Ace Combat: Assault Horizon [1]
|
## Ace Combat: Assault Horizon [1]
|
||||||
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
## Ace of Spades [3]
|
## Ace of Spades [3]
|
||||||
|
|
||||||
- Inspired entries: BetterSpades, Iceball, OpenSpades
|
- Inspired entries: BetterSpades, Iceball, OpenSpades
|
||||||
- Media: <https://en.wikipedia.org/wiki/Ace_of_Spades_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Ace_of_Spades_(video_game)
|
||||||
|
|
||||||
## Achtung, die Kurve! [4]
|
## Achtung, die Kurve! [4]
|
||||||
|
|
||||||
@ -37,7 +37,7 @@
|
|||||||
## Age of Empires [2]
|
## Age of Empires [2]
|
||||||
|
|
||||||
- Inspired entries: 0 A.D., openage
|
- Inspired entries: 0 A.D., openage
|
||||||
- Media: <https://en.wikipedia.org/wiki/Age_of_Empires_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Age_of_Empires_(video_game)
|
||||||
|
|
||||||
## Age of Empires II [2]
|
## Age of Empires II [2]
|
||||||
|
|
||||||
@ -56,7 +56,7 @@
|
|||||||
## Allegiance [1]
|
## Allegiance [1]
|
||||||
|
|
||||||
- Inspired entries: Free Allegiance
|
- Inspired entries: Free Allegiance
|
||||||
- Media: <https://en.wikipedia.org/wiki/Allegiance_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Allegiance_(video_game)
|
||||||
|
|
||||||
## Anno (series) [1]
|
## Anno (series) [1]
|
||||||
|
|
||||||
@ -297,7 +297,7 @@
|
|||||||
## Cadaver [1]
|
## Cadaver [1]
|
||||||
|
|
||||||
- Inspired entries: Cadaver
|
- Inspired entries: Cadaver
|
||||||
- Media: <https://en.wikipedia.org/wiki/Cadaver_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Cadaver_(video_game)
|
||||||
|
|
||||||
## Caesar 3 [2]
|
## Caesar 3 [2]
|
||||||
|
|
||||||
@ -462,6 +462,7 @@
|
|||||||
## Cube 2: Sauerbraten [2]
|
## Cube 2: Sauerbraten [2]
|
||||||
|
|
||||||
- Inspired entries: Inexor, Open Cube
|
- Inspired entries: Inexor, Open Cube
|
||||||
|
- Media: https://en.wikipedia.org/wiki/Cube_2:_Sauerbraten
|
||||||
|
|
||||||
## CUBE engine [1]
|
## CUBE engine [1]
|
||||||
|
|
||||||
@ -614,7 +615,7 @@
|
|||||||
## E.T. the Extra-Terrestrial [1]
|
## E.T. the Extra-Terrestrial [1]
|
||||||
|
|
||||||
- Inspired entries: javascript-E.T.
|
- Inspired entries: javascript-E.T.
|
||||||
- Media: <https://en.wikipedia.org/wiki/E.T._the_Extra-Terrestrial_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/E.T._the_Extra-Terrestrial_(video_game)
|
||||||
|
|
||||||
## Eat The Whistle [1]
|
## Eat The Whistle [1]
|
||||||
|
|
||||||
@ -737,7 +738,7 @@
|
|||||||
## Freelancer [1]
|
## Freelancer [1]
|
||||||
|
|
||||||
- Inspired entries: Librelancer
|
- Inspired entries: Librelancer
|
||||||
- Media: <https://en.wikipedia.org/wiki/Freelancer_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Freelancer_(video_game)
|
||||||
|
|
||||||
## Freeserf [1]
|
## Freeserf [1]
|
||||||
|
|
||||||
@ -778,7 +779,7 @@
|
|||||||
## GoldenEye 007 [2]
|
## GoldenEye 007 [2]
|
||||||
|
|
||||||
- Inspired entries: ges-code, GoldenEye: Source
|
- Inspired entries: ges-code, GoldenEye: Source
|
||||||
- Media: <https://en.wikipedia.org/wiki/GoldenEye_007_(1997_video_game)>
|
- Media: https://en.wikipedia.org/wiki/GoldenEye_007_(1997_video_game)
|
||||||
|
|
||||||
## Gorillas [2]
|
## Gorillas [2]
|
||||||
|
|
||||||
@ -944,7 +945,7 @@
|
|||||||
## Krush Kill 'n' Destroy [1]
|
## Krush Kill 'n' Destroy [1]
|
||||||
|
|
||||||
- Inspired entries: KKnD
|
- Inspired entries: KKnD
|
||||||
- Media: <https://en.wikipedia.org/wiki/KKnD_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/KKnD_(video_game)
|
||||||
|
|
||||||
## Kula World [1]
|
## Kula World [1]
|
||||||
|
|
||||||
@ -981,7 +982,7 @@
|
|||||||
## Lemmings [5]
|
## Lemmings [5]
|
||||||
|
|
||||||
- Inspired entries: Lemmings.ts, Lemmini, Lix, Pingus, Rabbit Escape
|
- Inspired entries: Lemmings.ts, Lemmini, Lix, Pingus, Rabbit Escape
|
||||||
- Media: <https://en.wikipedia.org/wiki/Lemmings_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Lemmings_(video_game)
|
||||||
|
|
||||||
## Liero [4]
|
## Liero [4]
|
||||||
|
|
||||||
@ -1056,7 +1057,7 @@
|
|||||||
## Marathon [1]
|
## Marathon [1]
|
||||||
|
|
||||||
- Inspired entries: Aleph One
|
- Inspired entries: Aleph One
|
||||||
- Media: <https://marathongame.fandom.com/wiki/Marathon_(Game)>
|
- Media: https://marathongame.fandom.com/wiki/Marathon_(Game)
|
||||||
|
|
||||||
## Marathon 2 [1]
|
## Marathon 2 [1]
|
||||||
|
|
||||||
@ -1507,7 +1508,7 @@
|
|||||||
## Seven Kingdoms: Ancient Adversaries [1]
|
## Seven Kingdoms: Ancient Adversaries [1]
|
||||||
|
|
||||||
- Inspired entries: Seven Kingdoms: Ancient Adversaries
|
- Inspired entries: Seven Kingdoms: Ancient Adversaries
|
||||||
- Media: <https://en.wikipedia.org/wiki/Seven_Kingdoms_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Seven_Kingdoms_(video_game)
|
||||||
|
|
||||||
## sfxr [1]
|
## sfxr [1]
|
||||||
|
|
||||||
@ -1528,17 +1529,17 @@
|
|||||||
## Ship Simulator 2006 [1]
|
## Ship Simulator 2006 [1]
|
||||||
|
|
||||||
- Inspired entries: Bridge Command
|
- Inspired entries: Bridge Command
|
||||||
- Media: <https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)
|
||||||
|
|
||||||
## Ship Simulator 2008 [1]
|
## Ship Simulator 2008 [1]
|
||||||
|
|
||||||
- Inspired entries: Bridge Command
|
- Inspired entries: Bridge Command
|
||||||
- Media: <https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)
|
||||||
|
|
||||||
## Ship Simulator Extremes [1]
|
## Ship Simulator Extremes [1]
|
||||||
|
|
||||||
- Inspired entries: Bridge Command
|
- Inspired entries: Bridge Command
|
||||||
- Media: <https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Ship_Simulator_(video_game)
|
||||||
|
|
||||||
## Shobon Action [1]
|
## Shobon Action [1]
|
||||||
|
|
||||||
@ -1571,7 +1572,7 @@
|
|||||||
## SimCity [9]
|
## SimCity [9]
|
||||||
|
|
||||||
- Inspired entries: 3d.city, Citybound, Cytopia, Divercity, Lincity, LinCity-NG, Micropolis, micropolisJS, OpenCity
|
- Inspired entries: 3d.city, Citybound, Cytopia, Divercity, Lincity, LinCity-NG, Micropolis, micropolisJS, OpenCity
|
||||||
- Media: <https://en.wikipedia.org/wiki/SimCity_(1989_video_game)>
|
- Media: https://en.wikipedia.org/wiki/SimCity_(1989_video_game)
|
||||||
|
|
||||||
## SimCity 2000 [1]
|
## SimCity 2000 [1]
|
||||||
|
|
||||||
@ -1783,7 +1784,7 @@
|
|||||||
## Super Monkey Ball [4]
|
## Super Monkey Ball [4]
|
||||||
|
|
||||||
- Inspired entries: irrlamb, Neverball, Nuncabola, Veraball
|
- Inspired entries: irrlamb, Neverball, Nuncabola, Veraball
|
||||||
- Media: <https://en.wikipedia.org/wiki/Super_Monkey_Ball_(video_game)>
|
- Media: https://en.wikipedia.org/wiki/Super_Monkey_Ball_(video_game)
|
||||||
|
|
||||||
## Super Smash Bros. [3]
|
## Super Smash Bros. [3]
|
||||||
|
|
||||||
@ -2010,7 +2011,7 @@
|
|||||||
## Turmoil [1]
|
## Turmoil [1]
|
||||||
|
|
||||||
- Inspired entries: Data Storm
|
- Inspired entries: Data Storm
|
||||||
- Media: <https://en.wikipedia.org/wiki/Turmoil_(1984_video_game)>
|
- Media: https://en.wikipedia.org/wiki/Turmoil_(1984_video_game)
|
||||||
|
|
||||||
## Turok [1]
|
## Turok [1]
|
||||||
|
|
||||||
@ -2146,7 +2147,7 @@
|
|||||||
## Warlords II [2]
|
## Warlords II [2]
|
||||||
|
|
||||||
- Inspired entries: FreeLords, LordsAWar!
|
- Inspired entries: FreeLords, LordsAWar!
|
||||||
- Media: <https://en.wikipedia.org/wiki/Warlords_(game_series)>
|
- Media: https://en.wikipedia.org/wiki/Warlords_(game_series)
|
||||||
|
|
||||||
## Warrior Kings [1]
|
## Warrior Kings [1]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user