Skip to content

Instantly share code, notes, and snippets.

@hot-2130
Created May 3, 2019 19:29
Show Gist options
  • Select an option

  • Save hot-2130/6a5f7f7b6b963083079fa20e5cb2c943 to your computer and use it in GitHub Desktop.

Select an option

Save hot-2130/6a5f7f7b6b963083079fa20e5cb2c943 to your computer and use it in GitHub Desktop.
ブラウザ三国志 領地破棄サポート
// ==UserScript==
// @name bro3_remove_support
// @namespace bro3_remove_support
// @description ブラウザ三国志 領地破棄サポート byほっと
// @include https://*.3gokushi.jp/map.php*
// @include http://*.3gokushi.jp/map.php*
// @include https://*.3gokushi.jp/big_map.php*
// @include http://*.3gokushi.jp/big_map.php*
// @version 1.1
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @resource jqueryui_css http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css
// ==/UserScript==
// version date author
// 1.1 2018/08/29 作成開始
// to do
// 地図でボタンを押すと、破棄中の領地に印がつきます
// 右クリックで破棄ボタン、破棄キャンセルボタンが出ます
// load jQuery
jQuery.noConflict();
j$ = jQuery;
//----------//
// 変数定義 //
//----------//
// ソフトウェアバージョン
var VERSION = "1.1";
var SERVER_NAME = location.hostname.match(/^(.*)\.3gokushi/)[1];
// 特殊定数
var PROTOCOL = location.protocol;
var HOST = location.hostname; // アクセスURLホスト
var SERVICE = ''; // サービス判定が必要な場合に使用する予約定数
var SVNAME = HOST.substr(0,location.hostname.indexOf(".")) + SERVICE;
var RST_KEY = "RST_" + HOST.substr(0,HOST.indexOf("."));
var m_img_rst = 'data:image/png;base64,'+
'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';
// マップデータ保持用
var m_mapdata1 = [];
var RST_SETTING = 'rst_setting'; //設定保存
//----------------------
// メインルーチン
//----------------------
(function() {
//css定義を追加
rst_addCss();
var l_setting=rst_getValue(RST_KEY + '_' + RST_SETTING, "");
if (location.search.indexOf('type=4')!=-1){
// ボタンを設置
j$("#map-scroll").append(
"<li'>" +
"<span>" +
"<input type='button' id='rst_display2' style='margin-left: 90px;' value='破棄表示'></input>" +
"<input type='button' id='rst_hide2' style='display:none; margin-left: 90px;' value='破棄非表示'></input>" +
"</span>" +
"</li>"
);
//---------------------
// 表示ボタン
//---------------------
j$("#rst_display2").on("click", function(){
j$("#rst_display2").css({'display':'none'});
j$("#rst_hide2").css({'display':'block'});
rst_contextmenu2();
rst_remove_area2();
l_setting=true;
rst_setValue(RST_KEY + '_' + RST_SETTING, true);
});
//---------------------
// 非表示ボタン
//---------------------
j$("#rst_hide2").on("click", function(){
j$("#rst_hide2").css({'display':'none'});
j$("#rst_display2").css({'display':'block'});
rst_hide_area2();
l_setting=false;
rst_setValue(RST_KEY + '_' + RST_SETTING, false);
j$(function(){
j$('body').off('contextmenu');
});
});
if (l_setting==true){
j$('#rst_display2').click();
}
} else if (location.search.indexOf('type=6')==-1){
// ボタンを設置
j$("#change-map-scale ul").append(
"<li'>" +
"<span>" +
"<input type='button' id='rst_display' style='margin-left: 20px;' value='破棄表示'></input>" +
"<input type='button' id='rst_hide' style='display:none; margin-left: 20px;' value='破棄非表示'></input>" +
"</span>" +
"</li>"
);
//---------------------
// 表示ボタン
//---------------------
j$("#rst_display").on("click", function(){
j$("#rst_display").css({'display':'none'});
j$("#rst_hide").css({'display':'block'});
rst_contextmenu();
rst_remove_area();
l_setting=true;
rst_setValue(RST_KEY + '_' + RST_SETTING, true);
});
//---------------------
// 非表示ボタン
//---------------------
j$("#rst_hide").on("click", function(){
j$("#rst_hide").css({'display':'none'});
j$("#rst_display").css({'display':'block'});
rst_hide_area();
l_setting=false;
rst_setValue(RST_KEY + '_' + RST_SETTING, false);
j$(function(){
j$('body').off('contextmenu');
});
});
if (l_setting==true){
j$('#rst_display').click();
}
}
})();
//---------------------
// 破棄中領地画像変更
//---------------------
function rst_remove_area(){
var l_num=0;
j$("map[id=mapOverlayMap] area").each(function(index){
l_num=l_num+1;
if (j$(this).attr("onmouseover").substr(20,1)=="1"){
// 破棄フラグ="1" で画像変更
var l_strnum=""
if (l_num<10){
l_strnum= "0"+ String(l_num);
} else {
l_strnum= String(l_num);
}
if (j$("div[id=mapsAll] img[class='mapAll"+ l_strnum +"']").attr("src").indexOf("territory_b_s.png")!=-1){
j$("div[id=mapsAll] img[class='mapAll"+ l_strnum +"']").attr('src', m_img_rst);
}
}
});
}
//---------------------
// 領地画像を戻す
//---------------------
function rst_hide_area(){
j$('img[src="' + m_img_rst +'"]').attr('src','https://cdn-3gokushi.marv-games.jp/20180829-01/extend_project/w945/img/panel/territory_b_s.png');
}
//---------------------
// 破棄中領地色変更
//---------------------
function rst_remove_area2(){
j$("div[id=map51-content] ul li").each(function(index){
if ((j$(this).attr("class").indexOf("bg_my_territory"))!=-1){
if ((j$(this).find('a').attr('onmouseover').indexOf("破棄中"))!=-1){
j$(this).css('background', '#0465f7');
if(j$(this).hasClass('focused-res')){
//j$(this).addClass("rst_removemark");
j$(this).find('a').text('×');
} else {
j$(this).addClass("focused-res");
j$(this).find('a').text('×');
}
}
}
});
}
//---------------------
// 領地色を戻す
//---------------------
function rst_hide_area2(){
j$("div[id=map51-content] ul li").each(function(index){
if ((j$(this).attr("class").indexOf("bg_my_territory"))!=-1){
j$(this).css('background', '#4ea1df');
if ((j$.trim(j$(this).find('a').text()))=='×'){
//j$(this).removeClass("rst_removemark");
var match1 = j$(this).find('a').attr('onmouseover').match(/<dd>(★*[^<])<\/dd>/);
j$(this).find('a').text(match1[1].length);
}
}
});
}
//---------------------
// 右クリックメニュー作成
//---------------------
function rst_contextmenu(){
j$(function(){
j$('body').on('contextmenu',function(e){return false;});
});
//表示コンテナ作成
var l_html = "<div class='rst_my-contextmenu' id='rst_js-contextmenu'><ul id='rst_action'><li><a href='javascript:void(0);'>破棄する</a></li></ul></div>"
var rst_facContainer = j$(l_html);
j$("#change-map-scale").after(rst_facContainer);
var l_num=0;
j$("map[id=mapOverlayMap] area").each(function(index){
l_num=l_num+1;
// 青領地画像で自分の領地か判定
var l_strnum=""
if (l_num<10){
l_strnum= "0"+ String(l_num);
} else {
l_strnum= String(l_num);
}
var myContextMenu= new Object;
if (j$("div[id=mapsAll] img[class='mapAll"+ l_strnum +"']").attr("src").indexOf("territory_b_s.png")!=-1){
j$(this).on('contextmenu', function(e){
var l_setting=rst_getValue(RST_KEY + '_' + RST_SETTING, "");
if (l_setting==false){
myContextMenu = j$('#rst_js-contextmenu').get(0);
myContextMenu.classList.remove('show');
return false;
}
if (j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover").substr(20,1)=="1"){
//破棄中止に変更
j$('#rst_action').append("<li><a href='javascript:void(0);'>破棄中止</a></li>");
j$('#rst_action li:eq(0)').remove();
} else {
//破棄中止に変更
j$('#rst_action').append("<li><a href='javascript:void(0);'>破棄する</a></li>");
j$('#rst_action li:eq(0)').remove();
}
myContextMenu = j$('#rst_js-contextmenu').get(0);
var posX = e.clientX;
var posY = e.clientY;
myContextMenu.style.left = posX+'px';
myContextMenu.style.top = posY+'px';
myContextMenu.classList.add('show');
j$('#rst_action li').on("click", function(){
myContextMenu.classList.remove('show');
var search_pattern = new RegExp("rewriteAddRemoving\\('.*','.*', '.*', '.*', '(.*)', '.*', '[★]*', '.*', '.*', '.*', '.*', '.*', '.*', '.*', .*\\); overOperat");
var l_match = j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover").match(search_pattern);
var pos = l_match[1].match(/([-]*\d+),([-]*\d+)/);
var params = new Object;
params['x'] = pos[1];
params['y'] = pos[2];
if (j$(this).text()=='破棄する'){
// 破棄する
params['mode'] = 'remove';
j$.ajax({
url: PROTOCOL + '//' + location.hostname + '/territory_proc.php',
type: 'get',
datatype: 'html',
cache: false,
data: params
}).done(function(data) {
console.log('破棄処理完了');
var str=j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover");
j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover", str.substr(0, 20) + '1' + str.substr(20+1));
j$("div[id=mapsAll] img[class='mapAll"+ l_strnum +"']").attr('src', m_img_rst);
});
} else {
params['mode'] = 'cancel';
j$.ajax({
url: PROTOCOL + '//' + location.hostname + '/territory_proc.php',
type: 'get',
datatype: 'html',
cache: false,
data: params
}).done(function(data) {
console.log('破棄キャンセル処理完了');
var str=j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover");
j$("map[id=mapOverlayMap] area").eq(parseInt(l_strnum, 10)-1).attr("onmouseover", str.substr(0, 20) + '0' + str.substr(20+1));
j$("div[id=mapsAll] img[class='mapAll"+ l_strnum +"']").attr('src', 'https://cdn-3gokushi.marv-games.jp/20180829-01/extend_project/w945/img/panel/territory_b_s.png');
});
}
});
j$('document').on("click", function(){
myContextMenu.classList.remove('show');
});
});
}
});
}
//---------------------
// 右クリックメニュー作成
//---------------------
function rst_contextmenu2(){
j$(function(){
j$('body').on('contextmenu',function(e){return false;});
});
//表示コンテナ作成
var l_html = "<div class='rst_my-contextmenu' id='rst_js-contextmenu'><ul id='rst_action'><li><a href='javascript:void(0);'>破棄する</a></li></ul></div>"
var rst_facContainer = j$(l_html);
j$("#change-map-scale2").after(rst_facContainer);
var myContextMenu= new Object;
j$("div[id=map51-content] ul li").each(function(index){
if ((j$(this).attr("class").indexOf("bg_my_territory"))!=-1){
j$(this).on('contextmenu', function(e){
var l_setting=rst_getValue(RST_KEY + '_' + RST_SETTING, "");
if (l_setting==false){
myContextMenu = j$('#rst_js-contextmenu').get(0);
myContextMenu.classList.remove('show');
return false;
}
if ((j$(this).find('a').attr('onmouseover').indexOf("破棄中"))!=-1){
//破棄中止に変更
j$('#rst_action').append("<li><a href='javascript:void(0);'>破棄中止</a></li>");
j$('#rst_action li:eq(0)').remove();
} else {
//破棄中止に変更
j$('#rst_action').append("<li><a href='javascript:void(0);'>破棄する</a></li>");
j$('#rst_action li:eq(0)').remove();
}
myContextMenu = j$('#rst_js-contextmenu').get(0);
var posX = e.clientX;
var posY = e.clientY;
myContextMenu.style.left = posX+'px';
myContextMenu.style.top = posY+'px';
myContextMenu.classList.add('show');
var l_match =j$(e.currentTarget).find('a').attr('href').match(/land.php\?x=([-]*\d+)&y=([-]*\d+)#ptop/);
j$('#rst_action li').on("click", function(){
myContextMenu.classList.remove('show');
var params = new Object;
params['x'] = l_match[1];
params['y'] = l_match[2];
if (j$(this).text()=='破棄する'){
// 破棄する
params['mode'] = 'remove';
j$.ajax({
url: PROTOCOL + '//' + location.hostname + '/territory_proc.php',
type: 'get',
datatype: 'html',
cache: false,
data: params
}).done(function(data) {
console.log('破棄処理完了');
var str=j$(e.currentTarget).find('a').attr('onmouseover');
if (str.indexOf("破棄中")==-1){
j$(e.currentTarget).find('a').attr('onmouseover', str.substr(0, str.length-8)+'<dt class=\"bigmap-remove\">破棄状況</dt><dd class=\"bigmap-remove bold\">破棄中</div></dd></dl>\');');
j$(e.currentTarget).css('background', '#0465f7');
if(j$(e.currentTarget).hasClass('focused-res')){
j$(e.currentTarget).find('a').text('×');
} else {
j$(e.currentTarget).addClass("focused-res");
j$(e.currentTarget).find('a').text('×');
}
}
});
} else {
params['mode'] = 'cancel';
j$.ajax({
url: PROTOCOL + '//' + location.hostname + '/territory_proc.php',
type: 'get',
datatype: 'html',
cache: false,
data: params
}).done(function(data) {
console.log('破棄キャンセル処理完了');
var str=j$(e.currentTarget).find('a').attr('onmouseover');
if (str.indexOf("破棄中")!=-1){
j$(e.currentTarget).find('a').attr('onmouseover', str.substr(0, str.length-88)+'</dl>\');');
j$(e.currentTarget).css('background', '#4ea1df');
if ((j$.trim( j$(e.currentTarget).find('a').text()))=='×'){
var match2 = j$(e.currentTarget).find('a').attr('onmouseover').match(/<dd>(★*[^<])<\/dd>/);
j$(e.currentTarget).find('a').text(match2[1].length);
}
}
});
}
});
j$('document').on("click", function(){
myContextMenu.classList.remove('show');
});
});
}
});
}
//---------------//
// css定義の追加 //
//---------------//
function rst_addCss() {
var css =" \
.rst_removemark { \
text-decoration: line-through; \
}\
.rst_my-contextmenu {\
display: none;\
position: fixed;\
width: 100px;\
background-color: #fff;\
border: 1px solid #ccc;\
box-shadow: 1px 1px 1px rgba(0,0,0,.2);\
z-index:9999; \
}\
.rst_my-contextmenu.show {\
display: block;\
}\
.rst_my-contextmenu ul {\
list-style: none;\
padding: 10px 0;\
}\
.rst_my-contextmenu ul li a {\
padding: 4px 10px;\
font-size: 14px;\
color: #333;\
}\
";
rst_addGlobalStyle(css);
}
function rst_addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
function rst_setValue(name, value) {
value = (typeof value)[0] + value;
localStorage.setItem(name, value);
}
function rst_getValue(name, defaultvalue) {
var value = localStorage.getItem(name);
if (!value) return defaultvalue;
var type = value[0];
value = value.substring(1);
switch (type) {
case 'b':
return value == 'true';
case 'n':
return Number(value);
default:
return value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment