PSO2:NGSをDeskMini A300で遊ぶまでの無駄な苦労をメモる


 やー、久々だなPSO2!
 旧PSO2を数ヶ月やって以来だわ。割と好きだったし、あれの為にビデオカード買ったりもしたなあ。クロト銀行に飽きてやめたが。なおビデオカードはその後ろくに使われないまま壊れた。クソもったいねえ。

 で。

 今の俺の常用PCは、DeskMini A300にRyzen 5 2400Gを積んでる奴なので、ビデオ性能は設定で頑張るしか手は無い。
 BIOSが古いとUMA Frame Buffer Sizeが2GBまでしか選べないが、NGSのVRAM消費は4GBくらいっぽい(?)から、メモリたっぷりな環境ならBIOS更新はありかも、と言いたいが、うちでBIOS更新したらMBR飛んだ時みたいに起動出来なくなったんだよな。ファイルは見えるのにブート対象にならない感じ。直し方はあるんだろうけど、面倒なのでバックアップからリストアした。
 まあ、UMA Frame Bufferが2GBでも微差みたいな話だと思うから、お勧めは絶対しない。

 あと、CPU温度が80℃とか当たり前に上がってたけど、側面の穴からUSB扇風機当てたら65℃とかになって笑ったので、扇風機あるなら試す価値あり。
 ちなみに、試しに上面から当てたら90℃とかになった。他の要因なのかもだが、こんな温度を見たの初めてなのでもうやらない。
 なお、USB扇風機は最初はSilky Windで試したけど、一般的な用途のUSB扇風機は短寿命らしいので、連続運転向けなBIGFAN80Uに変えた。ファンコン無しだとCPUクーラー全力運転くらいの音が出るので、後から同社製ファンコンも注文した。ヨドバシだから送料掛からんけど、まとめて買うべきだったなあ。すまん。

 で、うちのモニターはDellのS2721Q。クソ安4Kモニターだぜ。内蔵GPUには荷が重いぜ。
 4Kモニター自体は、色々と面倒はあるけど、もう戻れんくらいには気に入ってるけど。
 この環境だと、設定で頑張らんとNGSはマジできつい。仮想フルスクリーンで遊びたいのに、ウィンドウモードじゃないと解像度が自前で設定出来ないんよな。

 具体的にどの程度きついか。
 窓の解像度を下げた時と、3Dレンダリング解像度を切り替えた時と、解像度の自動縮小機能をON/OFFした時とで、Xbox Game Barのfps読みで雑に比較すると、

3Dレ解 自動縮小 fps
仮想フル 3840*2160(4K) OFF 6-7
ON 8-9
OFF 8-9
ON 11-12
窓 2560*1440(QHD) OFF 12-13
ON 15-16
OFF 15-17
ON 20-21

って感じ。(今は少し設定を詰めて、低/ONで25-27fpsくらい)
 窓の解像度も下げて、3Dレンダリング解像度も下げて、自動縮小も入れて、と全部やらないとフレームレート上がらんのだ。ぐぬぬ。さすがに20fps切ると別ゲー感あるんで、下げまくるしか無し。
 ただ、うちのCFDのメモリがDDR2666でしか安定してくれない問題があるんで、DDR3200環境でQHDなら30fps狙えるんじゃねーかなー。
 4Kモニターで低スペGPUとか考慮されてない気もするが、そもそもディスプレイ設定の「テキスト、アプリ、その他の項目のサイズを変更する」が100%じゃないと画面表示がピンぼけでディザリングもりもりのザラザラになる辺り、4Kモニターでテストしてるのか怪しく思えるレベル。
 まー、テストしてるのか怪しい挙動は他にも色々あるけどな!

 なお、この「テキスト、アプリ、その他の項目のサイズを変更する」は、27インチくらいの4Kモニターとか使ってる人だと150%推奨とかWindows自体に言われるくらいなので、困ってる人結構いるんじゃなかろか。
 これに引っ掛かってる場合、ウィンドウモードなら設定解像度とゲーム画面のサイズが全然合わなくなるからすぐ分かるし、仮想フルスクリーンでもスクリーンショットの解像度で確認出来る。つーかそもそも画面がボンヤリでガビッガビになる。
 対処方法は、pso2.exeのプロパティ→互換性→高DPI設定の変更→高いDPIスケールの動作を上書きします、にチェックして、拡大縮小の実行元の選択肢がアプリケーションになってればOK。詳しくは「pso2.exe 高dpi設定」とかで検索すれば解説多数。

 ここまで来るのにだいぶ掛かったが、うちで起きた大きな問題はこれくらいかな。
 「作業進行度」って毎回出る問題はみんな起きてたと思うけど。PSO2JP.iniがゲーム終了時におそらくnProtectの手で巻き戻されちゃうバグのせいで、毎回ファイルチェック掛かってたんですよ。6/17にサイレント対応されたっぽい。

 あとは、細かい設定項目の話でもするか。乏しい3Dグラフィックスの知識で。

エフェクト光源
 攻撃のエフェクトとかが光ってる時、その周囲に光を照らす。
 俺はON。NGSは暗い絵作りなので、明るくなる要素を削るのは怖い。
地形光源
 上と大体同じ。背景の光り物とかが周囲を照らす。
 俺はON。
カメラライト
 スマホのカメラでライト点灯するのと同じようなもの、だろうか。
 俺はデフォの50。
周辺減光
 画面の端が暗くなるだけ。
 俺はOFF。
グローバルイルミネーション
 光の処理をうまいこと端折りつつも格段に綺麗に見せる。これが無い場合、壁に当たって跳ね返った間接光などはバッサリ無くなると思われるし、屈折や散乱なども多分無くなる。
 俺はON。それなりに重いけど、このゲームがグローバルイルミネーション前提で作られているとしたら、切っちゃうとシーンによってはえらい真っ暗になりそうな気がして。暗くなる設定は基本避けたい。
ブルーム処理
 ある程度以上に明るいものを、こう、もわっと光らせる感じの奴(語彙)。
 俺はON。キラキラ飛んでる粉とかが綺麗になるので。正直OFFでいい気はする。
ライトシャフト
 太陽や月などから差す光が、こう、線になる奴(だから語彙)。薄明光線とか天使の梯子とかがそれだけど、このゲームでちゃんと確認したこと無いな。
 俺はON。要らんとは思うのだが、fps読みをしててもほとんど違いが分からんし、いつか綺麗な薄明光線が見えるかもと期待して。
ボリュームフォグ
 説明通り、霧などの表現。
 俺はOFF。
エフェクトの歪み表現
 一部のエフェクトで、空間が歪んで見える。
 俺はOFF。
ファー表現
 説明通り、髪や毛皮の質感が大幅に変わる。
 俺はON。他の人とプレイ体験が違いすぎるのも怖いので。
ブラー
 高速に動く物をぼかす。
 俺はOFF。どのゲームでもOFF。一瞬の間にいい物が見えてたら大変だろ!
色調トーンカーブ
 説明通り。シーンで色合いが変わる。
 俺はON。軽そうな気がするけど、どうなんすかね。
被写界深度
 ピントが合ってないとこをボカすだけ。
 俺はOFF。あらゆるゲームでOFF。いい物が見えてたら大変だろ!
アンチスペキュラエイリアシング
 良く分からん。鏡面反射に関する何かの改善らしい。テカテカしたとことかは違いが分かりやすい。
 俺はOFF。
テッセレーション
 ポリゴン自体を変形させて凹凸を作ったりしちゃう奴。良く知らんけど。地面を見ながらON/OFFすると露骨に変わって面白い。
 俺はON。そこそこ重いので迷うが。
アンチエイリアシング
 ドットのギザギザ感を減らす奴。
 俺はFXAA。最低限は欲しいし、TAAよりキレがあると思えなくもないし。
スクリーンスペースリフレクション
 水面の映り込みとか。見た目の違いはめちゃくちゃ分かりやすい。
 俺はON。
アンビエントオクルージョン
 環境光の遮蔽(直訳)。わからん。影の付き方が明らかに綺麗にはなる。
 俺はOFF。暗くする系は、切っても致命的にはなりにくいので我慢。
スクリーンスペースシャドウ
 わからん。景色などの影が別物のように綺麗はなる。
 俺はOFF。
影品質
 影は地味に重いイメージだったけど、そうでもない?
 俺は3。下げていい気もする。
雲品質
 そのまま。見た目は相当変わる。負荷はfps読みだと違いが分からんレベル。
 俺は3(最大)。
パーティクル品質
 主にエフェクトのだと思うけど、粒とか破片とかをどんだけ盛るか。
 俺は2。多いと盛りすぎ感もあるし。
対象キャラクターのアクセサリー非表示
 これは描画負荷には関係無いので、お好みで。
詳細に描写するキャラクター表示数
 ロード直後などは、他PCがみんな泥人形みたいになるけど、あれをちゃんとした表示に変える人数。
 俺は32(上限)。
探索セクションのキャラクター表示数
 上と同じようなもの?
3Dレンダリング解像度
 内部処理の解像度、だよな。
 俺は低。つらい。
解像度の自動縮小機能
 重い時に、さらに解像度を下げて処理する。
 俺はON。
最大フレームレート
 そのまんま。
 俺は60fps。モニターの上限と同じでいいかと。昔のPSO2は無制限だと部分的にえらい軽くなった気がするけど、あれ直ったんかな?
非アクティブ時のフレームレート制限
 多分、他のアプリの窓に切り替えてる時とかに、フレームレート上限を下げる。
 俺はON。これ切るのって相当特殊では。
テクスチャフィルタリング
 大雑把に言うと、3Dモデルの表面のテクスチャを三次元で回転拡大縮小させる時に、どんだけ綺麗に処理するか。でいいのか?
 異方性フィルタリングが効果的なシーンといえば、草原なんかが良く例示される。カメラから見て角度の付いたテクスチャが縮小表示される時とか、異方性じゃないとディテールが潰れてのっぺりする。
 俺はバイリニア。キャラをアップで見た時の綺麗さ、とかにはほとんど関係無いので。
テクスチャ解像度
 まんま。大抵のゲームで、ここを変えると絵面も極端に変わる。
 俺は最高。ここはGPUの処理速度と無関係にゴリゴリ上げられることが多々あるのだが、うちも該当する。他が駄目でもここだけ上げる、というセッティングは試す価値大。
地形等の表示距離
 そのままだけど、下げても遠景の山が消えるとかは無くて、地面付近のディテールがバッサリされるだけっぽい。多分。地面付近の絵面は劇的に変わるが、負荷もトップクラスのでかさ。
 俺は3。しばらく5でやってたけど重すぎ。1だと地面に何も無くてさっぱりしすぎ。3ならかなり雰囲気は残る。

 こんな感じで。
 訂正とか補足とか歓迎。


ブレイドアンドソウルをやってみた頃の話


 下書きで放置された奴を連日のように書き上げる企画。
 今日は、BnSをやった時に書き掛けて投げた文章を元に、適当に仕上げてみる。

 で。

 んー、何だろこのゲーム。プチFFって感じ?
 懐かしいよなー。MMOってこういうギッスギスしたの多かったよなー。
 つーかMMOとかMOとかじゃなくて、ハードコアな難易度を目指されると俺には合わん。適当に一般人な装備で突っ込んでって、たまに死にながらもすぐ蘇生して少しずつ何とか切り拓いてく、みたいなのなら好きだけどさー。

 野良パーティに入ったら、装備しっかりしてないと蹴られることもありますよ、とか親切に教えられて、もう、ねえ。悪気は無いと思うし、むしろ有り難い人にとっては凄く有り難い存在な筈だけど、俺はもうそういう世界は無理になりました。FF11のお陰で。
 野良パーティで色々と親切に教えてくれる人と出会えて、出会ってしまって、やる気急降下して、「PvPの」デイリークエがPSO2の昔のクロトばりに必須っぽい雰囲気を醸し出してる、という状況がとどめの追い打ちとなった。さらば。

 まーでも、FF11のギスギスっぷりには負けるが。
 つっても、FF11の方がストーリーとかは楽しかったけど。映像も、古くてもFF11の印象の方が上だなー。

 かなり自由に飛び回れるのは良かった。あとアクションなのも良かった。FF11の世界をこんな風に走り回れたら気分良さそうだしな。戦闘はやっぱアクションの方が好きだな俺。
 ただ、装備が無いとどーしょもないです、ってゲームでなー。昔のマビみたいに、腕でカバー出来る範囲がものすっげー広いとか、雑魚いキャラで参加してもうざがられない空気とか、そういうのって稀だよな。

 これがFFみたいに、タイトルに思い入れが若干あるんならともかく、「洒落で触ってみた韓国製の開発費高そうだけど何だか色々と肌に合わないMMO」だと、別にそんな苦労してまで頑張るメリット感じないです、ってなっちゃう。
 キャラクリは良かったから、キャラクリでしっかり楽しんで、簡単に二色揃う秋風の衣とかいう露骨なエロ装備を取って、少し遊んだらもうそこで打ち切るのが一番幸せな感じかも。あれより好みのエロ服は俺には無かったし。エロくない服には好みのが無かったし。

 とまあ、そんな感想だったようです。
 もうほとんど内容忘れてる状態で書き上げたから、ちょっと自信無いけど、まー大丈夫だろーハハハ。
 あ、キャラクリはほんとに良かった。過去プレイした細かいキャラクリ可能なゲームの中でも、トップクラスに納得行く外見のキャラが複数仕上がったし。


Tree of Saviorやってた頃の話


 あんな記事書いた後に再開して、果ては久々にMMOで金払ってプレイしてたんすよね。ハハハ。二ヶ月も。結局やめたけど。
 どうやらプレイ再開の見込みは無さそうなので、適当に下書きしてた分を仕上げて公開。

 プレイスタイルは、何度も「こりゃもうやってられんわ」となりつつ、何となく食い足りなくて別クラスを育成、を繰り返す感じで。それを12回くらいやった。
 つーか同じスタイルの人が山ほどいたらしい。バランス設定間違ってるよなー。

 このゲーム、序盤は爽快なんだよな。敵が何十匹とか固まってるのをスパーンスパーンと一撃で潰しまくって、それでも次々と湧くから、先に進んだ方がいいのにスパーンスパーンを続けちゃう、みたいな。
 それが、育つとだんだんきつくなってきて、雑魚一匹でひーひー言うことになる訳ですよ。これもプレイヤーの為なんだ、パーティ戦闘の楽しみを味わわせたいんだ、ってことなんだろうか。単にひたすらつまんなくなるだけですが。実感を一言で言えば「育てると弱くなる」。
 つーか楽しませる為の設計には全く見えない。引き延ばしたいだけなのかも。でも引き延ばせる設計にも見えない。狙いがさっぱり。

 かなり低予算プレイ傾向の俺がトークン買っちゃった件については、効果が値段の割に強いかなー、と思ったので。
 あと、NET CASHのチャージが二万以上残ってたんで。PBWやってた頃の名残っすな。あの世界に比べたらトークンなんてタダみてーなもんだ。アイコン一個分のお値段だもんな。
 だがしかし、重度のゲーム中毒者を長年やってる身だと、場合によっては「いっそ成長が遅い方が遊べる」ってケースもある。
 ToSはかなりその傾向が強かった。成長させるほどにつまんなくなったし、この先も遊び方が広がりそうに見えなかったし。エンドコンテンツをゴリゴリ遊ぶ仲間がいたら別かもしれないけど、いたとしてもマビの時みたいに「高難易度エリアに少人数で気楽に突撃してみる」とかやる空気でもなさそうだしなー。
 実際、トークン買ってて有効期間中なのに、途中からトークンの効かない別鯖でプレイしまくってたし。
 とはいえ、ゲーム内で効率的にプレイしようとするのはゲームの楽しみのうちなので、「トークン買ってんのにトークン効かない別鯖に行って、トークン無し状態での効率をきっちり追求するプレイ」をしていた。馬鹿じゃないの。

 ということで、低予算傾向の強いblogなのに今回はトークン買っちゃったから記事書きにくいなー、とか思ってたのに、結局は骨の髄から低予算プレイに染まる俺なのであった。やれやれだぜ。
 ガチャ超苦手ってのもでかいけどな。最近ほんと「ガチャに使わないならどこに金使うの」なゲームばかりで。

 なお、昔からここを読んでてToSもやってた人(いなそう)なら分かりそうだけど、12キャラほどビルドした中で一番楽しかったのは巫女経由のキャラ。ヒーラー体質なことと、見た目が好きなことから。
 でも、結局Lv190にも行かずに投げた。10キャラくらいやる頃にはもうクエ潰すだけで辛くて。

 振り返るに、このゲームの何が駄目だったのか。
 …このゲームの何が駄目じゃなかったのか、を考えた方が早い。マジで。みんなそう言うと思う。

 キャラの見た目は良かった。音楽も良かった。
 ゲームシステムも、比較的シンプルなノンタゲ混じりARPG風、ってのは良かったと思う。バランス設定が腐ってたから悪く見えるけど、そこが良ければ「単純ながらドハマリ」みたいなこともあり得た。だからこそ、バランスが比較的まともな序盤は延々と遊べた。敵の必中遠隔で一気にげんなりして、雑魚がどんどん強くなってバカジャネーノになったけど。
 ものすごく頭の悪い主人公も、俺的には悪くなかった。

 まー、そんな感じっすかね。
 色々問題はあったけど、本当にまずいのは「プレイしてて気持ちいいとこが無い」ってとこだったと思う。そこだけクリアしてればプレイは続けられる。
 序盤は気持ちいいプレイ感覚あるんだから、出来ない訳ではなかっただろうになー。


Tree of Savior OBTをやってみた


 がっつり10日間ほどプレイしたので、久々に感想を。
 モンクに転職して少し遊んだとこでアンインストールしたので、その辺りまでの話。

 プレイしながら「RO2に求められてたのはこういうのなんだろなー」って何回も思った。2Dっぽい絵が好きな人には合うんじゃなかろか。
 ゲーム性は量産型なので、プレイ開始前から飽きてるといういつもの現象が起きたけど、一時期のように次から次へとイナゴごっこしてた訳でもないので、割と長時間飽きずに行けた。具体的には一週間飽きなかった。その後は惰性で三日ほど遊んで終わり。

 「ステ振りとスキル振りとクラスチェンジ分岐」という俺の苦手な離脱ポイントてんこ盛りの仕様なので、とりあえず海外情報サイト(Tree of Savior Fan Base)Public Buildsを眺めることに。
 いつもの習性でヒーラー路線を目指したんだけど、もうMMOとかイナゴする機会もなかなか無いだろうから、やったことの無かった殴りヒーラーに行ってみた。クレリック系二番人気のモンクビルドである。

 結論から言えば、何か失敗だった気がする。うむ。まーいいや。早く離脱した方がいいんだ。
 どうせひねくれるなら、ちょっと気になってたオラクルでも目指せば良かった気もする。

 ゲーム的に快適だなーと思ったのは、クエ報酬が経験値でなく「使うと経験値の入るアイテム」を貰える点で、適度に貯めれば適正レベルをひたすら維持し続けられる。
 あと、量産型MMOだと「初期だけクエ連発で死ぬほどホイホイ上がって、いきなりクエが尽きて急にマゾい作業に」が定番だったけど、ToSはとりあえず相当長い間はクエが続く。尽きた後もそこまでマゾい作業ではない、らしいけど。

 ただ、クエ自体が作業寄りの要素ではあるので。
 やっぱオフゲと比べると、作業じゃない部分の比率が低いな、とは思う。序盤のプレイで既にそんな感じ。
 あとボス戦も割と作業だったけど、それは序盤だからだろう。さすがに。

 俺の苦手なデイリーなんたら系は、ToSにもある。これがあると離脱が早まるので助かる。
 六年続けたマビをやめた理由でも、デイリーはかなりの比重を占めてたしなー。
 そういえばPSO2もだ。クロト銀行でやめたんだ。
 デイリー系は、プレイ時間が減った時に、一気に飽きを加速する。デイリーしかやってねー、でも行かないとまずすぎー、リアルきついけどデイリー消化しないとー、みたいな感じ。
 むしろ廃プレイしてる時の方が気にならないんだよな、デイリーがクソでも。

 で、恒例だけど、そろそろやめた理由を書いておく。
 たかだか10日間くらいのプレイだが、何しろ恒例なので。

 まず、プリーストC2辺りが非常に楽しかった、というのが伏線となる。カフリサン一式を買って、ブレッシングLv3に強化Maxでサクラメント付けて、バババッバババッと物凄い勢いで敵が吹っ飛んでった。
 それが次第に、ものすげー何発も殴らないと敵が倒せなくなり、良さげな装備はアホみたいな値段になり、「ここを耐えてモンクになったら、きっとあれ以上に暴れられる世界になる」って思ってたんだけどさ。

 ならんわな。

 とどめは、そこそこいい感じだけどちょっと飽きてたプリ服と比べて、モンク服はあんまり好みじゃなかったことで。
 過去に経験したクラスの服にはいつでも変えられるんだけど、この先ずっとプリ服ってのもなー、と。

 まー、クラスチェンジとか相当でかい離脱チャンスですよね。逃さず離脱出来ました。めでたくクリアです。
 ということで、ToS終了。食った食った。

 次はどうすっかなー。
 DMMイナゴも飽きてきて、事前ガチャも回してたのにほぼプレイせず終わりとか多くなってきたし、事前ガチャ自体を回さなくなってきたし。
 FF11、マビノギ、アイギスに続く「一年半飽きなかったゲーム」はいつ来るかなー。


ソシャゲ系にありがちな経験値計算を自作電卓に組み込んでみた


 こんなん書いてもなー、って思わなくもないが、どうでもいい狭いネタなんか過去に山のように書いてるしな。
 つーことで、自作電卓の話。

 元々、CUIな電卓の自作は好きで、DOS向けに小さいのをアセンブラで書いたりしたこともあった。
 小さいの、と言っても、実行ファイルのサイズが小さいって話で、アセンブラだからソースは無駄にでかい。内部はbigint/rationalな処理で、循環小数は循環節付きで出力するみたいな無駄に頑張った仕様だった。
 Wolfram Alphaとかがある今時なら、こんなもん作ろうとも思わなかっただろうけどさ。

 あの頃の俺はなー、ソースの可読性とか投げ捨てるもの以前で、「見易いソース」って感覚が皆無だった(←今でも怪しい)。そもそもアセンブラで何から何まで全部書いちまおうとか考えた時点で、悪い意味のバカであるな。だがそもそも当時の俺はC言語すら知らねえのだ(笑)。
 なお、TASMのIDEALモードとかいう、もう心底アレなソースだった。いや面白い仕様だったし好きだけど。でもなー。
 しかも、何も考えずに全ての箇所を最適化した。何でもないところでもcall+retをjmpに変えたり、sbbで分岐減らしたり、フラグレジスタ読んで論理演算でどーにかとか、再帰的なマクロでテーブル作って除算を高速にとかやってたような。しかもバカだから曲芸でもコメント書かねえ。
 このように典型的なクソコードであり、完成したからまだいいけど、本気で何やってるか分からんソースになったし、あの経験が特に役に立つことも無かった気はする。
 けど、ほら、アレだ、「昔オフゲで死ぬほどチートやって飽きたからもうオンラインゲームとかでわざわざチートしたいとか思わんし」って現象があるけど、同様に「昔アセンブラで死ぬほどパズルみたいなコード書いて飽きたからもう要らん最適化したいとか思わんし」みたいなのもあるかもしれん。どうだろう。

 何かどんどん狭い話をしてる気が。

 話を戻して。

 Pythonを触るようになって少し経った頃、evalでクソ簡単な電卓作れるよなー、と思った。
 いやまーPerlも入れてたから、ワンライナーで済む話ではあったのだが、そこはそれ。何か作りたくなったのだ。

from __future__ import division, print_function
import sys
expr = ' '.join(sys.argv[1:]) or 'None'
print(expr, '=', eval(expr))

こんな程度だし。

 で、普段から使うようになって、千年戦争アイギスの経験値の計算とかもやってたんだけど。
 ソシャゲ的な奴って、「育成目標は経験値2400、主要狩場で拾えるカードから得られる経験値は225と255、あと手持ちで素材にしたいカードは経験値40が2枚、70が1枚、140が3枚」みたいな状況が良くあるじゃん。
 それを、

>e game.xp(2400, 225, 255, (40,2), (70,1), (140,3))

とかで自動的に計算してくれる機能が欲しいな、と。
 面倒だからやらずにいたけど、アイギスのデイリー復刻実装でこういう計算の需要が俺的に多発したんで、試しに拡張してみた。

from __future__ import division, print_function
import sys
import collections


def clamp(v, min_v, max_v):
    return min(max_v, max(min_v, v))


class game(object):
    @staticmethod
    def xp(target, *exp_and_limits):
        RESULT_HEAD_LEN_MIN = 15
        RESULT_HEAD_LEN_MAX = 50
        RESULT_TAIL_LEN_MIN = 5
        RESULT_TAIL_LEN_MAX = 30

        exp_lims = [
            x if isinstance(x, collections.Iterable)
                else (x, float('inf'))
            for x in exp_and_limits]

        # return [[num, ...], ...]
        def inner_func(target_rest, exp_lims_rest):
            exp_unit, num_limit = exp_lims_rest[0]
            max_num = -(-target_rest // exp_unit)
              # just round up
            max_num = clamp(max_num, 0, num_limit)
            if len(exp_lims_rest) == 1:
                return [[max_num]]

            result = []
            inner_exp_lims = exp_lims_rest[1:]
            for num in range(0, max_num + 1):
                exp_product = exp_unit * num
                inner_target = target_rest - exp_product
                inner_result = inner_func(
                    inner_target, inner_exp_lims)
                for row in inner_result:
                    result.append([num] + row)
            return result

        raw_result = inner_func(target, exp_lims)
        result = []
        for row in raw_result:
            exp_total = sum(
                exp * num
                for (exp, limit), num
                in zip(exp_lims, row))
            excess = exp_total - target
            if excess < 0:
                continue
            result.append((excess, row))
        result.sort(
            key=lambda x: [-x[0], x[1:]], reverse=True)

        head_len = clamp(
            len([
                1 for row in result
                if row[0] == result[0][0]]),
            RESULT_HEAD_LEN_MIN, RESULT_HEAD_LEN_MAX)
        tail_len = clamp(
            len([
                1 for row in result
                if row[0] == result[-1][0]]),
            RESULT_TAIL_LEN_MIN, RESULT_TAIL_LEN_MAX)
        if len(result) > head_len + tail_len + 1:
            result[head_len:-tail_len] = [
                '{} sets omitted'.format(
                    len(result) - head_len - tail_len)]
        return result


expr = ' '.join(sys.argv[1:]) or 'None'
print(expr, '=', eval(expr))

こんな感じで。
 元ソースから他の俺向け機能を削除しまくってから貼ったんで、ちゃんと動くかは知らないけど、試しにさっきのコマンドを走らせてみたら、

>e game.xp(2400, 225, 255, (40,2), (70,1), (140,3))
game.xp(2400, 225, 255, (40,2), (70,1), (140,3)) = [(0, [10, 0, 2, 1, 0]), (0, [7, 1, 2, 1, 3]), (0, [5, 5, 0, 0, 0]), (0, [2, 6, 0, 0, 3]), (0, [1, 7, 1, 1, 2]), (0, [0, 8, 2, 0, 2]), (5, [8, 1, 0, 1, 2]), (5, [7, 2, 1, 0, 2]), (5, [6, 3, 2, 1, 1]), (5, [1, 8, 0, 0, 1]), (5, [0, 9, 1, 1, 0]), (10, [7, 3, 0, 1, 0]), (10, [6, 4, 1, 0, 0]), (10, [4, 4, 0, 1, 3]), (10, [3, 5, 1, 0, 3]), '109 sets omitted', (135, [4, 5, 2, 0, 2]), (150, [0, 10, 0, 0, 0]), (165, [8, 3, 0, 0, 0]), (195, [7, 4, 0, 0, 0]), (225, [6, 5, 0, 0, 0])]

って感じになったので、多分動く気はする。怪しいが。
 なお、出力の意味は、最初の等号の右の

(0, [10, 0, 2, 1, 0])

だけ説明すりゃ分かるかなーと。この場合は「超過0、225*10 + 255*0 + 40*2 + 70*1 + 140*0」ってことで。左の項目が多い方から順にソートされてるから、優先的に使いたい素材を左に指定すると便利とかそんな感じ。
 あと、項目数が10個くらいになるとメモリ使い切る勢いになってくるし、何千通りも最適解が表示されてもまともに見る気にもならないんで、大人しく7個くらいまでにしておいた方が。

 相変わらずの説明する気ねーだろ的記事であるが、まー、分かるべ。行ける行ける。
 あと、Python2.7.x用のつもりだけど、Python3.xでも動いてるようには見える。知らんけど。
 ついでにWindowsの場合、cmd.exeへのショートカットをデスクトップに置いてプロパティ開いてショートカットキーを設定しておけば更に楽に。

 たまにこういう小さいソースコード貼っただけみたいな記事を書くけど、需要無さそうだよなー本気で。ハハハ。
 まーでも、ちょっとコード書ける人なら「そーかーevalで手軽に自作電卓とか便利そうだなー」と思うかもしれないなー、というのもある。ワンライナーと違って、自分用の関数とか定数とか作れるのはかなり嬉しい。
 俺は当時最適だと思ったPythonで書いたけど、Node.jsが登場して一荒れして落ち着いて風格が出てきた今となっては、そっちで書いた方が良い気がしなくもない。電卓としてはPythonの除算演算子(新仕様)は便利だけど。いちいちintとかfloatとか考えなくて済むからなー。

 なお、これで色々な経験値素材の組み合わせを計算させてみたけど、素材を何種類か持ってれば、無駄の無い組み合わせは大抵はゴロゴロ出てくるっぽい。
 だが、そこまでして無駄をなくす意味は多分無い。