Created
May 10, 2017 18:29
-
-
Save insideone/4fac15190e07f04513e45c96447d4be4 to your computer and use it in GitHub Desktop.
Darkest Dungeon: получение данных предметов из Wiki и запись их в google-docs таблицу
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
Object.ksort = function(oldObject) { | |
var newObject = {}; | |
Object.keys(oldObject).sort().forEach(function(key) { | |
newObject[key] = oldObject[key]; | |
}); | |
return newObject; | |
} | |
if ( typeof Object.values == 'undefined' ) { | |
Object.values = function(oldObject) { | |
var objectValues = []; | |
Object.keys(oldObject).forEach(function(key) { | |
objectValues.push(oldObject[key]); | |
}); | |
return objectValues; | |
} | |
} | |
function alert(text) | |
{ | |
var ui = SpreadsheetApp.getUi(); | |
return ui.alert("Alert", text, ui.ButtonSet.OK); | |
} | |
function importWiki() | |
{ | |
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); | |
var sheet = spreadsheet.getSheetByName("Trinkets"); | |
var data = fetchTrinketsData(); | |
var propsListKeys = Object.keys(data.propsList); | |
var values = [], | |
notes = []; | |
// header | |
values.push([" Property →\n↓ Trinket"].concat(propsListKeys)); | |
notes.push([""].concat(Object.values(data.propsList))); | |
// trinket lines | |
data.trinkets.forEach(function(trinket, trinketNum) { | |
var line = [ | |
(trinket.className == 'All' ? '' : '['+trinket.className.substr(0, 2)+'] ') + | |
(trinket.isBacker ? '[!] ' : '') + | |
trinket.name | |
]; | |
Object.keys(data.propsList).forEach(function(propName) { | |
line.push(propName in trinket.props ? trinket.props[propName] : ""); | |
}); | |
values.push(line); | |
}); | |
// cleanup | |
sheet.getDataRange().setValue("").setNote(""); | |
// write | |
sheet | |
.getRange(1, 1, values.length, values[0].length) | |
.setValues(values); | |
sheet | |
.getRange(1, 1, 1, values[0].length) | |
.setNotes(notes); | |
} | |
function fetchTrinketsData() { | |
var wrapper = ['<table class="wikitable', '</table>']; | |
var parseList = { | |
"http://darkestdungeon.gamepedia.com/Trinkets": { | |
// 0-based | |
NAME: 1, | |
CLASS_NAME: 3, | |
PROPS: 5 | |
}, | |
"http://darkestdungeon.gamepedia.com/Backer_trinkets": { | |
NAME: 1, | |
PROPS: 2, | |
CLASS_NAME: -1 | |
} | |
}; | |
var propsAlias = { | |
"virtue chance": "VC", | |
"death blow resist": "DBR", | |
"stress healed": "SH", | |
"dmg when starving": "SDMG", | |
"heals received": "HR", | |
"move resist": "MR", | |
"bleed resist": "BDR", | |
"blight resist": "BTR", | |
"healing skills": "HS", | |
"trap disarm": "TD", | |
"max hp": "HP", | |
"disease resist": "DSSR", | |
"chance party surprised": "CPS", | |
"chance monsters surprised": "CMS", | |
"scouting chance": "SC", | |
"stun resist": "SR", | |
"ranged skills": "RS", | |
"food consumed": "FC", | |
"resolve xp": "XP", | |
"debuff resist": "DBDR", | |
"bleed skill chance": "BDSC", | |
"blight skill chance": "BTSC", | |
"debuff skill chance": "DSC", | |
"move skill chance": "MSC", | |
"stun skill chance": "SSC", | |
"transformation stress": "TS" | |
}; | |
var propsMods = { | |
"at Death\'s Door": "@D", | |
"while Camping": "@C", | |
"(Melee|Ranged) Skills": "!$1", | |
"(on|after) First Round": ":$1F", | |
"if in position (\\d)": ".$1", | |
"if (HP|Torch) (below|above) (\\d{2})%?": "?$1$2$3", | |
"vs (Eldritch|Beast|Unholy|Marked|Human|not size 1)": "+$1", | |
"to Party from skill Transform": "&T", | |
"from skill Revelation": "&R" | |
}; | |
var propRegex = new RegExp('(\\+|\\-)\\s?([\\d\\.]+)%?\\s+(('+Object.keys(propsAlias).join(')|(')+')|(\\S+))', 'i'); | |
// Список тринкетов | |
var trinkets = []; | |
// И возможных свойств | |
var propsList = {}; | |
// Спарсим со спец. страниц | |
for(var url in parseList) { | |
if ( ! parseList.hasOwnProperty(url) ) { | |
continue; | |
} | |
var isBacker = url.indexOf('Backer') != -1; | |
var COLMAP = parseList[url]; | |
var html = UrlFetchApp | |
.fetch(url) | |
.getContentText() | |
html = html | |
.substr(html.indexOf(wrapper[0])); | |
html = html.substr(0, html.indexOf(wrapper[1]) + wrapper[1].length); | |
var html = XmlService.parse(html).getRootElement(); | |
html.getChildren('tr').forEach(function(line) { | |
var tds = line.getChildren('td'); | |
if ( ! tds.length ) { | |
return; | |
} | |
var trinket = { | |
name: '', | |
className: 'All', | |
isBacker: isBacker, | |
props: {} | |
}; | |
tds.forEach(function(col, colNum) { | |
var val = ''; | |
switch(colNum) { | |
case COLMAP.NAME: | |
trinket.name = col.getText().trim(); | |
break; | |
case COLMAP.PROPS: | |
col.getChildren('ul')[0].getChildren('li').forEach(function(prop) { | |
var propText = prop.getText().trim() | |
propRawText = propText; | |
var m = propText.match(propRegex); | |
if ( m === null ) { | |
alert("Wrong trinket property: `"+propText+'`; trinket: `'+trinket.name+'`'); | |
return; | |
} | |
var propValue = (m[1] == '+' ? 1 : -1) * parseFloat(m[2]); | |
var propName = m[3].toLowerCase(); | |
if ( propName in propsAlias ) { | |
propName = propsAlias[propName]; | |
} else { | |
propName = propName.toUpperCase(); | |
} | |
propText = propText.replace(m[0], '').trim(); | |
if ( propText ) { | |
Object.keys(propsMods).forEach(function(modRegex) { | |
var m = propText.match(new RegExp(modRegex, 'i')); | |
if ( ! m ) { | |
return; | |
} | |
var postfix = propsMods[modRegex]; | |
for(var n in m) { | |
if ( n == 0 ) { continue; } | |
var mVal = m[n]; | |
if ( mVal == 'below' ) { | |
mVal = '<'; | |
} else if ( mVal == 'above' ) { | |
mVal = '>'; | |
} else if ( mVal.length > 2 ) { | |
mVal = mVal.substr(0, 1); | |
} | |
postfix = postfix.replace('$'+n, mVal); | |
} | |
if ( postfix.indexOf('$') != -1 ) { | |
alert("Postfix error: "+postfix); | |
return; | |
} | |
propName += postfix; | |
propText = propText.replace(m[0], '').trim(); | |
}); | |
} | |
if ( propText ) { | |
alert("Unknown mods: `"+propText+'`; trinket: `'+trinket.name+'`'); | |
} | |
propsList[propName] = propRawText; | |
if ( propName in trinket.props ) { | |
trinket.props[propName] += propValue; | |
} else { | |
trinket.props[propName] = propValue; | |
} | |
}); | |
break; | |
case COLMAP.CLASS_NAME: | |
trinket.className = col.getText().trim(); | |
break; | |
} | |
}); | |
trinkets.push(trinket); | |
}); | |
} | |
return {trinkets: trinkets, propsList: Object.ksort(propsList)}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment