ダメージ計算機-QB狩りオンライン用
いい武器手に入った?
/**
* Copyright QLU-KARUKARI ( http://wonderfl.net/user/QLU-KARUKARI )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kLTV
*/
package {
import flash.filters.BlurFilter;
import flash.display.Sprite;
import flash.display.*;
import flash.events.*;
import com.bit101.components.*;
import com.bit101.components.NumericStepper;
import com.bit101.components.ComboBox;
import net.wonderfl.utils.FontLoader;
import flash.text.TextFormat;
import flash.net.FileFilter;
import flash.net.FileReference;
public class FlashTest extends Sprite {
private var charaRadioArray:Array = new Array;
private var weaponRadioArray:Array = new Array;
private var fontname:String = "IPAGP";
private var charaComboBox:ComboBox;
private var chara:Chara = new Chara(-1);
private var baseStatusLabel:Label;
private var plusStatusSteps:Array = new Array();
private var weaponComboBox1:ComboBox;
private var weaponSteps1:Array;
private var weaponComboBox2:ComboBox;
private var weaponSteps2:Array;
private var outputRadio:Array = new Array();
private var addCalcDataCheck:CheckBox;
private var resultText:TextArea;
private var qbwave:Array = ['5', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100']
private var qbhp:Array = ['100','110','130','150','200','400','900','2500','3800','5100','6400']
public function FlashTest() {
var floader:FontLoader = new FontLoader();
floader.addEventListener(Event.COMPLETE, function (e:Event):void {
Style.embedFonts = true;
Style.fontName = fontname
Style.fontSize = 12;
main();
});
floader.load(fontname);
}
public function main():void{
stage.align = StageAlign.LEFT;
stage.scaleMode = StageScaleMode.EXACT_FIT;
var panel:* = new Panel(this, 0,0);
panel.setSize(stage.stageWidth, stage.stageHeight);
new Label(panel.content, 5, 5, "基礎ステータス");
var charaPanel:* = new Panel( panel,5,20 )
charaPanel.setSize( 105, 170 );
charaComboBox = new ComboBox( charaPanel.content,5,10,"キャラ選択" );
charaComboBox.width = 95;
charaComboBox.addItem( "未指定ちゃん" );
charaComboBox.addItem( Const.CHARACTER_NAME_MADOKA );
charaComboBox.addItem( Const.CHARACTER_NAME_HOMURA );
charaComboBox.addItem( Const.CHARACTER_NAME_SAYAKA );
charaComboBox.addItem( Const.CHARACTER_NAME_MAMI );
charaComboBox.addItem( Const.CHARACTER_NAME_KYOKO );
charaComboBox.addItem( Const.CHARACTER_NAME_MADOGAMI );
charaComboBox.addItem( Const.CHARACTER_NAME_MEGAHOMU );
charaComboBox.addItem( Const.CHARACTER_NAME_CHARLOTTE );
charaComboBox.addItem( Const.CHARACTER_NAME_HITOMI );
charaComboBox.addItem( Const.CHARACTER_NAME_KUROSAYA );
charaComboBox.addEventListener( Event.SELECT, changeCharaSelect );
charaComboBox.selectedIndex = 0;
charaComboBox.numVisibleItems = 11;
baseStatusLabel = new Label(charaPanel.content,5,40,"魔力"+chara.status.str+"\n精神"+chara.status.vit+"\n敏捷"+chara.status.dex+"\n幸運"+chara.status.luc);
new Label(panel.content, 5, 195, "追加ステータス");
var lvPanel:* = new Panel( panel,5,210 );
lvPanel.setSize( 105,100 );
new Label(lvPanel.content, 5, 10, "魔力");
new Label(lvPanel.content, 5, 25, "精神");
new Label(lvPanel.content, 5, 40, "敏捷");
new Label(lvPanel.content, 5, 55, "幸運");
new Label(lvPanel.content, 5, 75, "残HP");
var ns:NumericStepper = new NumericStepper(lvPanel.content, 40, 10 );
ns.width = 60;
ns.maximum = 100;
plusStatusSteps.push( ns );
ns = new NumericStepper(lvPanel.content, 40, 25 );
ns.width = 60;
ns.maximum = 100;
plusStatusSteps.push( ns );
ns = new NumericStepper(lvPanel.content, 40, 40 );
ns.width = 60;
ns.maximum = 100;
plusStatusSteps.push( ns );
ns = new NumericStepper(lvPanel.content, 40, 55 );
ns.width = 60;
ns.maximum = 100;
plusStatusSteps.push( ns );
ns = new NumericStepper(lvPanel.content, 40, 75 );
ns.width = 60;
ns.maximum = 200;
ns.minimum = 1;
ns.enabled = false;
plusStatusSteps.push( ns );
// 武器のUIをだーっと
for( var i:int = 0;i < 2; ++ i )
{
new Label(panel.content, 115+i*175, 5, "武器" + (i+1) );
var weaponPanel:* = new Panel( panel,115+i*175,20 );
weaponPanel.setSize(170,240);
var weaponComboBox:* = new ComboBox( weaponPanel.content,5,5,"射撃" );
weaponComboBox.width = 70;
weaponComboBox.addItem("射撃");
weaponComboBox.addItem("爆発");
weaponComboBox.addItem("近接");
weaponComboBox.numVisibleItems = 3;
new Label(weaponPanel.content, 5, 30, "最小ダメージ");
new Label(weaponPanel.content, 5, 45, "最大ダメージ");
new Label(weaponPanel.content, 5, 60, "射程or範囲");
new Label(weaponPanel.content, 5, 75, "攻撃速度");
new Label(weaponPanel.content, 5, 90, "リロード速度");
new Label(weaponPanel.content, 5, 105, "装弾数");
var weaponSteps:Array = new Array();
for( var j:int = 0; j < 6; ++ j ){
ns = new NumericStepper(weaponPanel.content, 85, 30 + j * 15 );
ns.width = 80;
ns.minimum = 1;
weaponSteps.push( ns );
}
weaponSteps[0].minimum = 1;
weaponSteps[1].minimum = 1;
weaponSteps[2].minimum = 16;
weaponSteps[3].minimum = 100;
weaponSteps[4].minimum = 300;
weaponSteps[5].minimum = 1;
new Label(weaponPanel.content, 5, 125, "魔力");
new Label(weaponPanel.content, 5, 140, "精神");
new Label(weaponPanel.content, 5, 155, "敏捷");
new Label(weaponPanel.content, 5, 170, "幸運");
for( var k:int = 0; k < 4; ++ k ){
ns = new NumericStepper(weaponPanel.content, 85, 125 + k * 15 );
ns.width = 80;
weaponSteps.push( ns );
}
new Label(weaponPanel.content, 5, 190, "クリティカル率");
new Label(weaponPanel.content, 5, 205, "ノックバック");
new Label(weaponPanel.content, 5, 220, "貫通");
for( var l:int = 0; l < 3; ++ l ){
ns = new NumericStepper(weaponPanel.content, 85, 190 + l * 15 );
ns.width = 80;
weaponSteps.push( ns );
}
if( i == 0 ){
weaponComboBox1 = weaponComboBox;
weaponSteps1 = weaponSteps;
weaponComboBox.addEventListener( Event.SELECT,changeWeapon1 );
}else{
weaponComboBox2 = weaponComboBox;
weaponSteps2 = weaponSteps;
weaponComboBox.addEventListener( Event.SELECT,changeWeapon2 );
}
weaponComboBox.selectedIndex = 0;
}
outputRadio.push( new RadioButton(panel.content, 5, 320, "簡易出力",true ) );
outputRadio.push( new RadioButton(panel.content, 5, 340, "詳細出力" ) );
new PushButton(panel.content, 5, 360, "計算!",onCalc );
addCalcDataCheck = new CheckBox( panel.content, 5, 385, "計算結果も\n一緒に保存" );
new PushButton(panel.content, 5, 415, "パラメータを保存",onSaveParam );
new PushButton(panel.content, 5, 440, "パラメータを読込",onLoadParam );
resultText = new TextArea(panel.content, 115, 265);
resultText.setSize(345, 195);
resultText.text = "計算結果がここに出ます。\n\n";
resultText.text += "使い方\n";
resultText.text += "①QB狩りオンラインを遊んでいい武器を手に入れる\n";
resultText.text += "②パラメータを頑張って入力する\n";
resultText.text += "③計算結果を見てニヤニヤする\n";
resultText.text += "\n";
resultText.text += "もうちょっと詳しい使い方\n";
resultText.text += "基礎ステータス欄\n";
resultText.text += " 使用しているキャラクターを選んで終わり\n";
resultText.text += " 基礎ステータスやスキルが表示されます\n";
resultText.text += " 未指定ちゃんは存在しません\n";
resultText.text += "追加ステータス欄\n";
resultText.text += " レベルアップで得られる増加分はここで入力してね\n";
resultText.text += "武器1&武器2欄\n";
resultText.text += " 装備している武器の種類とパラメータを入力してよ\n";
resultText.text += " 項目が多いけどまあがんばって\n";
resultText.text += "簡易出力\n";
resultText.text += " 使用キャラと実戦での武器の能力だけ出力します\n";
resultText.text += "詳細出力\n";
resultText.text += " やけくそにいろいろな情報を出力します\n";
resultText.text += "計算!ボタン\n";
resultText.text += " 計算して結果を出力欄に出力します\n";
resultText.text += "出力欄\n";
resultText.text += " 計算結果が出力されます 狭い?狭いよねぇ でも仕方ないからコピーしてメモ帳にでも貼りつけてね\n";
resultText.text += "パラメータを保存ボタン\n";
resultText.text += " 入力したパラメータをテキスト形式で保存します\n";
resultText.text += "パラメータを読込ボタン\n";
resultText.text += " パラメータを保存で作成したテキストファイルを読み込みます すげー楽\n";
resultText.text += "計算結果も一緒に保存\n";
resultText.text += " パラメータを保存するときに一緒に計算結果も保存します\n\n";
resultText.text += "項目解説\n";
resultText.text += "純粋総合火力\n";
resultText.text += " リロード時間を含まない1秒当たりの射撃武器・爆発武器の火力\n";
resultText.text += "戦術総合火力\n";
resultText.text += " リロード時間を含んだ1秒当たりの射撃武器・爆発武器の火力\n";
resultText.text += "総合火力\n";
resultText.text += " 近接武器の1秒当たりの火力\n";
resultText.text += " \n";
resultText.text += "QB抹殺率表(攻撃回数)\n";
resultText.text += " n回攻撃したときにQBの息の根を止めることが出来る確率の表\n";
resultText.text += " バットのような最小ダメージと最大ダメージの開きが大きい武器は抹殺率が低くなりがち\n";
resultText.text += " そのままだと見にくいのでメモ帳とかで見てください\n";
resultText.text += "純粋総合QB抹殺率・戦術総合QB抹殺率・総合QB抹殺率 表(攻撃時間)\n";
resultText.text += " n秒間攻撃したときにQBの息の根を止めることが出来る確率の表 純粋とか戦術とかつけてるけど実は自分でもよくわかっていない\n";
resultText.text += " 対QBでの武器の強さを見るにはここが一番いいと思う\n";
resultText.text += " \n";
resultText.text += "その他\n";
resultText.text += " とりあえず戦術総合火力(近接なら総合火力)が高ければ強いです。\n";
resultText.text += " でも射程や範囲やノックバックや貫通などのパラメータは火力に反映されてないので注意です。\n";
resultText.text += " すごく強いけど貫通0だったらすごく効率悪いですし貫通10でも威力がしょぼかったら全然倒せないです。\n";
resultText.text += " もっと詳しく見る場合はQB抹殺率表を参考にして下さい。\n";
resultText.text += " 総合QB抹殺率表は近接2回攻撃のさやかちゃんにやさしい仕様となっております。\n";
resultText.text += " でもやっぱり色々なパラメータが反映されていないのであくまでも参考までに。\n";
resultText.text += " \n";
resultText.text += "更新履歴 え?ここに書くの?\n";
resultText.text += " 2011/12/17 さやかがいつの間にか弱体してたのとQBがすげー強くなっているのでデータを更新\n";
resultText.text += " 2011/12/04 また変わったので対応 残HP要らなくなったけど死ぬことにさほどリスクがないから仕方が無い\n";
resultText.text += " 2011/12/03 シャルロッテに完全対応 腹パンは武器のクリティカルでどうにか\n";
resultText.text += " 2011/12/01 深夜 新キャラにうっすら対応 シャルロッテのスキルの計算が面倒なのでだいぶオミット すまぬ\n";
resultText.text += " 2011/11/10 夜 QB抹殺率は割とバグってたけどまあ色々と直して表にしてえらいことになった\n";
resultText.text += " 2011/11/09 夜 QB抹殺率を算出\n";
resultText.text += " 2011/11/08 夜とか さやかちゃんのスキルがいつの間にか変わっていたので修正 ステータスの限界値200\n";
resultText.text += " 2011/11/08 3:00 入力したパラメータをtxtで保存できるようになりました 入力がいちいち面倒くさいと常々思っていたんです\n";
resultText.text += " 2011/11/07 朝から夜にかけて いろいろ気に入らないところを直したりバグ取ったり あと宣伝\n";
resultText.text += " 2011/11/07 3:00ぐらい とりあえず完成\n";
resultText.text += " \n\n\n\nここだけの話、実はまどマギ見たこと無いです……。";
return;
}
private function changeCharaSelect(Boolean:Event):void{
chara = new Chara( charaComboBox.selectedIndex );
baseStatusLabel.text = "魔力"+chara.status.str+"\n精神"+chara.status.vit+"\n敏捷"
+chara.status.dex+"\n幸運"+chara.status.luc + "\n\n" + chara.skillText;
}
private function changeWeapon1( Boolean:Event ):void{
switch( weaponComboBox1.selectedIndex ){
case 0:
weaponSteps1[3].minimum = 100;
weaponSteps1[4].enabled = true;
weaponSteps1[5].enabled = true;
weaponSteps1[12].enabled = true;
break;
case 1:
weaponSteps1[3].minimum = 100;
weaponSteps1[4].enabled = true;
weaponSteps1[5].enabled = true;
weaponSteps1[12].enabled = false;
break;
case 2:
weaponSteps1[3].minimum = 300;
weaponSteps1[4].enabled = false;
weaponSteps1[5].enabled = false;
weaponSteps1[5].value = 1;
weaponSteps1[12].enabled = false;
break;
default:
break;
}
}
private function changeWeapon2( Boolean:Event ):void{
switch( weaponComboBox2.selectedIndex ){
case 0:
weaponSteps2[3].minimum = 100;
weaponSteps2[4].enabled = true;
weaponSteps2[5].enabled = true;
weaponSteps2[12].enabled = true;
break;
case 1:
weaponSteps2[3].minimum = 100;
weaponSteps2[4].enabled = true;
weaponSteps2[5].enabled = true;
weaponSteps2[12].enabled = false;
break;
case 2:
weaponSteps2[3].minimum = 300;
weaponSteps2[4].enabled = false;
weaponSteps2[5].enabled = false;
weaponSteps2[5].value = 1;
weaponSteps2[12].enabled = false;
break;
default:
break;
}
}
private function onCalc( Boolean:Event ):void{
calc();
}
private function calc():void{
// UIからデータを読み込む
chara = new Chara( charaComboBox.selectedIndex );
var weaponSteps:Array;
var weaponComboBox:ComboBox;
var i:int;
for( i = 0; i < 2; ++ i )
{
if( i == 0 ){
weaponSteps = weaponSteps1;
weaponComboBox = weaponComboBox1;
}else{
weaponSteps = weaponSteps2;
weaponComboBox = weaponComboBox2;
}
// 武器パラメータを元にインスタンス化
var weapon:* = new Weapon(int(weaponComboBox.selectedIndex),String(weaponComboBox.selectedItem),int(weaponSteps[0].value),
int(weaponSteps[1].value), int(weaponSteps[2].value), int(weaponSteps[3].value),int(weaponSteps[4].value),int(weaponSteps[5].value),
int(weaponSteps[6].value), int(weaponSteps[7].value), int(weaponSteps[8].value),int(weaponSteps[9].value),
int(weaponSteps[10].value),int(weaponSteps[11].value),int(weaponSteps[12].value) )
chara.weapons.push(weapon);
}
chara.sumStatus(new Status( plusStatusSteps[0].value, plusStatusSteps[1].value, plusStatusSteps[2].value, plusStatusSteps[3].value ));
chara.status.setHP( plusStatusSteps[4].value );
// 計算しながら出力していく
var text:String = "■ステータス\n["+chara.name+"]"+"(キャラクター)\n";
if( outputRadio[1].selected ){
if( chara.type != 0 ){
text += "[" + chara.skillText2 + "] (固有スキル)\n";
}
text += "[" + chara.status.str + "](魔力) [" + chara.status.vit
+ "](精神) [" + chara.status.dex + "](敏捷) [" + chara.status.luc + "] (幸運)\n";
text += "[" + chara.status.hp + "](HP) [" + chara.getRecoverTime()
+ "](復活時間[秒]) [" + chara.getMoveSpeed() + "](移動速度[1秒当たり])\n";
}
text += "\n";
for( i = 0; i < 2; ++ i ){
// 基礎能力
if( outputRadio[1].selected ){
text += "◇" + chara.weapons[i].text + "武器"+(i+1)+"の基礎能力\n";
text += "[最小:" + chara.weapons[i].minDam
+ ",最大:" + chara.weapons[i].maxDam + "] (1発当たりの通常ダメージ)\n";
if( chara.weapons[i].type == Const.ATTACKTYPE_EXPLOSIVE ){
text += "[" + chara.weapons[i].range + "] (爆発範囲) \n"
}else{
text += "[" + chara.weapons[i].range + "] (射程距離) \n"
}
if( chara.weapons[i].type == Const.ATTACKTYPE_MELEE ){
text += "["+chara.weapons[i].reloadRate+"] (攻撃速度[ミリ秒])\n";
}else {
text += "["+chara.weapons[i].attackRate+"] (攻撃速度[ミリ秒])\n";
text += "["+chara.weapons[i].reloadRate+"] (リロード速度[ミリ秒])\n";
text += "["+chara.weapons[i].maxAmmo+"] (装弾数)\n";
}
if( chara.weapons[i].status.str != 0 ){
text += "[" + chara.weapons[i].status.str + "](魔力) ";
}
if( chara.weapons[i].status.vit != 0 ){
text += "[" + chara.weapons[i].status.vit + "](精神) ";
}
if( chara.weapons[i].status.dex != 0 ){
text += "[" + chara.weapons[i].status.dex + "](敏捷) ";
}
if( chara.weapons[i].status.luc != 0 ){
text += "[" + chara.weapons[i].status.luc + "](幸運)";
}
if( chara.weapons[i].status.str != 0 || chara.weapons[i].status.vit != 0 || chara.weapons[i].status.dex != 0 || chara.weapons[i].status.luc != 0 ){
text += "\n";
}
if( chara.weapons[i].criticalRate != 0 ){
text += "[" + chara.weapons[i].criticalRate + "] (クリティカル率[%])\n";
}
if( chara.weapons[i].knockback != 0 ){
text += "[" + chara.weapons[i].knockback + "](ノックバック) \n";
}
if( chara.weapons[i].penetration > 0 ){
text += "[" + chara.weapons[i].penetration + "] (貫通[匹])\n";
}
}
// 実戦での武器の能力
text += "\n◆" + chara.weapons[i].text + "武器"+(i+1)+"の実戦能力\n";
text += "[最小:" + chara.getAttackDamage(i,0,false) + ",平均:" + chara.getAttackDamage(i,0.5,false) +
",最大:" + chara.getAttackDamage(i,1.0,false) + "] (1発当たりの通常ダメージ)\n";
if( chara.getFinalCriticalRate(i) > 0 ){
text += "[最小:" + chara.getAttackDamage(i,0.0,true) + ",平均:" + chara.getAttackDamage(i,0.5,true) +
",最大:" + chara.getAttackDamage(i,1.0,true) + "] (1発当たりのクリティカルダメージ)\n";
}
text += "[" + chara.getExpectedDamage(i) +"] (1発当たりの期待ダメージ)\n";
if( chara.weapons[i].type == Const.ATTACKTYPE_MELEE ){
text += "[" + chara.getTTFP(i) +"] (総合火力[ダメージ/秒])\n";
}else{
text += "[" + chara.getPTFP(i) +"] (純粋総合火力[ダメージ/秒])\n";
text += "[" + chara.getTTFP(i) +"] (戦術総合火力[ダメージ/秒])\n";
}
// 射程or爆発範囲
if( chara.weapons[i].type == Const.ATTACKTYPE_EXPLOSIVE ){
text += "[" + chara.getRange(i) + "] (爆発範囲) QB約"
+ chara.getRangeQBRatio(i)+ "匹分\n" ;
}else if(chara.weapons[i].type == Const.ATTACKTYPE_SHOOTING && chara.type == Const.CHARACTER_HOMURA ){
text += "[" + "無限" +"]\n";
}else{
text += "[" + chara.getRange(i) + "] (射程距離) QB約"
+ chara.getRangeQBRatio(i)+ "匹分 "
+ chara.getRangeScreenRatio(i) + "%\n";
}
// 近接武器は攻撃速度
// 射撃爆発はリロード速度のみ
if( chara.weapons[i].type == Const.ATTACKTYPE_MELEE ){
// さやかと黒さやの近接武器はどちらも表示
if( chara.type == Const.CHARACTER_SAYAKA || chara.type == Const.CHARACTER_KUROSAYA ){
text += "["+chara.getAttackRate(i)+"] (2回攻撃速度[ミリ秒])\n";
text += "["+chara.getReloadRate(i)+"] (攻撃(リロード)速度[ミリ秒])\n";
text += "[" + chara.getMaxAmmo(i)+ "] (攻撃回数)\n";
}else{
text += "["+chara.getReloadRate(i)+"] (攻撃速度[ミリ秒])\n";
}
}else{
// 射撃爆発
if( chara.type == Const.CHARACTER_MEGAHOMU ){
// メガほむは射撃爆発も攻撃速度が上がるので表示
text += "["+chara.getAttackRate(i)+"] (攻撃速度[ミリ秒])\n";
}
text += "["+chara.getReloadRate(i)+"] (リロード速度[ミリ秒])\n";
text += "["+chara.getMaxAmmo(i)+"] (装弾数)\n";
}
if( chara.getFinalCriticalRate(i) > 0 ){
text += "[" + chara.getFinalCriticalRate(i) + "] (クリティカル率[%])\n";
}
if( chara.getKnockback(i) > 0 ){
text += "[" + chara.getKnockback(i) +"] (ノックバック) QB約" + chara.getKnockbackQBRatio(i) + "匹分\n";
}
if( chara.weapons[i].type == Const.ATTACKTYPE_SHOOTING ){
if( chara.getPenetration(i) > 0 ){
text += "[" + chara.getPenetration(i) +"] (貫通[匹])\n";
}
}
// QB抹殺率の算出
var m:int,n:int;
var numbercr:Number = chara.getFinalCriticalRate(i) / 100;
var killRatio:Number,killRatioCrit:Number,finalKillRatio:Number;
if( outputRadio[1].selected )
{
text += "☆QB抹殺率表 難易度[wave] 抹殺率[率] |で区切られるごとに攻撃回数+1\n";
for( m=0; m < qbwave.length; ++ m ){
text += "[" + qbwave[m] + "] [";
for( n=1; n < 21; ++ n ){
// ノーマルな当たり方
killRatio = ( chara.calcKillRatio( qbhp[m],i,n,false ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,n,false ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,n,false ) * 0.075 );
// クリティカル
killRatioCrit = ( chara.calcKillRatio( qbhp[m],i,n,true ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,n,true ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,n,true ) * 0.075 );
finalKillRatio = ( killRatio * (1 - numbercr ) + killRatioCrit * numbercr );
text += Math.round(finalKillRatio*10000)/100 + "|";
if( Math.round(finalKillRatio*10000)/100 >= 100 ){
text += n + "回で確殺";
break;
}
}
text += "]\n";
}
// 純粋総合QB抹殺率
// 戦術総合QB抹殺率
// 総合QB抹殺率
// 純粋秒間攻撃回数(近接以外)
var patks:Number = chara.getPATKS(i);
// 総合秒間攻撃回数(近接の場合は秒間攻撃回数)
var tatks:Number = chara.getTATKS(i);
// waveごとの純粋総合QB抹殺率を求める 近接武器はやらない
if( chara.weapons[i].type != Const.ATTACKTYPE_MELEE ){
text += "★純粋総合QB抹殺率表 難易度[wave] 抹殺率[率] |で区切られるごとに攻撃時間+1秒\n";
for( m=0; m < qbwave.length; ++ m ){
text += "[" + qbwave[m] + "] [";
for( n=1; n < 11; ++ n ){
// ノーマルな当たり方
killRatio = ( chara.calcKillRatio( qbhp[m],i,patks*n,false ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,patks*n,false ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,patks*n,false ) * 0.075 );
// クリティカル
killRatioCrit = ( chara.calcKillRatio( qbhp[m],i,patks*n,true ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,patks*n,true ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,patks*n,true ) * 0.075 );
finalKillRatio = ( killRatio * (1 - numbercr ) + killRatioCrit * numbercr );
text += Math.round(finalKillRatio*10000)/100 + "|";
if( Math.round(finalKillRatio*10000)/100 >= 100 ){
break;
}
}
text += "]\n";
}
}
if( chara.weapons[i].type == Const.ATTACKTYPE_MELEE ){
text += "★総合QB抹殺率表 難易度[wave] 抹殺率[率] |で区切られるごとに攻撃時間+1秒\n";
}else{
text += "★戦術総合QB抹殺率表 難易度[wave] 抹殺率[率] |で区切られるごとに攻撃時間+1秒\n";
}
for( m=0; m < qbwave.length; ++ m ){
text += "[" + qbwave[m] + "] [";
for( n=1; n < 11; ++ n ){
// ノーマルな当たり方
killRatio = ( chara.calcKillRatio( qbhp[m],i,tatks*n,false ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,tatks*n,false ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,tatks*n,false ) * 0.075 );
// クリティカル
killRatioCrit = ( chara.calcKillRatio( qbhp[m],i,tatks*n,true ) * 0.85 +
chara.calcKillRatio( qbhp[m]*0.75,i,tatks*n,true ) * 0.075 +
chara.calcKillRatio( qbhp[m]*5,i,tatks*n,true ) * 0.075 );
finalKillRatio = ( killRatio * (1 - numbercr ) + killRatioCrit * numbercr );
text += Math.round(finalKillRatio*10000)/100 + "|";
if( Math.round(finalKillRatio*10000)/100 >= 100 ){
break;
}
}
text += "]\n";
}
}
text += "\n";
}
resultText.text = text;
}
private var fr:FileReference;
private function onSaveParam( Boolean:Event ):void{
fr = new FileReference();
saveparam()
}
private function saveparam():void{
// 保存したいデータを回収
var savedata:String = "";
savedata += charaComboBox.selectedIndex.toString() + ",";
savedata += plusStatusSteps[0].value.toString() + ",";
savedata += plusStatusSteps[1].value.toString() + ",";
savedata += plusStatusSteps[2].value.toString() + ",";
savedata += plusStatusSteps[3].value.toString() + ",";
savedata += plusStatusSteps[4].value.toString() + ",";
for( var i:int = 0; i < 2; ++ i )
{
var weaponSteps:Array;
var weaponComboBox:ComboBox;
var weaponStatus:Status;
if( i == 0 ){
weaponSteps = weaponSteps1;
weaponComboBox = weaponComboBox1;
}else{
weaponSteps = weaponSteps2;
weaponComboBox = weaponComboBox2;
}
savedata += weaponComboBox.selectedIndex.toString() + ",";
for( var j:int=0; j < 13; ++ j ){
savedata += weaponSteps[j].value.toString() + ",";
}
}
savedata += outputRadio[0].selected.toString() + ",";
savedata += outputRadio[1].selected.toString() + ",";
savedata += addCalcDataCheck.selected.toString() + ",";
savedata += "パラメータ保存用文字列終わり,";
// セーブする 超簡単
//var fr:FileReference=new FileReference();
if( addCalcDataCheck.selected )
{
calc();
savedata += "\n\n" + resultText.text;
//Windowsの改行に置換 linuxとかmacはようわからん
savedata = savedata.replace(/\r/g, "\r\n");
}
fr.save(savedata, "qbhuntparam.txt"); // ダイアログを表示する
}
private function onLoadParam(Boolean:Event):void{
fr = new FileReference();
fr.addEventListener(Event.SELECT, onSelect);
var filter:Array = [new FileFilter("テキストファイル","*.txt")];
fr.browse(filter);
// ([{description: "Images", extension: "*.jpg;*.gif;*.png"},
// {description: "SWF files", extension: "*.swf"},
// {description: "Documents", extension: "*.doc;*.pdf"}]);
}
private function onSelect(e:Event):void{
// イベントリスナーを追加
fr.addEventListener(Event.COMPLETE,onComplete);
fr.load(); // 読み込み処理を開始
}
private function onComplete(e:Event):void{
fr.removeEventListener(Event.COMPLETE,onComplete)
loadparam();
}
private function loadparam():void{
if( fr.type == ".txt" || fr.type == ".TXT" ){
}
else{
return;
}
var loadData:String = fr.data.toString();
var data:Array = loadData.split(",",36);
while( data.length < 36 )
{
data.push("1");
}
charaComboBox.selectedIndex = parseInt( data.shift() );
plusStatusSteps[0].value = parseInt( data.shift() );
plusStatusSteps[1].value = parseInt( data.shift() );
plusStatusSteps[2].value = parseInt( data.shift() );
plusStatusSteps[3].value = parseInt( data.shift() );
plusStatusSteps[4].value = parseInt( data.shift() );
for( var i:int = 0; i < 2; ++ i )
{
var weaponSteps:Array;
var weaponComboBox:ComboBox;
var weaponStatus:Status;
if( i == 0 ){
weaponSteps = weaponSteps1;
weaponComboBox = weaponComboBox1;
}else{
weaponSteps = weaponSteps2;
weaponComboBox = weaponComboBox2;
}
weaponComboBox.selectedIndex = parseInt( data.shift() );
for( var j:int=0; j < 13; ++ j ){
weaponSteps[j].value = parseInt( data.shift() );
}
}
outputRadio[0].selected = ( data.shift() == "false" ? false : true );
outputRadio[1].selected = ( data.shift() == "false" ? false : true );
addCalcDataCheck.selected = ( data.shift() == "false" ? false : true );
calc();
}
}
}
class Status{
public var str:int;
public var vit:int;
public var dex:int;
public var luc:int;
public var hp:int;// 残りHP(charlotte専用)
public function Status( s:int = 100,v:int = 100,d:int = 100,l:int = 100){
str = s;
vit = v;
dex = d;
luc = l;
hp = vit;
}
public function add(status:Status):void{
str += status.str;
vit += status.vit;
dex += status.dex;
luc += status.luc;
str = Math.min( str,200 );
vit = Math.min( vit,200 );
dex = Math.min( dex,200 );
luc = Math.min( luc,200 );
hp = vit;
}
public function setHP(h:int):void{
if( h > vit ){ h = vit; }
if( h < 1 ){ h=1; }
hp = h;
}
}
class Chara{
public var type:int;
public var status:Status;
public var skillText:String;
public var skillText2:String;
public var name:String;
public var weapons:Array;
public function Chara( ltype:int ){
weapons = new Array;
type = ltype;
switch( ltype ){
case Const.CHARACTER_MADOKA:
status = new Status(120,120,120,120);
name = Const.CHARACTER_NAME_MADOKA;
skillText = "射撃武器の\n貫通力2倍";
skillText2 = "射撃武器の貫通力2倍";
break;
case Const.CHARACTER_HOMURA:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_HOMURA;
skillText = "射撃武器の\n射程無限\n\n装弾数+100%";
skillText2 = "射撃武器の射程無限,装弾数+100%";
break;
case Const.CHARACTER_SAYAKA:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_SAYAKA;
skillText = "近接武器2回攻撃\n\n戦闘不能時\n回復3倍";
skillText2 = "近接武器2回攻撃,戦闘不能時回復3倍";
break;
case Const.CHARACTER_MAMI:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_MAMI;
skillText = "ダメージ+50%\n\nクリティカル率\n+15%";
skillText2 = "ダメージ+50%,クリティカル率+15%";
break;
case Const.CHARACTER_KYOKO:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_KYOKO;
skillText = "近接武器の\n射程+40%\n\nノックバック+8";
skillText2 = "近接武器の射程+40%,ノックバック+8";
break;
case Const.CHARACTER_MADOGAMI:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_MADOGAMI;
skillText = "リロード速度+50%";
skillText2 = "リロード速度+50%";
break;
case Const.CHARACTER_MEGAHOMU:
status = new Status(120,120,120,120);
name = Const.CHARACTER_NAME_MEGAHOMU;
skillText = "爆発武器の\n範囲+20%\n\n攻撃速度+30%";
skillText2 = "爆発武器の範囲+20%,攻撃速度+30%";
break;
case Const.CHARACTER_CHARLOTTE:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_CHARLOTTE;
skillText = "移動速度+50%\n\n接触したQBを\n捕食する";
skillText2 = "移動速度+50%,接触したQBを捕食する";
break;
case Const.CHARACTER_HITOMI:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_HITOMI;
skillText = "戦闘不能時\n毒ガス発生\n\n近距離で常に\nクリティカル";
skillText2 = "戦闘不能時毒ガス発生,近距離で常にクリティカル";
break;
case Const.CHARACTER_KUROSAYA:
status = new Status(100,100,100,100);
name = Const.CHARACTER_NAME_KUROSAYA;
skillText = "近接武器2回攻撃\n\n被ダメージ上限10";
skillText2 = "近接武器2回攻撃,被ダメージ上限10";
break;
default:
status = new Status(100,100,100,100);
name = "未指定ちゃん";
skillText = "";
skillText2 = "";
break;
}
}
// 元々のステータスにレベルアップ追加分のステータスと武器1武器2のステータスを加算
public function sumStatus(lstatus:Status):void{
status.add( lstatus );
status.add( weapons[0].status );
status.add( weapons[1].status );
}
public function getRecoverTime():Number{
var recoverTime:int = Const.PLAYER_RECOVER_TIME * 100 / status.vit;
if( type == Const.CHARACTER_SAYAKA ){
recoverTime /= 2;
}
var rtSecond:Number = recoverTime/1000;
return Math.round( rtSecond*100 ) / 100;
}
public function getMoveSpeed():int{
var moveSpeed:int = Const.PLAYER_SPEED * status.dex / 100;
if( type == Const.CHARACTER_CHARLOTTE ){
moveSpeed *= 1.5;
}
return moveSpeed;
}
// 実際に攻撃した際のダメージを取得
public function getAttackDamage( weaponNumber:int,rndRate:Number,isCritical:Boolean):int{
var result:Number = weapons[weaponNumber].minDam+(weapons[weaponNumber].rndDam)*rndRate;
if( type == Const.CHARACTER_MAMI ){
result *= 1.5;
}
result *= status.str / 100;
if( isCritical ){result*=5;}
return result;
}
public function getFinalCriticalRate( weaponNumber:int ):int{
var finalCriticalRate:int = Math.min( weapons[weaponNumber].criticalRate * status.luc / 100,100 );
if( type == Const.CHARACTER_MAMI ){
finalCriticalRate += 15;
}
return finalCriticalRate;
}
public function getExpectedDamage( weaponNumber:int ):int{
// 最終ダメージ(通常)
var finalAverageDamage:Number = getAttackDamage(weaponNumber,0.5,false);
// 最終ダメージ(クリティカル)
var finalAverageDamageCritical:Number = getAttackDamage(weaponNumber,0.5,true);
// 期待値
var expectedDamage:int =
int( finalAverageDamage * ( 100 - getFinalCriticalRate(weaponNumber) ) / 100 +
finalAverageDamageCritical * getFinalCriticalRate(weaponNumber) / 100);
return expectedDamage;
}
public function getAttackRate( weaponNumber:int ):int{
if( type == Const.ATTACKTYPE_MELEE )
{
return weapons[weaponNumber].attackRate;
}
var result:int = weapons[weaponNumber].attackRate;
if (type == Const.CHARACTER_MEGAHOMU) {
result = Math.max(100, result * 100 / 130);
}
return result;
}
public function getReloadRate(weaponNumber:int):int {
var dex:int = status.dex;
// dexも一部のキャラは補正
if( weapons[weaponNumber].type == Const.ATTACKTYPE_MELEE && type == Const.CHARACTER_MEGAHOMU ){
dex+=30;
}
if( weapons[weaponNumber].type != Const.ATTACKTYPE_MELEE && type == Const.CHARACTER_MADOGAMI ){
dex+=50;
}
return Math.max(150, weapons[weaponNumber].reloadRate * 100 / dex);
}
public function getMaxAmmo(weaponNumber:int):int {
var maxAmmo:int = weapons[weaponNumber].maxAmmo;
// 弾数をキャラによって補正
if( weapons[weaponNumber].type != Const.ATTACKTYPE_MELEE && type == Const.CHARACTER_HOMURA ){
maxAmmo *= 2;
}
if( weapons[weaponNumber].type == Const.ATTACKTYPE_MELEE && ( type == Const.CHARACTER_SAYAKA || type == Const.CHARACTER_KUROSAYA) ){
maxAmmo ++;
}
return maxAmmo;
}
// 純粋総合火力 PureTotalFirePower-PTFP-
public function getPTFP( weaponNumber:int ):int{
if( weapons[weaponNumber].type == Const.ATTACKTYPE_MELEE ){
return 0;// 近接の火力はTTFPで求めてね
}
var ptfp:Number = getExpectedDamage(weaponNumber) * 1000/getAttackRate(weaponNumber);
return int(ptfp);
}
//戦術総合火力(TacticalTotalFirePower-TTFP-)
public function getTTFP( weaponNumber:int ):int{
var ttfp:Number;
ttfp = getExpectedDamage(weaponNumber)*getMaxAmmo(weaponNumber) * 1000 /
((getMaxAmmo(weaponNumber)-1)*getAttackRate(weaponNumber)+(getReloadRate(weaponNumber)));
return int( ttfp );
}
public function getRange( weaponNumber:int ):Number{
var range:int = weapons[weaponNumber].range;
// メガほむなら爆発武器の範囲+
if (weapons[weaponNumber].type == Const.ATTACKTYPE_EXPLOSIVE && type == Const.CHARACTER_MEGAHOMU) {
range *= 1.2;
}
// 杏子なら近接武器の射程+
if (weapons[weaponNumber].type == Const.ATTACKTYPE_MELEE && type == Const.CHARACTER_KYOKO) {
range *= 1.4;
}
return range
}
// rangeのQB比を求める 爆発範囲の場合は面積
public function getRangeQBRatio( weaponNumber:int ):Number{
if( weapons[weaponNumber].type == Const.ATTACKTYPE_EXPLOSIVE ){
return Math.round( (getRange(weaponNumber) * getRange(weaponNumber) / (Const.QBWIDTH* Const.QBHEIGHT ) * 100) ) / 100;
}else{
return Math.round( (getRange(weaponNumber) / Const.QBWIDTH * 100) ) / 100;
}
}
// スクリーン比で返す
public function getRangeScreenRatio( weaponNumber:int ):Number{
return Math.round( (getRange(weaponNumber) / Const.SCREENWIDTH * 10000) ) / 100;
}
public function getKnockback( weaponNumber:int ):Number{
var knockback:* = weapons[weaponNumber].knockback * status.str / 100;
if( weapons[weaponNumber].type == Const.ATTACKTYPE_MELEE && type == Const.CHARACTER_KYOKO){
knockback += 8;
}
return int(knockback);
}
public function getKnockbackQBRatio( weaponNumber:int ):Number{
return Math.round( getKnockback(weaponNumber) / Const.QBWIDTH *100 ) / 100;
}
public function getPenetration( weaponNumber:int ):int{
var p:int = weapons[weaponNumber].penetration;
if( type == Const.CHARACTER_HOMURA ){
p *= 2;
}
return p;
}
// 抹殺率を計算する
// hp:奴のHP weaponNumber:武器1か武器2か isCritical:クリティカルか? attackNum:攻撃回数
public function calcKillRatio( hp:Number,weaponNumber:int,attacknum:Number,isCritical:Boolean ):Number{
var mindam:* = getAttackDamage(weaponNumber,0.0,isCritical);
var maxdam:* = getAttackDamage(weaponNumber,1.0,isCritical);
var wrdnp:Number = (maxdam-mindam)*attacknum+1;
return Math.max(Math.min( (wrdnp - (hp-mindam*attacknum) ) / wrdnp ,1),0);
}
// 純粋秒間攻撃回数(近接以外)??
public function getPATKS(weaponNumber:int):Number{
return 1000 / getAttackRate(weaponNumber);
}
// 総合秒間攻撃回数
public function getTATKS(weaponNumber:int):Number{
// 総合秒間攻撃回数(近接の場合は秒間攻撃回数)
return 1000 /
( ( (getMaxAmmo(weaponNumber)-1 ) * getAttackRate(weaponNumber)
+ ( getReloadRate(weaponNumber)*100 / status.dex ) ) / getMaxAmmo(weaponNumber) );
}
}
class Weapon{
public var type:int;
public var text:String;
public var minDam:int;
public var maxDam:int;
public var rndDam:int;
public var range:int;
public var attackRate:int;
public var reloadRate:int;
public var maxAmmo:int;
public var criticalRate:int;
public var knockback:int;
public var penetration:int;
public var status:Status;
public function Weapon( ltype:int,ltext:String,lminDam:int,lmaxDam:int,lrange:int,
lattackRate:int,lreloadRate:int,lmaxAmmo:int,
s:int,v:int,d:int,l:int,
lcriticalRate:int,lknockback:int,lpenetration:int ){
type = ltype;
text = ltext;
minDam = lminDam;
maxDam = lmaxDam;
range = lrange;
attackRate = lattackRate;
reloadRate = lreloadRate;
maxAmmo = lmaxAmmo;
status = new Status(s,v,d,l);
criticalRate = lcriticalRate;
knockback = lknockback;
penetration = lpenetration;
rndDam = maxDam-minDam;
if( type == Const.ATTACKTYPE_MELEE ){
reloadRate = attackRate;
attackRate = 150;// 近接武器の隠しパラメータ的な?
}
}
}
// 以下QB狩りONLINEからコピペ
class Const {
public static const QBWIDTH:int = 28;//BOUNDS_HALF_WIDTH*2 この3つは違うとこから持ってきた
public static const QBHEIGHT:int = 20;// BOUNDS_HEIGHT
public static const SCREENWIDTH:int = 465;// たぶん465
// プレイフィールドの設定
public static const FIELD_SIZE:int = 300;
public static const FIELD_OFFSET_X:int = 100;
public static const FIELD_OFFSET_Y:int = 165;
public static const FIELD_LFET_BOUND:int = -160;
public static const FIELD_RIGHT_BOUND:int = 370;
public static const FIELD_WAVE_TIME:int = 30000; //(ms)
public static const FIELD_WAVE_SPAWN_TIME:int = 25000; //(ms)
public static const FIELD_QB_QUOTA:int = 20;
// プレイヤーの基礎値
public static const PLAYER_SPEED:Number = 60; //(px/s)
public static const PLAYER_SWAP_TIME:int = 500; //(ms)
public static const PLAYER_INVINCIBLE_TIME_ON_DAMAGED:int = 250; //(ms)
public static const PLAYER_INVINCIBLE_TIME_ON_RECOVER:int = 3000; //(ms)
public static const PLAYER_RECOVER_TIME:int = 20000; //(ms)
public static const PLAYER_SEND_INTERVAL:int = 1000; //(ms)
// キャラクターのID
public static const CHARACTER_MADOKA:int = 1;
public static const CHARACTER_HOMURA:int = 2;
public static const CHARACTER_SAYAKA:int = 3;
public static const CHARACTER_MAMI:int = 4;
public static const CHARACTER_KYOKO:int = 5;
// public static const CHARACTER_QB:int = ;なにこいつ……
public static const CHARACTER_MADOGAMI:int = 6;
public static const CHARACTER_MEGAHOMU:int = 7;
public static const CHARACTER_CHARLOTTE:int = 8;
public static const CHARACTER_HITOMI:int = 9;
public static const CHARACTER_KUROSAYA:int = 10;
// キャラクターの名前
public static const CHARACTER_NAME_MADOKA:String = "まどっち";
public static const CHARACTER_NAME_HOMURA:String = "ほむほむ";
public static const CHARACTER_NAME_SAYAKA:String = "さやかちゃん";
public static const CHARACTER_NAME_MAMI:String = "マミさん";
public static const CHARACTER_NAME_KYOKO:String = "あんこ";
public static const CHARACTER_NAME_MADOGAMI:String = "まど神様";
public static const CHARACTER_NAME_MEGAHOMU:String = "メガほむ";
public static const CHARACTER_NAME_CHARLOTTE:String = "シャルロッテ";
public static const CHARACTER_NAME_HITOMI:String = "腹パン";
public static const CHARACTER_NAME_KUROSAYA:String = "黒さやか";
// 武器攻撃タイプのID
public static const ATTACKTYPE_SHOOTING:int = 0;
public static const ATTACKTYPE_EXPLOSIVE:int = 1;
public static const ATTACKTYPE_MELEE:int = 2;
}