done in last month:

* crafting fixture update
 * efefays logic implementation
done today:
 * added game.log log basics for the parser.
 * updated utf-8 headers.
This commit is contained in:
Gabor Körber 2014-08-04 19:55:42 +02:00
parent e9e6adc823
commit 36c8914181
23 changed files with 1205 additions and 59 deletions

57
analyze.py Normal file
View File

@ -0,0 +1,57 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Tool to analyze Logs in general.
"""
import os, sys, logging
from logs.logfiles import LogFileResolver as LogFile
from logs import combat, game, chat
from logs.session import LogSessionCollector
from logs.game import ClientInfo
# for windows its kinda this:
settings = {'root_path': os.path.join(os.path.expanduser('~'),
'Documents',
'My Games',
'StarConflict',),
'logfiles': os.path.join(os.path.expanduser('~'),
'Documents',
'My Games',
'StarConflict',
'logs'
)}
if __name__ == '__main__':
coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
'Documents', 'My Games', 'sc'))
coll.collect_unique()
#f = open('output.txt', 'w')
rex = {}
for logf in coll.sessions:
logf.parse_files(['game.log',])
print "Combat Log %s" % logf.idstr
if logf.combat_log:
for l in logf.combat_log.lines:
if isinstance(l, dict):
#print l
pass
else:
if not l.unpack():
rex[l.__class__.__name__] = rex.get(l.__class__.__name__, 0) + 1
if not isinstance(l, combat.UserEvent):
print l.values['log']
if logf.game_log:
for l in logf.game_log.lines:
if isinstance(l, dict):
pass
else:
if l.unpack():
pass
else:
print l.values['log']
# ClientInfo introspection for ping
if isinstance(l, ClientInfo) and l.values.get('clinfo', '') == 'avgPing':
print l.values
# fix avgPing parsing!
print rex

4
app.py
View File

@ -1,5 +1,5 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" """
Main application functions. Main application functions.

View File

@ -1,3 +1,5 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" """
Backup Directories, Handle Files... Backup Directories, Handle Files...
""" """

View File

@ -0,0 +1,2 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

View File

@ -16,7 +16,7 @@
""" """
#from win32com.shell import shell, shellcon #from win32com.shell import shell, shellcon
import os, sys, logging import os, sys, logging
from logs.logresolver import LogFileResolver as LogFile from logs.logfiles import LogFileResolver as LogFile
from logs import combat from logs import combat
# for windows its kinda this: # for windows its kinda this:

File diff suppressed because one or more lines are too long

View File

@ -53,9 +53,9 @@ def generate_fixtures():
data = [] data = []
ORES = [ ORES = [
{'name': 'Tungsten ore', 'sell_price': 6600, 'icon': 'resource_tungsten_ore'}, {'name': 'Impure tungsten', 'sell_price': 6600, 'icon': 'resource_tungsten_ore'},
{'name': 'Osmium ore', 'sell_price': 4500, 'icon': 'resource_osmium_ore'}, {'name': 'Impure osmium', 'sell_price': 4500, 'icon': 'resource_osmium_ore'},
{'name': 'Silicon ore', 'sell_price': 600, 'icon': 'resource_silicon_ore'}, {'name': 'Impure silicon', 'sell_price': 600, 'icon': 'resource_silicon_ore'},
{'name': 'Vanadium', 'sell_price': 500, 'icon': 'resource_vanadium'}, {'name': 'Vanadium', 'sell_price': 500, 'icon': 'resource_vanadium'},
{'name': 'Crystal shard', 'sell_price': 3500, 'icon': 'resource_crystal_shard'}, {'name': 'Crystal shard', 'sell_price': 3500, 'icon': 'resource_crystal_shard'},
] ]
@ -329,13 +329,13 @@ def generate_fixtures():
{'item': 'Duplicator', {'item': 'Duplicator',
'recipee': [(1, 'Processing Block'), (2,'Computing chip'), (2, 'Metal blank')]}, 'recipee': [(1, 'Processing Block'), (2,'Computing chip'), (2, 'Metal blank')]},
{'item': 'Tungsten plate', {'item': 'Tungsten plate',
'recipee': [(2, 'Tungsten ore'),]}, 'recipee': [(2, 'Impure tungsten'),]},
{'item': 'Screened battery', {'item': 'Screened battery',
'recipee': [(1, 'Tungsten plate'), (2, 'Computing chip')]}, 'recipee': [(1, 'Tungsten plate'), (2, 'Computing chip')]},
{'item': 'Osmium crystals', {'item': 'Osmium crystals',
'recipee': [(1, 'Osmium ore'),]}, 'recipee': [(1, 'Impure osmium'),]},
{'item': 'Pure Silicon', {'item': 'Pure Silicon',
'recipee': [(1, 'Silicon ore'),]}, 'recipee': [(1, 'Impure silicon'),]},
{'item': 'Computing chip', {'item': 'Computing chip',
'recipee': [(1, 'Crystal shard'),]}, 'recipee': [(1, 'Crystal shard'),]},
{'item': 'Processing block', {'item': 'Processing block',

View File

@ -90,6 +90,17 @@ class Item(models.Model):
def crafting_used_in(self): def crafting_used_in(self):
return CraftingInput.objects.filter(item=self) return CraftingInput.objects.filter(item=self)
def parents(self):
my_recipee = Crafting.objects.filter(output=self)
if my_recipee.count():
ci = CraftingInput.objects.filter(crafting=my_recipee).filter(primary=True)
if ci.count():
# ci.item is my parent
ret = [ci[0].item]
ret.extend(ci[0].item.parents())
return ret
return []
def get_full_name(self): def get_full_name(self):
if self.quality: if self.quality:
return '%s (%s)' % (self.name, D_QUALITY.get(self.quality, '')) return '%s (%s)' % (self.name, D_QUALITY.get(self.quality, ''))
@ -122,8 +133,8 @@ class Crafting(models.Model):
return 'Recipee for %s' % (self.output.name,) return 'Recipee for %s' % (self.output.name,)
class CraftingInput(models.Model): class CraftingInput(models.Model):
crafting = models.ForeignKey(Crafting) crafting = models.ForeignKey(Crafting) # the items you need.
item = models.ForeignKey(Item) item = models.ForeignKey(Item) # the item you get.
amount = models.IntegerField(default=1) amount = models.IntegerField(default=1)
primary = models.BooleanField(default=False, blank=True) primary = models.BooleanField(default=False, blank=True)

View File

@ -68,6 +68,7 @@
border-radius: 3px; border-radius: 3px;
} }
<!-- Copyright notice: -->
.arrowright { .arrowright {
background: #2C2C2C; background: #2C2C2C;
font-size: 12px; font-size: 12px;

View File

@ -0,0 +1,581 @@
[quote name="FunkyDonut" post="271113" timestamp="1402589748"]
This guide will only focus on the crafting system in the Invasion game mode. Please use the [url=http://forum.star-conflict.com/index.php?/topic/23371-invasion-introductory-guide/?p=269862][color=#0000cd]introductory guide[/color][/url], if you have general questions on the game mode itself, rather than the crafting system.
[center] [/center]
[center] [/center]
[center][color=#008000][b]Special thanks go to [/b][/color][b][url=http://forum.star-conflict.com/index.php?/user/239042-g4borg/][color=#0000cd]g4borg[/color][/url][/b][color=#008000][b], who mostly provided the information![/b][/color][/center]
In the Invasion game mode, you will be able to find trophies floating around in space. Those trophies can be simply credits, artefacts or debris, which is sold autmatically once you used a drone/returned to the station. But you may also find ressources - mostly close to asteroids, but sometimes also in cargo transports, shipwrecks or stolen containers from other pilots, which you shot down. These ressources can be used to craft to usefull items, such as new and powerful modules, new types of ammunition or the valuable duplicators, which allow you to reconstruct your ship, if you have been destroyed once. Below, you will see a listing
[color=#ff0000][u][b]Concerning updates:[/b][/u][/color] Please write me a private message, if you have something to add, or if there is anything wrong. I will edit/update this guide as soon as possible.
[indent=1] [/indent]
[size=6][b]Ressources[/b][/size]
[table][tr][th][b]Ressources[/b][/th][th][b][color=#ff8c00]Crafting result[/color]/[color=#8b4513]necessary ressources[/color][/b][/th][th][b]Used for...[/b][/th][/tr][tr]
[td][b]Tungsten Ore[/b]
[/td][td][b][color=#ff8c00]Tungsten Plate[/color]
[color=#8b4513]Tungsten ore x 2[/color][/b]
[/td][td]
[LIST]
[*]Screened battery (Tungsten plate)[/*]
[*]Pirate "Orion" Targeting Complex V (Tungsten plate)[/*]
[*]Pirate Engine Overcharge V (Tungsten plate)[/*]
[*]Reverse Thruster V (Tungsten plate)[/*]
[*]Alien Plasma Gun IV (Tungsten plate)[/*]
[*]Alien Plasma Gun V (Tungsten plate)[/*]
[*]Alien Assault Railgun IV (Tungsten plate)[/*]
[*]Alien Assault Railgun V (Tungsten plate)[/*]
[*]Alien Beam Cannon IV (Tungsten plate)[/*]
[*]Alien Beam Cannon V (Tungsten plate)[/*]
[/LIST]
[/td][/tr][tr][td][b]Osmium ore[/b]
[/td][td]
[b][color=#ff8c00]Osmium crystals[/color]
[color=#8b4513]Osmium ore x 1[/color][/b]
[/td][td]
[LIST]
[*]Double Deflector (Osmium crystals)[/*]
[*]Focusing Lens (Osmium crystals)[/*]
[*]Pirate Engine Overcharge V (Osmium crystals)[/*]
[*]Doomsday Missile (Osmium crystals)[/*]
[/LIST]
[indent=1][/td][/tr][tr][td][b]Silicon ore[/b]
[/td][td]
[b][color=#ff8c00]Pure Silicon[/color]
[color=#8b4513]Silicon ore x 1[/color][/b][/indent]
[/td][td]
[LIST]
[*]Processing block (Pure Silicon)[/*]
[*]Target Tracking Coprocessor III (Pure Silicon)[/*]
[*]Explosive Shells (Pure Silicon)[/*]
[*]Xenon Lamp (Pure Silicon)[/*]
[/LIST]
[indent=1][/td][/tr][tr][td][b]Vanadium[/b]
[/td][td]
[b][color=#ff8c00]Metal blank[/color]
[color=#8b4513]Vanadium x 2[/color][/b][/indent]
[/td][td]
[LIST]
[*]Duplicator (Metal blank)[/*]
[*]Target Tracking Coprocessor III (Metal blank)[/*]
[*]Explosive Shells (Metal blank)[/*]
[*]Iridium Slugs (Metal blank)[/*]
[*]A1MA IV (Metal blank)[/*]
[*]Pirate Mass Shield Generator V (Metal blank)[/*]
[*]Reverse Thruster III (Metal blank)[/*]
[*]Reverse Thruster IV (Metal blank)[/*]
[*]Alien Plasma Gun III (Metal blank)[/*]
[*]Alien Assault Railgun III (Metal blank)[/*]
[*]Alien Beam Cannon III (Metal blank)[/*]
[*]Doomsday Missile (Metal blank)[/td][/*]
[/LIST]
[/tr][tr][td][b]Crystal shard[/b]
[/td]
[td]
[b][color=#ff8c00]Computing chip[/color][/b]
[color=#8b4513][b]Crystal shard x 1[/b][/color]
[/td]
[td]
[LIST]
[*]Duplicator (Computing chip)[/*]
[*]Screened battery (Computing chip)[/*]
[*]Processing block (Computing chip)[/*]
[*]Attack Drone (Computing chip)[/*]
[*]Xenon Lamp (Computing chip)[/*]
[*]Supercooled Charges (Computing chip)[/*]
[*]Pirate "Orion" Targeting Complex V (Computing chip)[/*]
[*]Pirate Mass Shield Generator V (Computing chip)[/*]
[*]Reverse Thruster III (Computing chip)[/*]
[*]Reverse Thruster IV (Computing chip)[/*]
[*]Reverse Thruster V (Computing chip)[/*]
[*]Doomsday Missile (Computing chip)[/*]
[/LIST]
[/td][/tr][tr][td][b]Osmium crystals[/b]
[/td]
[td]
[b][color=#ff8c00]Double Deflector (Mk4)[/color][/b]
[color=#8b4513][b]Osmium crystals x 1[/b][/color][/td]
[td]
[LIST]
[*]Focusing Lens[/*]
[*]Pirate Engine Overcharge V[/*]
[*]Doomsday Missile[/*]
[/LIST]
[/td][/tr][tr][td][b]Alien Monocrystal[/b]
[/td][td]
[b][color=#ff8c00]Attack Drone (Universal)[/color][/b]
[color=#8b4513][b]Alien Monocrystal x 1[/b][/color]
[color=#8b4513][b]Computing chip x 1[/b][/color][/td][td]
[LIST]
[*]A1MA IV[/*]
[*]Pirate "Orion" Targeting Complex V[/*]
[*]Pirate Engine Overcharge V[/*]
[*]Pirate Mass Shield Generator V[/*]
[*]Reverse Thruster III[/*]
[*]Reverse Thruster IV[/*]
[*]Reverse Thruster V[/*]
[*]Alien Plasma Gun III[/*]
[*]Alien Plasma Gun IV[/*]
[*]Alien Plasma Gun V[/*]
[*]Alien Assault Railgun III[/*]
[*]Alien Assault Railgun IV[/*]
[*]Alien Assault Railgun V[/*]
[*]Alien Beam Cannon III[/*]
[*]Alien Beam Cannon IV[/*]
[*]Alien Beam Cannon V[/*]
[/LIST]
[/td][/tr][tr]
[td][b]Tungsten plate[/b][/td][td]
[b][color=#ff8c00]Screened battery[/color][/b]
[color=#8b4513][b]Tungsten plate x 1[/b][/color]
[color=#8b4513][b]Computing chip x 2[/b][/color][/td]
[td]
[LIST]
[*]Target Tracking Coprocessor III (Screened battery)[/*]
[*]A1MA IV (Screened battery)[/*]
[*]Reverse Thruster III (Screened battery)[/*]
[*]Reverse Thruster IV (Screened battery)[/*]
[*]Reverse Thruster V (Screened battery)[/*]
[*]Alien Plasma Gun III (Screened battery)[/*]
[*]Alien Plasma Gun IV (Screened battery)[/*]
[*]Alien Plasma Gun V (Screened battery)[/*]
[*]Alien Assault Railgun III (Screened battery)[/*]
[*]Alien Assault Railgun IV (Screened battery)[/*]
[*]Alien Assault Railgun V (Screened battery)[/*]
[*]Alien Beam Cannon III (Screened battery)[/*]
[*]Alien Beam Cannon IV (Screened battery)[/*]
[*]Alien Beam Cannon V (Screened battery)[/*]
[*]Pirate "Orion" Targeting Complex V[/*]
[*]Pirate Engine Overcharge V[/*]
[*]Reverse Thruster V[/*]
[*]Alien Plasma Gun IV[/*]
[*]Alien Plasma Gun V[/*]
[*]Alien Assault Railgun IV[/*]
[*]Alien Assault Railgun V[/*]
[*]Alien Beam Cannon IV[/*]
[*]Alien Beam Cannon V[/*]
[/LIST]
[/td][/tr][tr]
[td][b]Screened battery[/b][/td][td]
[b][color=#ff8c00]Target Tracking Coprocessor III[/color][/b]
[color=#8b4513][b]Screened battery x 1[/b][/color]
[color=#8b4513][b]Metal blank x 7[/b][/color]
[color=#8b4513][b]Pure Silicon x 5[/b][/color]
[/td][td]
[LIST]
[*]A1MA IV[/*]
[*]Reverse Thruster III[/*]
[*]Reverse Thruster IV[/*]
[*]Reverse Thruster V[/*]
[*]Alien Plasma Gun III[/*]
[*]Alien Plasma Gun IV[/*]
[*]Alien Plasma Gun V[/*]
[*]Alien Assault Railgun III[/*]
[*]Alien Assault Railgun IV[/*]
[*]Alien Assault Railgun V[/*]
[*]Alien Beam Cannon III[/*]
[*]Alien Beam Cannon IV[/*]
[*]Alien Beam Cannon V[/*]
[/LIST]
[/td][/tr][tr][td][b]Pure Silicon[/b][/td]
[td]
[b][color=#ff8c00]Processing block[/color][/b]
[color=#8b4513][b]Pure Silicon x 4[/b][/color]
[color=#8b4513][b]Computing chip x 2[/b][/color]
[/td][td]
[LIST]
[*]Duplicator (Processing block)[/*]
[*]A1MA IV (Processing block)[/*]
[*]Pirate "Orion" Targeting Complex V (Processing block)[/*]
[*]Pirate Engine Overcharge V (Processing block)[/*]
[*]Pirate Mass Shield Generator V (Processing block)[/*]
[*]Target Tracking Coprocessor III[/*]
[*]Explosive Shells[/*]
[*]Xenon Lamp[/*]
[/LIST]
[/td][/tr][tr]
[td][b]Metal blank[/b][/td]
[td]
[b][color=#ff8c00]Explosive Shells (Mk4)[/color][/b]
[color=#8b4513][b]Metal blank x 1[/b][/color]
[color=#8b4513][b]Pure Silicon x 2[/b][/color]
[/td][td]
[LIST]
[*]Duplicator[/*]
[*]Target Tracking Coprocessor III[/*]
[*]Explosive Shells[/*]
[*]Iridium Slugs[/*]
[*]A1MA IV[/*]
[*]Pirate Mass Shield Generator V[/*]
[*]Reverse Thruster III[/*]
[*]Reverse Thruster IV[/*]
[*]Alien Plasma Gun III[/*]
[*]Alien Assault Railgun III[/*]
[*]Alien Beam Cannon III[/*]
[*]Doomsday Missile[/*]
[/LIST]
[/td][/tr][tr]
[td][b]Computing chip[/b][/td][td]
[b][color=#ff8c00]Xenon Lamp (Mk4)[/color][/b]
[color=#8b4513][b]Computing chip x 1[/b][/color]
[color=#8b4513][b]Pure Silicon x 1[/b][/color] [/td][td]
[LIST]
[*]Duplicator[/*]
[*]Screened battery[/*]
[*]Target Tracking Coprocessor III (Screened battery)[/*]
[*]A1MA IV (Screened battery)[/*]
[*]Reverse Thruster III (Screened battery)[/*]
[*]Reverse Thruster IV (Screened battery)[/*]
[*]Reverse Thruster V (Screened battery)[/*]
[*]Alien Plasma Gun III (Screened battery)[/*]
[*]Alien Plasma Gun IV (Screened battery)[/*]
[*]Alien Plasma Gun V (Screened battery)[/*]
[*]Alien Assault Railgun III (Screened battery)[/*]
[*]Alien Assault Railgun IV (Screened battery)[/*]
[*]Alien Assault Railgun V (Screened battery)[/*]
[*]Alien Beam Cannon III (Screened battery)[/*]
[*]Alien Beam Cannon IV (Screened battery)[/*]
[*]Alien Beam Cannon V (Screened battery)[/*]
[*]Processing block[/*]
[*]Duplicator (Processing block)[/*]
[*]A1MA IV (Processing block)[/*]
[*]Pirate "Orion" Targeting Complex V (Processing block)[/*]
[*]Pirate Engine Overcharge V (Processing block)[/*]
[*]Pirate Mass Shield Generator V (Processing block)[/*]
[*]Attack Drone[/*]
[*]Xenon Lamp[/*]
[*]Supercooled Charges[/*]
[*]Pirate "Orion" Targeting Complex V[/*]
[*]Pirate Mass Shield Generator V[/*]
[*]Reverse Thruster III[/*]
[*]Reverse Thruster IV[/*]
[*]Reverse Thruster V[/*]
[*]Doomsday Missile[/*]
[/LIST]
[/td][/tr]
[/table]
[size=6][b]Known/Available Blueprints[/b][/size]
[indent=1][size=6][b][size=4][size=5][color=#008000]Important: [/color][/size][/size][/b][size=4][size=5]The ammunition-blueprints produce consumable items, which only last for one battle each! The same goes for duplicators and Doomsday missiles![/size][/size][/size][/indent]
[table][tr][th][b]Blueprints[/b][/th][th][color=#8b4513][b]Crafting parts[/b][/color][/th][th][b]Result[/b][/th][/tr][tr]
[td][b]Focusing Lens[/b][/td][td]
[LIST]
[*][b][color=#8b4513]Focusing Lens Blueprint x 1[/color][/b][/*]
[*][b][color=#8b4513]Osmium crystals x 1[/color][/b][/*]
[/LIST]
[/td][td]Focusing Lens Mk.4[/td][/tr][tr]
[td][b]Iridium Slugs[/b][/td][td]
[LIST]
[*][b][color=#8b4513]Iridium Slugs Blueprint x 1[/color][/b][/*]
[*][b][color=#8b4513]Metal blank x 1[/color][/b][/*]
[/LIST]
[/td][td]Iridium Slugs Mk.4[/td][/tr][tr]
[td][b]Supercooled Charges[/b][/td][td]
[LIST]
[*][b][color=#8b4513]Supercooled Charges Blueprint x 1[/color][/b][/*]
[*][b][color=#8b4513]Computing chip x 1[/color][/b][/*]
[/LIST]
[/td][td]Supercooled Charges Mk.4[/td][/tr][tr]
[td][b]A1MA T4[/b][/td][td]
[LIST]
[*][b][color=#8b4513]A1MA T4 Blueprint x 1[/color][/b][/*]
[*][b][color=#8b4513]Processing block x 2[/color][/b][/*]
[*][b][color=#8b4513]Metal blank x 14[/color][/b][/*]
[*][b][color=#8b4513]Screened battery x 2[/color][/b][/*]
[*][b][color=#8b4513]Alien Monocrystal x 20[/color][/b][/*]
[/LIST]
[/td][td]
A1MA IV[/td][/tr][tr]
[td][b]Orion-2 Targeting Complex[/b][/td][td]
Pirate "Orion" Targeting Complex V (Pirate Mk4)
[LIST]
[*][b][color=#8b4513]Orion-2 Targeting Complex Blueprint x 1[/color][/b][/*]
[*][b][color=#8b4513]Tungsten plate x 3[/color][/b][/*]
[*][b][color=#8b4513]Computing chip x 4[/color][/b][/*]
[*][b][color=#8b4513]Processing block x 2[/color][/b][/*]
[*][b][color=#8b4513]Alien Monocrystal x 30[/color][/b][/*]
[/LIST]
[/td][td]Pirate "Orion" Targeting Complex V[/td][/tr][tr]
[td][b]Engine Warp Overcharge[/b][/td][td]
Pirate Engine Overcharge V (Pirate Mk4)
[LIST]
[*][color=#8b4513][b]Engine Warp Overcharge Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 3[/b][/color][/*]
[*][color=#8b4513][b]Osmium crystals x 2[/b][/color][/*]
[*][color=#8b4513][b]Processing block x 2[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]Pirate Engine Overcharge V[/td][/tr][tr]
[td][b]Mass Shield Energizer[/b][/td][td]
Pirate Mass Shield Generator V (Pirate Mk4)
[LIST]
[*][color=#8b4513][b]Mass Shield Energizer Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 10[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 3[/b][/color][/*]
[*][color=#8b4513][b]Processing block x 3[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]Pirate Mass Shield Generator V[/td][/tr][tr]
[td][b]Reverse Thruster T3[/b][/td][td]
Reverse Thruster III (Mk1)
[LIST]
[*][color=#8b4513][b]Reverse Thruster T3 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 7[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 1[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 4[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 15[/b][/color][/*]
[/LIST]
[/td][td]Reverse Thruster III[/td][/tr][tr]
[td][b]Reverse Thruster T4[/b][/td][td]
Reverse Thruster IV (Mk1)
[LIST]
[*][color=#8b4513][b]Reverse Thruster T4 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 12[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 2[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 5[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 20[/b][/color][/*]
[/LIST]
[/td][td]Reverse Thruster IV[/td][/tr][tr][td][b]Reverse Thruster T5[/b][/td]
[td]
Reverse Thruster V (Mk1)
[LIST]
[*][color=#8b4513][b]Reverse Thruster T5 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 7[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 3[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 6[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]Reverse Thruster V[/td][/tr][tr]
[td][b]Beam Cannon Prototype T3[/b][/td][td]
Alien Beam Cannon III (Mk5)
[LIST]
[*][color=#8b4513][b]Beam Cannon Prototype T3 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Beam Cannon III x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 6[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 3[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]Alien Beam Cannon III[/td][/tr][tr]
[td][b]Beam Cannon Prototype T4[/b][/td][td]
Alien Beam Cannon IV (Mk5)
[LIST]
[*][color=#8b4513][b]Beam Cannon Prototype T4 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Beam Cannon IV x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 1[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 4[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 50[/b][/color][/*]
[/LIST]
[/td][td]Alien Beam Cannon IV[/td][/tr][tr]
[td][b]Beam Cannon Prototype T5[/b][/td][td]
Alien Beam Cannon V (Mk5)
[LIST]
[*][color=#8b4513][b]Beam Cannon Prototype T5 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Beam Cannon V x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 3[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 5[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 70[/b][/color][/*]
[/LIST]
[/td][td]Alien Beam Cannon V[/td][/tr][tr]
[td][b]Assault Railgun Prototype T3[/b][/td][td]
Alien Assault Railgun III (Mk5)
[LIST]
[*][color=#8b4513][b]Assault Railgun Prototype T3 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Assault Railgun III x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 6[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 3[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]
Alien Assault Railgun III
[/td][/tr][tr]
[td][b]Assault Railgun Prototype T4[/b][/td][td]
Alien Assault Railgun IV (Mk5)
[LIST]
[*][color=#8b4513][b]Assault Railgun Prototype T4 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Assault Railgun IV x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 1[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 4[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 50[/b][/color][/*]
[/LIST]
[/td][td]Alien Assault Railgun IV[/td][/tr][tr]
[td][b]Assault Railgun Prototype T5[/b][/td][td]
Alien Assault Railgun V (Mk5)
[LIST]
[*][color=#8b4513][b]Assault Railgun Prototype T5 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Assault Railgun V x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 3[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 5[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 70[/b][/color][/*]
[/LIST]
[/td][td]Alien Assault Railgun V[/td][/tr][tr]
[td][b]Plasma Gun Prototype T3[/b][/td][td]
Alien Plasma Gun III (Mk5)
[LIST]
[*][color=#8b4513][b]Plasma Gun Prototype T3 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Plasma Gun III x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 6[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 3[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 30[/b][/color][/*]
[/LIST]
[/td][td]Alien Plasma Gun III[/td][/tr][tr]
[td][b]Plasma Gun Prototype T4[/b][/td][td]
Alien Plasma Gun IV (Mk5)
[LIST]
[*][color=#8b4513][b]Plasma Gun Prototype T4 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Plasma Gun IV x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 1[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 4[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 50[/b][/color][/*]
[/LIST]
[/td][td]Alien Plasma Gun IV[/td][/tr][tr]
[td][b]Plasma Gun Prototype T5[/b][/td][td]
Alien Plasma Gun V (Mk5)
[LIST]
[*][color=#8b4513][b]Plasma Gun Prototype T5 Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Plasma Gun V x 1[/b][/color][/*]
[*][color=#8b4513][b]Tungsten plate x 3[/b][/color][/*]
[*][color=#8b4513][b]Screened battery x 5[/b][/color][/*]
[*][color=#8b4513][b]Alien Monocrystal x 70[/b][/color][/*]
[/LIST]
[/td][td]Alien Plasma Gun V[/td][/tr][tr]
[td][b]Doomsday Missile[/b][/td][td]
Doomsday Missile (Mk1)
[LIST]
[*][color=#8b4513][b]Doomsday Missile Blueprint x 1[/b][/color][/*]
[*][color=#8b4513][b]Osmium crystals x 2[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 1[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 1[/b][/color][/*]
[/LIST]
[/td][td]Doomsday Missile[/td][/tr][tr]
[td][b]Duplicator[/b][/td][td]
Duplicator
[LIST]
[*][color=#8b4513][b]Processing block x 1[/b][/color][/*]
[*][color=#8b4513][b]Computing chip x 2[/b][/color][/*]
[*][color=#8b4513][b]Metal blank x 2[/b][/color][/*]
[/LIST]
[/td][td]Duplicator[/td][/tr]
[/table]
[/quote]
[b][font=arial, sans-serif][size=14]The Color Code[/size][/font][/b]
[b][color=#595959][font=arial, sans-serif][size=12]Gray [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials of this color will be raw resources. [/size][/font]
[b][color=#00b050][font=arial, sans-serif][size=12]Green [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials here have been crafted once since being a raw resource.[/size][/font]
[b][color=#1f497d][font=arial, sans-serif][size=12]Blue [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials here have been at most crafted twice since being a raw resource.[/size][/font]
[b][color=#7030a0][font=arial, sans-serif][size=12]Purple [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials here have been at most crafted three times since being a raw resource.[/size][/font]
[b][color=#e46c0a][font=arial, sans-serif][size=12]Orange [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials here have been at most crafted four times since being a raw resource.[/size][/font]
[b][color=#ff3399][font=arial, sans-serif][size=12]Pink [/size][/font][/color][/b][font=arial, sans-serif][size=12] Materials here have been at most crafted five times since being a raw resource (I doubt this is even possible but just in case).[/size][/font]
[table]
[tr][th][b][font=arial, sans-serif][size=12]Crafting Result [/size][/font][/b]
[b][font=arial, sans-serif][size=12](the components you want)[/size][/font][/b][/th][th][b][font=arial, sans-serif][size=12]Prerequisite Materials [/size][/font][/b]
[b][font=arial, sans-serif][size=12](what you need to get the result)[/size][/font][/b][/th][/tr]
[tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Crystal Shard[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A[/size][/font][/td]
[/tr]
[tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Osmium Ore[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A[/size][/font][/td]
[/tr][tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Silicon Ore[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A[/size][/font][/td]
[/tr][tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Tungsten Ore[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A[/size][/font][/td]
[/tr][tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Vanadium (Ore)[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A[/size][/font][/td]
[/tr][tr]
[td][b][color=#595959][font=arial, sans-serif][size=12]Alien Monocrystal[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]N/A [/size][/font][font=arial, sans-serif](Although this is a component you cannot craft it using raw resources.)[/size][/font][/td]
[/tr][tr]
[td][b][color=#00b050][font=arial, sans-serif][size=12]Computing Chip[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]1x [/size][/font][b][color=#595959]Crystal Shard[/color][/b][/td]
[/tr][tr]
[td][b][color=#00b050][font=arial, sans-serif][size=12]Metal Blank[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]2x [/size][/font][b][color=#595959]Vanadium (Ore)[/color][/b][/td]
[/tr][tr]
[td][b][color=#00b050][font=arial, sans-serif][size=12]Osmium Crystals[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]1x [/size][/font][b][color=#595959]Osmium Ore[/color][/b][/td]
[/tr][tr]
[td][b][color=#00b050][font=arial, sans-serif][size=12]Pure Silicon[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]1x [/size][/font][b][color=#595959]Silicon Ore[/color][/b][/td]
[/tr][tr]
[td][b][color=#00b050][font=arial, sans-serif][size=12]Tungsten Plate[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]2x [/size][/font][b][color=#595959]Tungsten Ore[/color][/b][/td]
[/tr][tr]
[td][b][color=#1f497d][font=arial, sans-serif][size=12]Processing Block[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]4x [/size][/font][b][color=#00b050]Pure Silicon[/color][/b]
[font=arial, sans-serif]2x [/size][/font][b][color=#00b050]Computing Chip[/color][/b][/td]
[/tr][tr]
[td][b][color=#1f497d][font=arial, sans-serif][size=12]Screened Battery[/size][/font][/color][/b][/td]
[td][font=arial, sans-serif]1x [/size][/font][b][color=#00b050]Tungsten Plate[/color][/b]
[font=arial, sans-serif]2x [/size][/font][b][color=#00b050]Computing Chip[/color][/b][/td]
[/tr]
[/table]

View File

@ -0,0 +1,41 @@
{% extends "scon/base.html" %}
{% block context %}
<h1>Forum</h1>
<code>
[table][tr][th]Item[/th][th]Produces[/th][/tr]
{% for item in items %}
{% if item.primary_recipee %}
[tr]
{% with item.primary_recipee as recipee %}
[td]
{{ item.name }}
[/td]
[td]
{{ recipee.output.name }}
[LIST]
{% for ingredient in recipee.ingredients %}
{% if ingredient.item != item %}
[*]{{ ingredient.amount }} x {{ ingredient.item.name }}[/*]
{% else %}
{% if ingredient.amount > 1 %}
[*][b]{{ ingredient.amount }} x [/b]{{ ingredient.item.name }}[/*]
{% endif %}
{% endif %}
{% endfor %}
[/LIST]
[/td]
{% endwith %}
[/tr]
{% endif %}
{% endfor %}
[/table]
</code>
{% endblock context %}

View File

@ -0,0 +1,133 @@
{% extends "scon/base.html" %}
{% block css %}
{{ block.super }}
<style>
<!--
.parents-0 {
color: #595959;
}
.parents-1 {
color: #00b050;
}
.parents-2 {
color: #1f497d;
}
.parents-3 {
color: #7030a0;
}
.parents-4 {
color: #e46c0a;
}
.parents-5 {
color: #ff3399;
}
-->
</style>
{% endblock css %}
{% block context %}
<h1>Forum</h1>
<table>
<tr>
<th>What ya wanna</th>
<th>What ya needze</th>
</tr>
{% for ore in ores %}
<tr>
<td>{{ ore.name }}</td>
<td>N/A{% if ore.typ == 13 %} (This is a component you cannot craft){% endif %}</td>
</tr>
{% endfor %}
{% for item in items %}
{% if item.primary_recipee %}
<tr>
{% with item.primary_recipee as recipee %}
<td>
{{ recipee.output.name }}
</td>
<td>
<ul>
{% for ingredient in recipee.ingredients %}
<li class="parents-{{ ingredient.item.parents|length }}">
{% if ingredient.item != item %}
{{ ingredient.amount }} x {{ ingredient.item.name }}
{% else %}
{% if ingredient.amount > 1 %}
<b><i>{{ ingredient.amount }}</i> x {{ ingredient.item.name }}</b>
{% else %}
<b>{{ ingredient.amount }} x {{ ingredient.item.name }}</b>
{% endif %}
{% endif %}
</li>
{% endfor %}
</ul>
</td>
{% endwith %}
</tr>
{% else %}
{% endif %}
{% endfor %}
</table>
<code>
[table]
[tr][th][b][font=arial, sans-serif][size=12]Crafting Result [/size][/font][/b]
[b][font=arial, sans-serif][size=12](the components you want)[/size][/font][/b][/th][th][b][font=arial, sans-serif][size=12]Prerequisite Materials [/size][/font][/b]
[b][font=arial, sans-serif][size=12](what you need to get the result)[/size][/font][/b][/th][/tr]
{% for ore in ores %}
[tr]
[td][color=#595959]{{ ore.name }}[/color][/td]
[td]N/A{% if ore.typ == 13 %} (This is a component you cannot craft){% endif %}[/td]
[/tr]
{% endfor %}
{% for item in items %}
{% if item.primary_recipee %}
[tr]
{% with item.primary_recipee as recipee %}
[td]
{% with recipee.output.parents|length as depth %}
[color={% if depth == 0 %}#595959{% elif depth == 1 %}#00b050{% elif depth == 2 %}#1f497d{% else %}#7030a0{% endif %}]{{ recipee.output.name }}[/color]
{% endwith %}
[/td]
[td]
[LIST]
{% for ingredient in recipee.ingredients %}
[*]{% with ingredient.item.parents|length as depth %}
[font=arial, sans-serif][size=12]
{% if ingredient.item != item %}
{{ ingredient.amount }} x [color={% if depth == 0 %}#595959{% elif depth == 1 %}#00b050{% elif depth == 2 %}#1f497d{% else %}#7030a0{% endif %}]{{ ingredient.item.name }}[/color]
{% else %}
{% if ingredient.amount > 1 %}
[b][i]{{ ingredient.amount }}[/i] x [color={% if depth == 0 %}#595959{% elif depth == 1 %}#00b050{% elif depth == 2 %}#1f497d{% else %}#7030a0{% endif %}]{{ ingredient.item.name }}[/color][/b]
{% else %}
[b]{{ ingredient.amount }} x [color={% if depth == 0 %}#595959{% elif depth == 1 %}#00b050{% elif depth == 2 %}#1f497d{% else %}#7030a0{% endif %}]{{ ingredient.item.name }}[/color][/b]
{% endif %}
{% endif %}
{% endwith %}[/size][/font][/*]
{% endfor %}
[/LIST]
[/td]
{% endwith %}
[/tr]
{% endif %}
{% endfor %}
[/table]
</code>
{% endblock context %}

View File

@ -17,3 +17,16 @@ def crafting(request):
c = RequestContext(request, {'tree': tree, c = RequestContext(request, {'tree': tree,
'items': items}) 'items': items})
return HttpResponse(t.render(c)) return HttpResponse(t.render(c))
def crafting_forum(request):
t = loader.get_template('scon/crafting/forum_efefay.html')
items = models.Item.objects.filter(craftable=True)
ores = []
for item in items.filter(typ__in=[12, 13]):
if len(item.parents()) == 0 and item.primary_recipee():
ores.append(item)
tree = None
c = RequestContext(request, {'tree': tree,
'ores': ores,
'items': items})
return HttpResponse(t.render(c))

View File

@ -8,7 +8,9 @@ urlpatterns = patterns('',
# url(r'^$', 'dj.views.home', name='home'), # url(r'^$', 'dj.views.home', name='home'),
# url(r'^blog/', include('blog.urls')), # url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
url(r'^crafting/', 'dj.scon.views.crafting', name='scon_crafting'), url(r'^crafting/forum/$', 'dj.scon.views.crafting_forum', name='scon_crafting_forum'),
url(r'^crafting/$', 'dj.scon.views.crafting', name='scon_crafting'),
) )
if settings.DEBUG or getattr(settings, 'SERVE_INTERNAL', False): if settings.DEBUG or getattr(settings, 'SERVE_INTERNAL', False):

View File

@ -77,7 +77,7 @@ class Browser(QtGui.QMainWindow):
self.connect(self.bt_back, QtCore.SIGNAL("clicked()"), self.html.back) self.connect(self.bt_back, QtCore.SIGNAL("clicked()"), self.html.back)
self.connect(self.bt_ahead, QtCore.SIGNAL("clicked()"), self.html.forward) self.connect(self.bt_ahead, QtCore.SIGNAL("clicked()"), self.html.forward)
self.tb_url.setText('Search...') self.tb_url.setText('/crafting/forum')
self.browse() self.browse()
@ -87,10 +87,13 @@ class Browser(QtGui.QMainWindow):
Webview widget. Webview widget.
""" """
#url = self.tb_url.text() if self.tb_url.text() else self.default_url url = self.tb_url.text() if self.tb_url.text() else 'page:///'
#self.html.load(QtCore.QUrl(url)) if not str(url).startswith('page://'):
url = 'page://' + url
self.html.load(QtCore.QUrl(url))
#self.html.setHtml(self.serve()) #self.html.setHtml(self.serve())
self.html.load(QtCore.QUrl('page:///crafting/overview/'))
#self.html.load(QtCore.QUrl('page:///crafting/forum/'))
self.html.show() self.html.show()
def serve(self, what=None): def serve(self, what=None):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" """
Library dedicated to Star Conflict Logs. Library dedicated to Star Conflict Logs.

View File

@ -1,9 +1,16 @@
L_CMBT = 'CMBT'
L_WARNING = 'WARNING'
L_NET = 'NET'
L_CHAT = 'CHAT'
class Log(object): class Log(object):
matcher = None matcher = None
trash = False
@classmethod @classmethod
def is_handler(cls, log): def is_handler(cls, log):
return False return False
def unpack(self):
pass

View File

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
""" """
todo: todo:
- English implementation first. - English implementation first.
@ -19,9 +21,10 @@
The typical log entry The typical log entry
""" """
import re import re
from base import Log from base import Log, L_CMBT
class CombatLog(Log): class CombatLog(Log):
__slots__ = ['matcher', 'trash', '_match_id', 'values']
@classmethod @classmethod
def _log_handler(cls, log): def _log_handler(cls, log):
if log.get('log', '').strip().startswith(cls.__name__): if log.get('log', '').strip().startswith(cls.__name__):
@ -30,7 +33,7 @@ class CombatLog(Log):
@classmethod @classmethod
def is_handler(cls, log): def is_handler(cls, log):
if log.get('logtype', None) == 'CMBT': if log.get('logtype', None) == L_CMBT:
return cls._log_handler(log) return cls._log_handler(log)
return False return False
@ -38,22 +41,28 @@ class CombatLog(Log):
self.values = values self.values = values
def unpack(self): def unpack(self):
self._match_id = None
# unpacks the data from the values. # unpacks the data from the values.
if hasattr(self, 'matcher') and self.matcher: if hasattr(self, 'matcher') and self.matcher:
matchers = self.matcher matchers = self.matcher
if not isinstance(matchers, list): if not isinstance(matchers, list):
matchers = [matchers,] matchers = [matchers,]
for matcher in matchers: for i, matcher in enumerate(matchers):
m = matcher.match(self.values.get('log', '')) m = matcher.match(self.values.get('log', ''))
if m: if m:
self.values.update(m.groupdict()) self.values.update(m.groupdict())
self._match_id = i
return True return True
# unknown?
self.trash = True
# @todo: where does this come from? # @todo: where does this come from?
class Action(CombatLog): class Action(CombatLog):
__slots__ = CombatLog.__slots__
pass pass
class Gameplay(CombatLog): class Gameplay(CombatLog):
__slots__ = CombatLog.__slots__
matcher = [ matcher = [
# usual: team(reason). explained reason. # usual: team(reason). explained reason.
re.compile(r"^Gameplay\sfinished\.\sWinner\steam\:\s+(?P<winner_team>\d+)\((?P<winner_reason>\w+)\)\.\sFinish\sreason\:\s'(?P<reason_verbose>[^']+)'\.\sActual\sgame\stime\s+(?P<game_time>\d+|\d+\.\d+)\ssec"), re.compile(r"^Gameplay\sfinished\.\sWinner\steam\:\s+(?P<winner_team>\d+)\((?P<winner_reason>\w+)\)\.\sFinish\sreason\:\s'(?P<reason_verbose>[^']+)'\.\sActual\sgame\stime\s+(?P<game_time>\d+|\d+\.\d+)\ssec"),
@ -62,27 +71,35 @@ class Gameplay(CombatLog):
] ]
class Apply(CombatLog): # Apply Aura. class Apply(CombatLog): # Apply Aura.
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Apply\saura\s'(?P<aura_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<aura_type>\w+)\sto\s'(?P<target_name>[^\']+)'") matcher = re.compile(r"^Apply\saura\s'(?P<aura_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<aura_type>\w+)\sto\s'(?P<target_name>[^\']+)'")
class Damage(CombatLog): class Damage(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Damage\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))(?:\s(?P<module_class>[^\s]+)\s|\s{2,2})(?P<flags>(?:\w|\|)+)") matcher = re.compile(r"^Damage\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))(?:\s(?P<module_class>[^\s]+)\s|\s{2,2})(?P<flags>(?:\w|\|)+)")
class Spawn(CombatLog): class Spawn(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Spawn\sSpaceShip\sfor\splayer(?P<player>\d+)\s\((?P<name>[^,]+),\s+(?P<hash>#\w+)\)\.\s+'(?P<ship_class>\w+)'") matcher = re.compile(r"^Spawn\sSpaceShip\sfor\splayer(?P<player>\d+)\s\((?P<name>[^,]+),\s+(?P<hash>#\w+)\)\.\s+'(?P<ship_class>\w+)'")
class Spell(CombatLog): class Spell(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Spell\s'(?P<spell_name>\w+)'\sby\s+(?P<source_name>.*)(?:\((?P<module_name>\w+)\)|)\stargets\((?P<target_num>\d+)\)\:(?:$|\s(?P<targets>.+))") matcher = re.compile(r"^Spell\s'(?P<spell_name>\w+)'\sby\s+(?P<source_name>.*)(?:\((?P<module_name>\w+)\)|)\stargets\((?P<target_num>\d+)\)\:(?:$|\s(?P<targets>.+))")
class Reward(CombatLog): class Reward(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Reward\s+(?P<name>[^\s]+)(?:\s(?P<ship_class>\w+)\s+|\s+)(?P<amount>\d+)\s(?P<reward_type>.*)\s+for\s(?P<reward_reason>.*)") matcher = re.compile(r"^Reward\s+(?P<name>[^\s]+)(?:\s(?P<ship_class>\w+)\s+|\s+)(?P<amount>\d+)\s(?P<reward_type>.*)\s+for\s(?P<reward_reason>.*)")
class Participant(CombatLog): class Participant(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^\s+Participant\s+(?P<source_name>[^\s]+)(?:\s{2}(?P<ship_class>\w+)|\s{30,})\s+(?:totalDamage\s(?P<total_damage>(?:\d+|\d+\.\d+));\smostDamageWith\s'(?P<module_class>[^']+)';(?P<additional>.*)|<(?P<other>\w+)>)") matcher = re.compile(r"^\s+Participant\s+(?P<source_name>[^\s]+)(?:\s{2}(?P<ship_class>\w+)|\s{30,})\s+(?:totalDamage\s(?P<total_damage>(?:\d+|\d+\.\d+));\smostDamageWith\s'(?P<module_class>[^']+)';(?P<additional>.*)|<(?P<other>\w+)>)")
class Rocket(CombatLog): class Rocket(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Rocket\s(?P<event>launch|detonation)\.\sowner\s'(?P<name>[^']+)'(?:,\s(?:def\s'(?P<missile_type>\w+)'|target\s'(?P<target>[^']+)'|reason\s'(?P<reason>\w+)'|directHit\s'(?P<direct_hit>[^']+)'))+") matcher = re.compile(r"^Rocket\s(?P<event>launch|detonation)\.\sowner\s'(?P<name>[^']+)'(?:,\s(?:def\s'(?P<missile_type>\w+)'|target\s'(?P<target>[^']+)'|reason\s'(?P<reason>\w+)'|directHit\s'(?P<direct_hit>[^']+)'))+")
class Heal(CombatLog): class Heal(CombatLog):
__slots__ = CombatLog.__slots__
matcher = [ matcher = [
# heal by module # heal by module
re.compile(r"^Heal\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))\s(?P<module_class>[^\s]+)"), re.compile(r"^Heal\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))\s(?P<module_class>[^\s]+)"),
@ -91,6 +108,7 @@ class Heal(CombatLog):
] ]
class Killed(CombatLog): class Killed(CombatLog):
__slots__ = CombatLog.__slots__
matcher = [ matcher = [
re.compile(r"^Killed\s(?P<target_name>[^\s]+)\s+(?P<ship_class>\w+);\s+killer\s(?P<source_name>[^\s]+)\s*"), re.compile(r"^Killed\s(?P<target_name>[^\s]+)\s+(?P<ship_class>\w+);\s+killer\s(?P<source_name>[^\s]+)\s*"),
re.compile(r"^Killed\s(?P<object>[^\(]+)\((?P<target_name>\w+)\);\s+killer\s(?P<source_name>[^\s]+)\s*"), re.compile(r"^Killed\s(?P<object>[^\(]+)\((?P<target_name>\w+)\);\s+killer\s(?P<source_name>[^\s]+)\s*"),
@ -98,19 +116,24 @@ class Killed(CombatLog):
] ]
class Captured(CombatLog): class Captured(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Captured\s'(?P<objective>[^']+)'\(team\s(?P<team>\d+)\)\.(?:\sAttackers\:(?P<attackers>.*)|.*)") matcher = re.compile(r"^Captured\s'(?P<objective>[^']+)'\(team\s(?P<team>\d+)\)\.(?:\sAttackers\:(?P<attackers>.*)|.*)")
class AddStack(CombatLog): class AddStack(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^AddStack\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\.\snew\sstacks\scount\s(?P<stack_count>\d+)") matcher = re.compile(r"^AddStack\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\.\snew\sstacks\scount\s(?P<stack_count>\d+)")
class Cancel(CombatLog): class Cancel(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Cancel\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\sfrom\s'(?P<source_name>[^']+)'") matcher = re.compile(r"^Cancel\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\sfrom\s'(?P<source_name>[^']+)'")
class Scores(CombatLog): class Scores(CombatLog):
__slots__ = CombatLog.__slots__
matcher = re.compile(r"^Scores\s+-\sTeam1\((?P<team1_score>(?:\d+|\d+\.\d+))\)\sTeam2\((?P<team2_score>(?:\d+|\d+\.\d+))\)") matcher = re.compile(r"^Scores\s+-\sTeam1\((?P<team1_score>(?:\d+|\d+\.\d+))\)\sTeam2\((?P<team2_score>(?:\d+|\d+\.\d+))\)")
# Special classes # Special classes
class GameEvent(CombatLog): class GameEvent(CombatLog):
__slots__ = CombatLog.__slots__
matcher = [ matcher = [
# game session identifier. # game session identifier.
re.compile(r"^Connect\sto\sgame\ssession\s+(?P<game_session>\d+)"), re.compile(r"^Connect\sto\sgame\ssession\s+(?P<game_session>\d+)"),
@ -127,20 +150,25 @@ class GameEvent(CombatLog):
return False return False
def unpack(self): def unpack(self):
self._match_id = None
# unpacks the data from the values. # unpacks the data from the values.
# small override to remove trailing "="s in the matching. # small override to remove trailing "="s in the matching.
if hasattr(self, 'matcher') and self.matcher: if hasattr(self, 'matcher') and self.matcher:
matchers = self.matcher matchers = self.matcher
if not isinstance(matchers, list): if not isinstance(matchers, list):
matchers = [matchers,] matchers = [matchers,]
for matcher in matchers: for i, matcher in enumerate(matchers):
m = matcher.match(self.values.get('log', '').strip('=').strip()) m = matcher.match(self.values.get('log', '').strip('=').strip())
if m: if m:
self.values.update(m.groupdict()) self.values.update(m.groupdict())
self._match_id = i
return True return True
# unknown?
self.trash = True
class UserEvent(CombatLog): class UserEvent(CombatLog):
""" special class for combat logs that might be associated with the playing player """ """ special class for combat logs that might be associated with the playing player """
__slots__ = CombatLog.__slots__
@classmethod @classmethod
def _log_handler(cls, log): def _log_handler(cls, log):
if log.get('log', '').strip(): if log.get('log', '').strip():

View File

@ -1,4 +1,172 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from logs.base import Log, L_WARNING
import re
"""
Interesting Lines:
23:16:27.427 | Steam initialized appId 212070, userSteamID 1|1|4c5a01, userName 'G4bOrg'
23:16:36.214 | ====== starting level: 'levels/mainmenu/mainmenu' ======
23:16:38.822 | ====== level started: 'levels/mainmenu/mainmenu' success ======
23:16:44.251 | ====== starting level: 'levels\mainmenu\mm_empire' ======
23:16:46.464 | ====== level started: 'levels\mainmenu\mm_empire' success ======
--- Date: 2014-07-18 (Fri Jul 2014) Mitteleuropäische Sommerzeit UTC+01:00
23:55:55.517 | MasterServerSession: connect to dedicated server, session 6777304, at addr 159.253.138.162|35005
23:55:55.543 | client: start connecting to 159.253.138.162|35005...
23:55:55.683 | client: connected to 159.253.138.162|35005, setting up session...
23:55:55.886 | client: ADD_PLAYER 0 (OregyenDuero [OWL], 00039C86) status 6 team 1 group 1178422
23:55:55.886 | client: ADD_PLAYER 1 (R0gue, 0012768A) status 6 team 2 group 1178451
23:55:55.886 | client: ADD_PLAYER 2 (g4borg [OWL], 0003A848) status 1 team 1 group 1178422
23:55:55.886 | client: ADD_PLAYER 3 (WladTepes, 001210D8) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 4 (oberus [], 000FE9B2) status 6 team 2
23:55:55.886 | client: ADD_PLAYER 5 (TheGuns58, 00121C58) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 6 (Belleraphon, 0004C744) status 2 team 2
23:55:55.886 | client: ADD_PLAYER 7 (TopoL, 00007E1F) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 8 (unicoimbraPT, 000C4FAC) status 6 team 2
23:55:55.886 | client: ADD_PLAYER 9 (AeroBobik [], 00082047) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 10 (Samson4321 [], 000B93AF) status 6 team 2
23:55:55.886 | client: ADD_PLAYER 11 (nol [], 00069165) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 12 (Pudwoppa, 000334A4) status 2 team 2
23:55:55.886 | client: ADD_PLAYER 13 (IgorMad [], 000D2AF3) status 6 team 1
23:55:55.886 | client: ADD_PLAYER 14 (YokaI, 000F1CC9) status 6 team 2
23:55:55.886 | client: ADD_PLAYER 15 (MrAnyKey [], 0012246C) status 6 team 2 group 1178451
23:55:55.886 | client: ADD_PLAYER 30 ((bot)David, 00000000) status 4 team 1
23:55:55.886 | client: ADD_PLAYER 31 ((bot)George, 00000000) status 4 team 2
23:55:55.886 | client: server assigned id 2
23:55:55.886 | client: got level load message 's1340_thar_aliendebris13'
23:55:55.889 | reset d3d device
23:55:56.487 | ReplayManager: stopping activity due to map change
23:55:56.576 | ====== starting level: 'levels\area2\s1340_thar_aliendebris13' KingOfTheHill client ======
"""
class GameLog(Log):
__slots__ = ['matcher', 'trash', '_match_id', 'values']
@classmethod
def is_handler(cls, log):
if log.get('logtype', None) == '': # we handle only logs with empty logtype.
return cls._is_handler(log)
return False
@classmethod
def _is_handler(cls, log):
return False
def __init__(self, values=None):
self.values = values
def unpack(self):
self._match_id = None
# unpacks the data from the values.
if hasattr(self, 'matcher') and self.matcher:
matchers = self.matcher
if not isinstance(matchers, list):
matchers = [matchers,]
for i, matcher in enumerate(matchers):
m = matcher.match(self.values.get('log', ''))
if m:
self.values.update(m.groupdict())
self._match_id = i
return True
# unknown?
self.trash = True
class WarningLog(Log):
__slots__ = ['trash',]
trash = True
@classmethod
def is_handler(cls, log):
if log.get('logtype', None) == L_WARNING:
return True
return False
def __init__(self, values=None):
pass
########################################################################################################
# Individual logs.
class SteamInitialization(GameLog):
matcher = []
class MasterServerSession(GameLog):
matcher = [
re.compile(r"^MasterServerSession\:\sconnect\sto\sdedicated\sserver(?:,\s|session\s(?P<session_id>\d+)|at addr (?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+))+"),
]
@classmethod
def _is_handler(cls, log):
if log.get('log', '').startswith('MasterServerSession'):
return True
return False
class ClientInfo(GameLog):
# Note: clinfo holds the subtype of this packet.
matcher = [
# connecting; addr, port
re.compile(r"^client\:\sstart\s(?P<clinfo>connecting)\sto\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+)\.\.\."),
# connected; addr, port
re.compile(r"^client\:\s(?P<clinfo>connected)\sto\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+).*"),
# ADD_PLAYER; pnr, player, clantag, player_id, status, team, group
re.compile(r"^client\:\s(?P<clinfo>ADD_PLAYER)\s+(?P<pnr>\d+)\s+\((?P<player>[^\s\,]+)(?:\s\[(?P<clantag>\w+)\],|\s\[\],|,)\s(?P<player_id>\w+)\)(?:\s|status\s(?P<status>\d+)|team\s(?P<team>\d+)|group\s(?P<group>\d+))+"),
# assigned; myid
re.compile(r"^client\:\sserver\s(?P<clinfo>assigned)\sid\s(?P<myid>\d+)"),
# level; level
re.compile(r"^client\:\sgot\s(?P<clinfo>level)\sload\smessage\s'(?P<level>[^']+)'"),
# leave; pnr
re.compile(r"^client\:\splayer\s(?P<pnr>\d+)\s(?P<clinfo>leave)\sgame"),
# avgPing; avg_ping, avg_packet_loss, avg_snapshot_loss
re.compile(r"^client\:\s(?P<clinfo>avgPing)\s(?P<avg_ping>[^;]+)(?:\;|\s|avgPacketLoss\s(?P<avg_packet_loss>[^;]+)|avgSnapshotLoss\s(?P<avg_snapshot_loss>[^;$]+))+"),
# closed; dr
re.compile(r"^client\:\sconnection\s(?P<clinfo>closed)\.(?:\s|(?P<dr>.*))+"),
# disconnect; addr, port, dr
re.compile(r"^client\:\s(?P<clinfo>disconnect)\sfrom\sserver\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+)\.(?:\s|(?P<dr>\w+))+"),
# ready;
re.compile(r"^client\:\ssend\s(?P<clinfo>ready)\smessage"),
# init; ping
re.compile(r"^client\:\sgot\s(?P<clinfo>init)\smessage\s+\(and\s1st\ssnapshot\)\.\sping\s(?P<ping>\d+)"),
]
@classmethod
def _is_handler(cls, log):
if log.get('log', '').startswith('client:'):
return True
return False
class StartingLevel(GameLog):
# level, gametype, unknown_gametype
matcher = [
re.compile(r"^======\sstarting\slevel\:\s'(?P<level>[^']+)'(?:\s|client|(?P<gametype>KingOfTheHill)|(?P<unknown_gametype>[^\s]+))+======"),
]
@classmethod
def _is_handler(cls, log):
if log.get('log', '').startswith('====== starting'):
return True
return False
class LevelStarted(GameLog):
matcher = []
@classmethod
def _is_handler(cls, log):
if log.get('log', '').startswith('====== level'):
return True
return False
GAME_LOGS = [] GAME_LOGS = [#SteamInitialization,
MasterServerSession,
ClientInfo,
StartingLevel,
#LevelStarted,
]

View File

@ -1,4 +1,5 @@
# #!/usr/bin/python
# -*- coding: utf-8 -*-
""" """
Author: Gabor Guzmics, 2013-2014 Author: Gabor Guzmics, 2013-2014
@ -30,6 +31,9 @@ class LogFile(object):
def set_data(self, data): def set_data(self, data):
self._data = data self._data = data
def _unset_data(self):
self._data = None
def parse(self): def parse(self):
# parse _data if we still have no lines. # parse _data if we still have no lines.
if self._data: if self._data:

View File

@ -1,3 +1,5 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
""" """
Resolves Logs. Resolves Logs.
""" """

View File

@ -9,6 +9,7 @@ class LogSession(object):
The Log-Session is supposed to save one directory of logs. The Log-Session is supposed to save one directory of logs.
It can parse its logs, and build up its internal structure into Battle Instances etc. It can parse its logs, and build up its internal structure into Battle Instances etc.
""" """
VALID_FILES = ['combat.log', 'game.log', ] # extend this to other logs.
def __init__(self, directory): def __init__(self, directory):
''' if directory is a file, it will be handled as a compressed folder ''' ''' if directory is a file, it will be handled as a compressed folder '''
@ -22,21 +23,46 @@ class LogSession(object):
# self.net_log = None # self.net_log = None
self.directory = directory self.directory = directory
self._zip_source = False self._zip_source = None
self.idstr = None # id string to identify this log instance.
self._error = False
def parse_files(self): def validate(self, contents=False):
''' parses the logfiles ''' """
# check if directory is a file - validates if the logfiles are within this package.
- sets the idstr of this object.
@todo: in-depth validation of logs, on contents=True.
"""
self._zip_source = os.path.isfile(self.directory) or False self._zip_source = os.path.isfile(self.directory) or False
v = False
try:
if self._zip_source: if self._zip_source:
self._unzip_logs() v = self._unzip_validate()
if v > 0:
self.idstr = os.path.split(self.directory)[1].replace('.zip', '').lower()
else: else:
v = self._validate_files_exist()
if v > 0:
self.idstr = os.path.split(self.directory)[1].lower()
except:
return False
return v
def parse_files(self, files=None):
''' parses the logfiles '''
# perform simple validation.
if self._zip_source is None:
self.validate(False)
if self._zip_source:
self._unzip_logs(files)
else:
if 'combat.log' in files:
self.combat_log = CombatLogFile(os.path.join(self.directory, 'combat.log')) self.combat_log = CombatLogFile(os.path.join(self.directory, 'combat.log'))
self.combat_log.read() self.combat_log.read()
self.combat_log.parse()
if 'game.log' in files:
self.game_log = GameLogFile(os.path.join(self.directory, 'game.log')) self.game_log = GameLogFile(os.path.join(self.directory, 'game.log'))
self.game_log.read() self.game_log.read()
# parse all files
self.combat_log.parse()
self.game_log.parse() self.game_log.parse()
def determine_owner(self): def determine_owner(self):
@ -47,18 +73,78 @@ class LogSession(object):
''' parses the battles ''' ''' parses the battles '''
pass pass
def _unzip_logs(self): def _unzip_logs(self, files=None):
z = zipfile.ZipFile(self.directory, "r") z = zipfile.ZipFile(self.directory, "r")
try:
for filename in z.namelist(): for filename in z.namelist():
fn = os.path.split(filename)[1] or '' fn = os.path.split(filename)[1] or ''
fn = fn.lower() fn = fn.lower()
if fn: if fn:
if fn == 'combat.log': if fn == 'combat.log' and (not files or fn in files):
self.combat_log = CombatLogFile(fn) self.combat_log = CombatLogFile(fn)
self.combat_log.set_data(z.read(filename)) self.combat_log.set_data(z.read(filename))
elif fn == 'game.log': elif fn == 'game.log' and (not files or fn in files):
self.game_log = GameLogFile(fn) self.game_log = GameLogFile(fn)
self.game_log.set_data(z.read(filename)) self.game_log.set_data(z.read(filename))
except:
self._error = True
return
finally:
z.close()
def _unzip_validate(self):
z = zipfile.ZipFile(self.directory, "r")
found = 0
for filename in z.namelist():
fn = os.path.split(filename)[1] or ''
fn = fn.lower()
if fn and fn in self.VALID_FILES:
found += 1
z.close()
return found
def _validate_files_exist(self):
found = 0
for f in self.VALID_FILES:
if os.path.exists(os.path.join(self.directory, f)):
found += 1
return found
class LogSessionCollector(object):
def __init__(self, directory):
self.initial_directory = directory
self.sessions = []
self.find_sessions()
def find_sessions(self):
for f in os.listdir(self.initial_directory):
full_dir = os.path.join(self.initial_directory, f)
if os.path.isdir(full_dir) or full_dir.lower().endswith('.zip'):
self.sessions.append(LogSession(full_dir))
def collect(self):
sessions = []
for session in self.sessions:
try:
if session.validate():
sessions.append(session)
except:
continue
return sessions
def collect_unique(self):
''' collects all sessions into a dictionary ordered by their idstr.
sessions without idstr, or already existing (first served) are omitted
parsing is not done.
'''
# note this function resets sessions to the working ones.
self.sessions = self.collect()
sessions_dict = {}
for session in self.sessions:
if session.idstr and not session.idstr in sessions_dict.keys():
sessions_dict[session.idstr] = session
return sessions_dict
@ -68,3 +154,6 @@ if __name__ == '__main__':
l_zip.parse_files() l_zip.parse_files()
print l_zip.combat_log.lines print l_zip.combat_log.lines
collector = LogSessionCollector('D:\\Users\\g4b\\Documents\\My Games\\sc\\')
print collector.collect_unique()