Compare commits

..
20 Commits
Author SHA1 Message Date
Hide_D dca341f35e fix: 연산단위 최소값 지정 2022-06-15 23:11:07 +09:00
Hide_D d38ddcd79e fix: 피장파장에서 모든 국가에(불가)가 나타나는 버그 2022-06-15 22:34:32 +09:00
Hide_D 03675349d8 fix: 사기진작 커맨드가 금소모를 하지 않음 2022-06-15 00:35:40 +09:00
Hide_D 72768ba7b5 fix: 경매 로그 마저 수정 2022-06-14 22:31:01 +09:00
Hide_D a5477db6b6 fix: 거래 완료시 메시지가 반대로 뜨는 버그 수정 2022-06-14 22:19:23 +09:00
Hide_D c146e8587b feat: 명장일람에 진행중인 유니크 경매 표시 2022-06-12 17:52:02 +09:00
Hide_D 24b65b0395 fix: 금쌀 경매장에 최근 로그 없음 2022-06-12 01:50:33 +09:00
Hide_D 2f42691d2b fix: 연감에 전투 시드가 겉으로 드러남 2022-06-11 15:09:35 +09:00
Hide_D ea619bd693 misc: 인사부에서 추방을 가장 아래로 2022-06-11 14:39:57 +09:00
Hide_D 35a56e74bb refac: 금쌀 경매장 UI 2022-06-11 03:53:30 +09:00
Hide_D 6fb2358161 refac: 유니크 경매 UI 수정 2022-06-10 02:07:05 +09:00
Hide_D a039fb871b fix: CreateManyNPC에서 모든 m장 사망년도가 같은 버그 수정 2022-06-10 00:49:47 +09:00
Hide_D a19da6cda5 fix: 경매장 갱신 버튼 2022-06-10 00:43:47 +09:00
Hide_D e5ba980865 fix: 종료된 유니크 경매 입찰시 버그 2022-06-10 00:38:34 +09:00
Hide_D f95ee8fab8 fix: 경매에서 이미 소지 수가 찬 유니크 획득 가능한 문제 수정 2022-06-09 22:28:51 +09:00
Hide_D 120706ef3f misc: 경매장 진입로를 금/쌀, 유니크로 2원화 2022-06-09 16:16:58 +09:00
Hide_D 58da20f276 fix: 동일 부위 유니크 소유시, '1턴' 연장하도록 수정 2022-06-09 15:49:13 +09:00
Hide_D 64af68e2d6 fix: 유니크 경매 시 종류 제한 계산 버그 2022-06-09 02:03:38 +09:00
Hide_D 76a8740644 fix: 유니크 경매시 10포인트 더 높아야 함 2022-06-09 01:53:19 +09:00
Hide_D 0863fafec0 fix: 경매가 시작후 3개월이 아니라 4개월로 설정됨 2022-06-09 01:49:22 +09:00
25 changed files with 645 additions and 252 deletions
+29
View File
@@ -2,7 +2,9 @@
namespace sammo;
use Ds\Set;
use sammo\Enums\RankColumn;
use sammo\Enums\AuctionType;
include "lib.php";
include "func.php";
@@ -19,6 +21,7 @@ $gameStor = KVStorage::getStorage($db, 'game_env');
increaseRefresh("명장일람", 1);
$templates = new \League\Plates\Engine(__DIR__ . '/templates');
?>
<!DOCTYPE html>
<html>
@@ -326,6 +329,32 @@ $templates = new \League\Plates\Engine(__DIR__ . '/templates');
}
}
$dummyAuctionGeneral = [
'nation' => 0,
'no' => 0,
'ownerName' => '',
'pictureFullPath' => GetImageURL(0) . "/default.jpg",
'name' => '경매중',
'bgColor' => '#00582c',
'fgColor' => 'white',
'nationName' => '-',
];
foreach ($db->queryFirstColumn(
'SELECT `target` FROM ng_auction WHERE `finished` = 0 AND `type` = %s',
AuctionType::UniqueItem->value
) as $itemClassName) {
if(key_exists($itemClassName, $itemOwners)) {
$itemOwners[$itemClassName][] = $dummyAuctionGeneral;
}
else{
$itemOwners[$itemClassName] = [$dummyAuctionGeneral];
}
}
foreach (GameConst::$allItems as $itemType => $itemList) {
$itemNameType = $itemTypes[$itemType];
$itemList = array_reverse($itemList, true);
+47 -48
View File
@@ -25,6 +25,17 @@ if ($meLevel == 0) {
$nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nation where nation=%i', $nationID); //국가정보
if ($meLevel >= 5) {
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
} else {
$candidateStrength = [];
$candidateIntel = [];
$candidateAny = [];
}
?>
<!DOCTYPE html>
<html>
@@ -180,61 +191,21 @@ $nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nati
<td colspan=5><?= $eaglestr ?></td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td colspan=6 height=5></td>
<td colspan=4 height=5></td>
</tr>
<tr>
<td colspan=2 align=center bgcolor=red>추 방</td>
<td colspan=4 align=center bgcolor=blue>수 뇌 부 임 명</td>
</tr>
<tr>
<td width=498 align=right class='bg1'>대상 장수</td>
<td width=498>
<?php $officerLevelText = getOfficerLevelText(11, $nation['level']); ?>
<td width=98 align=right class='bg1'><?= getOfficerLevelText(12, $nation['level']) ?></td>
<td width=398><?= $level[12]['name'] ?> 【<?= CityConst::byID($level[12]['city'])->name ?>】</td>
<td width=98 align=right class='bg1'><?= $officerLevelText ?></td>
<td width=398>
<?php
if ($meLevel >= 5) {
$candidateStrength = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and strength>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateIntel = $db->query('SELECT no,name,officer_level,city,npc from general where nation=%i and officer_level!=12 and intel>=%i order by npc,binary(name)', $nationID, GameConst::$chiefStatMin);
$candidateAny = $db->query('SELECT no,name,officer_level,city,npc,leadership,strength,intel,killturn from general where nation=%i and officer_level!=12 order by npc,binary(name)', $nationID); //추방 때문에 조금 더 김
} else {
$candidateStrength = [];
$candidateIntel = [];
$candidateAny = [];
}
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) {
echo "
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
foreach ($candidateAny as $general) {
if ($general['no'] === $me['no']) {
continue;
}
echo "
<option data-officer_level='{$general['officer_level']}' data-name='{$general['name']}' value={$general['no']}>{$general['name']} <small>({$general['leadership']}/{$general['strength']}/{$general['intel']}, {$general['killturn']}턴)</small></option>";
}
echo "
</select>
<input type=$btn id='btn_kick' value=추방>";
}
$officerLevelText = getOfficerLevelText(11, $nation['level']);
echo "
</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr><td colspan=4 height=5></td></tr>
<tr><td colspan=4 align=center bgcolor=blue>수 뇌 부 임 명</td></tr>
<tr>
<td width=98 align=right class='bg1'>" . getOfficerLevelText(12, $nation['level']) . "</td>
<td width=398>{$level[12]['name']} 【" . CityConst::byID($level[12]['city'])->name . "】</td>
<td width=98 align=right class='bg1'>{$officerLevelText}</td>
<td width=398>
";
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], 11)) {
echo "
<select id='genlist_11' size=1 maxlength=15 style=color:white;background-color:black;>
@@ -553,6 +524,34 @@ $nation = $db->queryFirstRow('SELECT nation,name,level,color,chief_set from nati
<td colspan=5>※ <font color=orange>노란색</font>은 변경 불가능, 하얀색은 변경 가능 관직입니다.</td>
</tr>
</table>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
<td colspan=6 height=5></td>
</tr>
<tr>
<td colspan=2 align=center bgcolor=red>추 방</td>
</tr>
<tr>
<td width=498 align=right class='bg1'>대상 장수</td>
<td width=498>
<?php
if ($meLevel >= 5 && !isOfficerSet($nation['chief_set'], $meLevel)) : ?>
<select id='genlist_kick' size=1 style=color:white;background-color:black;>";
<?php foreach ($candidateAny as $general) : ?>
<?php if ($general['no'] === $me['no']) {
continue;
}
?>
<option data-officer_level='<?= $general['officer_level'] ?>' data-name='<?= $general['name'] ?>' value='<?= $general['no'] ?>'><?= $general['name'] ?> <small>(<?= $general['leadership'] ?>/<?= $general['strength'] ?>/<?= $general['intel'] ?>, <?= $general['killturn'] ?>턴)</small></option>
<?php endforeach; ?>
</select>
<input type=<?= $btn ?> id='btn_kick' value=추방>
<?php endif; ?>
</td>
</tr>
</table>
<br>
<table align=center width=1000 class='tb_layout bg0'>
<tr>
+29 -4
View File
@@ -114,10 +114,10 @@ if (!$otherTextInfo) {
$lastVoteID = $gameStor->lastVote;
$lastVote = null;
if($lastVoteID){
if ($lastVoteID) {
$voteStor = KVStorage::getStorage($db, 'vote');
$lastVote = VoteInfo::fromArray($voteStor->getValue("vote_{$lastVoteID}"));
if($lastVote->endDate && $lastVote->endDate < TimeUtil::now()){
if ($lastVote->endDate && $lastVote->endDate < TimeUtil::now()) {
$lastVote = null;
}
}
@@ -282,7 +282,21 @@ if($lastVoteID){
<div id="nation-position"><?php myNationInfo($generalObj); ?></div>
<div id="general-position"><?php generalInfo($generalObj); ?></div>
<div id="generalCommandButton" class="row gx-0">
<div class="buttonPlate bg2"><?= commandButton(['btnClass' => 'btn btn-sammo-nation', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?></div>
<div class="buttonPlate bg2">
<?= commandButton([
'splitBtnBegin' => '<div class="btn-group">',
'splitBtnEnd' => '</div>',
'splitZoneSign' => '<button type="button" class="btn btn-sammo-nation dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Toggle Dropdown</span></button>',
'splitZoneBegin' => '<ul class="dropdown-menu dropdown-menu-end">',
'splitZoneEnd' => '</ul>',
'splitSubBtnBegin' => '<li>',
'splitSubBtnEnd' => '</li>',
'btnClass' => 'btn btn-sammo-nation',
'btnSplitClass' => 'dropdown-item',
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
'isBettingActive' => $isBettingActive
])
?></div>
</div>
</div>
</div>
@@ -382,7 +396,18 @@ if($lastVoteID){
국가 메뉴
</div>
<ul class="dropdown-menu" aria-labelledby="navbarNation" id="navbarNationItems">
<?= commandButton(['btnBegin' => '<li>', 'btnEnd' => '</li>', 'btnClass' => 'dropdown-item', 'isTournamentApplicationOpen' => $isTournamentApplicationOpen, 'isBettingActive' => $isBettingActive]) ?>
<?= commandButton([
'btnBegin' => '<li>',
'btnEnd' => '</li>',
'splitMainBegin' => '<div class="d-none">',
'splitMainEnd' => '</div>',
'splitSubBtnBegin' => '<li>',
'splitSubBtnEnd' => '</li>',
'btnClass' => 'dropdown-item',
'btnSplitClass' => 'dropdown-item',
'isTournamentApplicationOpen' => $isTournamentApplicationOpen,
'isBettingActive' => $isBettingActive
]) ?>
</ul>
</li>
<li class="nav-item dropup">
@@ -9,8 +9,11 @@ use sammo\DB;
use sammo\DTO\AuctionBidItem;
use sammo\DTO\AuctionInfo;
use sammo\Enums\AuctionType;
use sammo\Enums\InheritanceKey;
use sammo\InheritancePointManager;
use sammo\TimeUtil;
use sammo\Validator;
use sammo\General;
class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
{
@@ -69,6 +72,13 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
];
}
$inheritMgr = InheritancePointManager::getInstance();
//preveious라서 column을 최대한 비울 수 있다.
$remainPoint = $inheritMgr->getInheritancePoint(
General::createGeneralObjFromDB($generalID, ['owner'], 0),
InheritanceKey::previous
);
$obfuscatedName = AuctionUniqueItem::genObfuscatedName($generalID);
return [
@@ -86,6 +96,7 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
],
'bidList' => $responseBid,
'obfuscatedName' => $obfuscatedName,
'remainPoint' => $remainPoint,
];
}
}
+1 -1
View File
@@ -73,7 +73,7 @@ class OpenBuyRiceAuction extends \sammo\BaseAPI
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
if($yearMonth < $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
@@ -73,7 +73,7 @@ class OpenSellRiceAuction extends \sammo\BaseAPI
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
if($yearMonth < $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
+1 -1
View File
@@ -64,7 +64,7 @@ class OpenUniqueAuction extends \sammo\BaseAPI
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
if($yearMonth < $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
+2 -2
View File
@@ -281,8 +281,8 @@ abstract class Auction
$general = $this->general;
$highestBid = $this->getHighestBid();
if ($highestBid !== null && $amount <= $highestBid->amount) {
return '현재입찰가보다 높게 입찰해야 합니다.';
if ($highestBid !== null && $amount < $highestBid->amount + 10) {
return '현재입찰가보다 10 포인트 높게 입찰해야 합니다.';
}
$myPrevBid = $this->getMyPrevBid();
+13 -5
View File
@@ -124,6 +124,13 @@ abstract class AuctionBasicResource extends Auction
$auctionHost->increaseVar($hostRes->value, $this->info->detail->amount);
$auctionHost->applyDB(DB::db());
if($this->info->hostGeneralID != 0){
$josaYiHost = JosaUtil::pick($auctionHost->getName(), '이');
$auctionAmount = $this->info->detail->amount;
$auctionLog = "{$this->auctionID}{$hostResName} 경매 <M>유찰</> : <Y>{$auctionHost->getName()}</>{$josaYiHost} {$hostResName} <C>{$auctionAmount}</> 판매, 그러나 입찰자 부재";
pushAuctionLog($auctionHost->getLogger()->formatText($auctionLog, ActionLogger::EVENT_PLAIN));
}
$staticNation = $auctionHost->getStaticNation();
$src = new MessageTarget(0, '', 0, 'System', '#000000');
$dest = new MessageTarget(
@@ -187,11 +194,11 @@ abstract class AuctionBasicResource extends Auction
$auctionID = $this->info->id;
$auctionHost->getLogger()->pushGeneralActionLog(
"{$auctionID}번 거래 <C>성사</>로 {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 지불, {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 획득!",
"{$auctionID}번 거래 <C>성사</>로 {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 판매, {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 획득!",
ActionLogger::EVENT_PLAIN
);
$bidder->getLogger()->pushGeneralActionLog(
"{$auctionID}번 거래 <C>성사</>로 {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 판매, {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 획득!",
"{$auctionID}번 거래 <C>성사</>로 {$bidderResName} <C>{$bidAmount}</>{$josaUlBidder} 지불, {$hostResName} <C>{$auctionAmount}</>{$josaUlHost} 획득!",
ActionLogger::EVENT_PLAIN
);
@@ -199,13 +206,14 @@ abstract class AuctionBasicResource extends Auction
$josaYiBidder = JosaUtil::pick($bidder->getName(), '이');
$auctionLog = [];
$auctionLog[] = "{$auctionID}{$hostResName} 경매 <C>성사</> : <Y>{$auctionHost->getName()}</>{$josaYiHost} {$hostResName} <C>{$auctionAmount}</> 판매, <Y>{$bidder->getName()}</>{$josaYiBidder} <C>{$bidAmount}</> 구매";
$josaRoBidder = JosaUtil::pick($bidAmount, '로');
$auctionLog[] = "{$auctionID}{$hostResName} 경매 <C>성사</> : <Y>{$auctionHost->getName()}</>{$josaYiHost} {$hostResName} <C>{$auctionAmount}</> 판매, <Y>{$bidder->getName()}</>{$josaYiBidder} {$bidderResName} <C>{$bidAmount}</>{$josaRoBidder} 구매";
if ($highestBid->amount === $this->info->detail->finishBidAmount) {
$auctionLog[0] .= ' <M>★ 즉시구매가 거래 ★</>';
$auctionLog[0] .= ' <M>★ 마감가 거래 ★</>';
} else if ($highestBid->amount === $this->info->detail->startBidAmount) {
$auctionLog[0] .= " <R>★ 최가 거래 ★</>";
$auctionLog[0] .= " <R>★ 최가 거래 ★</>";
}
pushAuctionLog(array_map(
+49 -14
View File
@@ -52,6 +52,17 @@ class AuctionUniqueItem extends Auction
return '아직 경매가 끝나지 않았습니다.';
}
$availableCnt = 0;
foreach(GameConst::$allItems as $itemType => $itemList){
$availableCnt += $itemList[$itemKey] ?? 0;
$availableCnt -= $db->queryFirstField('SELECT count(*) FROM `general` WHERE %b = %s', $itemType, $itemKey);
}
if($availableCnt <= 0){
return '그 유니크를 더 얻을 수 없습니다.';
}
$gameStor = KVStorage::getStorage($db, 'game_env');
$now = new DateTimeImmutable();
@@ -118,6 +129,10 @@ class AuctionUniqueItem extends Auction
public function bid(int $amount, bool $tryExtendCloseDate): ?string
{
if($this->info->finished){
return '경매가 종료되었습니다.';
}
$db = DB::db();
/** @var AuctionInfo[] */
$openUniqueAuctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
@@ -126,21 +141,28 @@ class AuctionUniqueItem extends Auction
) ?? []);
$auctionIDList = [];
foreach($openUniqueAuctions as $auction){
foreach ($openUniqueAuctions as $auction) {
$auctionIDList[] = $auction->id;
}
$db = DB::db();
$rawHighestBids = Util::convertArrayToDict($db->query(
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
SELECT `auction_id`, MAX(`amount`) as `max_amount`
FROM `ng_auction_bid`
WHERE `auction_id` IN %li
GROUP BY `auction_id`
ORDER BY `amount`
) AS max_bid
ON bid.`auction_id` = max_bid.`auction_id` AND bid.`amount` = max_bid.`max_amount`',
$auctionIDList,
) ?? [], 'auction_id');
if($auctionIDList){
$rawHighestBids = Util::convertArrayToDict($db->query(
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
SELECT `auction_id`, MAX(`amount`) as `max_amount`
FROM `ng_auction_bid`
WHERE `auction_id` IN %li
GROUP BY `auction_id`
ORDER BY `amount`
) AS max_bid
ON bid.`auction_id` = max_bid.`auction_id` AND bid.`amount` = max_bid.`max_amount`',
$auctionIDList,
) ?? [], 'auction_id');
}
else{
$rawHighestBids = [];
}
/** @var array<int,AuctionBidItem> */
$highestBids = Util::mapWithKey(
fn ($auctionID, $bid) => AuctionBidItem::fromArray($bid),
@@ -149,13 +171,13 @@ class AuctionUniqueItem extends Auction
$itemCode = $this->info->target;
if($itemCode === null){
if ($itemCode === null) {
throw new \Exception('아이템 코드가 없습니다.');
}
$bidItemTypes = new Set();
foreach (GameConst::$allItems as $itemType => $itemList) {
if (key_exists($itemCode, $itemList) && $itemList[$itemCode] <= 0) {
if (($itemList[$itemCode] ?? 0) <= 0) {
continue;
}
$bidItemTypes->add($itemType);
@@ -234,6 +256,7 @@ class AuctionUniqueItem extends Auction
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
}
$isExtendCloseDateRequired = false;
foreach (GameConst::$allItems as $itemType => $itemList) {
//아직은 그런 경우는 없지만 동일 유니크를 여러 부위에 장착할 수 있을지도 모름
if (!key_exists($itemKey, $itemList)) {
@@ -243,11 +266,13 @@ class AuctionUniqueItem extends Auction
$ownItem = $general->getItem($itemType);
if ($ownItem->getRawClassName() == $itemKey) {
//FIXME: 이 경우에는 환불이 되던가 해야함.
$isExtendCloseDateRequired = true;
$reasons[] = '이미 그 유니크를 가지고 있습니다.';
continue;
}
if (!$ownItem->isBuyable()) {
$isExtendCloseDateRequired = true;
$reasons[] = '이미 다른 유니크를 가지고 있습니다.';
continue;
}
@@ -263,6 +288,16 @@ class AuctionUniqueItem extends Auction
}
if (!$availableItemTypes) {
if ($isExtendCloseDateRequired) {
$turnTerm = $gameStor->getValue('turnterm');
//동일 부위 제한에 걸렸다면 자동 연장
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_LIMIT_BY_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_BY_BID) * 60
));
$this->extendCloseDate($extendedCloseDate, true);
$this->extendLatestBidCloseDate(null);
}
return join(' ', $reasons);
}
@@ -98,6 +98,9 @@ class che_사기진작 extends Command\GeneralCommand{
$general->addDex($general->getCrewTypeObj(), $score, false);
[$reqGold,] = $this->getCost();
$general->increaseVarWithLimit('gold', -$reqGold, 0);
$general->addExperience($exp);
$general->addDedication($ded);
$general->increaseVar('leadership_exp', 1);
+35 -20
View File
@@ -243,30 +243,14 @@ class che_피장파장 extends Command\NationCommand
{
$generalObj = $this->generalObj;
$nationID = $generalObj->getNationID();
$nationList = [];
$testTurn = new LastTurn($this->getName(), null, $this->getPreReqTurn());
foreach (getAllNationStaticInfo() as $destNation) {
$testCommand = new static($generalObj, $this->env, $testTurn, ['destNationID' => $destNation['nation']]);
$nationTarget = [
'id' => $destNation['nation'],
'name' => $destNation['name'],
'color' => $destNation['color'],
'power' => $destNation['power'],
];
if (!$testCommand->hasFullConditionMet()) {
$nationTarget['notAvailable'] = true;
}
if ($destNation['nation'] == $nationID) {
$nationTarget['notAvailable'] = true;
}
$nationList[] = $nationTarget;
}
$testTurn = new LastTurn($this->getName(), null, null);
$availableCommandTypeList = [];
$currYearMonth = Util::joinYearMonth($this->env['year'], $this->env['month']);
$oneAvailableCommandName = null;
foreach (GameConst::$availableChiefCommand['전략'] as $commandType) {
$cmd = buildNationCommandClass($commandType, $generalObj, $this->env, new LastTurn());
$cmdName = $cmd->getName();
@@ -276,9 +260,40 @@ class che_피장파장 extends Command\NationCommand
if ($nextAvailableTurn !== null && $currYearMonth < $nextAvailableTurn) {
$remainTurn = $nextAvailableTurn - $currYearMonth;
}
else{
$oneAvailableCommandName = $cmd->getRawClassName();
}
$availableCommandTypeList[$commandType] = ['name' => $cmdName, 'remainTurn' => $remainTurn];
}
$nationList = [];
foreach (getAllNationStaticInfo() as $destNation) {
$nationTarget = [
'id' => $destNation['nation'],
'name' => $destNation['name'],
'color' => $destNation['color'],
'power' => $destNation['power'],
];
if($oneAvailableCommandName === null){
$nationTarget['notAvailable'] = true;
}
else if ($destNation['nation'] == $nationID) {
$nationTarget['notAvailable'] = true;
}
else {
$testCommand = new static($generalObj, $this->env, $testTurn, [
'destNationID' => $destNation['nation'],
'commandType' => $oneAvailableCommandName
]);
if (!$testCommand->hasFullConditionMet()) {
$nationTarget['notAvailable'] = true;
}
}
$nationList[] = $nationTarget;
}
return [
'procRes' => [
'nationList' => $nationList,
+3 -3
View File
@@ -33,12 +33,12 @@ class CreateManyNPC extends \sammo\Event\Action
$env['year'],
$env['month']
)));
$age = $rng->nextRangeInt(20, 25);
$birthYear = $env['year'] - $age;
$deathYear = $env['year'] + $rng->nextRangeInt(10, 60);
$result = [];
foreach (pickGeneralFromPool(DB::db(), $rng, 0, $cnt) as $pickedNPC) {
$age = $rng->nextRangeInt(20, 25);
$birthYear = $env['year'] - $age;
$deathYear = $env['year'] + $rng->nextRangeInt(10, 50);
$newNPC = $pickedNPC->getGeneralBuilder();
$newNPC->setNationID(0)
->setNPCType(3)
+2 -2
View File
@@ -65,7 +65,7 @@ body {
}
#navbarNationItems {
columns: 2;
columns: 3;
}
#navbarQuickItems {
@@ -320,7 +320,7 @@ body {
font-weight: bold;
font-size: 14px;
}
.toolbarButton2 {
@extend .btn;
@extend .btn-sammo-base2;
+8 -1
View File
@@ -16,5 +16,12 @@
<?=$btnBegin??''?><a href='b_battleCenter.php' target='_blank' class='open-window commandButton <?=$btnClass??""?> <?= $showSecret ? '' : 'disabled' ?>'>감 찰 부</a><?=$btnEnd??''?>
<?=$btnBegin??''?><a href='v_inheritPoint.php' class='commandButton <?=$btnClass??""?>'>유산 관리</a><?=$btnEnd??''?>
<?=$btnBegin??''?><a href='b_myPage.php' class='commandButton <?=$btnClass??""?>'>내 정보&amp;설정</a><?=$btnEnd??''?>
<?=$btnBegin??''?><a href='v_auction.php' target='_blank' class='open-window commandButton <?=$btnClass??""?>'>거 래 장</a><?=$btnEnd??''?>
<?=$splitBtnBegin??''?>
<?=$splitMainBegin??''?><a href='v_auction.php' target='_blank' class='open-window commandButton <?=$btnClass??""?>'>경 매 장</a><?=$splitMainEnd??''?>
<?=$splitZoneSign??''?>
<?=$splitZoneBegin??''?>
<?=$splitSubBtnBegin??''?><a href='v_auction.php' target='_blank' class='open-window commandButton <?=$btnSplitClass??''?>'>금/쌀 경매장</a><?=$splitSubBtnEnd??''?>
<?=$splitSubBtnBegin??''?><a href='v_auction.php?type=unique' target='_blank' class='open-window commandButton <?=$btnSplitClass??''?>'>유니크 경매장</a><?=$splitSubBtnEnd??''?>
<?=$splitZoneEnd??''?>
<?=$splitBtnEnd??''?>
<?=$btnBegin??''?><a href='b_betting.php' target='_blank' class='open-window <?=$btnClassForBetting??""?>'>베 팅 장</a><?=$btnEnd??''?>
+22 -5
View File
@@ -4,8 +4,8 @@
<BButton @click="isResAuction = true">/</BButton>
<BButton @click="isResAuction = false">유니크</BButton>
</TopBackBar>
<AuctionResource v-if="isResAuction"></AuctionResource>
<AuctionUniqueItem v-else></AuctionUniqueItem>
<AuctionResource v-if="isResAuction" ref="auctionResource"></AuctionResource>
<AuctionUniqueItem v-else ref="auctionUniqueItem"></AuctionUniqueItem>
<BottomBar type="close"></BottomBar>
</BContainer>
</template>
@@ -24,9 +24,26 @@ import AuctionResource from "@/components/AuctionResource.vue";
import AuctionUniqueItem from "@/components/AuctionUniqueItem.vue";
import { ref } from "vue";
const isResAuction = ref(true);
const props = defineProps({
isResAuction: {
type: Boolean,
default: true,
},
});
function tryReload() {
console.log('갱신');
const auctionResource = ref<InstanceType<typeof AuctionResource> | null>(null);
const auctionUniqueItem = ref<InstanceType<typeof AuctionUniqueItem> | null>(null);
const isResAuction = ref(props.isResAuction);
async function tryReload() {
console.log(auctionResource.value);
console.log(auctionUniqueItem.value);
if(isResAuction.value && auctionResource.value){
await auctionResource.value.refresh();
}
if(!isResAuction.value && auctionUniqueItem.value){
await auctionUniqueItem.value.refresh();
}
}
</script>
+7
View File
@@ -221,4 +221,11 @@ onMounted(() => {
}
}
}
</style>
<style>
.hidden_but_copyable {
color: rgba(0, 0, 0, 0);
font-size: 0;
}
</style>
+2
View File
@@ -102,6 +102,7 @@
<NumberInputWithInfo
v-model="nationPolicy.minimumResourceActionAmount"
:step="100"
:min="100"
title="포상/몰수/헌납/삼/팜 최소 단위"
>
연산결과가 단위보다 적다면 수행하지 않습니다.
@@ -111,6 +112,7 @@
<NumberInputWithInfo
v-model="nationPolicy.maximumResourceActionAmount"
:step="100"
:min="100"
title="포상/몰수/헌납/삼/팜 최대 단위"
>
연산결과가 단위보다 크다면, 값에 맞춥니다.
+179 -75
View File
@@ -2,89 +2,101 @@
<div class="bg0">
<div class="bg2">거래장</div>
<div style="background-color: orange"> 구매</div>
<div class="row gx-0">
<div class="col">번호</div>
<div class="col">판매자</div>
<div class="col">물품</div>
<div class="col">수량</div>
<div class="col">시작 구매</div>
<div class="col">현재 구매</div>
<div class="col">즉시 구매</div>
<div class="col">단가</div>
<div class="col">구매 예정자</div>
<div class="col">거래 종료</div>
<div class="auctionItem gx-0">
<div class="idx">번호</div>
<div class="host">판매자</div>
<div class="amount">수량</div>
<div class="highestBidder">입찰자</div>
<div class="highestBid">입찰</div>
<div class="bidRatio"></div>
<div class="finishBid">마감</div>
<div class="closeDate">거래 종료</div>
</div>
<div v-for="auction of buyRice" :key="auction.id" class="row gx-0" @click="selectedBuyRiceAuction = auction">
<div class="col">{{ auction.id }}</div>
<div class="col">{{ auction.hostName }}</div>
<div class="col"></div>
<div class="col">{{ auction.amount }}</div>
<div class="col">{{ auction.startBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
<div class="col">{{ auction.finishBidAmount }}</div>
<div class="col">{{ auction.highestBid ? (auction.highestBid.amount / auction.amount).toFixed(2) : "-" }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.generalName : "-" }}</div>
<div class="col">{{ auction.closeDate }}</div>
<div
v-for="auction of buyRice"
:key="auction.id"
class="auctionItem gx-0"
@click="selectedBuyRiceAuction = auction"
>
<div class="idx f_tnum">{{ auction.id }}</div>
<div class="host">{{ auction.hostName }}</div>
<div class="amount f_tnum"> {{ auction.amount.toLocaleString() }}</div>
<div class="highestBidder">{{ auction.highestBid?.generalName ?? "-" }}</div>
<div :class="['highestBid f_tnum', auction.highestBid ? '' : 'noBid']">
{{ (auction.highestBid?.amount ?? auction.startBidAmount).toLocaleString() }}
</div>
<div class="bidRatio f_tnum">
{{ auction.highestBid ? (auction.highestBid.amount / auction.amount).toFixed(2) : "-" }}
</div>
<div class="finishBid f_tnum"> {{ auction.finishBidAmount.toLocaleString() }}</div>
<div class="closeDate f_tnum">{{ cutDateTime(auction.closeDate) }}</div>
</div>
<div v-if="selectedBuyRiceAuction !== undefined" class="row">
<div class="col">{{ selectedBuyRiceAuction.id }} {{ selectedBuyRiceAuction.amount }} 경매에</div>
<div class="col">
<div v-if="selectedBuyRiceAuction !== undefined" class="row gx-1">
<div class="offset-1 col-4 offset-md-3 col-md-2 align-self-center f_tnum text-end">
{{ selectedBuyRiceAuction.id }} {{ selectedBuyRiceAuction.amount }} 경매에
</div>
<div class="col-3 col-md-2">
<NumberInputWithInfo
v-model="bidAmountBuyRiceAuction"
:int="true"
:min="selectedBuyRiceAuction.startBidAmount"
:max="selectedBuyRiceAuction.finishBidAmount"
title="금"
:step="10"
></NumberInputWithInfo>
</div>
<div class="col"><BButton @click="bidBuyRiceAuction">입찰</BButton></div>
<div class="col-2 col-md-1 d-grid"><BButton @click="bidBuyRiceAuction">입찰</BButton></div>
</div>
<div style="background-color: skyblue"> 판매</div>
<div class="row gx-0">
<div class="col">번호</div>
<div class="col">판매자</div>
<div class="col">물품</div>
<div class="col">수량</div>
<div class="col">시작 구매</div>
<div class="col">현재 구매</div>
<div class="col">즉시 구매</div>
<div class="col">단가</div>
<div class="col">구매 예정자</div>
<div class="col">거래 종료</div>
<div class="auctionItem gx-0">
<div class="idx">번호</div>
<div class="host">판매자</div>
<div class="amount">수량</div>
<div class="highestBidder">입찰자</div>
<div class="highestBid">입찰</div>
<div class="bidRatio"></div>
<div class="finishBid">마감</div>
<div class="closeDate">거래 종료</div>
</div>
<div v-for="auction of sellRice" :key="auction.id" class="row gx-0" @click="selectedSellRiceAuction = auction">
<div class="col">{{ auction.id }}</div>
<div class="col">{{ auction.hostName }}</div>
<div class="col"></div>
<div class="col">{{ auction.amount }}</div>
<div class="col">{{ auction.startBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
<div class="col">{{ auction.finishBidAmount }}</div>
<div class="col">{{ auction.highestBid ? (auction.highestBid.amount / auction.amount).toFixed(2) : "-" }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.generalName : "-" }}</div>
<div class="col">{{ auction.closeDate }}</div>
<div
v-for="auction of sellRice"
:key="auction.id"
class="auctionItem gx-0"
@click="selectedSellRiceAuction = auction"
>
<div class="idx f_tnum">{{ auction.id }}</div>
<div class="host">{{ auction.hostName }}</div>
<div class="amount f_tnum">{{ auction.amount.toLocaleString() }}</div>
<div class="highestBidder">{{ auction.highestBid?.generalName ?? "-" }}</div>
<div :class="['highestBid f_tnum', auction.highestBid ? '' : 'noBid']">
{{ (auction.highestBid?.amount ?? auction.startBidAmount).toLocaleString() }}
</div>
<div class="bidRatio f_tnum">
{{ auction.highestBid ? (auction.highestBid.amount / auction.amount).toFixed(2) : "-" }}
</div>
<div class="finishBid f_tnum"> {{ auction.finishBidAmount.toLocaleString() }}</div>
<div class="closeDate f_tnum">{{ cutDateTime(auction.closeDate) }}</div>
</div>
<div v-if="selectedSellRiceAuction !== undefined" class="row">
<div class="col">{{ selectedSellRiceAuction.id }} {{ selectedSellRiceAuction.amount }} 경매에</div>
<div class="col">
<div v-if="selectedSellRiceAuction !== undefined" class="row gx-1">
<div class="offset-1 col-4 offset-md-3 col-md-2 align-self-center f_tnum text-end">
{{ selectedSellRiceAuction.id }} {{ selectedSellRiceAuction.amount }} 경매에
</div>
<div class="col-3 col-md-2">
<NumberInputWithInfo
v-model="bidAmountSellRiceAuction"
:int="true"
:min="selectedSellRiceAuction.startBidAmount"
:max="selectedSellRiceAuction.finishBidAmount"
title="쌀"
:step="10"
></NumberInputWithInfo>
</div>
<div class="col"><BButton @click="bidSellRiceAuction">입찰</BButton></div>
<div class="col-2 col-md-1 d-grid"><BButton @click="bidSellRiceAuction">입찰</BButton></div>
</div>
<div>경매 등록</div>
<div class="row">
<div class="col">
매물
<div class="row gx-1">
<div class="col-2 offset-md-2 col-md-1">
매물<br />
<BButtonGroup>
<BButton :pressed="openAuctionInfo.type == 'buyRice'" @click="openAuctionInfo.type = 'buyRice'"> </BButton>
<BButton :pressed="openAuctionInfo.type == 'sellRice'" @click="openAuctionInfo.type = 'sellRice'">
@@ -92,50 +104,56 @@
</BButton>
</BButtonGroup>
</div>
<div class="col">
<NumberInputWithInfo
v-model="openAuctionInfo.closeTurnCnt"
:int="true"
:min="3"
:max="24"
title="기간(턴)"
:step="1"
></NumberInputWithInfo>
</div>
<div class="col">
<div class="col col-md-2">
수량 ({{ openAuctionInfo.type == "buyRice" ? "쌀" : "금" }})<br />
<NumberInputWithInfo
v-model="openAuctionInfo.amount"
:int="true"
:min="100"
:max="10000"
title="수량"
:step="10"
></NumberInputWithInfo>
</div>
<div class="col">
<div class="col-2 col-md-1">
기간()
<NumberInputWithInfo
v-model="openAuctionInfo.closeTurnCnt"
:int="true"
:min="3"
:max="24"
:step="1"
></NumberInputWithInfo>
</div>
<div class="col col-md-2">
시작가 ({{ openAuctionInfo.type == "buyRice" ? "금" : "쌀" }})
<NumberInputWithInfo
v-model="openAuctionInfo.startBidAmount"
:int="true"
:min="100"
:max="10000"
title="시작구매가"
:step="10"
></NumberInputWithInfo>
</div>
<div class="col">
</div>
<div class="col col-md-2">
마감가 ({{ openAuctionInfo.type == "buyRice" ? "금" : "쌀" }})
<NumberInputWithInfo
v-model="openAuctionInfo.finishBidAmount"
:int="true"
:min="100"
:max="10000"
title="즉시구매가"
:step="10"
></NumberInputWithInfo>
</div>
<div class="col">
<div class="col-1 d-grid">
<BButton @click="openAuction">등록</BButton>
</div>
</div>
<div>이전 경매(최근 20)</div>
<div v-for="(log, idx) in recentLogs" :key="idx">
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-html="formatLog(log)" />
</div>
</div>
</template>
@@ -147,10 +165,12 @@ import { useToast, BButtonGroup, BButton } from "bootstrap-vue-3";
import { isString } from "lodash";
import { onMounted, reactive, ref, watch } from "vue";
import NumberInputWithInfo from "@/components/NumberInputWithInfo.vue";
import { formatLog } from "@/utilGame/formatLog";
const toasts = unwrap(useToast());
const buyRice = ref<BasicResourceAuctionInfo[]>([]);
const sellRice = ref<BasicResourceAuctionInfo[]>([]);
const recentLogs = ref<string[]>([]);
const selectedBuyRiceAuction = ref<BasicResourceAuctionInfo | undefined>(undefined);
const bidAmountBuyRiceAuction = ref<number>(0);
@@ -162,6 +182,12 @@ watch(selectedBuyRiceAuction, (auction) => {
bidAmountBuyRiceAuction.value = auction.highestBid ? auction.highestBid.amount : auction.startBidAmount;
});
function cutDateTime(dateTime: string, showSecond = false) {
if (showSecond) {
return dateTime.substring(5, 19);
}
return dateTime.substring(5, 16);
}
async function bidBuyRiceAuction() {
if (selectedBuyRiceAuction.value === undefined) {
@@ -244,6 +270,7 @@ async function refresh() {
const result = await SammoAPI.Auction.GetActiveResourceAuctionList();
buyRice.value = result.buyRice;
sellRice.value = result.sellRice;
recentLogs.value = result.recentLogs;
} catch (e) {
console.error(e);
if (isString(e)) {
@@ -282,8 +309,85 @@ async function openAuction() {
}
}
defineExpose({
refresh,
});
onMounted(async () => {
void refresh();
console.log("mounted");
});
</script>
<style lang="scss" scoped>
@import "@scss/common/break_500px.scss";
.auctionItem {
display: grid;
text-align: center;
> div {
align-self: center;
}
.noBid {
color: #ccc;
}
border-bottom: solid gray 1px;
}
@include media-500px {
.auctionItem {
grid-template-columns: 1fr 3fr 3fr 1fr 2fr 2fr;
grid-template-rows: 1fr 1fr;
.idx {
grid-column: 1 / 2;
grid-row: 1 / 3;
}
.host {
grid-column: 2 / 3;
grid-row: 1 / 2;
}
.amount {
grid-column: 2 / 3;
grid-row: 2/ 3;
}
.highestBidder {
grid-column: 3 / 4;
grid-row: 1 / 2;
}
.highestBid {
grid-column: 3 / 4;
grid-row: 2 / 3;
}
.bidRatio {
grid-column: 4 / 5;
grid-row: 1 / 3;
}
.finishBid {
grid-column: 5 / 6;
grid-row: 1 / 3;
}
.closeDate {
grid-column: 6 / 7;
grid-row: 1 / 3;
}
}
}
@include media-1000px {
.auctionItem {
grid-template-columns: 1fr 2fr 2fr 2fr 2fr 1fr 3fr 2fr;
grid-template-rows: 1fr;
}
}
</style>
+143 -44
View File
@@ -1,61 +1,121 @@
<template>
<div class="bg0">
<div class="bg2">유니크 경매장</div>
<div> 가명: {{ obfuscatedName }}</div>
<div>
가명: <span class="isMe">{{ obfuscatedName }}</span>
</div>
<template v-if="currentAuction !== undefined">
<div class="bg1">상세</div>
<div class="row gx-0">
<div class="col-4 col-md-2 bg2">경매 번호</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.id }}</div>
<div class="col-4 col-md-2 bg2">경매명</div>
<div class="bg2">경매 {{ currentAuction.auction.id }} 상세</div>
<div class="row gx-0 text-center">
<div class="col-2 col-md-1 bg1">경매</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.title }}</div>
<div class="col-4 col-md-2 bg2">주최자(익명)</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.hostName }}</div>
<div class="col-2 col-md-1 bg1">주최자(익명)</div>
<div :class="['col-4 col-md-2', currentAuction.auction.isCallerHost ? 'isMe' : '']">
{{ currentAuction.auction.hostName }}
</div>
<div class="col-4 col-md-2 bg2">종료시</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.closeDate }}</div>
<div class="col-2 col-md-1 bg1">종료</div>
<div class="col-4 col-md-2 f_tnum">{{ cutDateTime(currentAuction.auction.closeDate, true) }}</div>
<div class="col-4 col-md-2 bg2">최대지연</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.availableLatestBidCloseDate }}</div>
<div class="col-2 col-md-1 bg1">최대지연</div>
<div class="col-4 col-md-2 f_tnum">
{{ cutDateTime(currentAuction.auction.availableLatestBidCloseDate, true) }}
</div>
</div>
<div class="bg1">입찰자 목록</div>
<div class="row gx-0 bg2">
<div class="col-4">입찰자</div>
<div class="col-4">입찰포인트</div>
<div class="col-4">시각</div>
<div
class="row gx-0 px-md-5 text-center"
:style="{
borderBottom: 'solid 1px white',
}"
>
<div class="col-4 offset-md-2 col-md-3">입찰자</div>
<div class="col-4 col-md-2 text-end px-5">입찰포인트</div>
<div class="col-4 col-md-3">시각</div>
</div>
<div v-for="bidder of currentAuction.bidList" :key="bidder.amount" class="row gx-0">
<div class="col-4">{{ bidder.generalName }}</div>
<div class="col-4">{{ bidder.amount }}</div>
<div class="col-4">{{ bidder.date }}</div>
<div v-for="bidder of currentAuction.bidList" :key="bidder.amount" class="row gx-0 px-md-5 text-center">
<div :class="['col-4 offset-md-2 col-md-3', bidder.isCallerHighestBidder ? 'isMe' : '']">{{ bidder.generalName }}</div>
<div class="col-4 col-md-2 text-end px-5 f_tnum">{{ bidder.amount.toLocaleString() }}</div>
<div class="col-4 col-md-3 f_tnum">{{ cutDateTime(bidder.date) }}</div>
</div>
<div class="bg1">입찰하기</div>
<div class="row">
<div class="col">
<label class="col-5 offset-md-3 col-md-3 col-form-label text-center">유산포인트 (잔여: {{ currentAuction.remainPoint.toLocaleString() }}포인트)</label>
<div class="col-4 col-md-2">
<NumberInputWithInfo
v-model="bidAmount"
:int="true"
:min="currentAuction.bidList[0].amount"
title="유산포인트"
:max="currentAuction.remainPoint"
title=""
:step="1"
></NumberInputWithInfo>
</div>
<div class="col"><BButton @click="bidAuction">입찰</BButton></div>
<div class="col-3 col-md-1 d-grid"><BButton @click="bidAuction">입찰</BButton></div>
</div>
</template>
<div class="bg1">목록</div>
<div v-for="[auctionID, auction] of auctionList" :key="auctionID" class="row" @click="currentAuctionID = auctionID">
<div class="col">{{ auction.id }}</div>
<div class="col">{{ auction.finished ? "종료됨" : "진행중" }}</div>
<div class="col">{{ auction.title }}</div>
<div class="col">{{ auction.hostName }}</div>
<div class="col">{{ auction.closeDate }}</div>
<div class="col">{{ auction.remainCloseDateExtensionCnt > 0 ? "남음" : "소진" }}</div>
<div class="col">{{ auction.highestBid.generalName }}</div>
<div class="col">{{ auction.highestBid.amount }}</div>
<div class="bg1">진행중인 경매 목록</div>
<div
class="row gx-0 text-center"
:style="{
borderBottom: 'solid 1px white',
}"
>
<div class="col-1">번호</div>
<div class="col-4">경매명</div>
<div class="col-1">주최자</div>
<div class="col-2">종료일시</div>
<div class="col-1">연장</div>
<div class="col-1">1순위</div>
<div class="col-2 text-end px-2">포인트</div>
</div>
<div
v-for="[auctionID, auction] of ongoingAuctionList"
:key="auctionID"
class="row gx-0 text-center clickableRow"
@click="currentAuctionID = auctionID"
>
<div class="col-1">{{ auction.id }}</div>
<div class="col-4">{{ auction.title }}</div>
<div :class="['col-1', auction.isCallerHost ? 'isMe' : '']">{{ auction.hostName }}</div>
<div class="col-2 f_tnum">{{ cutDateTime(auction.closeDate) }}</div>
<div class="col-1">{{ auction.remainCloseDateExtensionCnt > 0 ? "남음" : "소진" }}</div>
<div :class="['col-1', auction.highestBid.isCallerHighestBidder ? 'isMe' : '']">
{{ auction.highestBid.generalName }}
</div>
<div class="col-2 text-end px-2 f_tnum">{{ auction.highestBid.amount.toLocaleString() }}</div>
</div>
<div class="bg1">종료된 경매 목록</div>
<div
class="row gx-0 text-center"
:style="{
borderBottom: 'solid 1px white',
}"
>
<div class="col-1">번호</div>
<div class="col-4">경매명</div>
<div class="col-1">주최자</div>
<div class="col-2">종료일시</div>
<div class="col-1">연장</div>
<div class="col-1">1순위</div>
<div class="col-2 text-end px-2">포인트</div>
</div>
<div
v-for="[auctionID, auction] of finishedAuctionList"
:key="auctionID"
class="row gx-0 text-center clickableRow"
@click="currentAuctionID = auctionID"
>
<div class="col-1">{{ auction.id }}</div>
<div class="col-4">{{ auction.title }}</div>
<div :class="['col-1', auction.isCallerHost ? 'isMe' : '']">{{ auction.hostName }}</div>
<div class="col-2 f_tnum">{{ cutDateTime(auction.closeDate) }}</div>
<div class="col-1">{{ auction.remainCloseDateExtensionCnt > 0 ? "남음" : "소진" }}</div>
<div :class="['col-1', auction.highestBid.isCallerHighestBidder ? 'isMe' : '']">
{{ auction.highestBid.generalName }}
</div>
<div class="col-2 text-end px-2 f_tnum">{{ auction.highestBid.amount.toLocaleString() }}</div>
</div>
</div>
</template>
@@ -95,19 +155,35 @@ async function refreshDetail() {
watch(currentAuctionID, () => {
void refreshDetail();
});
const auctionList = ref(new Map<number, AuctionItemInfo>());
const ongoingAuctionList = ref(new Map<number, AuctionItemInfo>());
const finishedAuctionList = ref(new Map<number, AuctionItemInfo>());
const obfuscatedName = ref("");
const toasts = unwrap(useToast());
async function refresh() {
function cutDateTime(dateTime: string, showSecond = false) {
if (showSecond) {
return dateTime.substring(5, 19);
}
return dateTime.substring(5, 16);
}
async function refreshList() {
try {
const result = await SammoAPI.Auction.GetUniqueItemAuctionList();
obfuscatedName.value = result.obfuscatedName;
auctionList.value = new Map(result.list.map((auction) => [auction.id, auction]));
if (currentAuctionID.value === undefined && result.list.length > 0) {
currentAuctionID.value = result.list[0].id;
bidAmount.value = result.list[0].highestBid.amount;
finishedAuctionList.value = new Map(
result.list.filter((auction) => auction.finished).map((auction) => [auction.id, auction])
);
ongoingAuctionList.value = new Map(
result.list.filter((auction) => !auction.finished).map((auction) => [auction.id, auction])
);
if (currentAuctionID.value === undefined && ongoingAuctionList.value.size > 0) {
const auctionIterator = ongoingAuctionList.value.values().next();
if (!auctionIterator.done) {
currentAuctionID.value = auctionIterator.value.id;
bidAmount.value = auctionIterator.value.highestBid.amount;
}
}
} catch (e) {
console.error(e);
@@ -135,8 +211,7 @@ async function bidAuction() {
title: "성공",
body: "입찰이 완료되었습니다.",
});
void refreshDetail();
void refresh();
await refresh();
} catch (e) {
console.error(e);
if (isString(e)) {
@@ -149,7 +224,31 @@ async function bidAuction() {
}
}
async function refresh() {
const waiters = [refreshList(), refreshDetail()];
await Promise.all(waiters);
}
defineExpose({
refresh,
});
onMounted(() => {
void refresh();
void refreshList();
});
</script>
<style>
.isMe {
font-weight: bold;
color: aquamarine;
}
.clickableRow{
cursor: pointer;
}
.clickableRow:hover{
background-color: rgba(255, 255, 255, 0.3);
}
</style>
+19 -5
View File
@@ -1,7 +1,7 @@
<template>
<div class="row form-group number-input-with-info">
<label v-if="!right" class="col-6 col-form-label">{{ title }}</label>
<div class="col-6">
<label v-if="!right && title" class="col col-form-label">{{ title }}</label>
<div class="col">
<input
ref="input"
v-model="rawValue"
@@ -23,13 +23,14 @@
@focus="onFocusText"
/>
</div>
<label v-if="right" class="col-6 col-form-label">{{ title }}</label>
<label v-if="right && title" class="col col-form-label">{{ title }}</label>
</div>
<div style="text-align: right">
<small class="form-text text-muted"><slot /></small>
</div>
</template>
<script lang="ts">
import { clamp } from "lodash";
import { defineComponent } from "vue";
export default defineComponent({
@@ -47,7 +48,8 @@ export default defineComponent({
},
title: {
type: String,
required: true,
required: false,
default: null,
},
min: {
type: Number,
@@ -97,11 +99,23 @@ export default defineComponent({
this.rawValue = Math.floor(this.rawValue);
}
this.printValue = this.rawValue.toLocaleString();
this.$emit("update:modelValue", this.rawValue);
if (this.min !== undefined || this.max !== undefined) {
const clampedValue = clamp(this.rawValue, this.min ?? this.rawValue, this.max ?? this.rawValue);
this.$emit("update:modelValue", clampedValue);
} else {
this.$emit("update:modelValue", this.rawValue);
}
},
onBlurNumber() {
this.editmode = false;
this.printValue = this.rawValue.toLocaleString();
if (this.min !== undefined || this.max !== undefined) {
const clampedValue = clamp(this.rawValue, this.min ?? this.rawValue, this.max ?? this.rawValue);
if (clampedValue !== this.rawValue) {
this.rawValue = clampedValue;
this.updateValue();
}
}
},
onFocusText() {
if (this.readonly) {
+2 -1
View File
@@ -17,7 +17,7 @@ export type BasicResourceAuctionInfo = {
amount: number;
startBidAmount: number;
finishBidAmount: number;
highestBid: BasicResourceAuctionBidder;
highestBid?: BasicResourceAuctionBidder;
};
export type UniqueItemAuctionBidder = {
@@ -57,6 +57,7 @@ export type UniqueItemAuctionDetail = ValidResponse & {
auction: UniqueItemAuctionInfo;
bidList: UniqueItemAuctionBidder[];
obfuscatedName: string;
remainPoint: number;
};
export type OpenAuctionResponse = ValidResponse & {
+24 -19
View File
@@ -23,14 +23,31 @@
현재 피장파장이 불가능한 국가는
<span style="color: red">붉은색</span>으로 표시됩니다.<br />
</div>
<div class="row">
<div class="col-6 col-md-3">
<div class="row gx-3">
<div class="col-5 col-md-3">
국가 :
<SelectNation v-model="selectedNationID" :nations="nationList" :searchable="searchable" />
</div>
<div class="col-3 col-md-2">
<div class="col-4 col-md-2">
<label>전략 :</label>
<b-form-select v-model="selectedCommandID" :options="commandTypesOption" />
<select
v-model="selectedCommandID"
class="form-control"
:style="{
color: availableCommandTypeList[selectedCommandID].remainTurn > 0 ? 'red' : undefined,
}"
>
<option
v-for="(command, commandRawName) in availableCommandTypeList"
:key="commandRawName"
:value="commandRawName"
:style="{
color: command.remainTurn > 0 ? 'red' : 'black',
}"
>
{{ command.name }} {{ command.remainTurn > 0 ? `(불가, ${command.remainTurn}턴)` : "" }}
</option>
</select>
</div>
<div class="col-3 col-md-2 d-grid">
<b-button @click="submit">
@@ -56,7 +73,7 @@ declare const procRes: {
delayCnt: number;
postReqTurn: number;
availableCommandTypeList: Record<
number,
string,
{
name: string;
remainTurn: number;
@@ -98,7 +115,6 @@ void Promise.all([storeP]).then(() => {
asyncReady.value = true;
});
const nationList = new Map<number, procNationItem>();
for (const nationItem of procRes.nationList) {
nationList.set(nationItem.id, nationItem);
@@ -111,19 +127,8 @@ const map = ref<MapResult>();
const delayCnt = procRes.delayCnt;
const postReqTurn = procRes.postReqTurn;
const commandTypesOption: { html: string; value: string }[] = [];
for (const [commandTypeID, commandTypeInfo] of Object.entries(procRes.availableCommandTypeList)) {
const notAvailable = commandTypeInfo.remainTurn > 0;
const notAvailableText = notAvailable ? " (불가)" : "";
const name = `${commandTypeInfo.name}${notAvailableText}`;
const html = notAvailable ? `<span style='color:red;'>${name}</span>` : name;
commandTypesOption.push({
html,
value: commandTypeID,
});
}
const selectedCommandID = ref(Object.keys(procRes.availableCommandTypeList)[0]);
const availableCommandTypeList = procRes.availableCommandTypeList;
const selectedCommandID = ref(Object.keys(availableCommandTypeList)[0]);
async function submit(e: Event) {
const event = new CustomEvent<Args>("customSubmit", {
+10 -1
View File
@@ -6,9 +6,18 @@ import { auto500px } from "./util/auto500px";
import { insertCustomCSS } from "./util/customCSS";
import { htmlReady } from "./util/htmlReady";
declare const staticValues: {
serverID: string,
turnterm: number,
serverNick: string,
isResAuction: boolean,
};
auto500px();
htmlReady(() => {
insertCustomCSS();
});
createApp(PageAuction).use(BootstrapVue3).use(BToastPlugin).mount('#app')
createApp(PageAuction, {
isResAuction: staticValues.isResAuction,
}).use(BootstrapVue3).use(BToastPlugin).mount('#app')
+3
View File
@@ -11,6 +11,8 @@ $userID = Session::getUserID();
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$isResAuction = Util::getReq('type') !== 'unique';
$me = $db->queryFirstRow('SELECT no, nation, officer_level, permission, con, turntime, belong, penalty FROM general WHERE owner=%i', $userID);
?>
@@ -28,6 +30,7 @@ $me = $db->queryFirstRow('SELECT no, nation, officer_level, permission, con, tur
'serverID' => UniqueConst::$serverID,
'serverNick' => DB::prefix(),
'turnterm' => $gameStor->turnterm,
'isResAuction' => $isResAuction,
]
]) ?>
<?= WebUtil::printDist('vue', 'v_auction', true) ?>