feat,fix,wip: 버그 수정, 연장 시간 로직 변경

This commit is contained in:
2022-06-09 01:21:21 +09:00
parent d18ae3dd11
commit 717ec012ba
18 changed files with 232 additions and 137 deletions
-2
View File
@@ -45,7 +45,6 @@ return [
'hwe/api.php', 'hwe/api.php',
'hwe/a_traffic.php', 'hwe/a_traffic.php',
'hwe/battle_simulator.php', 'hwe/battle_simulator.php',
'hwe/b_auction.php',
'hwe/b_battleCenter.php', 'hwe/b_battleCenter.php',
'hwe/b_betting.php', 'hwe/b_betting.php',
'hwe/v_chiefCenter.php', 'hwe/v_chiefCenter.php',
@@ -60,7 +59,6 @@ return [
'hwe/v_processing.php', 'hwe/v_processing.php',
'hwe/b_tournament.php', 'hwe/b_tournament.php',
'hwe/b_troop.php', 'hwe/b_troop.php',
'hwe/c_auction.php',
'hwe/c_tournament.php', 'hwe/c_tournament.php',
'hwe/func_auction.php', 'hwe/func_auction.php',
'hwe/func_command.php', 'hwe/func_command.php',
+14 -7
View File
@@ -4,6 +4,7 @@ namespace sammo;
use DateTime; use DateTime;
use Ds\Set; use Ds\Set;
use sammo\Enums\AuctionType;
use sammo\Enums\InheritanceKey; use sammo\Enums\InheritanceKey;
use sammo\Enums\RankColumn; use sammo\Enums\RankColumn;
use sammo\Event\Action; use sammo\Event\Action;
@@ -1558,6 +1559,7 @@ function CheckHall($no)
function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireType): bool function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireType): bool
{ {
$db = DB::db(); $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
//아이템 습득 상황 //아이템 습득 상황
$availableUnique = []; $availableUnique = [];
@@ -1589,6 +1591,18 @@ function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireTy
} }
} }
$auctionItems = $db->queryFirstColumn(
'SELECT `target` FROM `ng_auction` WHERE `type` = %s AND `finished` = 0',
AuctionType::UniqueItem->value
);
foreach ($auctionItems as $itemCode) {
if (key_exists($itemCode, $occupiedUnique)) {
$occupiedUnique[$itemCode]++;
} else {
$occupiedUnique[$itemCode] = 1;
}
}
foreach ($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]) { foreach ($db->queryAllLists('SELECT namespace, count(*) as cnt FROM `storage` WHERE namespace LIKE "ut_%" GROUP BY namespace') as [$uniqueNS, $cnt]) {
$itemCode = substr($uniqueNS, 3); $itemCode = substr($uniqueNS, 3);
$itemClass = buildItemClass($itemCode); $itemClass = buildItemClass($itemCode);
@@ -1632,10 +1646,7 @@ function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireTy
return false; return false;
} }
if ($general->getAuxVar('inheritRandomUnique')) { if ($general->getAuxVar('inheritRandomUnique')) {
$gameStor = KVStorage::getStorage($db, 'game_env');
[$year, $month, $initYear, $initMonth] = $gameStor->getValuesAsArray(['year', 'month', 'init_year', 'init_month']); [$year, $month, $initYear, $initMonth] = $gameStor->getValuesAsArray(['year', 'month', 'init_year', 'init_month']);
$relMonthByInit = Util::joinYearMonth($year, $month) - Util::joinYearMonth($initYear, $initMonth); $relMonthByInit = Util::joinYearMonth($year, $month) - Util::joinYearMonth($initYear, $initMonth);
@@ -1666,10 +1677,6 @@ function giveRandomUniqueItem(RandUtil $rng, General $general, string $acquireTy
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!"); $logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
$logger->pushGlobalHistoryLog("<C><b>【{$acquireType}】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!"); $logger->pushGlobalHistoryLog("<C><b>【{$acquireType}】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
$givenUnique =$gameStor->getValue('givenUnique') ?? [];
$givenUnique[$itemCode] = ($givenUnique[$itemCode] ?? 0) + 1;
$gameStor->setValue('givenUnique', $givenUnique);
return true; return true;
} }
+2 -2
View File
@@ -14,7 +14,7 @@ function registerAuction(RandUtil $rng)
$avgRice = Util::valueFit($avgRice, 1000, 20000); $avgRice = Util::valueFit($avgRice, 1000, 20000);
$neutralAuctionCnt = Util::convertPairArrayToDict($db->queryAllLists( $neutralAuctionCnt = Util::convertPairArrayToDict($db->queryAllLists(
'SELECT `type`, count(*) FROM ng_auction WHERE `type` IN %s AND `host_general_id`=0 GROUP BY `type`', 'SELECT `type`, count(*) FROM ng_auction WHERE `type` IN %ls AND `host_general_id`=0 GROUP BY `type`',
[AuctionType::BuyRice->value, AuctionType::SellRice->value], [AuctionType::BuyRice->value, AuctionType::SellRice->value],
)); ));
@@ -64,7 +64,7 @@ function processAuction()
$now = TimeUtil::now(); $now = TimeUtil::now();
$auctionList = $db->queryFirstColumn( $auctionList = $db->queryAllLists(
'SELECT id, `type` FROM ng_auction WHERE `close_date` <= %s AND finished = 0', 'SELECT id, `type` FROM ng_auction WHERE `close_date` <= %s AND finished = 0',
$now $now
); );
@@ -37,7 +37,7 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
$sellRiceList = []; $sellRiceList = [];
/** @var AuctionInfo[] */ /** @var AuctionInfo[] */
$auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query( $auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` DESC', 'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` ASC',
[ [
AuctionType::BuyRice->value, AuctionType::BuyRice->value,
AuctionType::SellRice->value, AuctionType::SellRice->value,
@@ -80,8 +80,9 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
'target' => $auction->target, 'target' => $auction->target,
'isCallerHost' => $auction->hostGeneralID === $generalID, 'isCallerHost' => $auction->hostGeneralID === $generalID,
'hostName' => $auction->detail->hostName, 'hostName' => $auction->detail->hostName,
'closeDate' => TimeUtil::format($auction->closeDate, false),
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt, 'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseDate, 'availableLatestBidCloseDate' => TimeUtil::format($auction->detail->availableLatestBidCloseDate, false),
], ],
'bidList' => $responseBid, 'bidList' => $responseBid,
'obfuscatedName' => $obfuscatedName, 'obfuscatedName' => $obfuscatedName,
@@ -32,10 +32,21 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
/** @var AuctionInfo[] */ /** @var AuctionInfo[] */
$auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query( $auctions = array_map(fn($raw)=>AuctionInfo::fromArray($raw), $db->query(
'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_date` DESC', 'SELECT * FROM `ng_auction` WHERE `type` = %s ORDER BY `close_date` ASC',
AuctionType::UniqueItem->value AuctionType::UniqueItem->value
) ?? []); ) ?? []);
$obfuscatedName = AuctionUniqueItem::genObfuscatedName($generalID);
if(!$auctions){
return [
'result' => true,
'list' => [],
'obfuscatedName' => $obfuscatedName,
];
}
$auctionIDList = []; $auctionIDList = [];
foreach ($auctions as $auction) { foreach ($auctions as $auction) {
$auctionIDList[] = $auction->id; $auctionIDList[] = $auction->id;
@@ -58,8 +69,6 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
$rawHighestBids $rawHighestBids
); );
$obfuscatedName = AuctionUniqueItem::genObfuscatedName($generalID);
$response = []; $response = [];
foreach ($auctions as $auction) { foreach ($auctions as $auction) {
$auctionID = $auction->id; $auctionID = $auction->id;
@@ -5,9 +5,12 @@ namespace sammo\API\Auction;
use sammo\Session; use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\AuctionBuyRice; use sammo\AuctionBuyRice;
use sammo\DB;
use sammo\Validator; use sammo\Validator;
use sammo\GameConst; use sammo\GameConst;
use sammo\General; use sammo\General;
use sammo\KVStorage;
use sammo\Util;
class OpenBuyRiceAuction extends \sammo\BaseAPI class OpenBuyRiceAuction extends \sammo\BaseAPI
{ {
@@ -64,6 +67,16 @@ class OpenBuyRiceAuction extends \sammo\BaseAPI
$general = General::createGeneralObjFromDB($generalID); $general = General::createGeneralObjFromDB($generalID);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
$auctionResult = AuctionBuyRice::openResourceAuction( $auctionResult = AuctionBuyRice::openResourceAuction(
$general, $general,
$amount, $amount,
@@ -5,9 +5,12 @@ namespace sammo\API\Auction;
use sammo\Session; use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\AuctionSellRice; use sammo\AuctionSellRice;
use sammo\DB;
use sammo\Validator; use sammo\Validator;
use sammo\GameConst; use sammo\GameConst;
use sammo\General; use sammo\General;
use sammo\KVStorage;
use sammo\Util;
class OpenSellRiceAuction extends \sammo\BaseAPI class OpenSellRiceAuction extends \sammo\BaseAPI
{ {
@@ -64,6 +67,16 @@ class OpenSellRiceAuction extends \sammo\BaseAPI
$general = General::createGeneralObjFromDB($generalID); $general = General::createGeneralObjFromDB($generalID);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
$auctionResult = AuctionSellRice::openResourceAuction( $auctionResult = AuctionSellRice::openResourceAuction(
$general, $general,
$amount, $amount,
@@ -5,9 +5,12 @@ namespace sammo\API\Auction;
use sammo\Session; use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\AuctionUniqueItem; use sammo\AuctionUniqueItem;
use sammo\DB;
use sammo\Validator; use sammo\Validator;
use sammo\GameConst; use sammo\GameConst;
use sammo\General; use sammo\General;
use sammo\KVStorage;
use sammo\Util;
use function sammo\buildItemClass; use function sammo\buildItemClass;
@@ -55,6 +58,16 @@ class OpenUniqueAuction extends \sammo\BaseAPI
$itemObj = buildItemClass($itemID); $itemObj = buildItemClass($itemID);
$general = General::createGeneralObjFromDB($generalID); $general = General::createGeneralObjFromDB($generalID);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
[$initYear, $initMonth, $year, $month] = $gameStor->getValuesAsArray(['init_year', 'init_month', 'year', 'month']);
$initYearMonth = Util::joinYearMonth($initYear, $initMonth);
$yearMonth = Util::joinYearMonth($year, $month);
if($yearMonth <= $initYearMonth + 3){
return '시작 후 3개월이 지나야 경매를 열 수 있습니다.';
}
$auctionResult = AuctionUniqueItem::openItemAuction($itemObj, $general, $amount); $auctionResult = AuctionUniqueItem::openItemAuction($itemObj, $general, $amount);
if(is_string($auctionResult)) { if(is_string($auctionResult)) {
-17
View File
@@ -62,23 +62,6 @@ class DropItem extends \sammo\BaseAPI
if (!$item->isBuyable()) { if (!$item->isBuyable()) {
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!"); $logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
$logger->pushGlobalHistoryLog("<R><b>【망실】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!"); $logger->pushGlobalHistoryLog("<R><b>【망실】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 잃었습니다!");
$gameStor = KVStorage::getStorage($db, 'game_env');
$givenUnique = $gameStor->getValue('givenUnique') ?? [];
$itemCode = $item->getRawClassName();
if (key_exists($itemCode, $givenUnique)) {
$givenUniqueCnt = $givenUnique[$itemCode];
$givenUniqueCnt -= 1;
if ($givenUniqueCnt <= 0) {
unset($givenUnique[$itemCode]);
} else {
$givenUnique[$itemCode] = $givenUniqueCnt;
}
} else {
//XXX: 처리하지 못한 코드가 있는가?
//FIXME: 여기에서 무언가 경고를 내야함
}
$gameStor->setValue('givenUnique', $givenUnique);
} }
$me->applyDB($db); $me->applyDB($db);
+72 -22
View File
@@ -21,7 +21,7 @@ abstract class Auction
static AuctionType $auctionType; static AuctionType $auctionType;
public const COEFF_AUCTION_CLOSE_MINUTES = 24; public const COEFF_AUCTION_CLOSE_MINUTES = 24;
public const COEFF_EXTENSION_MINUTES_PER_BID = 1 / 6; public const COEFF_EXTENSION_MINUTES_PER_BID = (1 / 6);
public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 1; public const COEFF_EXTENSION_MINUTES_LIMIT_BY_BID = 1;
public const COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 1; public const COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY = 1;
public const MIN_AUCTION_CLOSE_MINUTES = 30; public const MIN_AUCTION_CLOSE_MINUTES = 30;
@@ -157,32 +157,55 @@ abstract class Auction
return null; return null;
} }
public function extendLatestBidCloseDate(?DateTimeInterface $date): ?string
{
if ($date === null) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$turnTerm = $gameStor->getValue('turnterm');
$date = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
));
}
else{
$date = DateTimeImmutable::createFromInterface($date);
}
if ($this->info->detail->availableLatestBidCloseDate !== null && $date < $this->info->detail->availableLatestBidCloseDate) {
return '기간보다 짧습니다.';
}
$this->info->detail->availableLatestBidCloseDate = $date;
return null;
}
public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string public function extendCloseDate(DateTimeInterface $date, bool $force = false): ?string
{ {
if (!$force) { if (!$force) {
if ($this->info->remainCloseExtensionCnt === null) { if ($this->info->detail->remainCloseDateExtensionCnt === null) {
return '연장할 수 없는 경매입니다.'; return '연장할 수 없는 경매입니다.';
} }
if ($this->info->remainCloseExtensionCnt === 0) { if ($this->info->detail->remainCloseDateExtensionCnt === 0) {
return '더 이상 연장할 수 없습니다'; return '더 이상 연장할 수 없습니다';
} }
if ($this->info->remainCloseExtensionCnt > 0) { if ($this->info->detail->remainCloseDateExtensionCnt > 0) {
$this->info->remainCloseExtensionCnt--; $this->info->detail->remainCloseDateExtensionCnt--;
} }
} }
$db = DB::db(); if ($date < $this->info->closeDate) {
$gameStor = KVStorage::getStorage($db, 'game_env'); return '종료 기간보다 짧습니다.';
$turnTerm = $gameStor->getValue('turnterm'); }
$closeDate = DateTimeImmutable::createFromInterface($date); $closeDate = DateTimeImmutable::createFromInterface($date);
$this->info->closeDate = $closeDate; $this->info->closeDate = $closeDate;
$this->info->availableLatestBidCloseDate = $closeDate->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
));
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
return null; return null;
} }
public function applyDB(): void
{
$db = DB::db();
$db->update('ng_auction', $this->info->toArray('id'), 'id = %i', $this->info->id);
}
public function refundBid(AuctionBidItem $bidItem, string $reason): void public function refundBid(AuctionBidItem $bidItem, string $reason): void
{ {
if ($bidItem->auctionID !== $this->info->id) { if ($bidItem->auctionID !== $this->info->id) {
@@ -190,7 +213,7 @@ abstract class Auction
} }
$db = DB::db(); $db = DB::db();
if ($bidItem->generalID === $this->general->generalID) { if ($bidItem->generalID === $this->general->getID()) {
$oldBidder = $this->general; $oldBidder = $this->general;
} else { } else {
$oldBidder = General::createGeneralObjFromDB($bidItem->generalID); $oldBidder = General::createGeneralObjFromDB($bidItem->generalID);
@@ -198,10 +221,15 @@ abstract class Auction
if ($this->info->reqResource === ResourceType::inheritancePoint) { if ($this->info->reqResource === ResourceType::inheritancePoint) {
$oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount); $oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount);
$oldBidder->increaseRankVar(RankColumn::inherit_point_spent_dynamic, -$bidItem->amount);
} else { } else {
$oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount); $oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount);
} }
if ($oldBidder instanceof DummyGeneral) {
return;
}
$staticNation = $oldBidder->getStaticNation(); $staticNation = $oldBidder->getStaticNation();
$src = new MessageTarget(0, '', 0, 'System', '#000000'); $src = new MessageTarget(0, '', 0, 'System', '#000000');
$dest = new MessageTarget( $dest = new MessageTarget(
@@ -258,7 +286,7 @@ abstract class Auction
} }
$myPrevBid = $this->getMyPrevBid(); $myPrevBid = $this->getMyPrevBid();
if($myPrevBid !== null && $highestBid->no !== $myPrevBid->no){ if ($myPrevBid !== null && $highestBid->no !== $myPrevBid->no) {
//이미 환불 받았으니 무효. //이미 환불 받았으니 무효.
$myPrevBid = null; $myPrevBid = null;
} }
@@ -293,13 +321,14 @@ abstract class Auction
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$turnTerm = $gameStor->getValue('turnterm'); $turnTerm = $gameStor->getValue('turnterm');
if ($this->info->availableLatestBidCloseDate !== null) { if ($this->info->detail->availableLatestBidCloseDate !== null) {
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval( $extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60 max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
)); ));
if ($extendedCloseDate > $this->info->closeDate && $this->info->closeDate < $this->info->availableLatestBidCloseDate) { if ($extendedCloseDate > $this->info->closeDate && $this->info->closeDate < $this->info->detail->availableLatestBidCloseDate) {
$this->extendCloseDate(min($extendedCloseDate, $this->info->availableLatestBidCloseDate)); $this->extendCloseDate(min($extendedCloseDate, $this->info->detail->availableLatestBidCloseDate), true);
$this->applyDB();
} }
} }
@@ -332,11 +361,11 @@ abstract class Auction
} }
if (!$auctionInfo->detail->isReverse) { if (!$auctionInfo->detail->isReverse) {
if ($auctionInfo->buyImmediatelyAmount !== null && $auctionInfo->buyImmediatelyAmount < $amount) { if ($auctionInfo->detail->finishBidAmount !== null && $auctionInfo->detail->finishBidAmount < $amount) {
return '즉시판매가보다 높을 수 없습니다.'; return '즉시판매가보다 높을 수 없습니다.';
} }
} else { } else {
if ($auctionInfo->buyImmediatelyAmount !== null && $auctionInfo->buyImmediatelyAmount > $amount) { if ($auctionInfo->detail->finishBidAmount !== null && $auctionInfo->detail->finishBidAmount > $amount) {
return '즉시판매가보다 낮을 수 없습니다.'; return '즉시판매가보다 낮을 수 없습니다.';
} }
} }
@@ -363,7 +392,7 @@ abstract class Auction
$myPrevBid = $this->getMyPrevBid(); $myPrevBid = $this->getMyPrevBid();
if($myPrevBid !== null && $highestBid->no !== $myPrevBid->no){ if ($myPrevBid !== null && $highestBid->no !== $myPrevBid->no) {
//이미 환불 받았으니 무효. //이미 환불 받았으니 무효.
$myPrevBid = null; $myPrevBid = null;
} }
@@ -402,6 +431,17 @@ abstract class Auction
$general->increaseVar($resType->value, -$morePoint); $general->increaseVar($resType->value, -$morePoint);
$gameStor = KVStorage::getStorage($db, 'game_env');
$turnTerm = $gameStor->getValue('turnterm');
$extendedCloseDate = $now->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_PER_BID, $turnTerm * static::COEFF_EXTENSION_MINUTES_PER_BID) * 60
));
if ($extendedCloseDate > $this->info->closeDate) {
$this->extendCloseDate($extendedCloseDate, true);
$this->applyDB();
}
if ($highestBid !== null && $myPrevBid === null) { if ($highestBid !== null && $myPrevBid === null) {
$this->refundBid($highestBid, "{$auctionInfo->id}{$auctionInfo->detail->title}에 상회입찰자가 나타났습니다."); $this->refundBid($highestBid, "{$auctionInfo->id}{$auctionInfo->detail->title}에 상회입찰자가 나타났습니다.");
} }
@@ -424,12 +464,18 @@ abstract class Auction
} }
if ($highestBid->aux->tryExtendCloseDate) { if ($highestBid->aux->tryExtendCloseDate) {
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$turnTerm = $gameStor->getValue('turnterm');
//연장 요청이 있었다. //연장 요청이 있었다.
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval( $extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $this->info->turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60 max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60
)); ));
if ($this->extendCloseDate($extendedCloseDate) === null) { if ($this->extendCloseDate($extendedCloseDate) === null) {
$this->extendLatestBidCloseDate(null);
$this->applyDB();
return false; return false;
} }
} }
@@ -441,6 +487,10 @@ abstract class Auction
return true; return true;
} }
if ($bidder instanceof DummyGeneral) {
return false;
}
$staticNation = $bidder->getStaticNation(); $staticNation = $bidder->getStaticNation();
$src = new MessageTarget(0, '', 0, 'System', '#000000'); $src = new MessageTarget(0, '', 0, 'System', '#000000');
$dest = new MessageTarget( $dest = new MessageTarget(
+1 -1
View File
@@ -8,7 +8,7 @@ use sammo\Enums\ResourceType;
/** 경매에 쌀을 매물로 등록, 입찰자가 금으로 구매 */ /** 경매에 쌀을 매물로 등록, 입찰자가 금으로 구매 */
class AuctionBuyRice extends AuctionBasicResource class AuctionBuyRice extends AuctionBasicResource
{ {
static AuctionType $auctionType = AuctionType::SellRice; static AuctionType $auctionType = AuctionType::BuyRice;
static ResourceType $hostRes = ResourceType::rice; static ResourceType $hostRes = ResourceType::rice;
static ResourceType $bidderRes = ResourceType::gold; static ResourceType $bidderRes = ResourceType::gold;
} }
+16 -19
View File
@@ -14,6 +14,7 @@ use sammo\RandUtil;
class AuctionUniqueItem extends Auction class AuctionUniqueItem extends Auction
{ {
const COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT = 24;
static AuctionType $auctionType = AuctionType::UniqueItem; static AuctionType $auctionType = AuctionType::UniqueItem;
@@ -52,18 +53,6 @@ class AuctionUniqueItem extends Auction
} }
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$givenUnique = $gameStor->getValue('givenUnique') ?? [];
$givenUniqueCnt = $givenUnique[$itemKey] ?? 0;
$remainUniqueCnt = 0;
foreach (GameConst::$allItems as $itemList) {
if (!key_exists($itemKey, $itemList)) {
continue;
}
$remainUniqueCnt += $itemList[$itemKey];
}
if ($remainUniqueCnt > 1 && $givenUniqueCnt >= $remainUniqueCnt - 1) {
return '더이상 이 아이템을 경매로 가져갈 수 없습니다.';
}
$now = new DateTimeImmutable(); $now = new DateTimeImmutable();
@@ -115,7 +104,7 @@ class AuctionUniqueItem extends Auction
$josaRa = JosaUtil::pick($item->getRawName(), '라'); $josaRa = JosaUtil::pick($item->getRawName(), '라');
$logger = new ActionLogger(0, 0, $year, $month); $logger = new ActionLogger(0, 0, $year, $month);
$logger->pushGlobalHistoryLog("누군가가 <C>{$itemName}</>{$josaRa}는 보물을 구한다는 소문이 들려옵니다."); $logger->pushGlobalHistoryLog("<C><b>【보물수배】</b></>누군가가 <C>{$itemName}</>{$josaRa}는 보물을 구한다는 소문이 들려옵니다.");
$logger->flush(); $logger->flush();
return $auction; return $auction;
@@ -159,9 +148,14 @@ class AuctionUniqueItem extends Auction
); );
$itemCode = $this->info->target; $itemCode = $this->info->target;
if($itemCode === null){
throw new \Exception('아이템 코드가 없습니다.');
}
$bidItemTypes = new Set(); $bidItemTypes = new Set();
foreach (GameConst::$allItems as $itemType => $itemList) { foreach (GameConst::$allItems as $itemType => $itemList) {
if (($itemList[$itemCode] ?? 0) <= 0) { if (key_exists($itemCode, $itemList) && $itemList[$itemCode] <= 0) {
continue; continue;
} }
$bidItemTypes->add($itemType); $bidItemTypes->add($itemType);
@@ -228,12 +222,15 @@ class AuctionUniqueItem extends Auction
} }
if ($availableEquipUniqueCnt <= 0) { if ($availableEquipUniqueCnt <= 0) {
$turnTerm = $gameStor->getValue('turnterm');
//제한에 걸렸다면 자동 연장 //제한에 걸렸다면 자동 연장
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval( $extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $this->info->turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60 max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $turnTerm * static::COEFF_EXTENSION_MINUTES_LIMIT_UNIQUE_CNT) * 60
)); ));
$this->extendCloseDate($extendedCloseDate, true); $this->extendCloseDate($extendedCloseDate, true);
$this->extendLatestBidCloseDate(null);
$this->applyDB();
return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.'; return '유니크 아이템 소유 제한 상태입니다. 종료 시간이 연장됩니다.';
} }
@@ -284,13 +281,13 @@ class AuctionUniqueItem extends Auction
$logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 습득했습니다!"); $logger->pushGeneralActionLog("<C>{$itemName}</>{$josaUl} 습득했습니다!");
$logger->pushGeneralHistoryLog("<C>{$itemName}</>{$josaUl} 습득"); $logger->pushGeneralHistoryLog("<C>{$itemName}</>{$josaUl} 습득");
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!"); $logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
$logger->pushGlobalHistoryLog("<C><b>【보물발견】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!"); $logger->pushGlobalHistoryLog("<C><b>【보물수배】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 습득했습니다!");
$userLogger = new UserLogger($general->getVar('owner'));
$userLogger->push(sprintf("유니크 %s 경매로 %d 포인트 사용", $itemName, $highestBid->amount), "inheritPoint");
$general->applyDB($db); $general->applyDB($db);
$givenUnique = $gameStor->getValue('givenUnique') ?? [];
$givenUnique[$itemKey] = ($givenUnique[$itemKey] ?? 0) + 1;
$gameStor->setValue('givenUnique', $givenUnique);
return null; return null;
} }
} }
@@ -188,22 +188,6 @@ class che_장비매매 extends Command\GeneralCommand
$nationName = $general->getStaticNation()['name']; $nationName = $general->getStaticNation()['name'];
$logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 판매했습니다!"); $logger->pushGlobalActionLog("<Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 판매했습니다!");
$logger->pushGlobalHistoryLog("<R><b>【판매】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 판매했습니다!"); $logger->pushGlobalHistoryLog("<R><b>【판매】</b></><D><b>{$nationName}</b></>의 <Y>{$generalName}</>{$josaYi} <C>{$itemName}</>{$josaUl} 판매했습니다!");
$gameStor = KVStorage::getStorage($db, 'game_env');
$givenUnique = $gameStor->getValue('givenUnique') ?? [];
if (key_exists($itemCode, $givenUnique)) {
$givenUniqueCnt = $givenUnique[$itemCode];
$givenUniqueCnt -= 1;
if ($givenUniqueCnt <= 0) {
unset($givenUnique[$itemCode]);
} else {
$givenUnique[$itemCode] = $givenUniqueCnt;
}
} else {
//XXX: 처리하지 못한 코드가 있는가?
//FIXME: 여기에서 무언가 경고를 내야함
}
$gameStor->setValue('givenUnique', $givenUnique);
} }
} }
+40 -28
View File
@@ -4,67 +4,79 @@ namespace sammo;
use sammo\Enums\InheritanceKey; use sammo\Enums\InheritanceKey;
class DummyGeneral extends General{ class DummyGeneral extends General
public function __construct(bool $initLogger=true){ {
public function __construct(bool $initLogger = true)
{
$raw = [ $raw = [
'no'=>0, 'no' => 0,
'name'=>'Dummy', 'name' => 'Dummy',
'npc'=>3, 'npc' => 3,
'city'=>0, 'city' => 0,
'nation'=>0, 'nation' => 0,
'officer_level'=>0, 'officer_level' => 0,
'crewtype'=>-1, 'crewtype' => -1,
'turntime'=>'2012-03-04 05:06:07.000000', 'turntime' => '2012-03-04 05:06:07.000000',
'experience'=>0, 'experience' => 0,
'dedication'=>0, 'dedication' => 0,
'gold'=>0, 'gold' => 0,
'rice'=>0, 'rice' => 0,
'leadership'=>10, 'leadership' => 10,
'strength'=>10, 'strength' => 10,
'intel'=>10, 'intel' => 10,
'imgsvr' => 0,
'picture' => 'default.jpg',
]; ];
$this->raw = $raw; $this->raw = $raw;
$this->resultTurn = new LastTurn(); $this->resultTurn = new LastTurn();
if($initLogger){ if ($initLogger) {
$this->initLogger(1, 1); $this->initLogger(1, 1);
} }
} }
public function getBattleInitSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{ public function getBattleInitSkillTriggerList(WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(); return new WarUnitTriggerCaller();
} }
public function getBattlePhaseSkillTriggerList(WarUnit $unit):?WarUnitTriggerCaller{ public function getBattlePhaseSkillTriggerList(WarUnit $unit): ?WarUnitTriggerCaller
{
return new WarUnitTriggerCaller(); return new WarUnitTriggerCaller();
} }
public function onCalcStat(General $general, string $statName, $value, $aux=null){ public function onCalcStat(General $general, string $statName, $value, $aux = null)
{
return $value; return $value;
} }
public function onCalcOpposeStat(General $general, string $statName, $value, $aux=null){ public function onCalcOpposeStat(General $general, string $statName, $value, $aux = null)
{
return $value; return $value;
} }
public function getInheritancePoint(InheritanceKey $key, &$aux = null, bool $forceCalc = false): int|float{ public function getInheritancePoint(InheritanceKey $key, &$aux = null, bool $forceCalc = false): int|float
{
return 0; return 0;
} }
public function setInheritancePoint(InheritanceKey $key, $value, $aux = null){ public function setInheritancePoint(InheritanceKey $key, $value, $aux = null)
{
return; return;
} }
public function increaseInheritancePoint(InheritanceKey $key, $value, $aux = null){ public function increaseInheritancePoint(InheritanceKey $key, $value, $aux = null)
{
return; return;
} }
function applyDB($db):bool{ function applyDB($db): bool
if($this->logger){ {
if ($this->logger) {
$this->initLogger($this->logger->getYear(), $this->logger->getMonth()); $this->initLogger($this->logger->getYear(), $this->logger->getMonth());
} }
return true; return true;
} }
} }
+2 -2
View File
@@ -1,12 +1,12 @@
<template> <template>
<BContainer id="container" :toast="{ root: true }" class="bg0"> <BContainer id="container" :toast="{ root: true }" class="bg0">
<TopBackBar type="normal" :title="isResAuction ? '경매장' : '유니크 경매장'" :reloadable="true" @reload="tryReload"> <TopBackBar type="close" :title="isResAuction ? '경매장' : '유니크 경매장'" :reloadable="true" @reload="tryReload">
<BButton @click="isResAuction = true">/</BButton> <BButton @click="isResAuction = true">/</BButton>
<BButton @click="isResAuction = false">유니크</BButton> <BButton @click="isResAuction = false">유니크</BButton>
</TopBackBar> </TopBackBar>
<AuctionResource v-if="isResAuction"></AuctionResource> <AuctionResource v-if="isResAuction"></AuctionResource>
<AuctionUniqueItem v-else></AuctionUniqueItem> <AuctionUniqueItem v-else></AuctionUniqueItem>
<BottomBar></BottomBar> <BottomBar type="close"></BottomBar>
</BContainer> </BContainer>
</template> </template>
<script lang="ts"> <script lang="ts">
+13 -3
View File
@@ -22,11 +22,11 @@
<div class="col">{{ auction.startBidAmount }}</div> <div class="col">{{ auction.startBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div> <div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
<div class="col">{{ auction.finishBidAmount }}</div> <div class="col">{{ auction.finishBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount / auction.amount : "-" }}</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.highestBid ? auction.highestBid.generalName : "-" }}</div>
<div class="col">{{ auction.closeDate }}</div> <div class="col">{{ auction.closeDate }}</div>
</div> </div>
<div v-if="selectedBuyRiceAuction !== undefined"> <div v-if="selectedBuyRiceAuction !== undefined" class="row">
<div class="col">{{ selectedBuyRiceAuction.id }} {{ selectedBuyRiceAuction.amount }} 경매에</div> <div class="col">{{ selectedBuyRiceAuction.id }} {{ selectedBuyRiceAuction.amount }} 경매에</div>
<div class="col"> <div class="col">
<NumberInputWithInfo <NumberInputWithInfo
@@ -62,7 +62,7 @@
<div class="col">{{ auction.startBidAmount }}</div> <div class="col">{{ auction.startBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div> <div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
<div class="col">{{ auction.finishBidAmount }}</div> <div class="col">{{ auction.finishBidAmount }}</div>
<div class="col">{{ auction.highestBid ? auction.highestBid.amount / auction.amount : "-" }}</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.highestBid ? auction.highestBid.generalName : "-" }}</div>
<div class="col">{{ auction.closeDate }}</div> <div class="col">{{ auction.closeDate }}</div>
</div> </div>
@@ -92,6 +92,16 @@
</BButton> </BButton>
</BButtonGroup> </BButtonGroup>
</div> </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">
<NumberInputWithInfo <NumberInputWithInfo
v-model="openAuctionInfo.amount" v-model="openAuctionInfo.amount"
+18 -13
View File
@@ -17,8 +17,8 @@
<div class="col-4 col-md-2 bg2">종료시점</div> <div class="col-4 col-md-2 bg2">종료시점</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.closeDate }}</div> <div class="col-4 col-md-2">{{ currentAuction.auction.closeDate }}</div>
<div class="col-4 col-md-2 bg2"> 허용</div> <div class="col-4 col-md-2 bg2">최대지</div>
<div class="col-4 col-md-2">{{ currentAuction.auction.remainCloseDateExtensionCnt }}</div> <div class="col-4 col-md-2">{{ currentAuction.auction.availableLatestBidCloseDate }}</div>
</div> </div>
<div class="bg1">입찰자 목록</div> <div class="bg1">입찰자 목록</div>
<div class="row gx-0 bg2"> <div class="row gx-0 bg2">
@@ -42,7 +42,7 @@
:step="1" :step="1"
></NumberInputWithInfo> ></NumberInputWithInfo>
</div> </div>
<div><BButton @click="bidAuction">입찰</BButton></div> <div class="col"><BButton @click="bidAuction">입찰</BButton></div>
</div> </div>
</template> </template>
@@ -74,10 +74,12 @@ type AuctionItemInfo = UniqueItemAuctionList["list"][0];
const currentAuctionID = ref<number>(); const currentAuctionID = ref<number>();
const currentAuction = ref<UniqueItemAuctionDetail | undefined>(undefined); const currentAuction = ref<UniqueItemAuctionDetail | undefined>(undefined);
const bidAmount = ref<number>(5000); const bidAmount = ref<number>(5000);
watch(currentAuctionID, async (auctionID) => {
if (auctionID === undefined) { async function refreshDetail() {
if (currentAuctionID.value === undefined) {
return; return;
} }
const auctionID = currentAuctionID.value;
try { try {
currentAuction.value = await SammoAPI.Auction.GetUniqueItemAuctionDetail({ auctionID }); currentAuction.value = await SammoAPI.Auction.GetUniqueItemAuctionDetail({ auctionID });
} catch (e) { } catch (e) {
@@ -89,6 +91,9 @@ watch(currentAuctionID, async (auctionID) => {
}); });
} }
} }
}
watch(currentAuctionID, () => {
void refreshDetail();
}); });
const auctionList = ref(new Map<number, AuctionItemInfo>()); const auctionList = ref(new Map<number, AuctionItemInfo>());
const obfuscatedName = ref(""); const obfuscatedName = ref("");
@@ -115,26 +120,26 @@ async function refresh() {
} }
} }
async function bidAuction(){ async function bidAuction() {
if(currentAuction.value === undefined){ if (currentAuction.value === undefined) {
return; return;
} }
const amount = bidAmount.value; const amount = bidAmount.value;
const auctionInfo = currentAuction.value.auction; const auctionInfo = currentAuction.value.auction;
if(confirm(`${auctionInfo.title}${amount}유산포인트를 입찰하시겠습니까?`)){ if (confirm(`${auctionInfo.title}${amount}유산포인트를 입찰하시겠습니까?`)) {
try{ try {
await SammoAPI.Auction.BidUniqueAuction({ auctionID: auctionInfo.id, amount }); await SammoAPI.Auction.BidUniqueAuction({ auctionID: auctionInfo.id, amount });
toasts.success({ toasts.success({
title: "성공", title: "성공",
body: "입찰이 완료되었습니다.", body: "입찰이 완료되었습니다.",
}); });
await refresh(); void refreshDetail();
}catch(e){ void refresh();
} catch (e) {
console.error(e); console.error(e);
if(isString(e)){ if (isString(e)) {
toasts.danger({ toasts.danger({
title: "에러", title: "에러",
body: e, body: e,