commit
b2144b38fe
BIN
README - OCM Event.pdf
Normal file
BIN
README - OCM Event.pdf
Normal file
Binary file not shown.
@ -1,10 +1,10 @@
|
||||
{
|
||||
"shopName": "Bayshore",
|
||||
"shopNickname": "BSH",
|
||||
"regionName": "Bayshore",
|
||||
"shopNickname": "Bayshore",
|
||||
"regionName": "JPN0123",
|
||||
"serverIp": "127.0.0.1",
|
||||
"gameOptions": {
|
||||
"grantFullTuneTicketToNewUsers": 3,
|
||||
"grantFullTuneTicketToNewUsers": 5,
|
||||
"giftCarsFullyTuned": 0,
|
||||
"scratchEnabled": 1,
|
||||
"scratchType": 1,
|
||||
|
119
prisma/migrations/20220812021720_ocm/migration.sql
Normal file
119
prisma/migrations/20220812021720_ocm/migration.sql
Normal file
@ -0,0 +1,119 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Car" ALTER COLUMN "stLoseBits" SET DEFAULT 0;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "CarState" ADD COLUMN "competitionState" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GhostBattleRecord" ADD COLUMN "ocmBattle" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "ocmMainDay" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GhostTrail" ADD COLUMN "ocmBattle" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "ocmMainDay" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMEvent" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"qualifyingPeriodStartAt" INTEGER NOT NULL,
|
||||
"qualifyingPeriodCloseAt" INTEGER NOT NULL,
|
||||
"competitionStartAt" INTEGER NOT NULL,
|
||||
"competitionCloseAt" INTEGER NOT NULL,
|
||||
"competitionEndAt" INTEGER NOT NULL,
|
||||
"lengthOfPeriod" INTEGER NOT NULL,
|
||||
"lengthOfInterval" INTEGER NOT NULL,
|
||||
"area" INTEGER NOT NULL DEFAULT 0,
|
||||
"minigamePatternId" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "OCMEvent_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMPlayRecord" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"carId" INTEGER NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"brakingPoint" INTEGER,
|
||||
"playedAt" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "OCMPlayRecord_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMTop1Ghost" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"carId" INTEGER NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"result" INTEGER NOT NULL,
|
||||
"tunePower" INTEGER NOT NULL DEFAULT 0,
|
||||
"tuneHandling" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "OCMTop1Ghost_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMTally" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"carId" INTEGER NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"result" INTEGER NOT NULL,
|
||||
"tunePower" INTEGER NOT NULL DEFAULT 0,
|
||||
"tuneHandling" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "OCMTally_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMGhostBattleRecord" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"carId" INTEGER NOT NULL,
|
||||
"tunePower" INTEGER NOT NULL DEFAULT 0,
|
||||
"tuneHandling" INTEGER NOT NULL DEFAULT 0,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"result" INTEGER NOT NULL,
|
||||
"area" INTEGER NOT NULL DEFAULT 0,
|
||||
"playedAt" INTEGER NOT NULL DEFAULT 0,
|
||||
"playedShopName" TEXT NOT NULL DEFAULT 'Bayshore',
|
||||
"ocmMainDraw" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "OCMGhostBattleRecord_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMGhostTrail" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"carId" INTEGER NOT NULL,
|
||||
"area" INTEGER NOT NULL,
|
||||
"ramp" INTEGER NOT NULL,
|
||||
"path" INTEGER NOT NULL,
|
||||
"trail" BYTEA NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"playedAt" INTEGER NOT NULL DEFAULT 0,
|
||||
"tunePower" INTEGER NOT NULL DEFAULT 0,
|
||||
"tuneHandling" INTEGER NOT NULL DEFAULT 0,
|
||||
"ocmBattle" BOOLEAN NOT NULL DEFAULT false,
|
||||
"ocmMainDraw" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "OCMGhostTrail_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMPlayRecord" ADD CONSTRAINT "OCMPlayRecord_carId_fkey" FOREIGN KEY ("carId") REFERENCES "Car"("carId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMTop1Ghost" ADD CONSTRAINT "OCMTop1Ghost_carId_fkey" FOREIGN KEY ("carId") REFERENCES "Car"("carId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMTally" ADD CONSTRAINT "OCMTally_carId_fkey" FOREIGN KEY ("carId") REFERENCES "Car"("carId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMGhostBattleRecord" ADD CONSTRAINT "OCMGhostBattleRecord_carId_fkey" FOREIGN KEY ("carId") REFERENCES "Car"("carId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMGhostTrail" ADD CONSTRAINT "OCMGhostTrail_carId_fkey" FOREIGN KEY ("carId") REFERENCES "Car"("carId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
17
prisma/migrations/20220812022623_ocm_2/migration.sql
Normal file
17
prisma/migrations/20220812022623_ocm_2/migration.sql
Normal file
@ -0,0 +1,17 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Car" ALTER COLUMN "stLoseBits" SET DEFAULT 0;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OCMPeriod" (
|
||||
"dbId" SERIAL NOT NULL,
|
||||
"competitionDbId" INTEGER NOT NULL,
|
||||
"competitionId" INTEGER NOT NULL,
|
||||
"periodId" INTEGER NOT NULL,
|
||||
"startAt" INTEGER NOT NULL,
|
||||
"closeAt" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "OCMPeriod_pkey" PRIMARY KEY ("dbId")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OCMPeriod" ADD CONSTRAINT "OCMPeriod_competitionDbId_fkey" FOREIGN KEY ("competitionDbId") REFERENCES "OCMEvent"("dbId") ON DELETE RESTRICT ON UPDATE CASCADE;
|
17
prisma/migrations/20220812024922_ocm_2/migration.sql
Normal file
17
prisma/migrations/20220812024922_ocm_2/migration.sql
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `ocmBattle` on the `GhostTrail` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `ocmMainDay` on the `GhostTrail` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `ocmBattle` on the `OCMGhostTrail` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Car" ALTER COLUMN "stLoseBits" SET DEFAULT 0;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GhostTrail" DROP COLUMN "ocmBattle",
|
||||
DROP COLUMN "ocmMainDay";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "OCMGhostTrail" DROP COLUMN "ocmBattle";
|
13
prisma/migrations/20220812031106_ocm_3/migration.sql
Normal file
13
prisma/migrations/20220812031106_ocm_3/migration.sql
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `ocmBattle` on the `GhostBattleRecord` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `ocmMainDay` on the `GhostBattleRecord` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Car" ALTER COLUMN "stLoseBits" SET DEFAULT 0;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "GhostBattleRecord" DROP COLUMN "ocmBattle",
|
||||
DROP COLUMN "ocmMainDay";
|
31
prisma/migrations/20220812083231_ocm_4/migration.sql
Normal file
31
prisma/migrations/20220812083231_ocm_4/migration.sql
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Car" ADD COLUMN "country" TEXT NOT NULL DEFAULT 'JPN',
|
||||
ALTER COLUMN "stLoseBits" SET DEFAULT 0;
|
@ -2,274 +2,387 @@
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("POSTGRES_URL")
|
||||
provider = "postgresql"
|
||||
url = env("POSTGRES_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
chipId String @unique
|
||||
accessCode String
|
||||
cars Car[]
|
||||
carOrder Int[]
|
||||
items UserItem[]
|
||||
tutorials Boolean[]
|
||||
userBanned Boolean @default(false)
|
||||
bookmarks Int[]
|
||||
ScratchSheet ScratchSheet[]
|
||||
currentSheet Int @default(1)
|
||||
lastScratched Int @default(0) // Timestamp
|
||||
id Int @id @default(autoincrement())
|
||||
chipId String @unique
|
||||
accessCode String
|
||||
cars Car[]
|
||||
carOrder Int[]
|
||||
items UserItem[]
|
||||
tutorials Boolean[]
|
||||
userBanned Boolean @default(false)
|
||||
bookmarks Int[]
|
||||
ScratchSheet ScratchSheet[]
|
||||
currentSheet Int @default(1)
|
||||
lastScratched Int @default(0) // Timestamp
|
||||
}
|
||||
|
||||
model ScratchSheet {
|
||||
id Int @id @default(autoincrement())
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
sheetNo Int // Player's sheet number (i.e. first sheet)
|
||||
squares ScratchSquare[]
|
||||
id Int @id @default(autoincrement())
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
sheetNo Int // Player's sheet number (i.e. first sheet)
|
||||
squares ScratchSquare[]
|
||||
}
|
||||
|
||||
model ScratchSquare {
|
||||
id Int @id @default(autoincrement())
|
||||
Sheet ScratchSheet @relation(fields: [sheetId], references: [id])
|
||||
sheetId Int
|
||||
category Int
|
||||
itemId Int
|
||||
earned Boolean
|
||||
id Int @id @default(autoincrement())
|
||||
Sheet ScratchSheet @relation(fields: [sheetId], references: [id])
|
||||
sheetId Int
|
||||
category Int
|
||||
itemId Int
|
||||
earned Boolean
|
||||
}
|
||||
|
||||
model UserItem {
|
||||
userItemId Int @id @default(autoincrement())
|
||||
category Int
|
||||
itemId Int
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
type Int @default(0)
|
||||
earnedAt Int @default(0)
|
||||
userItemId Int @id @default(autoincrement())
|
||||
category Int
|
||||
itemId Int
|
||||
User User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
type Int @default(0)
|
||||
earnedAt Int @default(0)
|
||||
}
|
||||
|
||||
model Car {
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
userId Int
|
||||
|
||||
// This is the Car object itself
|
||||
carId Int @id @default(autoincrement())
|
||||
name String
|
||||
manufacturer Int
|
||||
regionId Int @default(0)
|
||||
model Int
|
||||
visualModel Int
|
||||
customColor Int @default(0)
|
||||
defaultColor Int
|
||||
wheel Int @default(0)
|
||||
wheelColor Int @default(0)
|
||||
aero Int @default(0)
|
||||
bonnet Int @default(0)
|
||||
wing Int @default(0)
|
||||
mirror Int @default(0)
|
||||
neon Int @default(0)
|
||||
trunk Int @default(0)
|
||||
plate Int @default(0)
|
||||
plateColor Int @default(0)
|
||||
plateNumber Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
title String @default("New Car")
|
||||
level Int @default(0)
|
||||
windowSticker Boolean @default(false)
|
||||
windowStickerString String @default("WANGAN")
|
||||
windowStickerFont Int @default(0)
|
||||
windowDecoration Int @default(0)
|
||||
rivalMarker Int @default(0)
|
||||
lastPlayedAt Int @default(0)
|
||||
aura Int @default(0)
|
||||
auraMotif Int @default(0)
|
||||
ghostLevel Int @default(1)
|
||||
// This is the Car object itself
|
||||
carId Int @id @default(autoincrement())
|
||||
name String
|
||||
manufacturer Int
|
||||
regionId Int @default(0)
|
||||
country String @default("JPN")
|
||||
model Int
|
||||
visualModel Int
|
||||
customColor Int @default(0)
|
||||
defaultColor Int
|
||||
wheel Int @default(0)
|
||||
wheelColor Int @default(0)
|
||||
aero Int @default(0)
|
||||
bonnet Int @default(0)
|
||||
wing Int @default(0)
|
||||
mirror Int @default(0)
|
||||
neon Int @default(0)
|
||||
trunk Int @default(0)
|
||||
plate Int @default(0)
|
||||
plateColor Int @default(0)
|
||||
plateNumber Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
title String @default("New Car")
|
||||
level Int @default(0)
|
||||
windowSticker Boolean @default(false)
|
||||
windowStickerString String @default("WANGAN")
|
||||
windowStickerFont Int @default(0)
|
||||
windowDecoration Int @default(0)
|
||||
rivalMarker Int @default(0)
|
||||
lastPlayedAt Int @default(0)
|
||||
aura Int @default(0)
|
||||
auraMotif Int @default(0)
|
||||
ghostLevel Int @default(1)
|
||||
|
||||
// This is more data about the car
|
||||
tuningPoints Int @default(0)
|
||||
odometer Int @default(0)
|
||||
playCount Int @default(0)
|
||||
earnedCustomColor Boolean @default(false)
|
||||
carSettingsDbId Int @unique
|
||||
settings CarSettings @relation(fields: [carSettingsDbId], references: [dbId])
|
||||
vsPlayCount Int @default(0)
|
||||
vsBurstCount Int @default(0)
|
||||
vsStarCount Int @default(0)
|
||||
vsCoolOrWild Int @default(0)
|
||||
vsSmoothOrRough Int @default(0)
|
||||
vsTripleStarMedals Int @default(0)
|
||||
vsDoubleStarMedals Int @default(0)
|
||||
vsSingleStarMedals Int @default(0)
|
||||
vsPlainMedals Int @default(0)
|
||||
rgPlayCount Int @default(0)
|
||||
rgWinCount Int @default(0)
|
||||
rgTrophy Int @default(0)
|
||||
rgScore Int @default(0)
|
||||
rgStamp Int @default(0)
|
||||
rgAcquireAllCrowns Boolean @default(false)
|
||||
rgRegionMapScore Int[]
|
||||
dressupLevel Int @default(0)
|
||||
dressupPoint Int @default(0)
|
||||
stPlayCount Int @default(0)
|
||||
stClearBits Int @default(0)
|
||||
stClearDivCount Int @default(0)
|
||||
stClearCount Int @default(0)
|
||||
stLoseBits BigInt @default(0)
|
||||
stConsecutiveWins Int @default(0)
|
||||
stConsecutiveWinsMax Int @default(0)
|
||||
stCompleted100Episodes Boolean @default(false)
|
||||
// This is more data about the car
|
||||
tuningPoints Int @default(0)
|
||||
odometer Int @default(0)
|
||||
playCount Int @default(0)
|
||||
earnedCustomColor Boolean @default(false)
|
||||
carSettingsDbId Int @unique
|
||||
settings CarSettings @relation(fields: [carSettingsDbId], references: [dbId])
|
||||
vsPlayCount Int @default(0)
|
||||
vsBurstCount Int @default(0)
|
||||
vsStarCount Int @default(0)
|
||||
vsCoolOrWild Int @default(0)
|
||||
vsSmoothOrRough Int @default(0)
|
||||
vsTripleStarMedals Int @default(0)
|
||||
vsDoubleStarMedals Int @default(0)
|
||||
vsSingleStarMedals Int @default(0)
|
||||
vsPlainMedals Int @default(0)
|
||||
rgPlayCount Int @default(0)
|
||||
rgWinCount Int @default(0)
|
||||
rgTrophy Int @default(0)
|
||||
rgScore Int @default(0)
|
||||
rgStamp Int @default(0)
|
||||
rgAcquireAllCrowns Boolean @default(false)
|
||||
rgRegionMapScore Int[]
|
||||
dressupLevel Int @default(0)
|
||||
dressupPoint Int @default(0)
|
||||
stPlayCount Int @default(0)
|
||||
stClearBits Int @default(0)
|
||||
stClearDivCount Int @default(0)
|
||||
stClearCount Int @default(0)
|
||||
stLoseBits BigInt @default(0)
|
||||
stConsecutiveWins Int @default(0)
|
||||
stConsecutiveWinsMax Int @default(0)
|
||||
stCompleted100Episodes Boolean @default(false)
|
||||
|
||||
items CarItem[]
|
||||
carGTWingDbId Int @unique
|
||||
gtWing CarGTWing @relation(fields: [carGTWingDbId], references: [dbId])
|
||||
carStateDbId Int @unique
|
||||
state CarState @relation(fields: [carStateDbId], references: [dbId])
|
||||
TimeAttackRecord TimeAttackRecord[]
|
||||
CarCrown CarCrown[]
|
||||
GhostTrail GhostTrail[]
|
||||
GhostBattleRecord GhostBattleRecord[]
|
||||
CarPathandTuning CarPathandTuning[]
|
||||
items CarItem[]
|
||||
carGTWingDbId Int @unique
|
||||
gtWing CarGTWing @relation(fields: [carGTWingDbId], references: [dbId])
|
||||
carStateDbId Int @unique
|
||||
state CarState @relation(fields: [carStateDbId], references: [dbId])
|
||||
TimeAttackRecord TimeAttackRecord[]
|
||||
|
||||
CarCrown CarCrown[]
|
||||
GhostTrail GhostTrail[]
|
||||
GhostBattleRecord GhostBattleRecord[]
|
||||
CarPathandTuning CarPathandTuning[]
|
||||
|
||||
OCMGhostBattleRecord OCMGhostBattleRecord[]
|
||||
OCMTally OCMTally[]
|
||||
OCMTop1Ghost OCMTop1Ghost[]
|
||||
OCMGhostTrail OCMGhostTrail[]
|
||||
OCMPlayRecord OCMPlayRecord[]
|
||||
}
|
||||
|
||||
model CarGTWing {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
|
||||
pillar Int @default(0)
|
||||
pillarMaterial Int @default(0)
|
||||
mainWing Int @default(0)
|
||||
mainWingColor Int @default(0)
|
||||
wingTip Int @default(0)
|
||||
material Int @default(0)
|
||||
pillar Int @default(0)
|
||||
pillarMaterial Int @default(0)
|
||||
mainWing Int @default(0)
|
||||
mainWingColor Int @default(0)
|
||||
wingTip Int @default(0)
|
||||
material Int @default(0)
|
||||
}
|
||||
|
||||
model CarItem {
|
||||
dbId Int @id @default(autoincrement())
|
||||
Car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
category Int
|
||||
itemId Int
|
||||
amount Int
|
||||
dbId Int @id @default(autoincrement())
|
||||
Car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
category Int
|
||||
itemId Int
|
||||
amount Int
|
||||
}
|
||||
|
||||
model CarSettings {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
|
||||
view Boolean @default(true)
|
||||
transmission Boolean @default(false)
|
||||
retire Boolean @default(false)
|
||||
meter Int @default(0)
|
||||
navigationMap Boolean @default(true)
|
||||
volume Int @default(1)
|
||||
bgm Int @default(0)
|
||||
nameplate Int @default(0)
|
||||
nameplateColor Int @default(0)
|
||||
terminalBackground Int @default(0)
|
||||
view Boolean @default(true)
|
||||
transmission Boolean @default(false)
|
||||
retire Boolean @default(false)
|
||||
meter Int @default(0)
|
||||
navigationMap Boolean @default(true)
|
||||
volume Int @default(1)
|
||||
bgm Int @default(0)
|
||||
nameplate Int @default(0)
|
||||
nameplateColor Int @default(0)
|
||||
terminalBackground Int @default(0)
|
||||
}
|
||||
|
||||
model CarState {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car?
|
||||
|
||||
hasOpponentGhost Boolean @default(false)
|
||||
eventJoined Boolean @default(false)
|
||||
transferred Boolean @default(false)
|
||||
toBeDeleted Boolean @default(false)
|
||||
}
|
||||
|
||||
model TimeAttackRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
|
||||
model Int // Car model, literally just the `model` field from Car
|
||||
time Int
|
||||
course Int
|
||||
isMorning Boolean
|
||||
section1Time Int @map("section1Time")
|
||||
section2Time Int @map("section2Time")
|
||||
section3Time Int @map("section3Time")
|
||||
section4Time Int @map("section4Time")
|
||||
section5Time Int? @map("section5Time")
|
||||
section6Time Int? @map("section6Time")
|
||||
section7Time Int? @map("section7Time")
|
||||
tunePower Int @default(0) // Car Power
|
||||
tuneHandling Int @default(0) // Car Handling
|
||||
}
|
||||
|
||||
model CarCrown {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int @unique
|
||||
ramp Int
|
||||
path Int
|
||||
playedAt Int @default(0)
|
||||
tunePower Int
|
||||
tuneHandling Int
|
||||
}
|
||||
|
||||
model GhostTrail {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int
|
||||
ramp Int
|
||||
path Int
|
||||
trail Bytes
|
||||
time Int?
|
||||
driveData Bytes? @db.ByteA
|
||||
driveDMergeSerial Int?
|
||||
trendBinaryByUser Bytes? @db.ByteA
|
||||
byUserMergeSerial Int?
|
||||
trendBinaryByArea Bytes? @db.ByteA
|
||||
byAreaMergeSerial Int?
|
||||
trendBinaryByCar Bytes? @db.ByteA
|
||||
byCarMergeSerial Int?
|
||||
playedAt Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
crownBattle Boolean @default(false)
|
||||
}
|
||||
|
||||
model GhostBattleRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
opponent1CarId Int
|
||||
opponent1Result Int
|
||||
opponent1TunePower Int
|
||||
opponent1TuneHandling Int
|
||||
opponent2CarId Int?
|
||||
opponent2Result Int?
|
||||
opponent2TunePower Int?
|
||||
opponent2TuneHandling Int?
|
||||
opponent3CarId Int?
|
||||
opponent3Result Int?
|
||||
opponent3TunePower Int?
|
||||
opponent3TuneHandling Int?
|
||||
area Int @default(0)
|
||||
playedAt Int @default(0)
|
||||
playedShopName String @default("Bayshore")
|
||||
hasOpponentGhost Boolean @default(false)
|
||||
eventJoined Boolean @default(false)
|
||||
transferred Boolean @default(false)
|
||||
toBeDeleted Boolean @default(false)
|
||||
competitionState Int @default(0)
|
||||
}
|
||||
|
||||
model CarPathandTuning {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int @default(0)
|
||||
ramp Int @default(0)
|
||||
path Int @default(0)
|
||||
tunePower Int @default(17)
|
||||
tuneHandling Int @default(17)
|
||||
lastPlayedAt Int @default(0)
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int @default(0)
|
||||
ramp Int @default(0)
|
||||
path Int @default(0)
|
||||
tunePower Int @default(17)
|
||||
tuneHandling Int @default(17)
|
||||
lastPlayedAt Int @default(0)
|
||||
}
|
||||
|
||||
model CarCrown {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int @unique
|
||||
ramp Int
|
||||
path Int
|
||||
playedAt Int @default(0)
|
||||
tunePower Int
|
||||
tuneHandling Int
|
||||
}
|
||||
|
||||
model TimeAttackRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
|
||||
model Int // Car model, literally just the `model` field from Car
|
||||
time Int
|
||||
course Int
|
||||
isMorning Boolean
|
||||
section1Time Int @map("section1Time")
|
||||
section2Time Int @map("section2Time")
|
||||
section3Time Int @map("section3Time")
|
||||
section4Time Int @map("section4Time")
|
||||
section5Time Int? @map("section5Time")
|
||||
section6Time Int? @map("section6Time")
|
||||
section7Time Int? @map("section7Time")
|
||||
tunePower Int @default(0) // Car Power
|
||||
tuneHandling Int @default(0) // Car Handling
|
||||
}
|
||||
|
||||
model GhostTrail {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int
|
||||
ramp Int
|
||||
path Int
|
||||
trail Bytes
|
||||
time Int?
|
||||
driveData Bytes? @db.ByteA
|
||||
driveDMergeSerial Int?
|
||||
trendBinaryByUser Bytes? @db.ByteA
|
||||
byUserMergeSerial Int?
|
||||
trendBinaryByArea Bytes? @db.ByteA
|
||||
byAreaMergeSerial Int?
|
||||
trendBinaryByCar Bytes? @db.ByteA
|
||||
byCarMergeSerial Int?
|
||||
playedAt Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
crownBattle Boolean @default(false)
|
||||
}
|
||||
|
||||
model GhostBattleRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
opponent1CarId Int
|
||||
opponent1Result Int
|
||||
opponent1TunePower Int
|
||||
opponent1TuneHandling Int
|
||||
opponent2CarId Int?
|
||||
opponent2Result Int?
|
||||
opponent2TunePower Int?
|
||||
opponent2TuneHandling Int?
|
||||
opponent3CarId Int?
|
||||
opponent3Result Int?
|
||||
opponent3TunePower Int?
|
||||
opponent3TuneHandling Int?
|
||||
area Int @default(0)
|
||||
playedAt Int @default(0)
|
||||
playedShopName String @default("Bayshore")
|
||||
}
|
||||
|
||||
model OCMEvent {
|
||||
dbId Int @id @default(autoincrement())
|
||||
competitionId Int
|
||||
qualifyingPeriodStartAt Int
|
||||
qualifyingPeriodCloseAt Int
|
||||
competitionStartAt Int
|
||||
competitionCloseAt Int
|
||||
competitionEndAt Int
|
||||
lengthOfPeriod Int
|
||||
lengthOfInterval Int
|
||||
area Int @default(0)
|
||||
minigamePatternId Int @default(0)
|
||||
|
||||
OCMPeriod OCMPeriod[]
|
||||
}
|
||||
|
||||
model OCMPlayRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
competitionId Int
|
||||
periodId Int
|
||||
brakingPoint Int?
|
||||
playedAt Int @default(0)
|
||||
}
|
||||
|
||||
model OCMTop1Ghost {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
competitionId Int
|
||||
periodId Int
|
||||
result Int
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
}
|
||||
|
||||
model OCMTop1GhostTrail {
|
||||
dbId Int @id @default(autoincrement())
|
||||
carId Int
|
||||
area Int
|
||||
ramp Int
|
||||
path Int
|
||||
trail Bytes
|
||||
competitionId Int
|
||||
periodId Int
|
||||
playedAt Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
ocmMainDraw Boolean @default(false)
|
||||
}
|
||||
|
||||
model OCMTally {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
competitionId Int
|
||||
periodId Int
|
||||
result Int
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
}
|
||||
|
||||
model OCMGhostBattleRecord {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
competitionId Int
|
||||
periodId Int
|
||||
result Int
|
||||
area Int @default(0)
|
||||
playedAt Int @default(0)
|
||||
playedShopName String @default("Bayshore")
|
||||
ocmMainDraw Boolean @default(false)
|
||||
}
|
||||
|
||||
model OCMGhostTrail {
|
||||
dbId Int @id @default(autoincrement())
|
||||
car Car @relation(fields: [carId], references: [carId])
|
||||
carId Int
|
||||
area Int
|
||||
ramp Int
|
||||
path Int
|
||||
trail Bytes
|
||||
competitionId Int
|
||||
periodId Int
|
||||
playedAt Int @default(0)
|
||||
tunePower Int @default(0)
|
||||
tuneHandling Int @default(0)
|
||||
ocmMainDraw Boolean @default(false)
|
||||
}
|
||||
|
||||
model OCMPeriod {
|
||||
dbId Int @id @default(autoincrement())
|
||||
OCMEvent OCMEvent @relation(fields: [competitionDbId], references: [dbId])
|
||||
competitionDbId Int
|
||||
competitionId Int
|
||||
periodId Int
|
||||
startAt Int
|
||||
closeAt Int
|
||||
}
|
24
src/index.ts
24
src/index.ts
@ -73,15 +73,26 @@ allnetApp.use((req, res, next) => {
|
||||
next()
|
||||
});
|
||||
|
||||
// Get all of the files in the modules directory
|
||||
let dirs = fs.readdirSync('dist/modules');
|
||||
for (let i of dirs) {
|
||||
if (i.endsWith('.js')) {
|
||||
// Loop over the files
|
||||
for (let i of dirs)
|
||||
{
|
||||
// If the file is a .js file
|
||||
if (i.endsWith('.js'))
|
||||
{
|
||||
// Require the module file
|
||||
let mod = require(`./modules/${i.substring(0, i.length - 3)}`); // .js extension
|
||||
|
||||
// Create an instance of the module
|
||||
let inst = new mod.default();
|
||||
|
||||
// Register the module with the app
|
||||
inst.register(appRouter);
|
||||
}
|
||||
}
|
||||
|
||||
// Host on / and /wmmt6/ path
|
||||
app.use('/', appRouter);
|
||||
app.use('/wmmt6/', appRouter);
|
||||
|
||||
@ -90,15 +101,22 @@ app.all('*', (req, res) => {
|
||||
res.status(200).end();
|
||||
})
|
||||
|
||||
// Register the ALL.NET / Mucha Server
|
||||
new AllnetModule().register(allnetApp);
|
||||
new MuchaModule().register(muchaApp);
|
||||
|
||||
// Sentry is in use
|
||||
if (useSentry)
|
||||
{
|
||||
// Use the sentry error handler
|
||||
app.use(Sentry.Handlers.errorHandler());
|
||||
}
|
||||
|
||||
// Get the wangan key / certificate file
|
||||
let key = fs.readFileSync('./server_wangan.key');
|
||||
let cert = fs.readFileSync('./server_wangan.crt');
|
||||
|
||||
// Create the (ALL.Net) server
|
||||
http.createServer(allnetApp).listen(PORT_ALLNET, '0.0.0.0', 511, () => {
|
||||
console.log(`ALL.net server listening on port ${PORT_ALLNET}!`);
|
||||
let unix = Config.getConfig().unix;
|
||||
@ -110,10 +128,12 @@ http.createServer(allnetApp).listen(PORT_ALLNET, '0.0.0.0', 511, () => {
|
||||
}
|
||||
})
|
||||
|
||||
// Create the mucha server
|
||||
https.createServer({key, cert}, muchaApp).listen(PORT_MUCHA, '0.0.0.0', 511, () => {
|
||||
console.log(`Mucha server listening on port ${PORT_MUCHA}!`);
|
||||
})
|
||||
|
||||
// Create the game server
|
||||
https.createServer({key, cert}, app).listen(PORT_BNGI, '0.0.0.0', 511, () => {
|
||||
console.log(`Game server listening on port ${PORT_BNGI}!`);
|
||||
})
|
||||
|
619
src/modules/cars.ts
Normal file
619
src/modules/cars.ts
Normal file
@ -0,0 +1,619 @@
|
||||
import { Application } from "express";
|
||||
import { Config } from "../config";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
import { User } from "@prisma/client";
|
||||
import Long from "long";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../util/common";
|
||||
import * as scratch from "../util/scratch";
|
||||
|
||||
|
||||
export default class CarModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Load Car
|
||||
app.post('/method/load_car', async (req, res) => {
|
||||
|
||||
// Get the request body for the load car request
|
||||
let body = wm.wm.protobuf.LoadCarRequest.decode(req.body);
|
||||
|
||||
// Get the car (required data only) with the given id
|
||||
let car = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
include: {
|
||||
settings: true,
|
||||
items: true,
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
// Error handling if ghostLevel accidentally set to 0 or more than 10
|
||||
if(car!.ghostLevel < 1){
|
||||
car!.ghostLevel = 1;
|
||||
}
|
||||
if(car!.ghostLevel > 11){
|
||||
car!.ghostLevel = 10;
|
||||
}
|
||||
|
||||
// Convert the database lose bits to a Long
|
||||
let longLoseBits = Long.fromString(car!.stLoseBits.toString());
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get current / previous active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where:{
|
||||
competitionEndAt:
|
||||
{
|
||||
lte: date // competitionEndAt less than current date
|
||||
}
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'desc'
|
||||
},
|
||||
{
|
||||
competitionEndAt: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
// Declare GhostCompetitionSchedule
|
||||
let ghostCarsNo1;
|
||||
let trailIdNo1: number = 0;
|
||||
if(ocmEventDate)
|
||||
{
|
||||
let pastDay = date - ocmEventDate.competitionEndAt
|
||||
|
||||
if(pastDay < 604800)
|
||||
{
|
||||
let getNo1OCM = await prisma.oCMTally.findFirst({
|
||||
where:{
|
||||
competitionId: ocmEventDate.competitionId,
|
||||
periodId: 999999999
|
||||
},
|
||||
orderBy:{
|
||||
result: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(getNo1OCM)
|
||||
{
|
||||
let carId = getNo1OCM.carId
|
||||
|
||||
// Get Car Data
|
||||
let cars = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: carId
|
||||
},
|
||||
include:{
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
// Get Place
|
||||
let playedPlace = wm.wm.protobuf.Place.create({
|
||||
placeId: 'JPN0123',
|
||||
shopName: Config.getConfig().shopName,
|
||||
regionId: 18,
|
||||
country: 'JPN'
|
||||
});
|
||||
|
||||
// Get Ghost Trail
|
||||
let ghostTrailNo1 = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where:{
|
||||
carId: carId,
|
||||
competitionId: ocmEventDate.competitionId,
|
||||
periodId: 999999999
|
||||
}
|
||||
});
|
||||
|
||||
trailIdNo1 = ghostTrailNo1!.dbId;
|
||||
|
||||
ghostCarsNo1 = wm.wm.protobuf.GhostCar.create({
|
||||
car: {
|
||||
...cars!,
|
||||
lastPlayedPlace: playedPlace
|
||||
},
|
||||
area: ghostTrailNo1!.area,
|
||||
ramp: ghostTrailNo1!.ramp,
|
||||
path: ghostTrailNo1!.path,
|
||||
nonhuman: false,
|
||||
type: wm.wm.protobuf.GhostType.GHOST_NORMAL,
|
||||
trailId: trailIdNo1
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
car: {
|
||||
...car!
|
||||
},
|
||||
tuningPoint: car!.tuningPoints,
|
||||
setting: car!.settings,
|
||||
vsStarCountMax: car!.vsStarCount,
|
||||
rgPreviousVersionPlayCount: 0,
|
||||
stCompleted_100Episodes: car!.stCompleted100Episodes,
|
||||
auraMotifAutoChange: false,
|
||||
screenshotCount: 0,
|
||||
transferred: false,
|
||||
...car!,
|
||||
stLoseBits: longLoseBits,
|
||||
ownedItems: car!.items,
|
||||
lastPlayedAt: car!.lastPlayedAt,
|
||||
announceEventModePrize: true,
|
||||
opponentGhost: ghostCarsNo1 || null,
|
||||
opponentTrailId: trailIdNo1 || null,
|
||||
opponentCompetitionId: ocmEventDate?.competitionId || null
|
||||
};
|
||||
|
||||
// Generate the load car response message
|
||||
let message = wm.wm.protobuf.LoadCarResponse.encode(msg);
|
||||
|
||||
// Send the response
|
||||
common.sendResponse(message, res);
|
||||
});
|
||||
|
||||
|
||||
// Create new car
|
||||
app.post('/method/create_car', async (req, res) => {
|
||||
|
||||
// Get the request body for the create car request
|
||||
let body = wm.wm.protobuf.CreateCarRequest.decode(req.body);
|
||||
|
||||
// Get the current date/time (unix epoch)
|
||||
let date = Math.floor(new Date().getTime() / 1000)
|
||||
|
||||
// Retrieve user from card chip / user id
|
||||
let user: User | null;
|
||||
|
||||
// User ID provided, use that
|
||||
if (body.userId) {
|
||||
user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
});
|
||||
} else { // No user id, use card chip
|
||||
user = await prisma.user.findFirst({
|
||||
where: {
|
||||
chipId: body.cardChipId,
|
||||
accessCode: body.accessCode
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// User not found, terminate
|
||||
if (!user) throw new Error();
|
||||
|
||||
// Generate blank car settings object
|
||||
let settings = await prisma.carSettings.create({
|
||||
data: {}
|
||||
});
|
||||
|
||||
// Generate blank car state object
|
||||
let state = await prisma.carState.create({
|
||||
data: {}
|
||||
})
|
||||
|
||||
let gtWing = await prisma.carGTWing.create({
|
||||
data: {}
|
||||
})
|
||||
|
||||
// Sets if full tune is used or not
|
||||
// let fullyTuned = false;
|
||||
|
||||
// 0: Stock Tune
|
||||
// 1: Basic Tune (600 HP)
|
||||
// 2: Fully Tuned (840 HP)
|
||||
let tune = 0;
|
||||
|
||||
// If a user item has been used
|
||||
if (body.userItemId)
|
||||
{
|
||||
console.log(`Item used - ID ${body.userItemId}`);
|
||||
|
||||
// Remove the user item from the database
|
||||
let item = await prisma.userItem.delete({
|
||||
where: {
|
||||
userItemId: body.userItemId
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Item deleted!');
|
||||
|
||||
switch(item.category)
|
||||
{
|
||||
case 203: // Car Tune Ticket
|
||||
|
||||
// Switch on item id
|
||||
switch(item.itemId)
|
||||
{
|
||||
// Discarded Vehicle Card
|
||||
case 1: tune = 1; break;
|
||||
case 2: tune = 1; break;
|
||||
case 3: tune = 1; break;
|
||||
|
||||
// Fully Tuned Ticket
|
||||
case 5: tune = 2; break;
|
||||
|
||||
default: // Unknown item type, throw unsupported error
|
||||
throw Error("Unsupported itemId: " + item.itemId);
|
||||
}
|
||||
break;
|
||||
|
||||
case 201: // Special Car Ticket
|
||||
|
||||
// Fully tuned special cars
|
||||
if (scratch.fullyTunedCars.includes(item.itemId))
|
||||
{
|
||||
// Car is fully tuned
|
||||
tune = 2;
|
||||
}
|
||||
// Basic tuned special cars
|
||||
if (scratch.basicTunedCars.includes(item.itemId))
|
||||
{
|
||||
// If gift cars fully tuned is set
|
||||
if (Config.getConfig().gameOptions.giftCarsFullyTuned)
|
||||
{
|
||||
// Car is fully tuned
|
||||
tune = 2;
|
||||
}
|
||||
else // Gift cars fully tuned not set
|
||||
{
|
||||
// Car is basic tuned
|
||||
tune = 1;
|
||||
}
|
||||
}
|
||||
// Stock tuned special cars
|
||||
if (scratch.stockTunedCars.includes(item.itemId))
|
||||
{
|
||||
// If gift cars fully tuned is set
|
||||
if (Config.getConfig().gameOptions.giftCarsFullyTuned)
|
||||
{
|
||||
// Car is fully tuned
|
||||
tune = 2;
|
||||
}
|
||||
else // Gift cars fully tuned not set
|
||||
{
|
||||
// Car is stock
|
||||
tune = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
console.log(`Item category was ${item.category} and item game ID was ${item.itemId}`);
|
||||
}
|
||||
|
||||
// Other cases, may occur if item is not detected as 'used'
|
||||
|
||||
// User item not used, but car has 740 HP by default
|
||||
else if (body.car &&
|
||||
(body.car.tunePower == 17) && (body.car.tuneHandling == 17))
|
||||
{
|
||||
// Car is fully tuned
|
||||
tune = 2;
|
||||
}
|
||||
// User item not used, but car has 600 HP by default
|
||||
else if (body.car &&
|
||||
(body.car.tunePower == 10) && (body.car.tuneHandling == 10))
|
||||
{
|
||||
// Car is basic tuned
|
||||
tune = 1;
|
||||
}
|
||||
// User item not used, but gift cars fully tuned switch is set
|
||||
else if (Config.getConfig().gameOptions.giftCarsFullyTuned)
|
||||
{
|
||||
// List of event / exclusive car IDs
|
||||
let event_cars = [
|
||||
0x7A, // Mini
|
||||
0x82, // S660
|
||||
0x83, // S2000
|
||||
0x89, // NDERC
|
||||
0x8B, // GS130 (Starts at 20 Stories by default)
|
||||
];
|
||||
|
||||
// If the car visual model is not null and is in the list of event cars
|
||||
if (body.car.visualModel && event_cars.includes(body.car.visualModel))
|
||||
{
|
||||
// Set full tune used to be true
|
||||
tune = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Default car values
|
||||
let randomRegionId = Math.floor(Math.random() * 47) + 1;
|
||||
let carInsert = {
|
||||
userId: user.id,
|
||||
manufacturer: body.car.manufacturer!,
|
||||
defaultColor: body.car.defaultColor!,
|
||||
model: body.car.model!,
|
||||
visualModel: body.car.visualModel!,
|
||||
name: body.car.name!,
|
||||
title: body.car.title!,
|
||||
level: body.car.level!,
|
||||
tunePower: body.car.tunePower!,
|
||||
tuneHandling: body.car.tuneHandling!,
|
||||
carSettingsDbId: settings.dbId,
|
||||
carStateDbId: state.dbId,
|
||||
carGTWingDbId: gtWing.dbId,
|
||||
regionId: randomRegionId,
|
||||
lastPlayedAt: date,
|
||||
};
|
||||
|
||||
// Check if user have more than one cars
|
||||
let checkWindowSticker = await prisma.car.findFirst({
|
||||
where: {
|
||||
userId: body.userId
|
||||
},
|
||||
select: {
|
||||
windowStickerString: true,
|
||||
windowStickerFont: true
|
||||
}
|
||||
});
|
||||
let additionalWindowStickerInsert = {
|
||||
|
||||
}
|
||||
|
||||
// If more than one cars, get the window sticker string
|
||||
if(checkWindowSticker)
|
||||
{
|
||||
additionalWindowStickerInsert = {
|
||||
windowStickerString: checkWindowSticker.windowStickerString,
|
||||
windowStickerFont: checkWindowSticker.windowStickerFont,
|
||||
}
|
||||
}
|
||||
|
||||
// Additional car values (for basic / full tune)
|
||||
let additionalInsert = {
|
||||
|
||||
}
|
||||
|
||||
// Switch on tune status
|
||||
switch(tune)
|
||||
{
|
||||
// 0: Stock, nothing extra
|
||||
|
||||
case 1: // Basic Tune
|
||||
|
||||
// Updated default values
|
||||
carInsert.level = 2; // C8
|
||||
carInsert.tunePower = 10; // 600 HP
|
||||
carInsert.tuneHandling = 10; // 600 HP
|
||||
|
||||
// Additional basic tune values
|
||||
additionalInsert = {
|
||||
ghostLevel: 4,
|
||||
stClearBits: 0,
|
||||
stLoseBits: 0,
|
||||
stClearCount: 20,
|
||||
stClearDivCount: 1,
|
||||
stConsecutiveWins: 20,
|
||||
stConsecutiveWinsMax: 20
|
||||
};
|
||||
break;
|
||||
|
||||
case 2: // Fully Tuned
|
||||
|
||||
// Updated default values
|
||||
carInsert.level = 8; // C3
|
||||
carInsert.tunePower = 17; // 740 HP
|
||||
carInsert.tuneHandling = 17; // 740 HP
|
||||
|
||||
// Additional full tune values
|
||||
additionalInsert = {
|
||||
ghostLevel: 10,
|
||||
stClearBits: 0,
|
||||
stLoseBits: 0,
|
||||
stClearCount: 80,
|
||||
stClearDivCount: 4,
|
||||
stConsecutiveWins: 80,
|
||||
stConsecutiveWinsMax: 80
|
||||
};
|
||||
}
|
||||
|
||||
// Insert the car into the database
|
||||
let car = await prisma.car.create({
|
||||
data: {
|
||||
...carInsert,
|
||||
...additionalInsert,
|
||||
...additionalWindowStickerInsert
|
||||
}
|
||||
});
|
||||
|
||||
// Get the user's current car order
|
||||
let carOrder = user.carOrder;
|
||||
|
||||
// Add the new car to the front of the id
|
||||
carOrder.unshift(car.carId);
|
||||
|
||||
// Add the car to the front of the order
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: user.id
|
||||
},
|
||||
data: {
|
||||
carOrder: carOrder
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Created new car ${car.name} with ID ${car.carId}`);
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
carId: car.carId,
|
||||
car,
|
||||
...carInsert,
|
||||
...additionalInsert
|
||||
}
|
||||
|
||||
// Generate the load car response message
|
||||
let message = wm.wm.protobuf.CreateCarResponse.encode(msg);
|
||||
|
||||
// Send the response
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Saving the certain car update (on saving bannapass screen or after exiting user's detail car data or after editing car dress up on terminal)
|
||||
app.post('/method/update_car', async (req, res) => {
|
||||
|
||||
// Get the request body for the update car request
|
||||
let body = wm.wm.protobuf.UpdateCarRequest.decode(req.body);
|
||||
|
||||
// Get the ghost result for the car
|
||||
let cars = body?.car;
|
||||
|
||||
// Declare data
|
||||
let data : any;
|
||||
|
||||
// Car is set
|
||||
if (cars)
|
||||
{
|
||||
// Car update data
|
||||
data = {
|
||||
customColor: cars.customColor || undefined,
|
||||
wheel: cars.wheel || undefined,
|
||||
wheelColor: cars.wheelColor || undefined,
|
||||
aero: cars.aero || undefined,
|
||||
bonnet: cars.bonnet || undefined,
|
||||
wing: cars.wing || undefined,
|
||||
mirror: cars.mirror || undefined,
|
||||
neon: cars.neon || undefined,
|
||||
trunk: cars.trunk || undefined,
|
||||
plate: cars.plate || undefined,
|
||||
plateColor: cars.plateColor || undefined,
|
||||
plateNumber: cars.plateNumber || undefined,
|
||||
windowSticker: cars.windowSticker || undefined,
|
||||
windowDecoration: cars.windowDecoration || undefined,
|
||||
rivalMarker: cars.rivalMarker || undefined,
|
||||
aura: cars.aura || undefined,
|
||||
auraMotif: cars.auraMotif || undefined,
|
||||
rgStamp: body?.rgStamp! || undefined,
|
||||
}
|
||||
|
||||
// Update the car info
|
||||
await prisma.car.update({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// Get the car with the given id
|
||||
let car = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
include: {
|
||||
settings: true,
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
// Update the car settings
|
||||
await prisma.carSettings.update({
|
||||
where: {
|
||||
dbId: car?.carSettingsDbId,
|
||||
},
|
||||
data: {
|
||||
...body.setting
|
||||
}
|
||||
});
|
||||
|
||||
// Update the user data
|
||||
let userData = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: body.carId
|
||||
},
|
||||
select:{
|
||||
userId: true,
|
||||
windowStickerString: true
|
||||
}
|
||||
})
|
||||
|
||||
// Newer window sticker string is different from the older one
|
||||
// Check if window sticker string is not null
|
||||
// (windowStickerString value when changing custom color in driver unit is undefined)
|
||||
if(body.car?.windowStickerString)
|
||||
{
|
||||
if(userData!.windowStickerString !== body.car.windowStickerString){
|
||||
console.log('Updating Window Sticker');
|
||||
|
||||
await prisma.car.updateMany({
|
||||
where: {
|
||||
userId: userData!.userId
|
||||
},
|
||||
data: {
|
||||
windowStickerString: body.car.windowStickerString,
|
||||
windowStickerFont: body.car.windowStickerFont!
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Get car item (custom color or discarded card)
|
||||
if(body.earnedItems.length !== 0){
|
||||
console.log('Car Item reward available, continuing ...');
|
||||
for(let i=0; i<body.earnedItems.length; i++){
|
||||
await prisma.carItem.create({
|
||||
data: {
|
||||
carId: body.carId,
|
||||
category: body.earnedItems[i].category,
|
||||
itemId: body.earnedItems[i].itemId,
|
||||
amount: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Update the GT Wing (custom wing) info
|
||||
// Get the GT Wing data for the car
|
||||
let gtWing = body.car?.gtWing;
|
||||
|
||||
// GT Wing is set
|
||||
if (gtWing)
|
||||
{
|
||||
let dataGTWing : any = {
|
||||
pillar: gtWing.pillar || undefined,
|
||||
pillarMaterial: gtWing.pillarMaterial || undefined,
|
||||
mainWing: gtWing.mainWing || undefined,
|
||||
mainWingColor: gtWing.mainWingColor || undefined,
|
||||
wingTip: gtWing.wingTip || undefined,
|
||||
material: gtWing.material || undefined,
|
||||
}
|
||||
|
||||
await prisma.carGTWing.update({
|
||||
where: {
|
||||
dbId: body.carId
|
||||
},
|
||||
data: dataGTWing
|
||||
})
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.UpdateCarResponse.encode(msg);
|
||||
|
||||
// Send the response
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
3089
src/modules/game.ts
3089
src/modules/game.ts
File diff suppressed because it is too large
Load Diff
640
src/modules/ghost.ts
Normal file
640
src/modules/ghost.ts
Normal file
@ -0,0 +1,640 @@
|
||||
import { Application } from "express";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
import { CarPathandTuning, GhostTrail } from "@prisma/client";
|
||||
import Long from "long";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
import * as wmsrv from "../wmmt/service.proto";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../util/common";
|
||||
import * as ghost_save_trail from "../util/games/ghost_save_trail";
|
||||
import * as ghost_trail from "../util/games/ghost_trail";
|
||||
|
||||
|
||||
export default class GhostModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Load Ghost Battle Info
|
||||
app.post('/method/load_ghost_battle_info', async (req, res) => {
|
||||
|
||||
// ---For testing only---
|
||||
let cars = await prisma.car.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
name: { startsWith: 'KITSU' }
|
||||
},
|
||||
{
|
||||
name: { startsWith: 'きつ' }
|
||||
},
|
||||
],
|
||||
},
|
||||
include:{
|
||||
gtWing: true
|
||||
},
|
||||
orderBy: {
|
||||
carId: 'asc'
|
||||
},
|
||||
take: 10
|
||||
});
|
||||
|
||||
for(let i=0; i<cars.length; i++)
|
||||
{
|
||||
// If regionId is 0 or not set, game will crash after defeating the ghost
|
||||
if(cars[i].regionId === 0)
|
||||
{
|
||||
let randomRegionId = Math.floor(Math.random() * 47) + 1;
|
||||
cars[i].regionId = randomRegionId; // Change car region id to 1 (Hokkaido)
|
||||
}
|
||||
}
|
||||
// ----------------------
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
stampSheetCount: 100,
|
||||
history: cars || null,
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadGhostBattleInfoResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Load Stamp Target (Still not working)
|
||||
app.post('/method/load_stamp_target', async (req, res) => {
|
||||
|
||||
// Get the request body for the load stamp target request
|
||||
let body = wm.wm.protobuf.LoadStampTargetRequest.encode(req.body);
|
||||
|
||||
// TODO: Actual stamp stuff here
|
||||
// This is literally just bare-bones
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadStampTargetResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Ghost Mode - Search ghost car by level
|
||||
app.post('/method/search_cars_by_level', async (req, res) => {
|
||||
|
||||
// Get the request body for the search cars by level request
|
||||
let body = wm.wm.protobuf.SearchCarsByLevelRequest.decode(req.body);
|
||||
|
||||
// Find ghost car by selected level
|
||||
let car = await prisma.car.findMany({
|
||||
where: {
|
||||
ghostLevel: body.ghostLevel
|
||||
},
|
||||
include:{
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
// Randomizing the starting ramp and path based on selected area
|
||||
let rampVal = 0;
|
||||
let pathVal = 0;
|
||||
if(body.area === 0){ // GID_RUNAREA_C1
|
||||
rampVal = Math.floor(Math.random() * 4);
|
||||
pathVal = Math.floor(Math.random() * 10);
|
||||
}
|
||||
else if(body.area === 1){ // GID_RUNAREA_RING
|
||||
rampVal = Math.floor(Math.random() * 2) + 4;
|
||||
pathVal = Math.floor(Math.random() * 6) + 10;
|
||||
}
|
||||
else if(body.area === 2){ // GID_RUNAREA_SUBTOKYO_3_4
|
||||
rampVal = Math.floor(Math.random() * 2) + 6;
|
||||
pathVal = Math.floor(Math.random() * 2) + 16;
|
||||
}
|
||||
else if(body.area === 3){ // GID_RUNAREA_SUBTOKYO_5
|
||||
rampVal = Math.floor(Math.random() * 2) + 8;
|
||||
pathVal = Math.floor(Math.random() * 2) + 18;
|
||||
}
|
||||
else if(body.area === 4){ // GID_RUNAREA_WANGAN
|
||||
rampVal = Math.floor(Math.random() * 4) + 10;
|
||||
pathVal = Math.floor(Math.random() * 7) + 20;
|
||||
}
|
||||
else if(body.area === 5){ // GID_RUNAREA_K1
|
||||
rampVal = Math.floor(Math.random() * 4) + 14;
|
||||
pathVal = Math.floor(Math.random() * 7) + 27;
|
||||
}
|
||||
else if(body.area === 6){ // GID_RUNAREA_YAESU
|
||||
rampVal = Math.floor(Math.random() * 3) + 18;
|
||||
pathVal = Math.floor(Math.random() * 4) + 34;
|
||||
}
|
||||
else if(body.area === 7){ // GID_RUNAREA_YOKOHAMA
|
||||
rampVal = Math.floor(Math.random() * 4) + 21;
|
||||
pathVal = Math.floor(Math.random() * 11) + 38;
|
||||
}
|
||||
else if(body.area === 8){ // GID_RUNAREA_NAGOYA
|
||||
rampVal = 25;
|
||||
pathVal = 49;
|
||||
}
|
||||
else if(body.area === 9){ // GID_RUNAREA_OSAKA
|
||||
rampVal = 26;
|
||||
pathVal = Math.floor(Math.random() * 4) + 50;
|
||||
}
|
||||
else if(body.area === 10){ // GID_RUNAREA_KOBE
|
||||
rampVal = Math.floor(Math.random() * 2) + 27;
|
||||
pathVal = Math.floor(Math.random() * 2) + 54;
|
||||
}
|
||||
else if(body.area === 11){ // GID_RUNAREA_FUKUOKA
|
||||
rampVal = Math.floor(Math.random() * 4) + 29;
|
||||
pathVal = Math.floor(Math.random() * 4) + 58;
|
||||
}
|
||||
else if(body.area === 12){ // GID_RUNAREA_HAKONE
|
||||
rampVal = Math.floor(Math.random() * 2) + 33;
|
||||
pathVal = Math.floor(Math.random() * 2) + 62;
|
||||
}
|
||||
else if(body.area === 13){ // GID_RUNAREA_TURNPIKE
|
||||
rampVal = Math.floor(Math.random() * 2) + 35;
|
||||
pathVal = Math.floor(Math.random() * 2) + 64;
|
||||
}
|
||||
//14 - 16 are dummy area, 17 is GID_RUNAREA_C1_CLOSED
|
||||
else if(body.area === 18){ // GID_RUNAREA_HIROSHIMA
|
||||
rampVal = Math.floor(Math.random() * 2) + 37;
|
||||
pathVal = Math.floor(Math.random() * 2) + 56;
|
||||
}
|
||||
|
||||
// Empty list of ghost car records
|
||||
let lists_ghostcar: wm.wm.protobuf.GhostCar[] = [];
|
||||
let arr = [];
|
||||
let maxNumber = 0;
|
||||
|
||||
// If all user car data available is more than 10 for certain level
|
||||
if(car.length > 10){
|
||||
maxNumber = 10 // Limit to 10 (game default)
|
||||
}
|
||||
// If no more than 10
|
||||
else{
|
||||
maxNumber = car.length;
|
||||
}
|
||||
|
||||
// Choose the user's car data randomly to appear
|
||||
while(arr.length < maxNumber){
|
||||
|
||||
// Pick random car Id
|
||||
let randomNumber: number = Math.floor(Math.random() * car.length);
|
||||
if(arr.indexOf(randomNumber) === -1){
|
||||
|
||||
// Push current number to array
|
||||
arr.push(randomNumber);
|
||||
|
||||
// Check if ghost trail for certain car is available
|
||||
let ghost_trails = await prisma.ghostTrail.findFirst({
|
||||
where: {
|
||||
carId: car[randomNumber].carId,
|
||||
area: body.area,
|
||||
crownBattle: false
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// If regionId is 0 or not set, game will crash after defeating the ghost
|
||||
if(car[randomNumber]!.regionId === 0)
|
||||
{
|
||||
let randomRegionId = Math.floor(Math.random() * 47) + 1;
|
||||
car[randomNumber].regionId = randomRegionId; // Hokkaido
|
||||
}
|
||||
|
||||
// Push user's car data without ghost trail
|
||||
if(!(ghost_trails)){
|
||||
lists_ghostcar.push(wm.wm.protobuf.GhostCar.create({
|
||||
car: car[randomNumber]
|
||||
}));
|
||||
}
|
||||
// Push user's car data with ghost trail
|
||||
else{
|
||||
|
||||
// Set the tunePower used when playing certain area
|
||||
car[randomNumber].tunePower = ghost_trails!.tunePower;
|
||||
|
||||
// Set the tuneHandling used when playing certain area
|
||||
car[randomNumber].tuneHandling = ghost_trails!.tuneHandling;
|
||||
|
||||
// Push data to Ghost car proto
|
||||
lists_ghostcar.push(wm.wm.protobuf.GhostCar.create({
|
||||
car: car[randomNumber],
|
||||
nonhuman: false,
|
||||
type: wm.wm.protobuf.GhostType.GHOST_NORMAL,
|
||||
trailId: ghost_trails!.dbId!
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
ghosts: lists_ghostcar,
|
||||
selectionMethod: Number(wm.wm.protobuf.GhostSelectionMethod.GHOST_SELECT_BY_LEVEL)
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.SearchCarsByLevelResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Load Normal Ghost Trail data
|
||||
app.post('/method/load_ghost_drive_data', async (req, res) => {
|
||||
|
||||
// Get the request body for the load ghost drive data request
|
||||
let body = wm.wm.protobuf.LoadGhostDriveDataRequest.decode(req.body);
|
||||
|
||||
// Get the path value from request body
|
||||
let path = body.path;
|
||||
|
||||
// Empty list of ghost drive data records
|
||||
let lists_ghostcar: wm.wm.protobuf.LoadGhostDriveDataResponse.GhostDriveData[] = [];
|
||||
|
||||
// Check how many opponent ghost data available (including user data)
|
||||
for(let i=0; i<body.carTunings.length; i++){
|
||||
|
||||
// Check if opponent ghost have trail
|
||||
let ghost_trails = await prisma.ghostTrail.findFirst({
|
||||
where: {
|
||||
carId: body.carTunings[i].carId!,
|
||||
path: body.path,
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// ---Get the user and opponent ghost trail data---
|
||||
let ghostType: number = wm.wm.protobuf.GhostType.GHOST_NORMAL;
|
||||
let lists_binarydriveData;
|
||||
if(ghost_trails?.driveData !== null && ghost_trails?.driveData !== undefined){
|
||||
lists_binarydriveData = wm.wm.protobuf.BinaryData.create({
|
||||
data: ghost_trails!.driveData!,
|
||||
mergeSerial: ghost_trails!.driveDMergeSerial!
|
||||
});
|
||||
}
|
||||
|
||||
let lists_binaryByArea
|
||||
if(ghost_trails?.trendBinaryByArea !== null && ghost_trails?.trendBinaryByArea !== undefined){
|
||||
lists_binaryByArea = wm.wm.protobuf.BinaryData.create({
|
||||
data: ghost_trails!.trendBinaryByArea!,
|
||||
mergeSerial: ghost_trails!.byAreaMergeSerial!
|
||||
});
|
||||
}
|
||||
|
||||
let lists_binaryByCar
|
||||
if(ghost_trails?.trendBinaryByCar !== null && ghost_trails?.trendBinaryByCar !== undefined){
|
||||
lists_binaryByCar = wm.wm.protobuf.BinaryData.create({
|
||||
data: ghost_trails!.trendBinaryByCar!,
|
||||
mergeSerial: ghost_trails!.byCarMergeSerial!
|
||||
});
|
||||
}
|
||||
|
||||
let lists_binaryByUser
|
||||
if(ghost_trails?.trendBinaryByUser !== null && ghost_trails?.trendBinaryByUser !== undefined){
|
||||
lists_binaryByUser = wm.wm.protobuf.BinaryData.create({
|
||||
data: ghost_trails!.trendBinaryByUser!,
|
||||
mergeSerial: ghost_trails!.byUserMergeSerial!
|
||||
});
|
||||
}
|
||||
// ------------------------------------------------
|
||||
|
||||
|
||||
// Push the data
|
||||
lists_ghostcar.push(wm.wm.protobuf.LoadGhostDriveDataResponse.GhostDriveData.create({ // Push the data
|
||||
carId: Number(body.carTunings[i].carId!),
|
||||
type: ghostType,
|
||||
driveData: lists_binarydriveData || null,
|
||||
trendBinaryByArea: lists_binaryByArea || null,
|
||||
trendBinaryByCar: lists_binaryByCar || null,
|
||||
trendBinaryByUser: lists_binaryByUser || null,
|
||||
}));
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
path: path,
|
||||
data: lists_ghostcar
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadGhostDriveDataResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Saving the ghost trail on mileage screen
|
||||
app.post('/method/register_ghost_trail', async (req, res) => {
|
||||
|
||||
// Get the request body for the register ghost trail request
|
||||
let body = wm.wm.protobuf.RegisterGhostTrailRequest.decode(req.body);
|
||||
|
||||
// Get the session id
|
||||
let actualSessionId: number = 0;
|
||||
|
||||
// If the session are set, and are long data
|
||||
if(Long.isLong(body.ghostSessionId))
|
||||
{
|
||||
// Convert them to BigInt and add to the data
|
||||
actualSessionId = common.getBigIntFromLong(body.ghostSessionId);
|
||||
}
|
||||
|
||||
// OCM game mode session id
|
||||
if(actualSessionId > 100 && actualSessionId < 201)
|
||||
{
|
||||
console.log('OCM Ghost Battle Game found');
|
||||
|
||||
// User playing ocm battle game mode
|
||||
await ghost_save_trail.saveOCMGhostTrail(body);
|
||||
}
|
||||
// Ghost Battle or Crown Ghost Battle game Mode session id
|
||||
else if(actualSessionId > 0 && actualSessionId < 101)
|
||||
{
|
||||
// Check if it is crown ghost battle or not (crown ghost battle don't have time, driveData, trendBinaryByArea, trendBinaryByCar, trendBinaryByUser value from request body)
|
||||
if(!(body.trendBinaryByArea) && !(body.trendBinaryByCar) && !(body.trendBinaryByUser))
|
||||
{
|
||||
console.log('Crown Ghost Battle Game found');
|
||||
|
||||
// User is playing crown ghost battle game mode
|
||||
await ghost_save_trail.saveCrownGhostTrail(body);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log('Normal Ghost Battle Game found');
|
||||
|
||||
// User is playing normal ghost battle game mode
|
||||
await ghost_save_trail.saveNormalGhostTrail(body);
|
||||
|
||||
// Saving Ghost Path and Tuning
|
||||
await ghost_save_trail.savePathAndTuning(body);
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.RegisterGhostTrailResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Load Crown Ghost Trail or Top 1 OCM Ghost Trail
|
||||
app.get('/resource/ghost_trail', async (req, res) => {
|
||||
|
||||
// Get url query parameter [For Crown Ghost Battle]
|
||||
let pCarId = Number(req.query.car_id);
|
||||
let pArea = Number(req.query.area);
|
||||
|
||||
// Get url query parameter [For OCM Ghost Battle]
|
||||
let pTrailId = Number(req.query.trail_id) || undefined;
|
||||
|
||||
// Declare variable
|
||||
let rampVal: number = 0;
|
||||
let pathVal: number = 0;
|
||||
let playedAt: number = 0;
|
||||
let ghostTrail;
|
||||
|
||||
// Query parameter from OCM Battle available
|
||||
if(pTrailId)
|
||||
{
|
||||
// Get the trail data
|
||||
let ghost_trails = await ghost_trail.getOCMGhostTrail(pCarId, pTrailId);
|
||||
|
||||
pArea = ghost_trails.areaVal;
|
||||
rampVal = ghost_trails.rampVal;
|
||||
pathVal = ghost_trails.pathVal;
|
||||
playedAt = ghost_trails.playedAt;
|
||||
ghostTrail = ghost_trails.ghostTrail;
|
||||
}
|
||||
// Query parameter from Crown Ghost Battle available
|
||||
else
|
||||
{
|
||||
// Get the crown trail data
|
||||
let ghost_trails = await ghost_trail.getCrownGhostTrail(pCarId, pArea);
|
||||
|
||||
rampVal = ghost_trails.rampVal;
|
||||
pathVal = ghost_trails.pathVal;
|
||||
playedAt = ghost_trails.playedAt;
|
||||
ghostTrail = ghost_trails.ghostTrail;
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
carId: pCarId,
|
||||
area: pArea,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
playedAt: playedAt,
|
||||
trail: ghostTrail
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.GhostTrail.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Load ghost path and tunings per area
|
||||
app.post('/method/load_paths_and_tunings', async (req, res) => {
|
||||
|
||||
// Get the request body for the load path and tunings request
|
||||
let body = wm.wm.protobuf.LoadPathsAndTuningsRequest.decode(req.body);
|
||||
|
||||
// Empty list of car path and tuning records
|
||||
let carTbyP: wm.wm.protobuf.LoadPathsAndTuningsResponse.CarTuningsByPath[] = [];
|
||||
|
||||
// Loop GID_RUNAREA_*
|
||||
for(let j=0; j<19; j++)
|
||||
{
|
||||
// 14 - 16 are dummy area, 17 is C1 Closed
|
||||
if(j >= 14){
|
||||
j = 18; // GID_RUNAREA_HIROSHIMA
|
||||
}
|
||||
let rampVal = 0;
|
||||
let pathVal = 0;
|
||||
if(j === 0){ // GID_RUNAREA_C1
|
||||
rampVal = Math.floor(Math.random() * 4);
|
||||
pathVal = Math.floor(Math.random() * 10);
|
||||
}
|
||||
else if(j === 1){ // GID_RUNAREA_RING
|
||||
rampVal = Math.floor(Math.random() * 2) + 4;
|
||||
pathVal = Math.floor(Math.random() * 6) + 10;
|
||||
}
|
||||
else if(j === 2){ // GID_RUNAREA_SUBTOKYO_3_4
|
||||
rampVal = Math.floor(Math.random() * 2) + 6;
|
||||
pathVal = Math.floor(Math.random() * 2) + 16;
|
||||
}
|
||||
else if(j === 3){ // GID_RUNAREA_SUBTOKYO_5
|
||||
rampVal = Math.floor(Math.random() * 2) + 8;
|
||||
pathVal = Math.floor(Math.random() * 2) + 18;
|
||||
}
|
||||
else if(j === 4){ // GID_RUNAREA_WANGAN
|
||||
rampVal = Math.floor(Math.random() * 4) + 10;
|
||||
pathVal = Math.floor(Math.random() * 7) + 20;
|
||||
}
|
||||
else if(j === 5){ // GID_RUNAREA_K1
|
||||
rampVal = Math.floor(Math.random() * 4) + 14;
|
||||
pathVal = Math.floor(Math.random() * 7) + 27;
|
||||
}
|
||||
else if(j === 6){ // GID_RUNAREA_YAESU
|
||||
rampVal = Math.floor(Math.random() * 3) + 18;
|
||||
pathVal = Math.floor(Math.random() * 4) + 34;
|
||||
}
|
||||
else if(j === 7){ // GID_RUNAREA_YOKOHAMA
|
||||
rampVal = Math.floor(Math.random() * 4) + 21;
|
||||
pathVal = Math.floor(Math.random() * 11) + 38;
|
||||
}
|
||||
else if(j === 8){ // GID_RUNAREA_NAGOYA
|
||||
rampVal = 25;
|
||||
pathVal = 49;
|
||||
}
|
||||
else if(j === 9){ // GID_RUNAREA_OSAKA
|
||||
rampVal = 26;
|
||||
pathVal = Math.floor(Math.random() * 4) + 50;
|
||||
}
|
||||
else if(j === 10){ // GID_RUNAREA_KOBE
|
||||
rampVal = Math.floor(Math.random() * 2) + 27;
|
||||
pathVal = Math.floor(Math.random() * 2) + 54;
|
||||
}
|
||||
else if(j === 11){ // GID_RUNAREA_FUKUOKA
|
||||
rampVal = Math.floor(Math.random() * 4) + 29;
|
||||
pathVal = Math.floor(Math.random() * 4) + 58;
|
||||
}
|
||||
else if(j === 12){ // GID_RUNAREA_HAKONE
|
||||
rampVal = Math.floor(Math.random() * 2) + 33;
|
||||
pathVal = Math.floor(Math.random() * 2) + 62;
|
||||
}
|
||||
else if(j === 13){ // GID_RUNAREA_TURNPIKE
|
||||
rampVal = Math.floor(Math.random() * 2) + 35;
|
||||
pathVal = Math.floor(Math.random() * 2) + 64;
|
||||
}
|
||||
//14 - 16 are dummy area, 17 is GID_RUNAREA_C1_CLOSED
|
||||
else if(j === 18){ // GID_RUNAREA_HIROSHIMA
|
||||
rampVal = Math.floor(Math.random() * 2) + 37;
|
||||
pathVal = Math.floor(Math.random() * 2) + 56;
|
||||
}
|
||||
|
||||
// Empty list of car tuning records
|
||||
let carTuning: wm.wm.protobuf.CarTuning[] = [];
|
||||
let pathAndTuning: CarPathandTuning | null;
|
||||
|
||||
// Loop to how many opponent ghost selected by user
|
||||
for(let i=0; i<body.selectedCars.length; i++)
|
||||
{
|
||||
// Get path and tuning per area
|
||||
pathAndTuning = await prisma.carPathandTuning.findFirst({
|
||||
where: {
|
||||
carId: body.selectedCars[i],
|
||||
area: j
|
||||
},
|
||||
orderBy: {
|
||||
area: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
// Opponent ghost have path and tuning record for certain area
|
||||
if(pathAndTuning)
|
||||
{
|
||||
// Push the data
|
||||
carTuning.push(wm.wm.protobuf.CarTuning.create({
|
||||
carId: body.selectedCars[i],
|
||||
tunePower: pathAndTuning!.tunePower,
|
||||
tuneHandling: pathAndTuning!.tuneHandling,
|
||||
lastPlayedAt: pathAndTuning!.lastPlayedAt
|
||||
}));
|
||||
}
|
||||
// Opponent ghost doesn't have path and tuning record for certain area
|
||||
else
|
||||
{
|
||||
// Get user's car last used tunePower and tuneHandling
|
||||
let car = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
select:{
|
||||
tunePower: true,
|
||||
tuneHandling: true
|
||||
}
|
||||
});
|
||||
|
||||
// Push the data
|
||||
carTuning.push(wm.wm.protobuf.CarTuning.create({
|
||||
carId: body.selectedCars[i],
|
||||
|
||||
// Set the tunePower used when last played the game
|
||||
tunePower: car!.tunePower,
|
||||
|
||||
// Set the tuneHandling used when last played the game
|
||||
tuneHandling: car!.tuneHandling
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Push the data
|
||||
carTbyP.push(wm.wm.protobuf.LoadPathsAndTuningsResponse.CarTuningsByPath.create({
|
||||
area: j,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
carTunings: carTuning,
|
||||
selectionMethod: wm.wm.protobuf.PathSelectionMethod.PATH_NORMAL // idk what this is
|
||||
}));
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
data: carTbyP
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadPathsAndTuningsResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// idk what this is this for
|
||||
app.post('/method/lock_crown', (req, res) => {
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wmsrv.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wmsrv.wm.protobuf.LockCrownResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
551
src/modules/ghost_ocm.ts
Normal file
551
src/modules/ghost_ocm.ts
Normal file
@ -0,0 +1,551 @@
|
||||
import { Application } from "express";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
import { Car, CarGTWing } from "@prisma/client";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../util/common";
|
||||
import * as ghost_ocm from "../util/games/ghost_ocm";
|
||||
import * as ghost_ocm_area from "../util/games/games_util/ghost_ocm_area";
|
||||
import { Config } from "../config";
|
||||
|
||||
|
||||
export default class GhostModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Get OCM Battle event info
|
||||
app.post('/method/load_ghost_competition_info', async (req, res) => {
|
||||
|
||||
// Get the request body for the load stamp target request
|
||||
let body = wm.wm.protobuf.LoadGhostCompetitionInfoRequest.decode(req.body);
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get currently active OCM event (query still not complete)
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
let msg: any;
|
||||
if(ocmEventDate)
|
||||
{
|
||||
// Check OCM Period
|
||||
let ocmPeriodCount = await prisma.oCMPeriod.count({
|
||||
where:{
|
||||
competitionId: ocmEventDate.competitionId
|
||||
}
|
||||
});
|
||||
|
||||
if(ocmPeriodCount === 0)
|
||||
{
|
||||
console.log('Calculating how many period(s) are available');
|
||||
|
||||
let competitionPeriodStartTimestamp = ocmEventDate.competitionStartAt;
|
||||
let competitionPeriodEndTimeStamp = 0;
|
||||
let period = 1;
|
||||
|
||||
// Count how many period
|
||||
while(competitionPeriodStartTimestamp < ocmEventDate.competitionCloseAt)
|
||||
{
|
||||
|
||||
// Count period closing timestamp
|
||||
competitionPeriodEndTimeStamp = competitionPeriodStartTimestamp + ocmEventDate.lengthOfPeriod;
|
||||
|
||||
// competitionPeriodEndTimeStamp is more than competitionCloseAt
|
||||
if(competitionPeriodEndTimeStamp > ocmEventDate.competitionCloseAt)
|
||||
{
|
||||
competitionPeriodEndTimeStamp = ocmEventDate.competitionCloseAt;
|
||||
}
|
||||
|
||||
// Insert to table
|
||||
await prisma.oCMPeriod.create({
|
||||
data:{
|
||||
competitionDbId: ocmEventDate.dbId,
|
||||
competitionId: ocmEventDate.competitionId,
|
||||
periodId: period,
|
||||
startAt: competitionPeriodStartTimestamp,
|
||||
closeAt: competitionPeriodEndTimeStamp
|
||||
}
|
||||
});
|
||||
|
||||
period++;
|
||||
competitionPeriodStartTimestamp = competitionPeriodEndTimeStamp + ocmEventDate.lengthOfInterval;
|
||||
}
|
||||
|
||||
if(ocmEventDate.lengthOfInterval !== 0)
|
||||
{
|
||||
let qualifyingEndTimeStamp = ocmEventDate.qualifyingPeriodCloseAt - ocmEventDate.lengthOfInterval
|
||||
await prisma.oCMEvent.update({
|
||||
where:{
|
||||
dbId: ocmEventDate.dbId
|
||||
},
|
||||
data:{
|
||||
qualifyingPeriodCloseAt: qualifyingEndTimeStamp
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
console.log('Calculating Period Completed!');
|
||||
}
|
||||
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt <= date && ocmEventDate!.competitionCloseAt >= date)
|
||||
{
|
||||
console.log('Current OCM Day : Competition Day / Main Draw');
|
||||
|
||||
// Get Current OCM Period
|
||||
let OCMCurrentPeriod = await prisma.oCMPeriod.findFirst({
|
||||
where: {
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
startAt:
|
||||
{
|
||||
lte: date, // competitionStartAt is less than current date
|
||||
},
|
||||
closeAt:
|
||||
{
|
||||
gte: date, // competitionCloseAt is greater than current date
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(OCMCurrentPeriod)
|
||||
{
|
||||
// Get OCM Tally Count
|
||||
let OCMTallyCount = await prisma.oCMTally.count({
|
||||
where: {
|
||||
competitionId: OCMCurrentPeriod.competitionId,
|
||||
periodId: OCMCurrentPeriod.periodId
|
||||
},
|
||||
orderBy:{
|
||||
periodId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// If not yet tallying
|
||||
if(OCMTallyCount === 0)
|
||||
{
|
||||
await ghost_ocm.ocmTallying(body, OCMCurrentPeriod.periodId, false);
|
||||
|
||||
// Completed
|
||||
console.log('Tally Completed!');
|
||||
}
|
||||
|
||||
// Get Competition Day Event Data for the car
|
||||
let ocmCompetitionDay = await ghost_ocm.ocmCompetitionDay(body, OCMCurrentPeriod!.competitionId, OCMCurrentPeriod!.periodId);
|
||||
|
||||
// Response Data
|
||||
msg = ocmCompetitionDay.msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Response data
|
||||
msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
closed: true,
|
||||
qualified: false, // if this set to false, user cannot enter OCM Battle game mode
|
||||
};
|
||||
}
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
console.log('Current OCM Day : Qualifying Day');
|
||||
|
||||
// Get Competition Day Event Data for the car
|
||||
let ocmCompetitionDay = await ghost_ocm.ocmQualifyingDay(body, ocmEventDate.competitionId);
|
||||
|
||||
// Response Data
|
||||
msg = ocmCompetitionDay.msg;
|
||||
}
|
||||
// OCM has ended
|
||||
else if(ocmEventDate!.competitionCloseAt < date && ocmEventDate!.competitionEndAt > date)
|
||||
{
|
||||
console.log('Current OCM Day : OCM has Ended');
|
||||
|
||||
// Tallying
|
||||
// Get Current OCM Period
|
||||
let OCMCurrentPeriod = await prisma.oCMPeriod.findFirst({
|
||||
where: {
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy: {
|
||||
periodId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(OCMCurrentPeriod)
|
||||
{
|
||||
// Get OCM Tally Count
|
||||
let OCMTallyCount = await prisma.oCMTally.count({
|
||||
where: {
|
||||
competitionId: OCMCurrentPeriod.competitionId,
|
||||
periodId: 999999999
|
||||
},
|
||||
orderBy:{
|
||||
periodId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// If not yet tallying
|
||||
if(OCMTallyCount === 0)
|
||||
{
|
||||
console.log('Tallying');
|
||||
|
||||
await ghost_ocm.ocmTallying(body, OCMCurrentPeriod.periodId, true);
|
||||
|
||||
// Completed
|
||||
console.log('Last Tally Completed!');
|
||||
}
|
||||
|
||||
|
||||
// Checking if nameplate reward is given
|
||||
let checkOneParticipant = await prisma.oCMPlayRecord.findFirst({
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(checkOneParticipant)
|
||||
{
|
||||
let itemId = 0;
|
||||
// 16th - C1
|
||||
if(ocmEventDate.competitionId === 1)
|
||||
{
|
||||
itemId = 204;
|
||||
}
|
||||
// 17th - Osaka
|
||||
else if(ocmEventDate.competitionId === 2)
|
||||
{
|
||||
itemId = 210;
|
||||
}
|
||||
// 18th - Fukuoka
|
||||
else if(ocmEventDate.competitionId === 3)
|
||||
{
|
||||
itemId = 216;
|
||||
}
|
||||
// 19th - Nagoya
|
||||
else if(ocmEventDate.competitionId === 4)
|
||||
{
|
||||
itemId = 222;
|
||||
}
|
||||
// 6th - C1
|
||||
else if(ocmEventDate.competitionId === 5)
|
||||
{
|
||||
itemId = 35;
|
||||
}
|
||||
// 20th - Kobe
|
||||
else if(ocmEventDate.competitionId === 6)
|
||||
{
|
||||
itemId = 228;
|
||||
}
|
||||
// 7th - Fukutoshin
|
||||
else if(ocmEventDate.competitionId === 7)
|
||||
{
|
||||
itemId = 41;
|
||||
}
|
||||
// 21st - Hiroshima
|
||||
else if(ocmEventDate.competitionId === 8)
|
||||
{
|
||||
itemId = 234;
|
||||
}
|
||||
// 8th - Hakone
|
||||
else if(ocmEventDate.competitionId === 9)
|
||||
{
|
||||
itemId = 47;
|
||||
}
|
||||
|
||||
let checkNameplate = await prisma.carItem.count({
|
||||
where:{
|
||||
carId: checkOneParticipant.carId,
|
||||
category: 17,
|
||||
itemId: itemId
|
||||
},
|
||||
orderBy:{
|
||||
itemId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if(checkNameplate === 0)
|
||||
{
|
||||
await ghost_ocm.ocmGiveNamePlateReward(ocmEventDate.competitionId);
|
||||
}
|
||||
|
||||
// else{} nameplate reward already given
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
closed: true
|
||||
};
|
||||
}
|
||||
}
|
||||
// No OCM Event
|
||||
else{
|
||||
msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
closed: true
|
||||
};
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadGhostCompetitionInfoResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Get the Top 1 OCM Ghost for qualifying day and competition day (this still not completed)
|
||||
app.get('/resource/ghost_competition_target', async (req, res) => {
|
||||
|
||||
// Get url query parameter (competition_id)
|
||||
let competition_id = Number(req.query.competition_id);
|
||||
|
||||
// Calling OCM Area function (BASE_PATH/src/util/games/games_util/ghost_ocm.ts)
|
||||
let OCMArea = await ghost_ocm_area.OCMArea(competition_id);
|
||||
|
||||
// Set the value from OCMArea
|
||||
let areaVal: number = OCMArea.areaVal;
|
||||
let rampVal: number = OCMArea.rampVal;
|
||||
let pathVal: number = OCMArea.pathVal;
|
||||
|
||||
// Get url query parameter (period_id)
|
||||
let period_id = Number(req.query.period_id);
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get currently active OCM event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Declare variable for Top 1 OCM Ghost
|
||||
let ghostCars: wm.wm.protobuf.GhostCar;
|
||||
let ghostTypes;
|
||||
let cars: wm.wm.protobuf.ICar | (Car & { gtWing: CarGTWing; }) | null;
|
||||
let playedPlace = wm.wm.protobuf.Place.create({
|
||||
placeId: 'JPN0123',
|
||||
shopName: Config.getConfig().shopName,
|
||||
regionId: 18,
|
||||
country: 'JPN'
|
||||
});
|
||||
|
||||
// Get default trail id
|
||||
let ghostTrailId = 0;
|
||||
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
console.log('OCM Competition Day / Main Draw');
|
||||
|
||||
// --- Tally (still not complete) ---
|
||||
// Get Top 1 qualifying car data
|
||||
let ocmTallyRecord = await prisma.oCMTop1Ghost.findFirst({
|
||||
where:{
|
||||
competitionId: competition_id,
|
||||
periodId: period_id
|
||||
},
|
||||
orderBy:{
|
||||
result: 'desc'
|
||||
},
|
||||
});
|
||||
|
||||
// Get Top 1 qualifying ghost trail id
|
||||
let checkGhostTrail = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where:{
|
||||
carId: ocmTallyRecord!.carId,
|
||||
area: areaVal,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
},
|
||||
orderBy:{
|
||||
playedAt: 'desc'
|
||||
},
|
||||
});
|
||||
// ----------------------------------
|
||||
|
||||
// Top 1 OCM Ghost trail data available
|
||||
if(checkGhostTrail)
|
||||
{
|
||||
// Get the Top 1 OCM car data
|
||||
cars = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: checkGhostTrail!.carId
|
||||
},
|
||||
include:{
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
// If regionId is 0 or not set, game will crash after defeating the ghost
|
||||
if(cars!.regionId === 0)
|
||||
{
|
||||
let randomRegionId = Math.floor(Math.random() * 47) + 1;
|
||||
cars!.regionId = randomRegionId;
|
||||
}
|
||||
|
||||
// Set the tunePower used when playing ghost crown
|
||||
cars!.tunePower = ocmTallyRecord!.tunePower;
|
||||
|
||||
// Set the tuneHandling used when playing ghost crown
|
||||
cars!.tuneHandling = ocmTallyRecord!.tuneHandling;
|
||||
|
||||
// Set Ghost stuff Value
|
||||
cars!.lastPlayedAt = checkGhostTrail.playedAt
|
||||
ghostTrailId = checkGhostTrail.dbId!;
|
||||
ghostTypes = wm.wm.protobuf.GhostType.GHOST_NORMAL;
|
||||
}
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
console.log('OCM Qualifying Day');
|
||||
|
||||
// Get the default ghost trail
|
||||
let checkGhostTrail = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where:{
|
||||
area: areaVal,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 0
|
||||
},
|
||||
orderBy:{
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Generate default S660 car data
|
||||
cars = wm.wm.protobuf.Car.create({
|
||||
carId: 999999999, // Don't change this
|
||||
name: 'S660',
|
||||
regionId: 18, // IDN (福井)
|
||||
manufacturer: 12, // HONDA
|
||||
model: 105, // S660 [JW5]
|
||||
visualModel: 130, // S660 [JW5]
|
||||
defaultColor: 0,
|
||||
customColor: 0,
|
||||
wheel: 20,
|
||||
wheelColor: 0,
|
||||
aero: 0,
|
||||
bonnet: 0,
|
||||
wing: 0,
|
||||
mirror: 0,
|
||||
neon: 0,
|
||||
trunk: 0,
|
||||
plate: 0,
|
||||
plateColor: 0,
|
||||
plateNumber: 0,
|
||||
tunePower: checkGhostTrail!.tunePower,
|
||||
tuneHandling: checkGhostTrail!.tuneHandling,
|
||||
rivalMarker: 32,
|
||||
aura: 551,
|
||||
windowSticker: true,
|
||||
windowStickerString: 'BAYSHORE',
|
||||
windowStickerFont: 0,
|
||||
title: 'You don\'t have S660? LMAO',
|
||||
level: 65, // SSSSS
|
||||
lastPlayedAt: checkGhostTrail!.playedAt,
|
||||
country: 'GLB'
|
||||
});
|
||||
|
||||
// Set Ghost stuff Value
|
||||
ghostTrailId = checkGhostTrail!.dbId!;
|
||||
ghostTypes = wm.wm.protobuf.GhostType.GHOST_NORMAL;
|
||||
}
|
||||
|
||||
// Push the Top 1 OCM ghost car data
|
||||
ghostCars = wm.wm.protobuf.GhostCar.create({
|
||||
car: {
|
||||
...cars!,
|
||||
lastPlayedPlace: playedPlace
|
||||
},
|
||||
area: areaVal,
|
||||
ramp: rampVal,
|
||||
path: pathVal,
|
||||
nonhuman: false,
|
||||
type: ghostTypes,
|
||||
trailId: ghostTrailId
|
||||
});
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
competitionId: competition_id,
|
||||
ghostCar: ghostCars!,
|
||||
trailId: ghostTrailId,
|
||||
updatedAt: date
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.GhostCompetitionTarget.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
@ -1,18 +1,128 @@
|
||||
import { Application } from "express";
|
||||
import {Module} from "module";
|
||||
import { Config } from "../config";
|
||||
import { prisma } from "..";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
import * as wmsrv from "../wmmt/service.proto";
|
||||
import { prisma } from "..";
|
||||
import { count } from "console";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../util/common";
|
||||
|
||||
|
||||
export default class StartupModule extends Module {
|
||||
register(app: Application): void {
|
||||
app.post('/method/register_system_info', (req, res) => {
|
||||
|
||||
// Register system info upon booting
|
||||
app.post('/method/register_system_info', async (req, res) => {
|
||||
|
||||
// Get the request body for the load stamp target request
|
||||
let body = wm.wm.protobuf.RegisterSystemInfoRequest.decode(req.body);
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get current / previous active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'desc'
|
||||
},
|
||||
{
|
||||
competitionEndAt: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if(!(ocmEventDate))
|
||||
{
|
||||
ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'desc'
|
||||
},
|
||||
{
|
||||
competitionEndAt: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// Declare GhostCompetitionSchedule
|
||||
let compeSch;
|
||||
if(ocmEventDate)
|
||||
{
|
||||
let pastDay = date - ocmEventDate.competitionEndAt
|
||||
|
||||
if(pastDay < 604800)
|
||||
{
|
||||
// Creating GhostCompetitionSchedule
|
||||
compeSch = wm.wm.protobuf.GhostCompetitionSchedule.create({
|
||||
|
||||
// OCM Competition ID (1 = C1 (Round 16), 4 = Nagoya (Round 19), 8 = Hiroshima (Round 21))
|
||||
competitionId: ocmEventDate.competitionId,
|
||||
|
||||
// OCM Qualifying Start Timestamp
|
||||
qualifyingPeriodStartAt: ocmEventDate.qualifyingPeriodStartAt,
|
||||
|
||||
// OCM Qualifying Close Timestamp
|
||||
qualifyingPeriodCloseAt: ocmEventDate.qualifyingPeriodCloseAt,
|
||||
|
||||
// OCM Competition (Main Draw) Start Timestamp
|
||||
competitionStartAt: ocmEventDate.competitionStartAt,
|
||||
|
||||
// OCM Competition (Main Draw) Close Timestamp
|
||||
competitionCloseAt: ocmEventDate.competitionCloseAt,
|
||||
|
||||
// OCM Competition (Main Draw) End Timestamp
|
||||
competitionEndAt: ocmEventDate.competitionEndAt,
|
||||
|
||||
// idk what this is
|
||||
lengthOfPeriod: ocmEventDate.lengthOfPeriod,
|
||||
|
||||
// idk what this is
|
||||
lengthOfInterval: ocmEventDate.lengthOfInterval,
|
||||
|
||||
// Area for the event (GID_RUNAREA_*, 8 is GID_RUNAREA_NAGOYA)
|
||||
area: ocmEventDate.area,
|
||||
|
||||
// idk what this is
|
||||
minigamePatternId: ocmEventDate.minigamePatternId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
regionId: 1,
|
||||
placeId: "JPN0123",
|
||||
regionId: body.allnetRegion0,
|
||||
placeId: body.regionName0,
|
||||
allowedClientLogTypes: [],
|
||||
ghostSelectionMinRedoWait: 30,
|
||||
ghostSelectionMaxRedoWait: 4000,
|
||||
@ -22,62 +132,80 @@ export default class StartupModule extends Module {
|
||||
month: 7,
|
||||
pluses: 0,
|
||||
releaseAt: 0 // idk what this is
|
||||
}
|
||||
},
|
||||
competitionSchedule: compeSch || null // OCM Event Available or not
|
||||
}
|
||||
let resp = wm.wm.protobuf.RegisterSystemInfoResponse.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.RegisterSystemInfoResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Place List
|
||||
app.get('/resource/place_list', (req, res) => {
|
||||
console.log('place list');
|
||||
|
||||
// Empty list of place records
|
||||
let places: wm.wm.protobuf.Place[] = [];
|
||||
|
||||
// Response data
|
||||
places.push(new wm.wm.protobuf.Place({
|
||||
placeId: "JPN0123",
|
||||
regionId: 1,
|
||||
shopName: Config.getConfig().shopName,
|
||||
country: "JPN"
|
||||
}));
|
||||
let resp = wm.wm.protobuf.PlaceList.encode({places});
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.PlaceList.encode({places});
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Get Ranking data for attract screen (TA, Ghost, VS)
|
||||
app.get('/resource/ranking', async (req, res) => {
|
||||
console.log('ranking');
|
||||
|
||||
// Empty list of all ranking records (Combination of TA, VS Stars, and Ghost Battle Win)
|
||||
let lists: wmsrv.wm.protobuf.Ranking.List[] = [];
|
||||
|
||||
// Get TA Ranking
|
||||
for(let i=0; i<25; i++){
|
||||
let ta_time = await prisma.timeAttackRecord.findMany({
|
||||
for(let i=0; i<25; i++){ // GID_TACOURSE ID
|
||||
|
||||
// Get the TA time per course
|
||||
let ta_time = await prisma.timeAttackRecord.findMany({
|
||||
where: {
|
||||
course: i
|
||||
},
|
||||
orderBy: {
|
||||
time: 'asc'
|
||||
},
|
||||
take: 10,
|
||||
take: 10, // Take top 10
|
||||
});
|
||||
if(ta_time.length > 0){
|
||||
let list_ta: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
for(let j=0; j<ta_time.length; j++){
|
||||
let car_ta = await prisma.car.findFirst({
|
||||
|
||||
// TA time record by user is available for certain course
|
||||
if(ta_time.length > 0){
|
||||
|
||||
// Empty list of ranking records for user time attack
|
||||
let list_ta: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
|
||||
// Get the TA time data
|
||||
for(let j=0; j<ta_time.length; j++){
|
||||
|
||||
// Get the car data
|
||||
let car_ta = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: ta_time[j].carId
|
||||
}
|
||||
});
|
||||
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// Push the data to the ranking data
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: ta_time[j].carId,
|
||||
rank: car_ta!.level,
|
||||
result: ta_time[j].time,
|
||||
@ -86,31 +214,39 @@ export default class StartupModule extends Module {
|
||||
model: car_ta!.model,
|
||||
visualModel: car_ta!.visualModel,
|
||||
defaultColor: car_ta!.defaultColor,
|
||||
tunePower: ta_time[j].tunePower,
|
||||
tuneHandling: ta_time[j].tuneHandling,
|
||||
tunePower: ta_time[j].tunePower, // Set the tunePower used when playing TA
|
||||
tuneHandling: ta_time[j].tuneHandling, // Set the tuneHandling used when playing TA
|
||||
title: car_ta!.title,
|
||||
level: car_ta!.level
|
||||
}));
|
||||
}
|
||||
if(ta_time.length < 11){
|
||||
for(let j=ta_time.length; j<11; j++){
|
||||
let resultTime = 599999;
|
||||
if(i === 22 || i === 23){
|
||||
resultTime = 1199999;
|
||||
|
||||
// If the TA time record by user is less than 10 user
|
||||
if(ta_time.length < 11){
|
||||
|
||||
// Take the remaining unfilled
|
||||
for(let j=ta_time.length; j<11; j++){
|
||||
let resultTime = 599999; // 9:59:999 time
|
||||
|
||||
// GID_TACOURSE_TOKYOALL & GID_TACOURSE_KANAGAWAALL area
|
||||
if(i === 22 || i === 23){
|
||||
resultTime = 1199999; // 19:59:999 time
|
||||
}
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// Push the data to the ranking data
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: 0,
|
||||
rank: 0,
|
||||
result: resultTime,
|
||||
name: 'GUEST',
|
||||
regionId: 0,
|
||||
model: Math.floor(Math.random() * 50),
|
||||
visualModel: Math.floor(Math.random() * 100),
|
||||
regionId: 1, // Hokkaido
|
||||
model: Math.floor(Math.random() * 50), // Randomizing GUEST Car data
|
||||
visualModel: Math.floor(Math.random() * 100), // Randomizing GUEST Car data
|
||||
defaultColor: 0,
|
||||
tunePower: 0,
|
||||
tuneHandling: 0,
|
||||
title: 'Wangan Beginner',
|
||||
level: 0
|
||||
title: 'Wangan Beginner', // 湾岸の新人
|
||||
level: 0 // N
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -120,47 +256,64 @@ export default class StartupModule extends Module {
|
||||
topRecords: list_ta
|
||||
}));
|
||||
}
|
||||
else{
|
||||
let list_ta: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
for(let j=0; j<11; j++){
|
||||
let resulttime = 599999;
|
||||
if(i === 22 || i === 23){
|
||||
resulttime = 1199999
|
||||
// There is no user's TA record for certain area
|
||||
else{
|
||||
|
||||
// Empty list of ranking records for GUEST time attack
|
||||
let list_ta: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
|
||||
// Generate the top 10 GUEST TA time data
|
||||
for(let j=0; j<11; j++){
|
||||
let resulttime = 599999; // 9:59:999 time
|
||||
|
||||
// GID_TACOURSE_TOKYOALL & GID_TACOURSE_KANAGAWAALL area
|
||||
if(i === 22 || i === 23){
|
||||
resulttime = 1199999 // 19:59:999 time
|
||||
}
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// Push the GUEST data to the ranking data
|
||||
list_ta.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: 0,
|
||||
rank: 0,
|
||||
result: resulttime,
|
||||
name: 'GUEST',
|
||||
regionId: 0,
|
||||
model: Math.floor(Math.random() * 50),
|
||||
visualModel: Math.floor(Math.random() * 100),
|
||||
regionId: 1, // Hokkaido
|
||||
model: Math.floor(Math.random() * 50), // Randomizing GUEST Car data
|
||||
visualModel: Math.floor(Math.random() * 100), // Randomizing GUEST Car data
|
||||
defaultColor: 0,
|
||||
tunePower: 0,
|
||||
tuneHandling: 0,
|
||||
title: 'Wangan Beginner',
|
||||
level: 0
|
||||
title: 'Wangan Beginner', // 湾岸の新人
|
||||
level: 0 // N
|
||||
}));
|
||||
}
|
||||
|
||||
lists.push(new wmsrv.wm.protobuf.Ranking.List({
|
||||
// Push the certain area ranking data to the list
|
||||
lists.push(new wmsrv.wm.protobuf.Ranking.List({
|
||||
rankingType: i, // RANKING_TA_*AREA*
|
||||
topRecords: list_ta
|
||||
topRecords: list_ta // Top 10 TA time record data
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get VS Star Ranking
|
||||
let car_vs = await prisma.car.findMany({
|
||||
// Get the user's VS Stars data
|
||||
let car_vs = await prisma.car.findMany({
|
||||
orderBy: {
|
||||
vsStarCount: 'desc'
|
||||
},
|
||||
take: 20,
|
||||
take: 20, // Take top 20
|
||||
});
|
||||
let list_vs: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
for(let i=0; i<car_vs.length; i++){
|
||||
list_vs.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// Empty list of ranking records for VS Stars
|
||||
let list_vs: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
|
||||
// Get the VS stars data
|
||||
for(let i=0; i<car_vs.length; i++){
|
||||
|
||||
// Push the car data to the ranking data
|
||||
list_vs.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: car_vs[i].carId,
|
||||
rank: car_vs[i].level,
|
||||
result: car_vs[i].vsStarCount,
|
||||
@ -175,40 +328,55 @@ export default class StartupModule extends Module {
|
||||
level: car_vs[i].level
|
||||
}));
|
||||
}
|
||||
if(car_vs.length < 20){
|
||||
for(let j=car_vs.length; j<21; j++){
|
||||
list_vs.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// If the VS stars record by user is less than 20 user
|
||||
if(car_vs.length < 20){
|
||||
|
||||
// Take the remaining unfilled
|
||||
for(let j=car_vs.length; j<21; j++){
|
||||
|
||||
// Push the GUEST data to the ranking data
|
||||
list_vs.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: 0,
|
||||
rank: 0,
|
||||
result: 0,
|
||||
name: 'GUEST',
|
||||
regionId: 0,
|
||||
model: Math.floor(Math.random() * 50),
|
||||
visualModel: Math.floor(Math.random() * 100),
|
||||
regionId: 1, // Hokkaido
|
||||
model: Math.floor(Math.random() * 50), // Randomizing GUEST Car data
|
||||
visualModel: Math.floor(Math.random() * 100), // Randomizing GUEST Car data
|
||||
defaultColor: 0,
|
||||
tunePower: 0,
|
||||
tuneHandling: 0,
|
||||
title: 'Wangan Beginner',
|
||||
level: 0
|
||||
title: 'Wangan Beginner', // 湾岸の新人
|
||||
level: 0 // N
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Push the data
|
||||
lists.push(new wmsrv.wm.protobuf.Ranking.List({
|
||||
rankingType: 100, // RANKING_VS_STAR
|
||||
topRecords: list_vs
|
||||
topRecords: list_vs // Top 20 VS stars record data
|
||||
}));
|
||||
|
||||
|
||||
// Get Ghost Defeated Ranking
|
||||
let car_ghost = await prisma.car.findMany({
|
||||
// Get the user's Ghost Win data
|
||||
let car_ghost = await prisma.car.findMany({
|
||||
orderBy: {
|
||||
rgWinCount: 'desc'
|
||||
},
|
||||
take: 20,
|
||||
take: 20, // Take top 20
|
||||
});
|
||||
let list_ghost: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
for(let i=0; i<car_ghost.length; i++){
|
||||
list_ghost.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// Empty list of ranking records for Ghost Battle Win
|
||||
let list_ghost: wmsrv.wm.protobuf.Ranking.Entry[] = [];
|
||||
|
||||
// Get the Ghost Battle Win data
|
||||
for(let i=0; i<car_ghost.length; i++){
|
||||
|
||||
// Push the car data to the ranking data
|
||||
list_ghost.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: car_ghost[i].carId,
|
||||
rank: car_ghost[i].level,
|
||||
result: car_ghost[i].rgWinCount,
|
||||
@ -223,72 +391,94 @@ export default class StartupModule extends Module {
|
||||
level: car_ghost[i].level
|
||||
}));
|
||||
}
|
||||
if(car_ghost.length < 20){
|
||||
for(let j=car_ghost.length; j<21; j++){
|
||||
list_ghost.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
|
||||
// If the Ghost Win record by user is less than 20 user
|
||||
if(car_ghost.length < 20){
|
||||
|
||||
// Take the remaining unfilled
|
||||
for(let j=car_ghost.length; j<21; j++){
|
||||
|
||||
// Push the GUEST data to the ranking data
|
||||
list_ghost.push(wmsrv.wm.protobuf.Ranking.Entry.create({
|
||||
carId: 0,
|
||||
rank: 0,
|
||||
result: 0,
|
||||
name: 'GUEST',
|
||||
regionId: 0,
|
||||
model: Math.floor(Math.random() * 50),
|
||||
visualModel: Math.floor(Math.random() * 100),
|
||||
regionId: 1, // Hokkaido
|
||||
model: Math.floor(Math.random() * 50), // Randomizing GUEST Car data
|
||||
visualModel: Math.floor(Math.random() * 100), // Randomizing GUEST Car data
|
||||
defaultColor: 0,
|
||||
tunePower: 0,
|
||||
tuneHandling: 0,
|
||||
title: 'Wangan Beginner',
|
||||
level: 0
|
||||
title: 'Wangan Beginner', // 湾岸の新人
|
||||
level: 0 // N
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Push the data
|
||||
lists.push(new wmsrv.wm.protobuf.Ranking.List({
|
||||
rankingType: 101, // RANKING_GHOST_DEFEATED_COUNT
|
||||
topRecords: list_ghost
|
||||
topRecords: list_ghost // Top 20 Ghost Win record data
|
||||
}));
|
||||
|
||||
let resp = wmsrv.wm.protobuf.Ranking.encode({lists});
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
})
|
||||
// Encode the response
|
||||
let message = wmsrv.wm.protobuf.Ranking.encode({lists});
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Ping
|
||||
app.post('/method/ping', (req, res) => {
|
||||
console.log('ping');
|
||||
let body = wm.wm.protobuf.PingRequest.decode(req.body);
|
||||
|
||||
// Response data
|
||||
let ping = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
pong: body.ping || 1
|
||||
};
|
||||
let resp = wm.wm.protobuf.PingResponse.encode(ping);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.PingResponse.encode(ping);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Crown List for attract screen and Crown Ghost Battle mode
|
||||
app.get('/resource/crown_list', async (req, res) => {
|
||||
console.log('crown_list');
|
||||
let list_crown: wmsrv.wm.protobuf.Crown[] = [];
|
||||
let car_crown = await prisma.carCrown.findMany({
|
||||
|
||||
// Empty list of crown records
|
||||
let list_crown: wmsrv.wm.protobuf.Crown[] = [];
|
||||
|
||||
// Get the crown holder data
|
||||
let car_crown = await prisma.carCrown.findMany({
|
||||
orderBy: {
|
||||
area: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
if(car_crown.length !== 0){
|
||||
// Crown holder data available
|
||||
if(car_crown.length !== 0){
|
||||
let counter = 0;
|
||||
for(let i=0; i<19; i++){
|
||||
if(i >= 14){
|
||||
i = 18;
|
||||
|
||||
// Loop GID_RUNAREA
|
||||
for(let i=0; i<19; i++){
|
||||
|
||||
// 14 - 16 are dummy area, 17 is C1 Closed
|
||||
if(i >= 14){
|
||||
i = 18; // GID_RUNAREA_HIROSHIMA
|
||||
}
|
||||
if(car_crown[counter].area === i){
|
||||
|
||||
// Crown holder for certain area available
|
||||
if(car_crown[counter].area === i){
|
||||
|
||||
// Get user's data
|
||||
let car = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: car_crown[counter].carId
|
||||
@ -297,14 +487,37 @@ export default class StartupModule extends Module {
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
if(car!.regionId === 0){
|
||||
car!.regionId = 1; // Hokkaido
|
||||
|
||||
// If regionId is 0 or not set, game will crash after defeating the ghost
|
||||
if(car!.regionId === 0)
|
||||
{
|
||||
/* Region Id
|
||||
01 = Hokkaido 北海道
|
||||
02 = Aomori 青森
|
||||
03 = Iwate 岩手
|
||||
04 = Miyagi 宮城
|
||||
05 = Akita 秋田
|
||||
06 = Yamagata 山形
|
||||
07 = Fukushima 福島
|
||||
08 = Ibaraki 茨城
|
||||
09 = Tochigi 栃木
|
||||
10 = Gunma 群馬
|
||||
11 = Saitama 埼玉
|
||||
12 = Chiba 千葉
|
||||
13 = Tokyo 東京
|
||||
19 = Yamanashi 山梨
|
||||
*/
|
||||
car!.regionId = i + 1; // Change car region id
|
||||
}
|
||||
car!.tunePower = car_crown[counter].tunePower;
|
||||
car!.tuneHandling = car_crown[counter].tuneHandling;
|
||||
|
||||
// Error handling if played At value is current date
|
||||
if(car_crown[counter].playedAt !== 0 && car_crown[counter].playedAt >= 1659805200)
|
||||
|
||||
// Set the tunePower used when capturing ghost crown
|
||||
car!.tunePower = car_crown[counter].tunePower;
|
||||
|
||||
// Set the tunePower used when capturing ghost crown
|
||||
car!.tuneHandling = car_crown[counter].tuneHandling;
|
||||
|
||||
// Error handling if played At timestamp value is current date and timestamp is bigger than 9 July 2022 (using GMT+7 timestamp)
|
||||
if(car_crown[counter].playedAt !== 0 && car_crown[counter].playedAt >= 1657299600)
|
||||
{
|
||||
// Acquired crown timestamp - 1 day
|
||||
car!.lastPlayedAt = car_crown[counter].playedAt - 172800;
|
||||
@ -312,29 +525,43 @@ export default class StartupModule extends Module {
|
||||
// Acquired crown timestamp - 1 day
|
||||
car_crown[counter].playedAt = car_crown[counter].playedAt - 172800;
|
||||
}
|
||||
// Error handling if played At value is 0
|
||||
else if(car_crown[counter].playedAt === 0 || car_crown[counter].playedAt < 1659805200)
|
||||
// Error handling if played At timestamp value is 0 or timestamp is less than 9 July 2022 (using GMT+7 timestamp)
|
||||
else if(car_crown[counter].playedAt === 0 || car_crown[counter].playedAt < 1657299600)
|
||||
{
|
||||
// Acquired crown timestamp become 7 August 2022
|
||||
car!.lastPlayedAt = 1659805200;
|
||||
// Acquired crown timestamp become 9 July 2022 (using GMT+7 timestamp)
|
||||
car!.lastPlayedAt = 1657299600;
|
||||
|
||||
// Acquired crown timestamp become 7 August 2022
|
||||
car_crown[counter].playedAt = 1659805200;
|
||||
// Acquired crown timestamp become 9 July 2022 (using GMT+7 timestamp)
|
||||
car_crown[counter].playedAt = 1657299600;
|
||||
}
|
||||
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
|
||||
let playedPlace = wm.wm.protobuf.Place.create({
|
||||
placeId: 'JPN0123',
|
||||
shopName: Config.getConfig().shopName,
|
||||
regionId: 18,
|
||||
country: 'JPN'
|
||||
});
|
||||
|
||||
// Push the car data to the crown holder data
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
carId: car_crown[counter].carId,
|
||||
area: car_crown[counter].area, // GID_RUNAREA_C1 - GID_RUNAREA_TURNPIKE & GID_RUNAREA_HIROSHIMA
|
||||
unlockAt: car_crown[counter].playedAt,
|
||||
car: car
|
||||
car: {
|
||||
...car!,
|
||||
lastPlayedPlace: playedPlace
|
||||
}
|
||||
}));
|
||||
|
||||
if(counter < car_crown.length-1){
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
else{
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
// Crown holder for certain area not available
|
||||
else{
|
||||
|
||||
// Push the default data by the game to the crown holder data
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
carId: i,
|
||||
area: i, // GID_RUNAREA_C1 - GID_RUNAREA_TURNPIKE & GID_RUNAREA_HIROSHIMA
|
||||
unlockAt: 0,
|
||||
@ -342,12 +569,19 @@ export default class StartupModule extends Module {
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(let i=0; i<19; i++){
|
||||
if(i >= 14){
|
||||
i = 18;
|
||||
// There is no user's crown holder data available
|
||||
else{
|
||||
|
||||
// Loop GID_RUNAREA
|
||||
for(let i=0; i<19; i++){
|
||||
|
||||
// 14 - 16 are dummy area, 17 is C1 Closed
|
||||
if(i >= 14){
|
||||
i = 18; // GID_RUNAREA_HIROSHIMA
|
||||
}
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
|
||||
// Push the default data by the game to the crown holder data
|
||||
list_crown.push(wmsrv.wm.protobuf.Crown.create({
|
||||
carId: i,
|
||||
area: i, // GID_RUNAREA_C1 - GID_RUNAREA_TURNPIKE & GID_RUNAREA_HIROSHIMA
|
||||
unlockAt: 0,
|
||||
@ -355,17 +589,16 @@ export default class StartupModule extends Module {
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
crowns: list_crown
|
||||
};
|
||||
let resp = wmsrv.wm.protobuf.CrownList.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
|
||||
// Encode the response
|
||||
let message = wmsrv.wm.protobuf.CrownList.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
892
src/modules/terminal.ts
Normal file
892
src/modules/terminal.ts
Normal file
@ -0,0 +1,892 @@
|
||||
import { Application } from "express";
|
||||
import { Config } from "../config";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
import { Car } from "@prisma/client";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as scratch from "../util/scratch";
|
||||
import * as common from "../util/common";
|
||||
|
||||
|
||||
export default class TerminalModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Load upon enter terminal
|
||||
app.post('/method/load_terminal_information', (req, res) => {
|
||||
|
||||
// Get the request body for the load terminal information request
|
||||
let body = wm.wm.protobuf.LoadTerminalInformationRequest.decode(req.body);
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
prizeReceivable: false,
|
||||
transferNotice: {
|
||||
needToSeeTransferred: false
|
||||
},
|
||||
announceFeature: false,
|
||||
freeScratched: true
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadTerminalInformationResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Recieve user items
|
||||
app.post('/method/receive_user_items', async (req, res) => {
|
||||
|
||||
// Get the request body
|
||||
let body = wm.wm.protobuf.ReceiveUserItemsRequest.decode(req.body);
|
||||
|
||||
// Loop over all of the item IDs
|
||||
for(let targetItem of body.targetItemIds)
|
||||
{
|
||||
// Get the item info for the target item
|
||||
let item = await prisma.userItem.findFirst({
|
||||
where: {
|
||||
userItemId: targetItem
|
||||
}
|
||||
});
|
||||
|
||||
// Item is returned
|
||||
if (item)
|
||||
{
|
||||
// Insert the item into the car items
|
||||
await prisma.carItem.create({
|
||||
data: {
|
||||
carId: body.carId,
|
||||
category: item.category,
|
||||
itemId: item.itemId,
|
||||
amount: 1
|
||||
}
|
||||
});
|
||||
|
||||
// Delete the accepted item
|
||||
await prisma.userItem.delete({
|
||||
where: {
|
||||
userItemId: targetItem
|
||||
}
|
||||
});
|
||||
}
|
||||
else // No item found
|
||||
{
|
||||
console.log("Warning: Item " + targetItem + " not found. Item not added.");
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadBookmarksResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Load user bookmarks
|
||||
app.post('/method/load_bookmarks', async (req, res) => {
|
||||
|
||||
// Get the save bookmark request
|
||||
let body = wm.wm.protobuf.LoadBookmarksRequest.decode(req.body);
|
||||
|
||||
// Check if the user has any existing bookmarks
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: Number(body.userId)
|
||||
}
|
||||
});
|
||||
|
||||
// Car bookmarks placeholder
|
||||
let cars : Car[] = [];
|
||||
|
||||
// User is not null
|
||||
if (user)
|
||||
{
|
||||
// Loop over the bookmarked cars
|
||||
for (let carId of user.bookmarks)
|
||||
{
|
||||
// Get the car with the bookmarked car id
|
||||
let car = await prisma.car.findFirst({
|
||||
where: {
|
||||
carId: carId
|
||||
}
|
||||
});
|
||||
|
||||
// If the car is not null
|
||||
if (car)
|
||||
{
|
||||
// Add the car to the cars list
|
||||
cars.push(car);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
cars: cars
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadBookmarksResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Save user bookmarks
|
||||
app.post('/method/save_bookmarks', async (req, res) => {
|
||||
|
||||
// Get the save bookmark request
|
||||
let body = wm.wm.protobuf.SaveBookmarksRequest.decode(req.body);
|
||||
|
||||
// Update existing bookmarks
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
data: {
|
||||
bookmarks: body.cars
|
||||
}
|
||||
})
|
||||
|
||||
// Generate the response to the terminal (success messsage)
|
||||
let resp = wm.wm.protobuf.LoadBookmarksResponse.encode({
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS
|
||||
});
|
||||
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
})
|
||||
|
||||
// Car Summary Request (for bookmarks, also for search ghost by name)
|
||||
app.get('/resource/car_summary', async (req, res) => {
|
||||
|
||||
// Get the query from the request
|
||||
let query = req.query;
|
||||
|
||||
// Get all of the cars matching the query
|
||||
let cars = await prisma.car.findMany({
|
||||
take: Number(query.limit),
|
||||
where: {
|
||||
name: {
|
||||
startsWith: String(query.name)
|
||||
}
|
||||
},
|
||||
include:{
|
||||
gtWing: true
|
||||
}
|
||||
});
|
||||
|
||||
for(let i=0; i<cars.length; i++)
|
||||
{
|
||||
if(cars[i].regionId === 0)
|
||||
{
|
||||
let randomRegionId = Math.floor(Math.random() * 47) + 1;
|
||||
cars[i].regionId = randomRegionId;
|
||||
}
|
||||
}
|
||||
|
||||
let msg = {
|
||||
hitCount: cars.length,
|
||||
cars: cars
|
||||
}
|
||||
|
||||
let resp = wm.wm.protobuf.CarSummary.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
|
||||
})
|
||||
|
||||
// Save upon timeout / exit terminal
|
||||
app.post('/method/save_terminal_result', async (req, res) => {
|
||||
|
||||
// Get the contents from the request
|
||||
let body = wm.wm.protobuf.SaveTerminalResultRequest.decode(req.body);
|
||||
|
||||
// user id is required field
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
});
|
||||
|
||||
if(user)
|
||||
{
|
||||
// Update the completed tutorials
|
||||
let storedTutorials = user.tutorials;
|
||||
|
||||
body.confirmedTutorials.forEach(
|
||||
(idx) => storedTutorials[idx] = true
|
||||
);
|
||||
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
data: {
|
||||
tutorials: storedTutorials
|
||||
}
|
||||
});
|
||||
|
||||
// If the car order was modified
|
||||
|
||||
// Update the car order in the table
|
||||
if (body.carOrder.length > 0)
|
||||
{
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
data: {
|
||||
carOrder: body.carOrder
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let msg = {
|
||||
// Success error code
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
}
|
||||
|
||||
// Encode the save terminal result response
|
||||
let resp = wm.wm.protobuf.SaveTerminalResultResponse.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
})
|
||||
|
||||
|
||||
// Terminal scratch
|
||||
app.post('/method/load_scratch_information', async (req, res) => {
|
||||
|
||||
// Get the information from the request
|
||||
let body = wm.wm.protobuf.LoadScratchInformationRequest.decode(req.body);
|
||||
|
||||
// Get the current date/time (unix epoch)
|
||||
let date = Math.floor(new Date().getTime() / 1000)
|
||||
|
||||
// Scratch sheet proto
|
||||
let scratchSheetProto : wm.wm.protobuf.ScratchSheet[] = [];
|
||||
|
||||
// Current scratch sheet (default: Sheet 1 (R2))
|
||||
let currentSheet = 1;
|
||||
|
||||
// User has scratched already (default: True)
|
||||
let scratched = 1;
|
||||
|
||||
// Get the scratch sheet configuration
|
||||
let scratchEnabled = Config.getConfig().gameOptions.scratchEnabled;
|
||||
|
||||
// If the scratch game is enabled
|
||||
if (scratchEnabled)
|
||||
{
|
||||
// Get all of the info for the user
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: body.userId
|
||||
}
|
||||
});
|
||||
|
||||
// Get the updated scratch sheet proto
|
||||
scratchSheetProto = await scratch.getScratchSheetProto(body.userId);
|
||||
|
||||
// User is defined
|
||||
if (user)
|
||||
{
|
||||
// Update the currentSheet, scratched values
|
||||
currentSheet = user.currentSheet;
|
||||
|
||||
// If unlimited scratches is set
|
||||
if (scratchEnabled == 2)
|
||||
{
|
||||
// User can scratch again
|
||||
scratched = 0;
|
||||
}
|
||||
else // Otherwise, daily scratches
|
||||
{
|
||||
// If a day has passed, allow the user to scratch again
|
||||
scratched = scratch.dayPassed(
|
||||
new Date(date*1000), // Todays date
|
||||
new Date(user.lastScratched*1000) // Last Scratched date
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Owned user items list
|
||||
let ownedUserItems : wm.wm.protobuf.UserItem[] = [];
|
||||
|
||||
// Get the user items list
|
||||
ownedUserItems = await scratch.getScratchItemList(body.userId, date);
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
scratchSheets: scratchSheetProto,
|
||||
currentSheet: currentSheet,
|
||||
numOfScratched: scratched,
|
||||
ownedUserItems: ownedUserItems
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadScratchInformationResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
});
|
||||
|
||||
|
||||
// Change terminal scratch page
|
||||
app.post('/method/turn_scratch_sheet', async (req, res) => {
|
||||
|
||||
// Get the request body for the turn scratch sheet request
|
||||
let body = wm.wm.protobuf.TurnScratchSheetRequest.decode(req.body);
|
||||
|
||||
// Update the active scratch sheet
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
data: {
|
||||
currentSheet: body.targetSheet
|
||||
}
|
||||
});
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.TurnScratchSheetResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Update scratch sheet
|
||||
app.post('/method/save_scratch_sheet', async (req, res) => {
|
||||
|
||||
// Get the information from the request
|
||||
let body = wm.wm.protobuf.SaveScratchSheetRequest.decode(req.body);
|
||||
|
||||
// Get the current date/time (unix epoch)
|
||||
let date = Math.floor(new Date().getTime() / 1000)
|
||||
|
||||
// Get all of the info for the user
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
id: body.userId
|
||||
}
|
||||
});
|
||||
|
||||
// Get all of the scratch sheets for the user
|
||||
let scratchSheets = await prisma.scratchSheet.findMany({
|
||||
where: {
|
||||
userId: body.userId
|
||||
},
|
||||
include: {
|
||||
squares: {
|
||||
orderBy: {
|
||||
id: 'asc'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Get the target scratch sheet (subtract one for zero-index)
|
||||
let scratchSheet = scratchSheets[Number(body.targetSheet)-1];
|
||||
|
||||
// Get all of the squares for the scratch sheet
|
||||
let scratchSquares = await prisma.scratchSquare.findMany({
|
||||
where: {
|
||||
sheetId: scratchSheet.id
|
||||
},
|
||||
orderBy: {
|
||||
id: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
// Get the target scratch square
|
||||
let scratchSquare = scratchSquares[Number(body.targetSquare)];
|
||||
|
||||
// Get the item from the scratch square
|
||||
let earnedItem = wm.wm.protobuf.UserItem.create({
|
||||
category: scratchSquare.category,
|
||||
itemId: scratchSquare.itemId,
|
||||
earnedAt: date
|
||||
});
|
||||
|
||||
try // Attempt to update scratch sheet
|
||||
{
|
||||
// Add the item to the user's scratch items list
|
||||
await prisma.userItem.create({
|
||||
data: {
|
||||
userId: body.userId,
|
||||
category: scratchSquare.category,
|
||||
itemId: scratchSquare.itemId,
|
||||
type: 1, // Scratch item
|
||||
earnedAt: date
|
||||
}
|
||||
});
|
||||
|
||||
// Update the revealed scratch square
|
||||
await prisma.scratchSquare.update({
|
||||
where: {
|
||||
id: scratchSquare.id
|
||||
},
|
||||
data: {
|
||||
earned: true
|
||||
}
|
||||
});
|
||||
|
||||
// Update the last scratched timestamp
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: body.userId
|
||||
},
|
||||
data: {
|
||||
lastScratched: date
|
||||
}
|
||||
});
|
||||
|
||||
// If the box we uncovered is the car
|
||||
if (scratchSquare.category == 201)
|
||||
{
|
||||
// Generate a new scratch sheet for the user
|
||||
await scratch.generateScratchSheet(body.userId, body.targetSheet + 1)
|
||||
}
|
||||
}
|
||||
catch (error) // Failed to update scratch sheet
|
||||
{
|
||||
console.log("Failed to update scratch sheet! Reason:", error);
|
||||
}
|
||||
|
||||
// Get the updated content for the scratch sheet
|
||||
|
||||
// Scratch sheet proto
|
||||
let scratchSheetProto : wm.wm.protobuf.ScratchSheet[] = []
|
||||
|
||||
// Get the updated scratch sheet proto
|
||||
scratchSheetProto = await scratch.getScratchSheetProto(body.userId);
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
scratchSheets : scratchSheetProto,
|
||||
currentSheet: body.targetSheet,
|
||||
numOfScratched: 1,
|
||||
earnedItem: earnedItem
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.SaveScratchSheetResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Terminal OCM Ranking
|
||||
app.post('/method/load_ghost_competition_ranking', async (req, res) => {
|
||||
// Get the information from the request
|
||||
let body = wm.wm.protobuf.LoadGhostCompetitionRankingRequest.decode(req.body);
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get current active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
competitionId: body.competitionId,
|
||||
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
competitionId: body.competitionId,
|
||||
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
competitionId: body.competitionId,
|
||||
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(!(ocmEventDate))
|
||||
{
|
||||
ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(ocmEventDate)
|
||||
{
|
||||
console.log('Previous OCM found');
|
||||
}
|
||||
}
|
||||
|
||||
// Declare GhostCompetitionSchedule
|
||||
let compeSch;
|
||||
let msg: any;
|
||||
|
||||
if(ocmEventDate){
|
||||
// Creating GhostCompetitionSchedule
|
||||
compeSch = wm.wm.protobuf.GhostCompetitionSchedule.create({
|
||||
|
||||
// OCM Competition ID (1 = C1 (Round 16), 4 = Nagoya (Round 19), 8 = Hiroshima (Round 21))
|
||||
competitionId: ocmEventDate.competitionId,
|
||||
|
||||
// OCM Qualifying Start Timestamp
|
||||
qualifyingPeriodStartAt: ocmEventDate.qualifyingPeriodStartAt,
|
||||
|
||||
// OCM Qualifying Close Timestamp
|
||||
qualifyingPeriodCloseAt: ocmEventDate.qualifyingPeriodCloseAt,
|
||||
|
||||
// OCM Competition (Main Draw) Start Timestamp
|
||||
competitionStartAt: ocmEventDate.competitionStartAt,
|
||||
|
||||
// OCM Competition (Main Draw) Close Timestamp
|
||||
competitionCloseAt: ocmEventDate.competitionCloseAt,
|
||||
|
||||
// OCM Competition (Main Draw) End Timestamp
|
||||
competitionEndAt: ocmEventDate.competitionEndAt,
|
||||
|
||||
// idk what this is
|
||||
lengthOfPeriod: ocmEventDate.lengthOfPeriod,
|
||||
|
||||
// idk what this is
|
||||
lengthOfInterval: ocmEventDate.lengthOfInterval,
|
||||
|
||||
// Area for the event (GID_RUNAREA_*, 8 is GID_RUNAREA_NAGOYA)
|
||||
area: ocmEventDate.area,
|
||||
|
||||
// idk what this is
|
||||
minigamePatternId: ocmEventDate.minigamePatternId
|
||||
});
|
||||
|
||||
|
||||
// Get Participant
|
||||
let numOfParticipants: number = 0;
|
||||
let periodId: number = 0;
|
||||
let ownRecords;
|
||||
let topRecords: wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry[] = [];
|
||||
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
console.log('Current OCM Day : Competition Day / Main Draw');
|
||||
|
||||
// Get Current OCM Period
|
||||
let OCMCurrentPeriod = await prisma.oCMPeriod.findFirst({
|
||||
where: {
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
startAt:
|
||||
{
|
||||
lte: date, // competitionStartAt is less than current date
|
||||
},
|
||||
closeAt:
|
||||
{
|
||||
gte: date, // competitionCloseAt is greater than current date
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let ocmParticipant = await prisma.oCMTally.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: OCMCurrentPeriod!.periodId
|
||||
},
|
||||
orderBy: {
|
||||
result: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
numOfParticipants = ocmParticipant.length;
|
||||
periodId = 0;
|
||||
let ranking = 0;
|
||||
|
||||
if(ocmParticipant)
|
||||
{
|
||||
for(let i=0; i<ocmParticipant.length; i++)
|
||||
{
|
||||
let cars = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: ocmParticipant[i].carId
|
||||
}
|
||||
});
|
||||
|
||||
let ocmGhostrecord = await prisma.oCMGhostBattleRecord.findFirst({
|
||||
where:{
|
||||
carId: ocmParticipant[i].carId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
}
|
||||
});
|
||||
|
||||
if(ocmParticipant[i].carId === body.carId && ranking === 0)
|
||||
{
|
||||
// User car setting
|
||||
ownRecords = wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmGhostrecord!.playedShopName,
|
||||
playedAt: ocmGhostrecord!.playedAt
|
||||
});
|
||||
|
||||
ranking++;
|
||||
}
|
||||
|
||||
// Generate OCM Top Records
|
||||
topRecords.push(wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmGhostrecord!.playedShopName,
|
||||
playedAt: ocmGhostrecord!.playedAt
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
console.log('Current OCM Day : Qualifying Day');
|
||||
|
||||
let ocmParticipant = await prisma.oCMGhostBattleRecord.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy: {
|
||||
result: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
numOfParticipants = ocmParticipant.length;
|
||||
periodId = 0;
|
||||
let ranking = 0;
|
||||
|
||||
if(ocmParticipant)
|
||||
{
|
||||
for(let i=0; i<ocmParticipant.length; i++)
|
||||
{
|
||||
let cars = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: ocmParticipant[i].carId
|
||||
}
|
||||
})
|
||||
|
||||
if(ocmParticipant[i].carId === body.carId && ranking === 0)
|
||||
{
|
||||
// User car setting
|
||||
ownRecords = wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmParticipant[i].playedShopName,
|
||||
playedAt: ocmParticipant[i].playedAt
|
||||
});
|
||||
|
||||
ranking++;
|
||||
}
|
||||
|
||||
// Generate OCM Top Records
|
||||
topRecords.push(wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmParticipant[i].playedShopName,
|
||||
playedAt: ocmParticipant[i].playedAt
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
// OCM has ended
|
||||
else
|
||||
{
|
||||
console.log('Current / Previous OCM Day : OCM has Ended');
|
||||
|
||||
let ocmParticipant = await prisma.oCMTally.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 999999999
|
||||
},
|
||||
orderBy: {
|
||||
result: 'desc'
|
||||
}
|
||||
})
|
||||
|
||||
numOfParticipants = ocmParticipant.length;
|
||||
periodId = 0;
|
||||
let ranking = 0;
|
||||
|
||||
if(ocmParticipant)
|
||||
{
|
||||
for(let i=0; i<ocmParticipant.length; i++)
|
||||
{
|
||||
let cars = await prisma.car.findFirst({
|
||||
where:{
|
||||
carId: ocmParticipant[i].carId
|
||||
}
|
||||
});
|
||||
|
||||
let ocmGhostrecord = await prisma.oCMGhostBattleRecord.findFirst({
|
||||
where:{
|
||||
carId: ocmParticipant[i].carId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
}
|
||||
});
|
||||
|
||||
if(ocmParticipant[i].carId === body.carId && ranking === 0)
|
||||
{
|
||||
// User car setting
|
||||
ownRecords = wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmGhostrecord!.playedShopName,
|
||||
playedAt: ocmGhostrecord!.playedAt
|
||||
});
|
||||
|
||||
ranking++;
|
||||
}
|
||||
|
||||
// Generate OCM Top Records
|
||||
topRecords.push(wm.wm.protobuf.LoadGhostCompetitionRankingResponse.Entry.create({
|
||||
rank: i + 1,
|
||||
result: ocmParticipant[i].result,
|
||||
carId: ocmParticipant[i].carId,
|
||||
name: cars!.name,
|
||||
regionId: cars!.regionId,
|
||||
model: cars!.model,
|
||||
visualModel: cars!.visualModel,
|
||||
defaultColor: cars!.defaultColor,
|
||||
title: cars!.title,
|
||||
level: cars!.level,
|
||||
windowStickerString: cars!.windowStickerString,
|
||||
playedShopName: ocmGhostrecord!.playedShopName,
|
||||
playedAt: ocmGhostrecord!.playedAt
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Response data
|
||||
msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
periodId: periodId,
|
||||
numOfParticipants: numOfParticipants,
|
||||
competitionSchedule: compeSch, // OCM Event Available or not
|
||||
ownRecord: ownRecords,
|
||||
topRecords: topRecords
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
numOfParticipants: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadGhostCompetitionRankingResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
89
src/modules/time_attack.ts
Normal file
89
src/modules/time_attack.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import { Application } from "express";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../util/common";
|
||||
|
||||
|
||||
export default class TimeAttackModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Load time Attack Record
|
||||
app.post('/method/load_time_attack_record', async (req, res) => {
|
||||
|
||||
// Get the request body for the load terminal information request
|
||||
let body = wm.wm.protobuf.LoadTimeAttackRecordRequest.decode(req.body);
|
||||
|
||||
let taRecordsForModel = await prisma.timeAttackRecord.findMany({
|
||||
take: 100,
|
||||
where: {
|
||||
model: body.model,
|
||||
course: body.course
|
||||
},
|
||||
orderBy: {
|
||||
time: 'asc'
|
||||
}
|
||||
});
|
||||
let taRecordsOverall = await prisma.timeAttackRecord.findMany({
|
||||
take: 100,
|
||||
where: {
|
||||
course: body.course
|
||||
},
|
||||
orderBy: {
|
||||
time: 'asc'
|
||||
}
|
||||
});
|
||||
let taRecordPb = await prisma.timeAttackRecord.findFirst({
|
||||
where: {
|
||||
carId: body.carId,
|
||||
course: body.course
|
||||
},
|
||||
orderBy: {
|
||||
time: 'asc'
|
||||
}
|
||||
});
|
||||
|
||||
if (!taRecordPb) {
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
wholeRanking: taRecordsOverall.map(a => a.time),
|
||||
modelRanking: taRecordsForModel.map(a => a.time)
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadTimeAttackRecordResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
return;
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
wholeRanking: taRecordsOverall.map(a => a.time),
|
||||
modelRanking: taRecordsForModel.map(a => a.time),
|
||||
personalBestTime: taRecordPb.time,
|
||||
pbSection_1Time: taRecordPb.section1Time,
|
||||
pbSection_2Time: taRecordPb.section2Time,
|
||||
pbSection_3Time: taRecordPb.section3Time,
|
||||
pbSection_4Time: taRecordPb.section4Time,
|
||||
pbSection_5Time: taRecordPb.section5Time,
|
||||
pbSection_6Time: taRecordPb.section6Time,
|
||||
pbSection_7Time: taRecordPb.section7Time,
|
||||
};
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadTimeAttackRecordResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
}
|
||||
}
|
647
src/modules/users.ts
Normal file
647
src/modules/users.ts
Normal file
@ -0,0 +1,647 @@
|
||||
import e, { Application } from "express";
|
||||
import { Config } from "../config";
|
||||
import { Module } from "module";
|
||||
import { prisma } from "..";
|
||||
|
||||
// Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as scratch from "../util/scratch";
|
||||
import * as common from "../util/common";
|
||||
|
||||
|
||||
export default class UserModule extends Module {
|
||||
register(app: Application): void {
|
||||
|
||||
// Load user data when entering the game or after tapping the bannapass card
|
||||
app.post('/method/load_user', async (req, res) => {
|
||||
|
||||
// Get the request body for the load user request
|
||||
let body = wm.wm.protobuf.LoadUserRequest.decode(req.body);
|
||||
|
||||
// Get the user from the database
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
chipId: body.cardChipId,
|
||||
accessCode: body.accessCode
|
||||
},
|
||||
include: {
|
||||
cars: {
|
||||
include: {
|
||||
state: true,
|
||||
gtWing: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// No user returned
|
||||
if (!user) {
|
||||
console.log('no such user');
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
numOfOwnedCars: 0,
|
||||
cars: [],
|
||||
spappState: wm.wm.protobuf.SmartphoneAppState.SPAPP_UNREGISTERED,
|
||||
transferState: wm.wm.protobuf.TransferState.NOT_REGISTERED,
|
||||
};
|
||||
if (!body.cardChipId || !body.accessCode) {
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_ID_BANNED,
|
||||
numOfOwnedCars: 0,
|
||||
spappState: wm.wm.protobuf.SmartphoneAppState.SPAPP_UNREGISTERED,
|
||||
transferState: wm.wm.protobuf.TransferState.NOT_REGISTERED
|
||||
}
|
||||
let resp = wm.wm.protobuf.LoadUserResponse.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
return;
|
||||
}
|
||||
let user = await prisma.user.create({
|
||||
data: {
|
||||
chipId: body.cardChipId,
|
||||
accessCode: body.accessCode,
|
||||
tutorials: [
|
||||
false, //TUTORIAL_ID_STORY
|
||||
false, //TUTORIAL_ID_TIME_ATTACK
|
||||
false, //TUTORIAL_ID_GHOST
|
||||
false, //TUTORIAL_ID_GHOST_CHALLENGE
|
||||
false, //TUTORIAL_ID_GHOST_LEVEL
|
||||
false, //TUTORIAL_ID_UNUSED_5
|
||||
false, //TUTORIAL_ID_GHOST_SEARCH
|
||||
false, //TUTORIAL_ID_GHOST_COMPETITION
|
||||
false, //TUTORIAL_ID_HP600_CARD
|
||||
false, //TUTORIAL_ID_UNUSED_9
|
||||
false, //TUTORIAL_ID_COMPETITION_QUALIFIED
|
||||
false, //TUTORIAL_ID_COMPETITION_TERMINAL
|
||||
false, //TUTORIAL_ID_COMPETITION_NOTICE
|
||||
false, //TUTORIAL_ID_COMPETITION_FINISHED
|
||||
false, //TUTORIAL_ID_UNUSED_14
|
||||
false, //TUTORIAL_ID_UNUSED_15
|
||||
false, //TUTORIAL_ID_UNUSED_16
|
||||
false, //TUTORIAL_ID_UNUSED_17
|
||||
false, //TUTORIAL_ID_UNUSED_18
|
||||
false, //TUTORIAL_ID_UNUSED_19
|
||||
false, //TUTORIAL_ID_GHOST_STAMP
|
||||
false, //TUTORIAL_ID_GHOST_STAMP_DECLINED
|
||||
false, //TUTORIAL_ID_GHOST_STAMP_FRIENDS
|
||||
true, //TUTORIAL_ID_TERMINAL_SCRATCH
|
||||
true, //TUTORIAL_ID_TURN_SCRATCH_SHEET
|
||||
false, //TUTORIAL_ID_INVITE_FRIEND_CAMPAIGN
|
||||
false, //TUTORIAL_ID_CAR_COUPON_FULL_TUNED_RECEIVABLE
|
||||
false, //TUTORIAL_ID_VS_CONTINUE_TICKET
|
||||
false, //TUTORIAL_ID_UNUSED_28
|
||||
false, //TUTORIAL_ID_UNUSED_29
|
||||
false, //TUTORIAL_ID_UNUSED_30
|
||||
false, //TUTORIAL_ID_DRESS_UP
|
||||
true, //TUTORIAL_ID_MULTI_GHOST
|
||||
true, //TUTORIAL_ID_STORY_NEW_FEATURE
|
||||
true, //TUTORIAL_ID_GHOST_NEW_FEATURE
|
||||
true, //TUTORIAL_ID_GHOST_REGION_MAP
|
||||
],
|
||||
}
|
||||
});
|
||||
console.log('user made')
|
||||
if (!user) {
|
||||
msg.error = wm.wm.protobuf.ErrorCode.ERR_REQUEST;
|
||||
}
|
||||
let ftTicketGrant = Config.getConfig().gameOptions.grantFullTuneTicketToNewUsers;
|
||||
if (ftTicketGrant > 0) {
|
||||
console.log(`Granting Full-Tune Ticket x${ftTicketGrant} to new user...`);
|
||||
for (let i=0; i<ftTicketGrant; i++) {
|
||||
await prisma.userItem.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
category: wm.wm.protobuf.ItemCategory.CAT_CAR_TICKET_FREE,
|
||||
itemId: 5,
|
||||
type: 0 // Car Ticket
|
||||
}
|
||||
});
|
||||
}
|
||||
console.log('Done!');
|
||||
}
|
||||
let resp = wm.wm.protobuf.LoadUserResponse.encode(msg);
|
||||
let end = resp.finish();
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
r.send(Buffer.from(end));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the number of scratch cards for the user
|
||||
let scratchSheetCount = await prisma.scratchSheet.count({
|
||||
where: {
|
||||
userId: user!.id
|
||||
}
|
||||
})
|
||||
|
||||
console.log("Current sheet count:", scratchSheetCount);
|
||||
|
||||
// If the user has no scratch sheets
|
||||
if (scratchSheetCount == 0)
|
||||
{
|
||||
console.log("Generating first sheet ...");
|
||||
|
||||
// Generate a new scratch sheet for the user
|
||||
await scratch.generateScratchSheet(user!.id, 1);
|
||||
|
||||
// Set the current scratch sheet to 1
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: user!.id
|
||||
},
|
||||
data: {
|
||||
currentSheet: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// If the car order array has not been created
|
||||
if (user.carOrder.length > 0)
|
||||
{
|
||||
// Sort the player's car list using the car order property
|
||||
user.cars = user.cars.sort(function(a, b){
|
||||
|
||||
// User, and both car IDs exist
|
||||
if (user)
|
||||
{
|
||||
// Compare both values using the car order array
|
||||
let compare: number = user?.carOrder.indexOf(a!.carId) - user?.carOrder.indexOf(b!.carId);
|
||||
|
||||
// Return the comparison
|
||||
return compare;
|
||||
}
|
||||
else // Car IDs not present in car order list
|
||||
{
|
||||
throw Error("UserNotFoundException");
|
||||
}
|
||||
});
|
||||
}
|
||||
else // Car order undefined
|
||||
{
|
||||
// We will define it here
|
||||
let carOrder : number[] = [];
|
||||
|
||||
// Loop over all of the user cars
|
||||
for(let car of user.cars)
|
||||
{
|
||||
// Add the car id to the list
|
||||
carOrder.push(car.carId);
|
||||
}
|
||||
|
||||
// Update the car id property for the user
|
||||
await prisma.user.update({
|
||||
where: {
|
||||
id: user.id
|
||||
},
|
||||
data: {
|
||||
carOrder: carOrder
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Get the states of the user's cars
|
||||
let carStates = user.cars.map(e => e.state);
|
||||
|
||||
// Get all of the user's tickets
|
||||
let tickets = await prisma.userItem.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
type: 0
|
||||
},
|
||||
select: {
|
||||
itemId: true,
|
||||
category: true,
|
||||
userItemId: true
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Error handling if windowStickerString and windowStickerFont is undefined or null
|
||||
// User is registering bannapass from terminal unit first instead of driver unit
|
||||
// Default value for windowStickerString and windowStickerFont
|
||||
let wsString = 'WANGAN';
|
||||
let wsFont = 0;
|
||||
|
||||
// user.cars found
|
||||
if(user.cars)
|
||||
{
|
||||
// User atleast have 1 car
|
||||
if(user.cars[0]?.windowStickerString !== null && user.cars[0]?.windowStickerString !== undefined &&
|
||||
user.cars[0]?.windowStickerString !== '')
|
||||
{
|
||||
wsString = user.cars[0].windowStickerString;
|
||||
wsFont = user.cars[0].windowStickerFont;
|
||||
}
|
||||
// else{} User don't have a car... returning default windowStickerString and windowStickerFont value
|
||||
}
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
numOfOwnedCars: user.cars.length,
|
||||
spappState: wm.wm.protobuf.SmartphoneAppState.SPAPP_UNREGISTERED,
|
||||
transferState: wm.wm.protobuf.TransferState.TRANSFERRED,
|
||||
carStates,
|
||||
userId: user.id,
|
||||
banapassportAmId: 1,
|
||||
mbId: 1,
|
||||
tutorials: user.tutorials,
|
||||
unusedCarTickets: tickets,
|
||||
|
||||
// 5 cars in-game, 200 cars on terminal
|
||||
cars: user.cars.slice(0, body.maxCars),
|
||||
|
||||
// Set the window sticker string for all cars
|
||||
windowStickerString: wsString,
|
||||
|
||||
// Set the window sticker font for all cars
|
||||
windowStickerFont: wsFont,
|
||||
|
||||
// Set initial value for competition (OCM) participation
|
||||
competitionUserState: wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_NOT_PARTICIPATED
|
||||
}
|
||||
|
||||
|
||||
// Check OCM Participation
|
||||
let ParticipationMainDrawCounter = 0;
|
||||
let ParticipationQualifyingCounter = 0;
|
||||
let ParticipationEndedCounter = 0;
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Check each car record
|
||||
for(let i=0; i<msg.cars.length; i++)
|
||||
{
|
||||
// Get current active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Check Competition (OCM) Participation, and available OCM event
|
||||
if(user.cars.length > 0 && ocmEventDate)
|
||||
{
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
// Check ghost battle record
|
||||
let checkParticipation = await prisma.oCMPlayRecord.findFirst({
|
||||
where:{
|
||||
carId: user.cars[i].carId,
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
}
|
||||
});
|
||||
|
||||
// Record found
|
||||
if(checkParticipation)
|
||||
{
|
||||
ParticipationMainDrawCounter++
|
||||
}
|
||||
|
||||
// Check Car State
|
||||
// Get OCM Data
|
||||
let ocmTallyRecord = await prisma.oCMTally.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
competitionId: 'desc',
|
||||
},
|
||||
{
|
||||
periodId: 'desc',
|
||||
},
|
||||
{
|
||||
result: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for(let j=0; j<ocmTallyRecord.length; j++)
|
||||
{
|
||||
if(carStates[i].dbId === ocmTallyRecord[j].carId)
|
||||
{
|
||||
carStates[i].eventJoined = true;
|
||||
carStates[i].competitionState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_QUALIFIED
|
||||
}
|
||||
if(carStates[i].dbId === ocmTallyRecord[j].carId && j === 0)
|
||||
{
|
||||
carStates[i].competitionState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_WON
|
||||
}
|
||||
}
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
// Check ghost battle record
|
||||
let checkParticipation = await prisma.oCMPlayRecord.findFirst({
|
||||
where:{
|
||||
carId: user.cars[i].carId,
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
}
|
||||
});
|
||||
|
||||
// Record found
|
||||
if(checkParticipation)
|
||||
{
|
||||
ParticipationQualifyingCounter++
|
||||
}
|
||||
|
||||
// Check Car State
|
||||
// Get OCM Data
|
||||
let ocmRecord = await prisma.oCMPlayRecord.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'asc',
|
||||
},
|
||||
{
|
||||
competitionId: 'desc',
|
||||
},
|
||||
{
|
||||
periodId: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for(let j=0; j<ocmRecord.length; j++)
|
||||
{
|
||||
if(carStates[i].dbId === ocmRecord[j].carId)
|
||||
{
|
||||
carStates[i].eventJoined = true;
|
||||
carStates[i].competitionState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_PARTICIPATED
|
||||
}
|
||||
}
|
||||
}
|
||||
// Current date is OCM ended
|
||||
else if(ocmEventDate!.competitionCloseAt < date && ocmEventDate!.competitionEndAt > date)
|
||||
{
|
||||
// Check ghost battle record
|
||||
let checkParticipation = await prisma.oCMPlayRecord.findFirst({
|
||||
where:{
|
||||
carId: user.cars[i].carId,
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
}
|
||||
});
|
||||
|
||||
// Record found
|
||||
if(checkParticipation)
|
||||
{
|
||||
ParticipationEndedCounter++
|
||||
}
|
||||
|
||||
// Check Car State
|
||||
// Get OCM Data
|
||||
let ocmTallyRecord = await prisma.oCMTally.findMany({
|
||||
where:{
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
competitionId: 'desc',
|
||||
},
|
||||
{
|
||||
periodId: 'desc',
|
||||
},
|
||||
{
|
||||
result: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for(let j=0; j<ocmTallyRecord.length; j++)
|
||||
{
|
||||
if(carStates[i].dbId === ocmTallyRecord[j].carId)
|
||||
{
|
||||
carStates[i].eventJoined = true;
|
||||
carStates[i].competitionState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_QUALIFIED
|
||||
}
|
||||
if(carStates[i].dbId === ocmTallyRecord[j].carId && j === 0)
|
||||
{
|
||||
carStates[i].competitionState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_WON
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Participated to OCM Event
|
||||
if(ParticipationMainDrawCounter > 0)
|
||||
{
|
||||
console.log('OCM Participation : '+ParticipationMainDrawCounter+' car(s) Qualified');
|
||||
msg.competitionUserState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_QUALIFIED;
|
||||
}
|
||||
else if(ParticipationQualifyingCounter > 0)
|
||||
{
|
||||
console.log('OCM Participation : '+ParticipationQualifyingCounter+' car(s) Participated');
|
||||
msg.competitionUserState = wm.wm.protobuf.GhostCompetitionParticipantState.COMPETITION_PARTICIPATED;
|
||||
}
|
||||
else if(ParticipationEndedCounter > 0)
|
||||
{
|
||||
console.log('OCM Participation : '+ParticipationEndedCounter+' car(s) played OCM Event');
|
||||
}
|
||||
else{
|
||||
console.log('OCM Participation : Not Participated / Qualified');
|
||||
}
|
||||
|
||||
// Response data if user is banned
|
||||
if (user.userBanned) {
|
||||
msg.error = wm.wm.protobuf.ErrorCode.ERR_ID_BANNED;
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadUserResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Create User Request
|
||||
app.post('/method/create_user', async (req, res) => {
|
||||
|
||||
// This request is sent by the terminal when you
|
||||
// select 'yes' to register on the starting menu
|
||||
// if you have not created your account yet.
|
||||
|
||||
// However, we don't really need to process it as
|
||||
// the load_user command already creates the user.
|
||||
// we do, however need to send a valid response
|
||||
// otherwise the terminal crashes.
|
||||
|
||||
// Get the request body for the create user request
|
||||
let body = wm.wm.protobuf.CreateUserRequest.decode(req.body);
|
||||
|
||||
// Get the user info via the card chip id
|
||||
let user = await prisma.user.findFirst({
|
||||
where: {
|
||||
chipId: body.cardChipId,
|
||||
accessCode: body.accessCode
|
||||
}
|
||||
});
|
||||
|
||||
// Message object
|
||||
let msg;
|
||||
|
||||
// User exists
|
||||
if (user)
|
||||
{
|
||||
msg = {
|
||||
// Success error message
|
||||
error : wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
|
||||
// User's user id
|
||||
userId : user?.id
|
||||
}
|
||||
}
|
||||
else // User does not exist
|
||||
{
|
||||
msg = {
|
||||
// User not found error message
|
||||
error : wm.wm.protobuf.ErrorCode.ERR_NOT_FOUND,
|
||||
|
||||
// No user id
|
||||
userId : 0
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the response for the create user request
|
||||
let message = wm.wm.protobuf.CreateUserResponse.encode(msg);
|
||||
|
||||
// Send response to client
|
||||
common.sendResponse(message, res);
|
||||
});
|
||||
|
||||
|
||||
// Load Drive Information
|
||||
app.post('/method/load_drive_information', async (req, res) => {
|
||||
|
||||
// Get the request body for the load drive information request
|
||||
let body = wm.wm.protobuf.LoadDriveInformationRequest.decode(req.body);
|
||||
|
||||
// Get all of the user's tickets
|
||||
let tickets = await prisma.userItem.findMany({
|
||||
where: {
|
||||
userId: body.userId,
|
||||
type: 0
|
||||
},
|
||||
select: {
|
||||
itemId: true,
|
||||
category: true,
|
||||
userItemId: true
|
||||
}
|
||||
})
|
||||
|
||||
// TODO: Add notices to config
|
||||
let notice = (Config.getConfig().notices || []);
|
||||
|
||||
// Create the notice window objects
|
||||
let noticeWindows = notice.map(a => wm.wm.protobuf.NoticeEntry.NOTICE_UNUSED_1);
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
noticeWindow: noticeWindows,
|
||||
noticeWindowMessage: notice,
|
||||
transferNotice: {
|
||||
needToSeeTransferred: false,
|
||||
totalMaxiGold: 0,
|
||||
numOfPorscheCars: 0,
|
||||
porscheModels: [],
|
||||
hasR35: false,
|
||||
},
|
||||
restrictedModels: [],
|
||||
announceFeature: false,
|
||||
announceMobile: false,
|
||||
availableTickets: tickets,
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.LoadDriveInformationResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
// Update User Session
|
||||
app.post('/method/update_user_session', (req, res) => {
|
||||
|
||||
// Response data
|
||||
let msg = {
|
||||
error: wm.wm.protobuf.ErrorCode.ERR_SUCCESS,
|
||||
}
|
||||
|
||||
// Encode the response
|
||||
let message = wm.wm.protobuf.UpdateUserSessionResponse.encode(msg);
|
||||
|
||||
// Send the response to the client
|
||||
common.sendResponse(message, res);
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
// Start Transfer
|
||||
app.post('/method/start_transfer', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Grant Car Right
|
||||
app.post('/method/grant_car_right', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Ask Access Code
|
||||
app.post('/method/ask_access_code', (req, res) => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
// Participate In Invite Friend Campaign
|
||||
app.post('/method/participate_in_invite_friend_campaign', (req, res) => {
|
||||
|
||||
});
|
||||
*/
|
||||
}
|
||||
}
|
44
src/util/common.ts
Normal file
44
src/util/common.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { Response } from "express";
|
||||
import Long from "long";
|
||||
import { Writer } from "protobufjs";
|
||||
|
||||
|
||||
// sendResponse(message, res): Void
|
||||
// Sends the server response to the client
|
||||
export function sendResponse(message: Writer, res: Response)
|
||||
{
|
||||
// Get the end of the message
|
||||
let end = message.finish();
|
||||
|
||||
// Built the response data
|
||||
let r = res
|
||||
.header('Server', 'v388 wangan')
|
||||
.header('Content-Type', 'application/x-protobuf; revision=8053')
|
||||
.header('Content-Length', end.length.toString())
|
||||
.status(200);
|
||||
|
||||
// Send the response to the client
|
||||
r.send(Buffer.from(end));
|
||||
}
|
||||
|
||||
|
||||
// getBigIntFromLong(n: Long): BigInt
|
||||
// Given a Long data object, converts
|
||||
// it into a BigInt and returns it.
|
||||
export function getBigIntFromLong(n: Long)
|
||||
{
|
||||
// Create the default value
|
||||
let bigInt = BigInt(0);
|
||||
|
||||
// If 'n' is a long data type
|
||||
if (n instanceof Long)
|
||||
{
|
||||
// Perform the bit-wise operations
|
||||
bigInt = bigInt | BigInt(n.high);
|
||||
bigInt = bigInt << BigInt(32);
|
||||
bigInt = bigInt | BigInt(n.low);
|
||||
}
|
||||
|
||||
// Return the finished value
|
||||
return Number(bigInt);
|
||||
}
|
57
src/util/games/games_util/check_step.ts
Normal file
57
src/util/games/games_util/check_step.ts
Normal file
@ -0,0 +1,57 @@
|
||||
// Import Proto
|
||||
import { wm } from "../../../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save story result
|
||||
export async function checkCurrentStep(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
// Get current step for updating the user's ghost level
|
||||
let currentStep = 0;
|
||||
currentStep = body.car!.tunePower! + body.car!.tuneHandling!;
|
||||
|
||||
// Set current ghost level based on current step
|
||||
let ghostLevel = 1;
|
||||
if(currentStep >= 0 && currentStep <= 5)
|
||||
{
|
||||
ghostLevel = 1
|
||||
}
|
||||
else if(currentStep >= 6 && currentStep <= 10)
|
||||
{
|
||||
ghostLevel = 2
|
||||
}
|
||||
else if(currentStep >= 11 && currentStep <= 15)
|
||||
{
|
||||
ghostLevel = 3
|
||||
}
|
||||
else if(currentStep >= 16 && currentStep <= 20)
|
||||
{
|
||||
ghostLevel = 4
|
||||
}
|
||||
else if(currentStep >= 21 && currentStep <= 26)
|
||||
{
|
||||
ghostLevel = 5
|
||||
}
|
||||
else if(currentStep >= 27 && currentStep <= 28)
|
||||
{
|
||||
ghostLevel = 6
|
||||
}
|
||||
else if(currentStep >= 29 && currentStep <= 30)
|
||||
{
|
||||
ghostLevel = 7
|
||||
}
|
||||
else if(currentStep === 31)
|
||||
{
|
||||
ghostLevel = 8
|
||||
}
|
||||
else if(currentStep >= 32 && currentStep <= 33)
|
||||
{
|
||||
ghostLevel = 9
|
||||
}
|
||||
else if(currentStep === 34)
|
||||
{
|
||||
ghostLevel = 10
|
||||
}
|
||||
|
||||
// Return the value to 'BASE_PATH/src/util/games/story.ts'
|
||||
return {ghostLevel}
|
||||
}
|
473
src/util/games/games_util/ghost_history.ts
Normal file
473
src/util/games/games_util/ghost_history.ts
Normal file
@ -0,0 +1,473 @@
|
||||
// Import Proto
|
||||
import { prisma } from "../../..";
|
||||
import { Config } from "../../../config";
|
||||
import { wm } from "../../../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save ghost history battle
|
||||
export async function saveGhostHistory(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
console.log('Saving Ghost Battle History');
|
||||
|
||||
let updateNewTrail: boolean = true;
|
||||
let saveExGhostHistory: any = {};
|
||||
|
||||
if (body.car?.carId !== null && body.car?.carId !== undefined) {
|
||||
saveExGhostHistory.carId = body.car?.carId!;
|
||||
}
|
||||
if (body.car?.tunePower !== null && body.car?.tunePower !== undefined) {
|
||||
saveExGhostHistory.tunePower = body.car?.tunePower!;
|
||||
}
|
||||
if (body.car?.tuneHandling !== null && body.car?.tuneHandling !== undefined) {
|
||||
saveExGhostHistory.tuneHandling = body.car?.tuneHandling!;
|
||||
}
|
||||
if (body.playedAt !== null && body.playedAt !== undefined){
|
||||
saveExGhostHistory.playedAt = body.playedAt!;
|
||||
}
|
||||
|
||||
// Get shop name
|
||||
saveExGhostHistory.playedShopName = Config.getConfig().shopName;
|
||||
|
||||
// Get how many opponents available
|
||||
for(let i=0; i<body.rgResult!.opponents!.length; i++)
|
||||
{
|
||||
// First opponent data
|
||||
if(i == 0)
|
||||
{
|
||||
// Get first opponent carId
|
||||
saveExGhostHistory.opponent1CarId = body.rgResult!.opponents![0].carId;
|
||||
|
||||
// Get first opponent tunePower
|
||||
saveExGhostHistory.opponent1TunePower = body.rgResult!.opponents![0].tunePower;
|
||||
|
||||
// Get first opponent tunePower
|
||||
saveExGhostHistory.opponent1TuneHandling = body.rgResult!.opponents![0].tuneHandling;
|
||||
|
||||
// Get the advantage distance between first opponent and user
|
||||
saveExGhostHistory.opponent1Result = body.rgResult!.opponents![0].result;
|
||||
}
|
||||
|
||||
// Second opponent data
|
||||
else if(i == 1)
|
||||
{
|
||||
// Get second opponent carId
|
||||
saveExGhostHistory.opponent2CarId = body.rgResult!.opponents![1].carId;
|
||||
|
||||
// Get second opponent tunePower
|
||||
saveExGhostHistory.opponent2TunePower = body.rgResult!.opponents![1].tunePower;
|
||||
|
||||
// Get second opponent tuneHandling
|
||||
saveExGhostHistory.opponent2TuneHandling = body.rgResult!.opponents![1].tuneHandling;
|
||||
|
||||
// Get the advantage distance between second opponent and user
|
||||
saveExGhostHistory.opponent2Result = body.rgResult!.opponents![1].result;
|
||||
}
|
||||
|
||||
// Third opponent data
|
||||
else if(i == 2)
|
||||
{
|
||||
// Get third opponent carId
|
||||
saveExGhostHistory.opponent3CarId = body.rgResult!.opponents![2].carId;
|
||||
|
||||
// Get third opponent tunePower
|
||||
saveExGhostHistory.opponent3TunePower = body.rgResult!.opponents![2].tunePower;
|
||||
|
||||
// Get third opponent tuneHandling
|
||||
saveExGhostHistory.opponent3TuneHandling = body.rgResult!.opponents![2].tuneHandling;
|
||||
|
||||
// Get the advantage distance between third opponent and user
|
||||
saveExGhostHistory.opponent3Result = body.rgResult!.opponents![2].result;
|
||||
}
|
||||
}
|
||||
|
||||
// Get played Area
|
||||
if(body.rgResult?.path !== null && body.rgResult?.path !== undefined)
|
||||
{
|
||||
if(body.rgResult?.path >= 0 && body.rgResult?.path <= 9){ // GID_PATH_C1
|
||||
saveExGhostHistory.area = Number(0);
|
||||
}
|
||||
else if(body.rgResult?.path >= 10 && body.rgResult?.path <= 15){ // GID_PATH_N9
|
||||
saveExGhostHistory.area = Number(1);
|
||||
}
|
||||
else if(body.rgResult?.path >= 16 && body.rgResult?.path <= 17){ // GID_PATH_WTEAST
|
||||
saveExGhostHistory.area = Number(2);
|
||||
}
|
||||
else if(body.rgResult?.path >= 18 && body.rgResult?.path <= 19){ // GID_PATH_WT_UP_DOWN
|
||||
saveExGhostHistory.area = Number(3);
|
||||
}
|
||||
else if(body.rgResult?.path >= 20 && body.rgResult?.path <= 26){ // GID_PATH_WG
|
||||
saveExGhostHistory.area = Number(4);
|
||||
}
|
||||
else if(body.rgResult?.path >= 27 && body.rgResult?.path <= 33){ // GID_PATH_KG
|
||||
saveExGhostHistory.area = Number(5);
|
||||
}
|
||||
else if(body.rgResult?.path >= 34 && body.rgResult?.path <= 37){ // GID_PATH_YS
|
||||
saveExGhostHistory.area = Number(6);
|
||||
}
|
||||
else if(body.rgResult?.path >= 38 && body.rgResult?.path <= 48){ // GID_PATH_KG_SHINYAMASHITA_MINATOMIRAI
|
||||
saveExGhostHistory.area = Number(7);
|
||||
}
|
||||
else if(body.rgResult?.path === 49){ // GID_PATH_NGR
|
||||
saveExGhostHistory.area = Number(8);
|
||||
}
|
||||
else if(body.rgResult?.path >= 50 && body.rgResult?.path <= 53){ // GID_PATH_OS
|
||||
saveExGhostHistory.area = Number(9);
|
||||
}
|
||||
else if(body.rgResult?.path >= 54 && body.rgResult?.path <= 55){ // GID_PATH_KB
|
||||
saveExGhostHistory.area = Number(10);
|
||||
}
|
||||
else if(body.rgResult?.path >= 58 && body.rgResult?.path <= 61){ // GID_PATH_FK
|
||||
saveExGhostHistory.area = Number(11);
|
||||
}
|
||||
else if(body.rgResult?.path >= 62 && body.rgResult?.path <= 63){ // GID_PATH_HK
|
||||
saveExGhostHistory.area = Number(12);
|
||||
}
|
||||
else if(body.rgResult?.path >= 64 && body.rgResult?.path <= 65){ // GID_PATH_TP
|
||||
saveExGhostHistory.area = Number(13);
|
||||
}
|
||||
else if(body.rgResult?.path >= 56 && body.rgResult?.path <= 57){ // GID_PATH_HS
|
||||
saveExGhostHistory.area = Number(18);
|
||||
}
|
||||
}
|
||||
|
||||
await prisma.ghostBattleRecord.create({
|
||||
data: saveExGhostHistory
|
||||
});
|
||||
|
||||
// Return the value to 'BASE_PATH/src/util/games/ghost.ts'
|
||||
return { updateNewTrail }
|
||||
}
|
||||
|
||||
|
||||
export async function saveOCMGhostHistory(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
let updateNewTrail: boolean = true;
|
||||
let saveExGhostHistory: any = {};
|
||||
|
||||
if (body.car?.carId !== null && body.car?.carId !== undefined) {
|
||||
saveExGhostHistory.carId = body.car?.carId!;
|
||||
}
|
||||
if (body.car?.tunePower !== null && body.car?.tunePower !== undefined) {
|
||||
saveExGhostHistory.tunePower = body.car?.tunePower!;
|
||||
}
|
||||
if (body.car?.tuneHandling !== null && body.car?.tuneHandling !== undefined) {
|
||||
saveExGhostHistory.tuneHandling = body.car?.tuneHandling!;
|
||||
}
|
||||
if (body.playedAt !== null && body.playedAt !== undefined){
|
||||
saveExGhostHistory.playedAt = body.playedAt!;
|
||||
}
|
||||
|
||||
// Get shop name
|
||||
saveExGhostHistory.playedShopName = Config.getConfig().shopName;
|
||||
|
||||
// Get the advantage distance between first opponent and user
|
||||
saveExGhostHistory.result = body.rgResult!.opponents![0].result;
|
||||
|
||||
// Get played Area
|
||||
if(body.rgResult?.path !== null && body.rgResult?.path !== undefined)
|
||||
{
|
||||
if(body.rgResult?.path >= 0 && body.rgResult?.path <= 9){ // GID_PATH_C1
|
||||
saveExGhostHistory.area = Number(0);
|
||||
}
|
||||
else if(body.rgResult?.path >= 10 && body.rgResult?.path <= 15){ // GID_PATH_N9
|
||||
saveExGhostHistory.area = Number(1);
|
||||
}
|
||||
else if(body.rgResult?.path >= 16 && body.rgResult?.path <= 17){ // GID_PATH_WTEAST
|
||||
saveExGhostHistory.area = Number(2);
|
||||
}
|
||||
else if(body.rgResult?.path >= 18 && body.rgResult?.path <= 19){ // GID_PATH_WT_UP_DOWN
|
||||
saveExGhostHistory.area = Number(3);
|
||||
}
|
||||
else if(body.rgResult?.path >= 20 && body.rgResult?.path <= 26){ // GID_PATH_WG
|
||||
saveExGhostHistory.area = Number(4);
|
||||
}
|
||||
else if(body.rgResult?.path >= 27 && body.rgResult?.path <= 33){ // GID_PATH_KG
|
||||
saveExGhostHistory.area = Number(5);
|
||||
}
|
||||
else if(body.rgResult?.path >= 34 && body.rgResult?.path <= 37){ // GID_PATH_YS
|
||||
saveExGhostHistory.area = Number(6);
|
||||
}
|
||||
else if(body.rgResult?.path >= 38 && body.rgResult?.path <= 48){ // GID_PATH_KG_SHINYAMASHITA_MINATOMIRAI
|
||||
saveExGhostHistory.area = Number(7);
|
||||
}
|
||||
else if(body.rgResult?.path === 49){ // GID_PATH_NGR
|
||||
saveExGhostHistory.area = Number(8);
|
||||
}
|
||||
else if(body.rgResult?.path >= 50 && body.rgResult?.path <= 53){ // GID_PATH_OS
|
||||
saveExGhostHistory.area = Number(9);
|
||||
}
|
||||
else if(body.rgResult?.path >= 54 && body.rgResult?.path <= 55){ // GID_PATH_KB
|
||||
saveExGhostHistory.area = Number(10);
|
||||
}
|
||||
else if(body.rgResult?.path >= 58 && body.rgResult?.path <= 61){ // GID_PATH_FK
|
||||
saveExGhostHistory.area = Number(11);
|
||||
}
|
||||
else if(body.rgResult?.path >= 62 && body.rgResult?.path <= 63){ // GID_PATH_HK
|
||||
saveExGhostHistory.area = Number(12);
|
||||
}
|
||||
else if(body.rgResult?.path >= 64 && body.rgResult?.path <= 65){ // GID_PATH_TP
|
||||
saveExGhostHistory.area = Number(13);
|
||||
}
|
||||
else if(body.rgResult?.path >= 56 && body.rgResult?.path <= 57){ // GID_PATH_HS
|
||||
saveExGhostHistory.area = Number(18);
|
||||
}
|
||||
}
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get currently active OCM event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// ----------Get available OCM Record (Qualifying or Main Draw)----------
|
||||
// Current date is OCM main draw
|
||||
let countGBR;
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
// Set OCM Main draw value to true
|
||||
saveExGhostHistory.ocmMainDraw = true
|
||||
|
||||
// Get the user's available OCM Battle Record data
|
||||
countGBR = await prisma.oCMTally.findFirst({
|
||||
where:{
|
||||
carId: saveExGhostHistory.carId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
}
|
||||
});
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else
|
||||
{
|
||||
// Set OCM Main draw value to false
|
||||
saveExGhostHistory.ocmMainDraw = false
|
||||
|
||||
// Get the user's available OCM Battle Record data
|
||||
countGBR = await prisma.oCMGhostBattleRecord.findFirst({
|
||||
where:{
|
||||
carId: saveExGhostHistory.carId,
|
||||
ocmMainDraw: saveExGhostHistory.ocmMainDraw,
|
||||
area: saveExGhostHistory.area,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// User have OCM Battle Record data available
|
||||
if(countGBR)
|
||||
{
|
||||
// Check if the newest advantage distance is bigger than the older advantage distance
|
||||
if(countGBR!.result < saveExGhostHistory.result)
|
||||
{
|
||||
console.log('OCM Ghost Tally found');
|
||||
// Current date is OCM Main Draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
// Get OCM Period ID
|
||||
let OCM_periodId = await prisma.oCMPeriod.findFirst({
|
||||
where:{
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
startAt:
|
||||
{
|
||||
lte: date, // competitionStartAt is less than current date
|
||||
},
|
||||
closeAt:
|
||||
{
|
||||
gte: date, // competitionCloseAt is greater than current date
|
||||
}
|
||||
},
|
||||
select:{
|
||||
periodId: true
|
||||
}
|
||||
});
|
||||
|
||||
let checkGhost = await prisma.oCMGhostBattleRecord.findFirst({
|
||||
where:{
|
||||
carId: saveExGhostHistory.carId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
}
|
||||
});
|
||||
|
||||
if(checkGhost)
|
||||
{
|
||||
console.log('Updating OCM Ghost Battle Record entry');
|
||||
|
||||
// Get the user's available OCM Battle Record data
|
||||
let getGBR = await prisma.oCMGhostBattleRecord.findFirst({
|
||||
where:{
|
||||
carId: saveExGhostHistory.carId,
|
||||
area: saveExGhostHistory.area,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
}
|
||||
});
|
||||
|
||||
// Update ghost battle record
|
||||
await prisma.oCMGhostBattleRecord.update({
|
||||
where:{
|
||||
dbId: getGBR!.dbId
|
||||
},
|
||||
data: {
|
||||
...saveExGhostHistory,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: OCM_periodId!.periodId
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log('Creating new OCM Ghost Battle Record entry');
|
||||
|
||||
// Create new ghost battle record
|
||||
await prisma.oCMGhostBattleRecord.create({
|
||||
data: {
|
||||
...saveExGhostHistory,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: OCM_periodId!.periodId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Updating OCM Tally Record');
|
||||
|
||||
// Update the OCM Tally Record
|
||||
await prisma.oCMTally.update({
|
||||
where:{
|
||||
dbId: countGBR.dbId
|
||||
},
|
||||
data: {
|
||||
periodId: OCM_periodId!.periodId,
|
||||
result: body.rgResult!.opponents![0].result,
|
||||
tunePower: body.car?.tunePower!,
|
||||
tuneHandling: body.car?.tuneHandling!
|
||||
}
|
||||
});
|
||||
}
|
||||
// Current date is OCM Qualifying
|
||||
else
|
||||
{
|
||||
// Update ghost battle record
|
||||
await prisma.oCMGhostBattleRecord.update({
|
||||
where:{
|
||||
dbId: countGBR.dbId
|
||||
},
|
||||
data: {
|
||||
...saveExGhostHistory,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Newest advantage distance is smaller than the older advantage distance
|
||||
else
|
||||
{
|
||||
console.log('Result record is lower than previous record');
|
||||
|
||||
// Don't update the User's OCM ghost trail
|
||||
updateNewTrail = false;
|
||||
}
|
||||
}
|
||||
// User don't have OCM Battle Record data available
|
||||
else
|
||||
{
|
||||
console.log('OCM Ghost Battle Record not found');
|
||||
console.log('Creating new OOCM Ghost Battle Record entry');
|
||||
|
||||
// Current date is OCM Main Draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
// Get OCM Period ID
|
||||
let OCM_periodId = await prisma.oCMPeriod.findFirst({
|
||||
where:{
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId
|
||||
},
|
||||
orderBy:{
|
||||
periodId: 'desc'
|
||||
},
|
||||
select:{
|
||||
periodId: true
|
||||
}
|
||||
});
|
||||
|
||||
// Update ghost battle record
|
||||
await prisma.oCMGhostBattleRecord.create({
|
||||
data: {
|
||||
...saveExGhostHistory,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: OCM_periodId!.periodId
|
||||
}
|
||||
});
|
||||
|
||||
let ocmTallyfind = await prisma.oCMTally.findFirst({
|
||||
where:{
|
||||
carId: saveExGhostHistory.carId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
},
|
||||
});
|
||||
|
||||
if(ocmTallyfind)
|
||||
{
|
||||
console.log('Updating OCM Tally Record');
|
||||
// Update the OCM Tally Record
|
||||
await prisma.oCMTally.update({
|
||||
where:{
|
||||
dbId: ocmTallyfind.dbId
|
||||
},
|
||||
data: {
|
||||
periodId: OCM_periodId!.periodId,
|
||||
result: body.rgResult!.opponents![0].result,
|
||||
tunePower: body.car?.tunePower!,
|
||||
tuneHandling: body.car?.tuneHandling!
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Current date is OCM Qualifying
|
||||
else
|
||||
{
|
||||
// Update ghost battle record
|
||||
await prisma.oCMGhostBattleRecord.create({
|
||||
data: {
|
||||
...saveExGhostHistory,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 0
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Return the value to 'BASE_PATH/src/util/games/ghost.ts'
|
||||
return { updateNewTrail }
|
||||
}
|
120
src/util/games/games_util/ghost_ocm_area.ts
Normal file
120
src/util/games/games_util/ghost_ocm_area.ts
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
// Save ghost battle result
|
||||
export async function OCMArea(competition_id: number)
|
||||
{
|
||||
let areaVal = 0;
|
||||
let rampVal = 0;
|
||||
let pathVal = 0;
|
||||
|
||||
// 16th - C1
|
||||
if(competition_id === 1)
|
||||
{
|
||||
// GID_RUNAREA_C1
|
||||
areaVal = 0;
|
||||
|
||||
// GID_RAMP_C1_OUT_KANDABASHI
|
||||
rampVal = 2;
|
||||
|
||||
// GID_PATH_C1OUT_KANDABASHI03
|
||||
pathVal = 6;
|
||||
}
|
||||
// 17th - Osaka
|
||||
else if(competition_id === 2)
|
||||
{
|
||||
// GID_RUNAREA_OSAKA
|
||||
areaVal = 9;
|
||||
|
||||
// GID_RAMP_OOSAKA_DOUTONBORI
|
||||
rampVal = 26;
|
||||
|
||||
// GID_PATH_OS_TONBORI04
|
||||
pathVal = 53;
|
||||
}
|
||||
// 18th - Fukuoka
|
||||
else if(competition_id === 3)
|
||||
{
|
||||
// GID_RUNAREA_FUKUOKA
|
||||
areaVal = 11;
|
||||
|
||||
// GID_RAMP_FUKUOKA_EAST_NISHI
|
||||
rampVal = 31
|
||||
|
||||
// GID_PATH_FK_NISHIKOUEN;
|
||||
pathVal = 60;
|
||||
}
|
||||
// 19th - Nagoya
|
||||
else if(competition_id === 4)
|
||||
{
|
||||
// GID_RUNAREA_NAGOYA
|
||||
areaVal = 8;
|
||||
|
||||
// GID_RAMP_NAGOYA_MARUNOUCHI
|
||||
rampVal = 25;
|
||||
|
||||
// GID_PATH_NGR_MARUNOUCHI
|
||||
pathVal = 49;
|
||||
}
|
||||
// 6th - C1
|
||||
else if(competition_id === 5)
|
||||
{
|
||||
// GID_RUNAREA_C1
|
||||
areaVal = 0;
|
||||
|
||||
// GID_RAMP_C1_IN_KANDABASHI
|
||||
rampVal = 0;
|
||||
|
||||
// GID_PATH_C1IN_KANDABASHI02
|
||||
pathVal = 1;
|
||||
}
|
||||
// 20th - Kobe
|
||||
else if(competition_id === 6)
|
||||
{
|
||||
// GID_RUNAREA_KOBE
|
||||
areaVal = 10;
|
||||
|
||||
// GID_RAMP_KOBE_NADAOOHASHI
|
||||
rampVal = 28;
|
||||
|
||||
// GID_PATH_KB_NADA
|
||||
pathVal = 55;
|
||||
}
|
||||
// 7th - Fukutoshin
|
||||
else if(competition_id === 7)
|
||||
{
|
||||
// GID_RUNAREA_SUBTOKYO_3_4
|
||||
areaVal = 2;
|
||||
|
||||
// GID_RAMP_SUBTOKYO_GAIEN
|
||||
rampVal = 7;
|
||||
|
||||
// GID_PATH_WTWEST_GAIEN
|
||||
pathVal = 17;
|
||||
}
|
||||
// 21st - Hiroshima
|
||||
else if(competition_id === 8)
|
||||
{
|
||||
// GID_RUNAREA_HIROSHIMA
|
||||
areaVal = 18;
|
||||
|
||||
// GID_RAMP_HIROSHIMA_SHINONOME
|
||||
rampVal = 37;
|
||||
|
||||
// GID_PATH_HS_SHINONOME
|
||||
pathVal = 56;
|
||||
}
|
||||
// 8th - Hakone
|
||||
else if(competition_id === 9)
|
||||
{
|
||||
// GID_RUNAREA_HAKONE
|
||||
areaVal = 12;
|
||||
|
||||
// GID_RAMP_HAKONE_FOR
|
||||
rampVal = 33;
|
||||
|
||||
// GID_PATH_HKFOR
|
||||
pathVal = 62;
|
||||
}
|
||||
|
||||
// Return the value to 'BASE_PATH/src/modules/ghost_ocm.ts'
|
||||
return {areaVal, rampVal, pathVal};
|
||||
}
|
345
src/util/games/ghost.ts
Normal file
345
src/util/games/ghost.ts
Normal file
@ -0,0 +1,345 @@
|
||||
import { prisma } from "../..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../../wmmt/wm.proto";
|
||||
import wmproto from "../../wmmt/wm.proto";
|
||||
import * as ghost_history from "../games/games_util/ghost_history";
|
||||
|
||||
|
||||
// Save ghost battle result
|
||||
export async function saveGhostBattleResult(body: wm.protobuf.SaveGameResultRequest, car: any)
|
||||
{
|
||||
// Declare variable for return
|
||||
let ghostModePlay: boolean = false;
|
||||
let updateNewTrail: boolean = false;
|
||||
let OCMModePlay: boolean = false;
|
||||
|
||||
// If the game was not retired / timed out
|
||||
if (!(body.retired || body.timeup))
|
||||
{
|
||||
console.log('Saving Ghost Battle Result');
|
||||
|
||||
// Set ghost mode play to true for saving the ghost trail later
|
||||
ghostModePlay = true;
|
||||
|
||||
// Set update new trail to true for updating the user's ghost trail after playing OCM ghost battle mode later
|
||||
updateNewTrail = true;
|
||||
|
||||
// Get the ghost result for the car
|
||||
let ghostResult = body?.rgResult;
|
||||
|
||||
// Declare data
|
||||
let dataGhost : any;
|
||||
let dataCar : any;
|
||||
|
||||
// ghostResult is set
|
||||
if (ghostResult)
|
||||
{
|
||||
// Ghost update data
|
||||
dataGhost = {
|
||||
rgRegionMapScore: ghostResult.rgRegionMapScore || undefined,
|
||||
rgPlayCount: ghostResult.rgPlayCount || undefined,
|
||||
dressupLevel: ghostResult.dressupLevel || undefined,
|
||||
dressupPoint: ghostResult.dressupPoint || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
// Get the ghost result for the car
|
||||
let cars = body?.car;
|
||||
|
||||
// Car is set
|
||||
if (cars)
|
||||
{
|
||||
// Error handling to prevent set ghost level to out of range value
|
||||
if(cars.ghostLevel)
|
||||
{
|
||||
if(cars.ghostLevel < 1)
|
||||
{
|
||||
cars.ghostLevel = 1;
|
||||
}
|
||||
else if(cars.ghostLevel > 11)
|
||||
{
|
||||
cars.ghostLevel = 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Car update data
|
||||
dataCar = {
|
||||
wheel: cars.wheel || undefined,
|
||||
wheelColor: cars.wheelColor || undefined,
|
||||
aero: cars.aero || undefined,
|
||||
bonnet: cars.bonnet || undefined,
|
||||
wing: cars.wing || undefined,
|
||||
mirror: cars.mirror || undefined,
|
||||
neon: cars.neon || undefined,
|
||||
trunk: cars.trunk || undefined,
|
||||
plate: cars.plate || undefined,
|
||||
plateColor: cars.plateColor || undefined,
|
||||
plateNumber: cars.plateNumber || undefined,
|
||||
ghostLevel: cars.ghostLevel || undefined,
|
||||
}
|
||||
}
|
||||
|
||||
// Count total win based on region map score
|
||||
if(body.rgResult?.rgRegionMapScore && body.rgResult?.rgRegionMapScore.length !== 0)
|
||||
{
|
||||
let winCounter = 0;
|
||||
|
||||
// Count the total win
|
||||
for(let i=0; i<body.rgResult.rgRegionMapScore.length; i++)
|
||||
{
|
||||
winCounter += body.rgResult.rgRegionMapScore[i];
|
||||
}
|
||||
|
||||
// Set the data
|
||||
dataGhost.rgWinCount = winCounter;
|
||||
dataGhost.rgScore = winCounter;
|
||||
dataGhost.rgTrophy = winCounter;
|
||||
}
|
||||
|
||||
// Update the car properties
|
||||
await prisma.car.update({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
data: {
|
||||
...dataGhost,
|
||||
...dataCar
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// --------------GHOST BATTLE SELECTION MODE--------------
|
||||
// Calling save ghost history battle function (BASE_PATH/src/util/games/games_util/ghost_history.ts)
|
||||
let ghost_historys: any;
|
||||
|
||||
switch (body.rgResult!.selectionMethod)
|
||||
{
|
||||
case wmproto.wm.protobuf.GhostSelectionMethod.GHOST_SELECT_BY_LEVEL:
|
||||
{
|
||||
console.log('Normal Ghost Mode Found');
|
||||
|
||||
ghost_historys = await ghost_history.saveGhostHistory(body);
|
||||
|
||||
// Update the updateNewTrail value
|
||||
updateNewTrail = ghost_historys.updateNewTrail;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Crown Ghost Battle Mode
|
||||
case wmproto.wm.protobuf.GhostSelectionMethod.GHOST_SELECT_CROWN_MATCH:
|
||||
{
|
||||
// If not losing to the crown ghost battle
|
||||
if (body.rgResult?.acquireCrown !== false && body.rgResult?.acquireCrown)
|
||||
{
|
||||
console.log('Crown Ghost Mode Found');
|
||||
|
||||
// Get the ghost crown result
|
||||
let ghostResultCrown = body?.rgResult;
|
||||
|
||||
// Declare data
|
||||
let dataCrown : any;
|
||||
|
||||
// ghostResultCrown is set
|
||||
if (ghostResultCrown)
|
||||
{
|
||||
let carId: number = 0;
|
||||
if(body.carId)
|
||||
{
|
||||
carId = Number(body.carId);
|
||||
}
|
||||
|
||||
// Ghost Crown update data
|
||||
dataCrown = {
|
||||
carId: carId,
|
||||
playedAt: body.playedAt || undefined,
|
||||
tunePower: body.car?.tunePower || undefined,
|
||||
tuneHandling: body.car?.tuneHandling || undefined,
|
||||
}
|
||||
|
||||
// Get the area id and ramp id
|
||||
let area = 0;
|
||||
let ramp = 0;
|
||||
let path = 0;
|
||||
if(body.rgResult?.path)
|
||||
{
|
||||
if(body.rgResult?.path >= 0 && body.rgResult?.path <= 9){ // GID_PATH_C1
|
||||
area = Number(0);
|
||||
ramp = Number(Math.floor(Math.random() * 4));
|
||||
}
|
||||
else if(body.rgResult?.path >= 10 && body.rgResult?.path <= 15){ // GID_PATH_N9
|
||||
area = Number(1);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 4);
|
||||
}
|
||||
else if(body.rgResult?.path >= 16 && body.rgResult?.path <= 17){ // GID_PATH_WTEAST
|
||||
area = Number(2);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 6);
|
||||
}
|
||||
else if(body.rgResult?.path >= 18 && body.rgResult?.path <= 19){ // GID_PATH_WT_UP_DOWN
|
||||
area = Number(3);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 8);
|
||||
}
|
||||
else if(body.rgResult?.path >= 20 && body.rgResult?.path <= 26){ // GID_PATH_WG
|
||||
area = Number(4);
|
||||
ramp = Number(Math.floor(Math.random() * 4) + 10);
|
||||
}
|
||||
else if(body.rgResult?.path >= 27 && body.rgResult?.path <= 33){ // GID_PATH_KG
|
||||
area = Number(5);
|
||||
ramp = Number(Math.floor(Math.random() * 4) + 14);
|
||||
}
|
||||
else if(body.rgResult?.path >= 34 && body.rgResult?.path <= 37){ // GID_PATH_YS
|
||||
area = Number(6);
|
||||
ramp = Number(Math.floor(Math.random() * 3) + 18);
|
||||
}
|
||||
else if(body.rgResult?.path >= 38 && body.rgResult?.path <= 48){ // GID_PATH_KG_SHINYAMASHITA_MINATOMIRAI
|
||||
area = Number(7);
|
||||
ramp = Number(Math.floor(Math.random() * 4) + 21);
|
||||
}
|
||||
else if(body.rgResult?.path === 49){ // GID_PATH_NGR
|
||||
area = Number(8);
|
||||
ramp = Number(25);
|
||||
}
|
||||
else if(body.rgResult?.path >= 50 && body.rgResult?.path <= 53){ // GID_PATH_OS
|
||||
area = Number(9);
|
||||
ramp = Number(26);
|
||||
}
|
||||
else if(body.rgResult?.path >= 54 && body.rgResult?.path <= 55){ // GID_PATH_KB
|
||||
area = Number(10);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 27);
|
||||
}
|
||||
else if(body.rgResult?.path >= 58 && body.rgResult?.path <= 61){ // GID_PATH_FK
|
||||
area = Number(11);
|
||||
ramp = Number(Math.floor(Math.random() * 4) + 29);
|
||||
}
|
||||
else if(body.rgResult?.path >= 62 && body.rgResult?.path <= 63){ // GID_PATH_HK
|
||||
area = Number(12);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 33);
|
||||
}
|
||||
else if(body.rgResult?.path >= 64 && body.rgResult?.path <= 65){ // GID_PATH_TP
|
||||
area = Number(13);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 35);
|
||||
}
|
||||
else if(body.rgResult?.path >= 56 && body.rgResult?.path <= 57){ // GID_PATH_HS
|
||||
area = Number(18);
|
||||
ramp = Number(Math.floor(Math.random() * 2) + 27);
|
||||
}
|
||||
|
||||
path = Number(body.rgResult.path);
|
||||
}
|
||||
|
||||
// Get the available crown holder data
|
||||
let carCrowns = await prisma.carCrown.count({
|
||||
where: {
|
||||
area: area
|
||||
}
|
||||
});
|
||||
|
||||
// Crown holder data available
|
||||
if(carCrowns !== 0)
|
||||
{
|
||||
// Update it to the new one
|
||||
let areaVal = Number(area);
|
||||
await prisma.carCrown.update({
|
||||
where: {
|
||||
area: areaVal
|
||||
},
|
||||
data: {
|
||||
...dataCrown,
|
||||
area: area,
|
||||
ramp: ramp,
|
||||
path: path
|
||||
}
|
||||
});
|
||||
}
|
||||
// Crown holder data not available or still default crown holder data
|
||||
else
|
||||
{
|
||||
await prisma.carCrown.create({
|
||||
data: {
|
||||
...dataCrown,
|
||||
area: area,
|
||||
ramp: ramp,
|
||||
path: path
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ghost_historys = await ghost_history.saveGhostHistory(body);
|
||||
|
||||
// Update the updateNewTrail value
|
||||
updateNewTrail = ghost_historys.updateNewTrail;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// OCM Ghost Battle Mode
|
||||
case wmproto.wm.protobuf.GhostSelectionMethod.GHOST_COMPETITION:
|
||||
{
|
||||
console.log('OCM Ghost Mode Found');
|
||||
OCMModePlay = true;
|
||||
let saveExOCM: any = {};
|
||||
saveExOCM.carId = body.carId;
|
||||
if(body.rgResult?.competitionId){
|
||||
saveExOCM.competitionId = body.rgResult?.competitionId!;
|
||||
}
|
||||
if(body.rgResult?.periodId){
|
||||
saveExOCM.periodId = body.rgResult?.periodId!;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveExOCM.periodId = 0;
|
||||
}
|
||||
if(body.rgResult?.brakingPoint){
|
||||
saveExOCM.brakingPoint = body.rgResult?.brakingPoint!;
|
||||
}
|
||||
if(body?.playedAt){
|
||||
saveExOCM.playedAt = body?.playedAt!;
|
||||
}
|
||||
|
||||
// Get the user's available OCM Battle data
|
||||
let countOCM = await prisma.oCMPlayRecord.count({
|
||||
where: {
|
||||
competitionId: saveExOCM.competitionId,
|
||||
carId: body.carId
|
||||
}
|
||||
});
|
||||
|
||||
// User's OCM Battle data available
|
||||
if(countOCM !== 0){
|
||||
console.log('OCM Play Record found');
|
||||
console.log('Updaing OCM Play Record entry');
|
||||
|
||||
await prisma.oCMPlayRecord.updateMany({
|
||||
where:{
|
||||
carId: saveExOCM.carId,
|
||||
competitionId: saveExOCM.competitionId,
|
||||
},
|
||||
data: saveExOCM
|
||||
});
|
||||
}
|
||||
// First time User playing OCM Battle
|
||||
else{
|
||||
console.log('OCM Play Record not found');
|
||||
console.log('Creating new OCM Play Record entry');
|
||||
|
||||
await prisma.oCMPlayRecord.create({
|
||||
data: saveExOCM
|
||||
});
|
||||
}
|
||||
|
||||
ghost_historys = await ghost_history.saveOCMGhostHistory(body);
|
||||
|
||||
// Update the updateNewTrail value
|
||||
updateNewTrail = ghost_historys.updateNewTrail;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the value to 'BASE_PATH/src/modules/game.ts'
|
||||
return { ghostModePlay, updateNewTrail, OCMModePlay }
|
||||
}
|
1130
src/util/games/ghost_ocm.ts
Normal file
1130
src/util/games/ghost_ocm.ts
Normal file
File diff suppressed because it is too large
Load Diff
430
src/util/games/ghost_save_trail.ts
Normal file
430
src/util/games/ghost_save_trail.ts
Normal file
@ -0,0 +1,430 @@
|
||||
import { prisma } from "../..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save OCM ghost battle result
|
||||
export async function saveOCMGhostTrail(body: wm.protobuf.RegisterGhostTrailRequest)
|
||||
{
|
||||
console.log('Checking OCM Ghost Battle trail history');
|
||||
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get current active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy:{
|
||||
dbId: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
if(ocmEventDate)
|
||||
{
|
||||
// Get OCM Period ID
|
||||
let OCM_periodId = await prisma.oCMPeriod.findFirst({
|
||||
where:{
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
startAt:
|
||||
{
|
||||
lte: date, // competitionStartAt is less than current date
|
||||
},
|
||||
closeAt:
|
||||
{
|
||||
gte: date, // competitionCloseAt is greater than current date
|
||||
}
|
||||
},
|
||||
select:{
|
||||
periodId: true
|
||||
}
|
||||
});
|
||||
let ocmMainDraws: boolean = false;
|
||||
let periodId = 0;
|
||||
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
periodId = OCM_periodId!.periodId;
|
||||
ocmMainDraws = true;
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
ocmMainDraws = false;
|
||||
}
|
||||
|
||||
// Get the ghost result for the car
|
||||
let ghostResult = body?.ghost;
|
||||
|
||||
// Declare data
|
||||
let data : any;
|
||||
|
||||
// ghostResult is set
|
||||
if (ghostResult)
|
||||
{
|
||||
// Ghost update data
|
||||
let grArea: number = 0;
|
||||
let grRamp: number = 0;
|
||||
let grPath: number = 0;
|
||||
if(ghostResult.area)
|
||||
{
|
||||
grArea = ghostResult.area;
|
||||
}
|
||||
if(ghostResult.ramp)
|
||||
{
|
||||
grRamp = ghostResult.ramp;
|
||||
}
|
||||
if(ghostResult.path)
|
||||
{
|
||||
grPath = ghostResult.path;
|
||||
}
|
||||
|
||||
data = {
|
||||
carId: Number(ghostResult.car.carId),
|
||||
area: grArea,
|
||||
ramp: grRamp,
|
||||
path: grPath,
|
||||
trail: body.trail || undefined,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
playedAt: ghostResult.car.lastPlayedAt || undefined,
|
||||
tunePower: ghostResult.car.tunePower || undefined,
|
||||
tuneHandling: ghostResult.car.tuneHandling || undefined,
|
||||
ocmMainDraw: ocmMainDraws
|
||||
}
|
||||
|
||||
// Check OCM Ghost Battle Record if playing OCM Ghost Battle Mode
|
||||
let gtCount = await prisma.oCMGhostTrail.findFirst({
|
||||
where:{
|
||||
carId: ghostResult.car.carId!,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
area: ghostResult.area!,
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Record exist, update it
|
||||
if(gtCount)
|
||||
{
|
||||
console.log('OCM Ghost Trail history found');
|
||||
console.log('Updating OCM ghost trail to the newest trail');
|
||||
|
||||
// Update the data
|
||||
await prisma.oCMGhostTrail.update({
|
||||
where: {
|
||||
dbId: gtCount.dbId
|
||||
},
|
||||
data: {
|
||||
...data,
|
||||
periodId: periodId
|
||||
}
|
||||
});
|
||||
}
|
||||
// Record does not exist, create new
|
||||
else
|
||||
{
|
||||
console.log('No OCM ghost trail history');
|
||||
console.log('Creating new OCM ghost trail entry');
|
||||
|
||||
// Create new data
|
||||
await prisma.oCMGhostTrail.create({
|
||||
data: {
|
||||
...data,
|
||||
periodId: periodId
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save Crown ghost battle result
|
||||
export async function saveCrownGhostTrail(body: wm.protobuf.RegisterGhostTrailRequest)
|
||||
{
|
||||
console.log('Checking Crown Ghost Battle trail history');
|
||||
|
||||
// Get the ghost result for the car
|
||||
let ghostResult = body?.ghost;
|
||||
|
||||
// Declare data
|
||||
let data : any;
|
||||
|
||||
// ghostResult is set
|
||||
if (ghostResult)
|
||||
{
|
||||
// Ghost update data
|
||||
let grArea: number = 0;
|
||||
let grRamp: number = 0;
|
||||
let grPath: number = 0;
|
||||
if(ghostResult.area)
|
||||
{
|
||||
grArea = ghostResult.area;
|
||||
}
|
||||
if(ghostResult.ramp)
|
||||
{
|
||||
grRamp = ghostResult.ramp;
|
||||
}
|
||||
if(ghostResult.path)
|
||||
{
|
||||
grPath = ghostResult.path;
|
||||
}
|
||||
|
||||
data = {
|
||||
carId: Number(ghostResult.car.carId),
|
||||
area: grArea,
|
||||
ramp: grRamp,
|
||||
path: grPath,
|
||||
trail: body.trail || undefined,
|
||||
time: body.time || undefined,
|
||||
driveData: body.driveData?.data || undefined,
|
||||
driveDMergeSerial: body.driveData?.mergeSerial || undefined,
|
||||
trendBinaryByArea: body.trendBinaryByArea?.data || undefined,
|
||||
byAreaMergeSerial: body.trendBinaryByArea?.mergeSerial || undefined,
|
||||
trendBinaryByCar: body.trendBinaryByCar?.data || undefined,
|
||||
byCarMergeSerial: body.trendBinaryByCar?.mergeSerial || undefined,
|
||||
trendBinaryByUser: body.trendBinaryByUser?.data || undefined,
|
||||
byUserMergeSerial: body.trendBinaryByUser?.mergeSerial || undefined,
|
||||
playedAt: ghostResult.car.lastPlayedAt || undefined,
|
||||
tunePower: ghostResult.car.tunePower || undefined,
|
||||
tuneHandling: ghostResult.car.tuneHandling || undefined,
|
||||
crownBattle: true,
|
||||
}
|
||||
|
||||
// Check Crown Ghost Battle Record if playing Crown Ghost Battle Mode
|
||||
let gtCount = await prisma.ghostTrail.findFirst({
|
||||
where:{
|
||||
area: ghostResult.area!,
|
||||
crownBattle: true,
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Record exist, update it
|
||||
if(gtCount)
|
||||
{
|
||||
console.log('Crown Trail history found');
|
||||
console.log('Updating crown trail to the newest trail');
|
||||
|
||||
// Update the data
|
||||
await prisma.ghostTrail.update({
|
||||
where: {
|
||||
dbId: gtCount.dbId
|
||||
},
|
||||
data: data
|
||||
});
|
||||
}
|
||||
// Record does not exist, create new
|
||||
else
|
||||
{
|
||||
console.log('No crown trail history');
|
||||
console.log('Creating new crown trail entry');
|
||||
|
||||
// Create new data
|
||||
await prisma.ghostTrail.create({
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// Update crown randomized ramp and path to the correct value
|
||||
console.log('Updating crown\'s area records to the correct value')
|
||||
await prisma.carCrown.update({
|
||||
where: {
|
||||
area: ghostResult.area!
|
||||
},
|
||||
data: {
|
||||
area: ghostResult.area!,
|
||||
ramp: ghostResult.ramp!,
|
||||
path: ghostResult.path!,
|
||||
playedAt: ghostResult.car.lastPlayedAt!
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Save Crown ghost battle result
|
||||
export async function saveNormalGhostTrail(body: wm.protobuf.RegisterGhostTrailRequest)
|
||||
{
|
||||
console.log('Checking Normal Ghost Battle trail history');
|
||||
|
||||
// Get the ghost result for the car
|
||||
let ghostResult = body?.ghost;
|
||||
|
||||
// Declare data
|
||||
let data : any;
|
||||
|
||||
// ghostResult is set
|
||||
if (ghostResult)
|
||||
{
|
||||
// Ghost update data
|
||||
let grArea: number = 0;
|
||||
let grRamp: number = 0;
|
||||
let grPath: number = 0;
|
||||
if(ghostResult.area)
|
||||
{
|
||||
grArea = ghostResult.area;
|
||||
}
|
||||
if(ghostResult.ramp)
|
||||
{
|
||||
grRamp = ghostResult.ramp;
|
||||
}
|
||||
if(ghostResult.path)
|
||||
{
|
||||
grPath = ghostResult.path;
|
||||
}
|
||||
|
||||
data = {
|
||||
carId: Number(ghostResult.car.carId),
|
||||
area: grArea,
|
||||
ramp: grRamp,
|
||||
path: grPath,
|
||||
trail: body.trail || undefined,
|
||||
time: Number(body.time) || undefined,
|
||||
driveData: body.driveData?.data || undefined,
|
||||
driveDMergeSerial: body.driveData?.mergeSerial || undefined,
|
||||
trendBinaryByArea: body.trendBinaryByArea?.data || undefined,
|
||||
byAreaMergeSerial: body.trendBinaryByArea?.mergeSerial || undefined,
|
||||
trendBinaryByCar: body.trendBinaryByCar?.data || undefined,
|
||||
byCarMergeSerial: body.trendBinaryByCar?.mergeSerial || undefined,
|
||||
trendBinaryByUser: body.trendBinaryByUser?.data || undefined,
|
||||
byUserMergeSerial: body.trendBinaryByUser?.mergeSerial || undefined,
|
||||
playedAt: ghostResult.car.lastPlayedAt || undefined,
|
||||
tunePower: ghostResult.car.tunePower || undefined,
|
||||
tuneHandling: ghostResult.car.tuneHandling || undefined,
|
||||
crownBattle: false,
|
||||
}
|
||||
|
||||
// Check Normal Ghost Battle Record if playing Crown Ghost Battle Mode
|
||||
let gtCount = await prisma.ghostTrail.findFirst({
|
||||
where:{
|
||||
carId: ghostResult.car.carId!,
|
||||
area: ghostResult.area!,
|
||||
path: ghostResult.path!,
|
||||
crownBattle: false,
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Record exist, update it
|
||||
if(gtCount)
|
||||
{
|
||||
console.log('Trail history found');
|
||||
console.log('Updating trail to the newest trail');
|
||||
|
||||
// Update the data
|
||||
let gdbId = gtCount.dbId;
|
||||
await prisma.ghostTrail.update({
|
||||
where: {
|
||||
dbId: gdbId
|
||||
},
|
||||
data: data
|
||||
});
|
||||
}
|
||||
// Record does not exist, create new
|
||||
else
|
||||
{
|
||||
console.log('No trail history');
|
||||
console.log('Creating new trail entry');
|
||||
|
||||
// Create new data
|
||||
await prisma.ghostTrail.create({
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save path and tuning result
|
||||
export async function savePathAndTuning(body: wm.protobuf.RegisterGhostTrailRequest)
|
||||
{
|
||||
console.log('Saving Car Path and Tuning');
|
||||
|
||||
// Get the ghost result for the car
|
||||
let ghostResult = body?.ghost;
|
||||
|
||||
// ghostResult is set
|
||||
if (ghostResult)
|
||||
{
|
||||
//Check Car Path and Tuning Record for certain area
|
||||
let cPaT_count = await prisma.carPathandTuning.findFirst({
|
||||
where:{
|
||||
carId: ghostResult.car.carId!,
|
||||
area: ghostResult.area!,
|
||||
path: ghostResult.path!,
|
||||
},
|
||||
orderBy: {
|
||||
lastPlayedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
// Record (Car Path and Tuning) exist, update it
|
||||
if(cPaT_count)
|
||||
{
|
||||
console.log('Updating path and tuning record');
|
||||
|
||||
await prisma.carPathandTuning.update({
|
||||
where: {
|
||||
dbId: cPaT_count.dbId
|
||||
},
|
||||
data:{
|
||||
carId: ghostResult.car.carId!,
|
||||
area: ghostResult.area!,
|
||||
ramp: ghostResult.ramp!,
|
||||
path: ghostResult.path!,
|
||||
tunePower: ghostResult.car.tunePower!,
|
||||
tuneHandling: ghostResult.car.tuneHandling!,
|
||||
lastPlayedAt: ghostResult.car.lastPlayedAt!
|
||||
}
|
||||
});
|
||||
}
|
||||
// Record (Car Path and Tuning) does not exist, create new
|
||||
else
|
||||
{
|
||||
console.log('Creating new path and tuning record');
|
||||
|
||||
await prisma.carPathandTuning.create({
|
||||
data: {
|
||||
carId: ghostResult.car.carId!,
|
||||
area: ghostResult.area!,
|
||||
ramp: ghostResult.ramp!,
|
||||
path: ghostResult.path!,
|
||||
tunePower: ghostResult.car.tunePower!,
|
||||
tuneHandling: ghostResult.car.tuneHandling!,
|
||||
lastPlayedAt: ghostResult.car.lastPlayedAt!
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
309
src/util/games/ghost_trail.ts
Normal file
309
src/util/games/ghost_trail.ts
Normal file
@ -0,0 +1,309 @@
|
||||
import { prisma } from "../..";
|
||||
import { OCMTop1GhostTrail } from "@prisma/client";
|
||||
|
||||
// Import Proto
|
||||
import * as ghost_ocm_area from "../games/games_util/ghost_ocm_area";
|
||||
|
||||
|
||||
// Save ghost battle result
|
||||
export async function getOCMGhostTrail(carId: number, trailId: number)
|
||||
{
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get current / previous active OCM Event
|
||||
let ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
// qualifyingPeriodStartAt is less than current date
|
||||
qualifyingPeriodStartAt: { lte: date },
|
||||
|
||||
// qualifyingPeriodCloseAt is greater than current date
|
||||
qualifyingPeriodCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionStartAt is less than current date
|
||||
competitionStartAt: { lte: date },
|
||||
|
||||
// competitionCloseAt is greater than current date
|
||||
competitionCloseAt: { gte: date },
|
||||
},
|
||||
{
|
||||
// competitionCloseAt is less than current date
|
||||
competitionCloseAt: { lte: date },
|
||||
|
||||
// competitionEndAt is greater than current date
|
||||
competitionEndAt: {gte: date },
|
||||
}
|
||||
],
|
||||
},
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'desc'
|
||||
},
|
||||
{
|
||||
competitionEndAt: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if(!(ocmEventDate))
|
||||
{
|
||||
ocmEventDate = await prisma.oCMEvent.findFirst({
|
||||
orderBy: [
|
||||
{
|
||||
dbId: 'desc'
|
||||
},
|
||||
{
|
||||
competitionEndAt: 'desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
let ghost_trails: OCMTop1GhostTrail | null;
|
||||
// Current date is OCM main draw
|
||||
if(ocmEventDate!.competitionStartAt < date && ocmEventDate!.competitionCloseAt > date)
|
||||
{
|
||||
// Get Current OCM Period
|
||||
let OCMCurrentPeriod = await prisma.oCMPeriod.findFirst({
|
||||
where: {
|
||||
competitionDbId: ocmEventDate!.dbId,
|
||||
startAt:
|
||||
{
|
||||
lte: date, // competitionStartAt is less than current date
|
||||
},
|
||||
closeAt:
|
||||
{
|
||||
gte: date, // competitionCloseAt is greater than current date
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ghost_trails = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where: {
|
||||
carId: carId,
|
||||
dbId: trailId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: OCMCurrentPeriod!.periodId
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
}
|
||||
// Current date is OCM qualifying day
|
||||
else if(ocmEventDate!.qualifyingPeriodStartAt < date && ocmEventDate!.qualifyingPeriodCloseAt > date)
|
||||
{
|
||||
ghost_trails = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where: {
|
||||
carId: carId,
|
||||
dbId: trailId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 0
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ghost_trails = await prisma.oCMTop1GhostTrail.findFirst({
|
||||
where: {
|
||||
carId: carId,
|
||||
dbId: trailId,
|
||||
competitionId: ocmEventDate!.competitionId,
|
||||
periodId: 999999999
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let areaVal = 0;
|
||||
let rampVal = 0;
|
||||
let pathVal = 0;
|
||||
let playedAt = 0;
|
||||
let ghostTrail;
|
||||
|
||||
// Trails data for certain area is available
|
||||
if(ghost_trails)
|
||||
{
|
||||
console.log('OCM Ghost Trail found');
|
||||
|
||||
// Set to OCM starting ramp data
|
||||
areaVal = ghost_trails!.area;
|
||||
|
||||
// Set to OCM starting ramp data
|
||||
rampVal = ghost_trails!.ramp;
|
||||
|
||||
// Set to OCM starting path data
|
||||
pathVal = ghost_trails!.path;
|
||||
|
||||
// Set to OCM starting path data
|
||||
playedAt = ghost_trails!.playedAt;
|
||||
|
||||
// Set to OCM trail data
|
||||
ghostTrail = ghost_trails!.trail;
|
||||
}
|
||||
// Trails data for certain area is not available
|
||||
else
|
||||
{
|
||||
console.log('OCM Ghost Trail not found');
|
||||
|
||||
// Calling OCM Area function (BASE_PATH/src/util/games/ghost_ocm.ts)
|
||||
let OCMArea = await ghost_ocm_area.OCMArea(ocmEventDate!.competitionId);
|
||||
|
||||
// Set the value from OCMArea
|
||||
areaVal = OCMArea.areaVal;
|
||||
rampVal = OCMArea.rampVal;
|
||||
pathVal = OCMArea.pathVal;
|
||||
|
||||
// Random value lmao, for default ghost trail stuff (any value maybe works)
|
||||
playedAt = date
|
||||
ghostTrail = new Uint8Array([1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
return { areaVal, rampVal, pathVal, playedAt, ghostTrail }
|
||||
}
|
||||
|
||||
|
||||
export async function getCrownGhostTrail(carId: number, areaId: number)
|
||||
{
|
||||
// Get current date
|
||||
let date = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// Get the trail data for certain area
|
||||
let ghost_trails = await prisma.ghostTrail.findFirst({
|
||||
where: {
|
||||
carId: carId,
|
||||
area: areaId,
|
||||
crownBattle: true,
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
}
|
||||
});
|
||||
|
||||
let rampVal = 0;
|
||||
let pathVal = 0;
|
||||
let playedAt = 0;
|
||||
let ghostTrail: Uint8Array;
|
||||
|
||||
// Trails data for certain area is available
|
||||
if(ghost_trails)
|
||||
{
|
||||
console.log('Crown Ghost Trail found');
|
||||
|
||||
// Set to crown holder starting ramp data
|
||||
rampVal = ghost_trails!.ramp;
|
||||
|
||||
// Set to crown holder starting path data
|
||||
pathVal = ghost_trails!.path;
|
||||
|
||||
let time = await prisma.carCrown.findFirst({
|
||||
where: {
|
||||
carId: carId,
|
||||
area: areaId
|
||||
},
|
||||
orderBy: {
|
||||
playedAt: 'desc'
|
||||
},
|
||||
select: {
|
||||
playedAt: true
|
||||
}
|
||||
});
|
||||
|
||||
// Error handling if played At timestamp value is current date and timestamp is bigger than 9 July 2022 (using GMT+7 timestamp)
|
||||
if(time!.playedAt !== 0 && time!.playedAt >= 1657299600)
|
||||
{
|
||||
// Acquired crown timestamp - 1 day
|
||||
playedAt = time!.playedAt - 172800;
|
||||
}
|
||||
// Error handling if played At timestamp value is 0 or timestamp is less than 9 July 2022 (using GMT+7 timestamp)
|
||||
else if(time!.playedAt === 0 || time!.playedAt < 1657299600)
|
||||
{
|
||||
// Acquired crown timestamp become 9 July 2022 (using GMT+7 timestamp)
|
||||
playedAt = 1657299600;
|
||||
}
|
||||
|
||||
// Set to crown holder trails data
|
||||
ghostTrail = ghost_trails!.trail;
|
||||
}
|
||||
// Trails data for certain area is not available
|
||||
else
|
||||
{
|
||||
console.log('Crown Ghost Trail not found');
|
||||
|
||||
if(areaId === 0){ // GID_RUNAREA_C1
|
||||
rampVal = Math.floor(Math.random() * 4);
|
||||
pathVal = Math.floor(Math.random() * 10);
|
||||
}
|
||||
else if(areaId === 1){ // GID_RUNAREA_RING
|
||||
rampVal = Math.floor(Math.random() * 2) + 4;
|
||||
pathVal = Math.floor(Math.random() * 6) + 10;
|
||||
}
|
||||
else if(areaId === 2){ // GID_RUNAREA_SUBTOKYO_3_4
|
||||
rampVal = Math.floor(Math.random() * 2) + 6;
|
||||
pathVal = Math.floor(Math.random() * 2) + 16;
|
||||
}
|
||||
else if(areaId === 3){ // GID_RUNAREA_SUBTOKYO_5
|
||||
rampVal = Math.floor(Math.random() * 2) + 8;
|
||||
pathVal = Math.floor(Math.random() * 2) + 18;
|
||||
}
|
||||
else if(areaId === 4){ // GID_RUNAREA_WANGAN
|
||||
rampVal = Math.floor(Math.random() * 4) + 10;
|
||||
pathVal = Math.floor(Math.random() * 7) + 20;
|
||||
}
|
||||
else if(areaId === 5){ // GID_RUNAREA_K1
|
||||
rampVal = Math.floor(Math.random() * 4) + 14;
|
||||
pathVal = Math.floor(Math.random() * 7) + 27;
|
||||
}
|
||||
else if(areaId === 6){ // GID_RUNAREA_YAESU
|
||||
rampVal = Math.floor(Math.random() * 3) + 18;
|
||||
pathVal = Math.floor(Math.random() * 4) + 34;
|
||||
}
|
||||
else if(areaId === 7){ // GID_RUNAREA_YOKOHAMA
|
||||
rampVal = Math.floor(Math.random() * 4) + 21;
|
||||
pathVal = Math.floor(Math.random() * 11) + 38;
|
||||
}
|
||||
else if(areaId === 8){ // GID_RUNAREA_NAGOYA
|
||||
rampVal = 25;
|
||||
pathVal = 49;
|
||||
}
|
||||
else if(areaId === 9){ // GID_RUNAREA_OSAKA
|
||||
rampVal = 26;
|
||||
pathVal = Math.floor(Math.random() * 4) + 50;
|
||||
}
|
||||
else if(areaId === 10){ // GID_RUNAREA_KOBE
|
||||
rampVal = 28;
|
||||
pathVal = 55;
|
||||
}
|
||||
else if(areaId === 11){ // GID_RUNAREA_FUKUOKA
|
||||
rampVal = Math.floor(Math.random() * 4) + 29;
|
||||
pathVal = Math.floor(Math.random() * 4) + 58;
|
||||
}
|
||||
else if(areaId === 12){ // GID_RUNAREA_HAKONE
|
||||
rampVal = Math.floor(Math.random() * 2) + 33;
|
||||
pathVal = Math.floor(Math.random() * 2) + 62;
|
||||
}
|
||||
else if(areaId === 13){ // GID_RUNAREA_TURNPIKE
|
||||
rampVal = Math.floor(Math.random() * 2) + 35;
|
||||
pathVal = Math.floor(Math.random() * 2) + 64;
|
||||
}
|
||||
//14 - 16 are dummy area, 17 is GID_RUNAREA_C1_CLOSED
|
||||
else if(areaId === 18){ // GID_RUNAREA_HIROSHIMA
|
||||
rampVal = Math.floor(Math.random() * 2) + 37;
|
||||
pathVal = Math.floor(Math.random() * 2) + 56;
|
||||
}
|
||||
|
||||
// Random value lmao, for default ghost trail stuff (any value maybe works)
|
||||
playedAt = date
|
||||
ghostTrail = new Uint8Array([1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
return { areaId, rampVal, pathVal, playedAt, ghostTrail }
|
||||
}
|
85
src/util/games/story.ts
Normal file
85
src/util/games/story.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import Long from "long";
|
||||
import { prisma } from "../..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../../wmmt/wm.proto";
|
||||
|
||||
// Import Util
|
||||
import * as common from "../common";
|
||||
import * as check_step from "../games/games_util/check_step";
|
||||
|
||||
|
||||
// Save story result
|
||||
export async function saveStoryResult(body: wm.protobuf.SaveGameResultRequest, car: any)
|
||||
{
|
||||
// If the game was not retired / timed out
|
||||
if (!(body.retired || body.timeup))
|
||||
{
|
||||
// Get the story result for the car
|
||||
let storyResult = body?.stResult;
|
||||
|
||||
// storyResult is set
|
||||
if (storyResult)
|
||||
{
|
||||
// Check if stClearDivCount is not 0
|
||||
let stClearDivCount = undefined;
|
||||
if(storyResult.stClearDivCount && storyResult.stClearDivCount !== 0)
|
||||
{
|
||||
stClearDivCount = storyResult.stClearDivCount
|
||||
}
|
||||
|
||||
// Check if stClearCount is not 0
|
||||
let stClearCount = undefined;
|
||||
if(storyResult.stClearCount && storyResult.stClearCount !== 0)
|
||||
{
|
||||
stClearCount = storyResult.stClearCount
|
||||
}
|
||||
|
||||
// Story update data
|
||||
let data : any = {
|
||||
stClearDivCount: stClearDivCount || undefined,
|
||||
stPlayCount: storyResult.stPlayCount || undefined,
|
||||
stClearCount: stClearCount || undefined,
|
||||
stClearBits: storyResult.stClearBits || undefined,
|
||||
stConsecutiveWins: storyResult.stConsecutiveWins || undefined,
|
||||
tuningPoints: storyResult.tuningPoint || 0,
|
||||
stCompleted100Episodes: storyResult.stCompleted_100Episodes || undefined,
|
||||
}
|
||||
|
||||
// If the current consecutive wins is greater than the previous max
|
||||
if (body.stResult!.stConsecutiveWins! > car!.stConsecutiveWinsMax)
|
||||
{
|
||||
// Update the maximum consecutive wins;
|
||||
data.stConsecutiveWinsMax = body.stResult!.stConsecutiveWins!;
|
||||
}
|
||||
|
||||
// If the lose bits are set, and are long data
|
||||
if (Long.isLong(storyResult.stLoseBits))
|
||||
{
|
||||
// Convert them to BigInt and add to the data
|
||||
data.stLoseBits = common.getBigIntFromLong(storyResult.stLoseBits);
|
||||
|
||||
// If a loss has been recorded
|
||||
if (data.stLoseBits > 0)
|
||||
{
|
||||
// End the win streak
|
||||
data.stConsecutiveWins = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Calling give meter reward function (BASE_PATH/src/util/meter_reward.ts)
|
||||
let check_steps = await check_step.checkCurrentStep(body);
|
||||
|
||||
// Set the ghost level to the correct level
|
||||
data.ghostLevel = check_steps.ghostLevel;
|
||||
|
||||
// Update the car properties
|
||||
await prisma.car.update({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
72
src/util/games/time_attack.ts
Normal file
72
src/util/games/time_attack.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { prisma } from "../..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save time attack result
|
||||
export async function saveTimeAttackResult(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
// If the game was not retired / timed out
|
||||
if (!(body.retired || body.timeup)) {
|
||||
console.log('Game not retired / timed out, continuing ...')
|
||||
|
||||
// Get the current time attack record for the car
|
||||
let currentRecord = await prisma.timeAttackRecord.findFirst({
|
||||
where: {
|
||||
carId: body.carId, // , model: body.car!.model!,
|
||||
course: body.taResult!.course
|
||||
}
|
||||
});
|
||||
|
||||
// Record already exists
|
||||
if (currentRecord)
|
||||
{
|
||||
// If the existing record is faster, do not continue
|
||||
if (body.taResult!.time < currentRecord.time){
|
||||
console.log('Updating time attack record...')
|
||||
await prisma.timeAttackRecord.update({
|
||||
where: {
|
||||
// Could be null - if it is null, this will insert.
|
||||
dbId: currentRecord!.dbId
|
||||
},
|
||||
data: {
|
||||
time: body.taResult!.time,
|
||||
section1Time: body!.taResult!.section_1Time,
|
||||
section2Time: body!.taResult!.section_2Time,
|
||||
section3Time: body!.taResult!.section_3Time,
|
||||
section4Time: body!.taResult!.section_4Time,
|
||||
section5Time: body!.taResult!.section_5Time,
|
||||
section6Time: body!.taResult!.section_6Time,
|
||||
section7Time: body!.taResult!.section_7Time,
|
||||
tunePower: body!.car!.tunePower,
|
||||
tuneHandling: body!.car!.tuneHandling
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else // Creating a new record
|
||||
{
|
||||
console.log('Creating new time attack record');
|
||||
|
||||
await prisma.timeAttackRecord.create({
|
||||
data: {
|
||||
carId: body.carId,
|
||||
model: body.car!.model!,
|
||||
time: body.taResult!.time,
|
||||
isMorning: body.taResult!.isMorning,
|
||||
course: body.taResult!.course,
|
||||
section1Time: body!.taResult!.section_1Time,
|
||||
section2Time: body!.taResult!.section_2Time,
|
||||
section3Time: body!.taResult!.section_3Time,
|
||||
section4Time: body!.taResult!.section_4Time,
|
||||
section5Time: body!.taResult!.section_5Time,
|
||||
section6Time: body!.taResult!.section_6Time,
|
||||
section7Time: body!.taResult!.section_7Time,
|
||||
tunePower: body!.car!.tunePower,
|
||||
tuneHandling: body!.car!.tuneHandling
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
63
src/util/games/versus.ts
Normal file
63
src/util/games/versus.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { prisma } from "../..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save versus battle result
|
||||
export async function saveVersusBattleResult(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
if (!(body.retired || body.timeup))
|
||||
{
|
||||
// Get the vs result for the car
|
||||
let vsResult = body?.vsResult;
|
||||
|
||||
// storyResult is set
|
||||
if (vsResult)
|
||||
{
|
||||
// Check if vsTripleStarMedals is not 0
|
||||
let vsTripleStarMedals = undefined;
|
||||
if(vsResult.vsTripleStarMedals && vsResult.vsTripleStarMedals !== 0){
|
||||
vsTripleStarMedals = vsResult.vsTripleStarMedals!;
|
||||
}
|
||||
|
||||
// Check if vsDoubleStarMedals is not 0
|
||||
let vsDoubleStarMedals = undefined;
|
||||
if(vsResult.vsDoubleStarMedals && vsResult.vsDoubleStarMedals !== 0){
|
||||
vsDoubleStarMedals = vsResult.vsDoubleStarMedals!;
|
||||
}
|
||||
|
||||
// Check if vsSingleStarMedals is not 0
|
||||
let vsSingleStarMedals = undefined;
|
||||
if(vsResult.vsSingleStarMedals && vsResult.vsSingleStarMedals !== 0){
|
||||
vsSingleStarMedals = vsResult.vsSingleStarMedals!;
|
||||
}
|
||||
|
||||
// Check if vsPlainMedals is not 0
|
||||
let vsPlainMedals = undefined;
|
||||
if(vsResult.vsPlainMedals && vsResult.vsPlainMedals !== 0){
|
||||
vsPlainMedals = vsResult.vsPlainMedals!;
|
||||
}
|
||||
|
||||
// vs result update data
|
||||
let data : any = {
|
||||
vsPlayCount: vsResult.vsPlayCount || undefined,
|
||||
vsBurstCount: vsResult.vsBurstCount || undefined,
|
||||
vsStarCount: vsResult.vsStarCount || undefined,
|
||||
vsCoolOrWild: vsResult.vsCoolOrWild || undefined,
|
||||
vsSmoothOrRough: vsResult.vsSmoothOrRough || undefined,
|
||||
vsTripleStarMedals: vsTripleStarMedals || undefined,
|
||||
vsDoubleStarMedals: vsDoubleStarMedals || undefined,
|
||||
vsSingleStarMedals: vsSingleStarMedals || undefined,
|
||||
vsPlainMedals: vsPlainMedals || undefined,
|
||||
}
|
||||
|
||||
await prisma.car.update({
|
||||
where: {
|
||||
carId: body.carId
|
||||
},
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
112
src/util/meter_reward.ts
Normal file
112
src/util/meter_reward.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { prisma } from "..";
|
||||
|
||||
// Import Proto
|
||||
import { wm } from "../wmmt/wm.proto";
|
||||
|
||||
|
||||
// Save story result
|
||||
export async function giveMeterRewards(body: wm.protobuf.SaveGameResultRequest)
|
||||
{
|
||||
// Get user's available meter data
|
||||
let carItemCount = await prisma.carItem.count({
|
||||
where: {
|
||||
carId: body.carId,
|
||||
category: 15,
|
||||
itemId: {
|
||||
lte: 34,
|
||||
gte: 1,
|
||||
},
|
||||
NOT: {
|
||||
itemId: { in: [2, 3, 5, 6, 29, 30, 31, 32, 33 ,34] }, // Except story meter
|
||||
},
|
||||
},
|
||||
/*where: {
|
||||
itemId: { notIn: [2, 3, 5, 6, 29, 30, 31, 32, 33 ,34] },
|
||||
},*/
|
||||
})
|
||||
let itemIdVal = 0;
|
||||
if(carItemCount === 0){
|
||||
itemIdVal = 1; // Namco Meter
|
||||
}
|
||||
else if(carItemCount === 1){
|
||||
itemIdVal = 4; // Special Meter
|
||||
}
|
||||
else if(carItemCount === 2){
|
||||
itemIdVal = 7; // Metal 1 (Black)
|
||||
}
|
||||
else if(carItemCount === 3){
|
||||
itemIdVal = 8; // Metal 2 (Red)
|
||||
}
|
||||
else if(carItemCount === 4){
|
||||
itemIdVal = 9; // Cyber 1 (Blue)
|
||||
}
|
||||
else if(carItemCount === 5){
|
||||
itemIdVal = 10; // Cyber 2 (Red)
|
||||
}
|
||||
else if(carItemCount === 6){
|
||||
itemIdVal = 11; // Aluminium 1 (Blue)
|
||||
}
|
||||
else if(carItemCount === 7){
|
||||
itemIdVal = 12; // Aluminium 1 (Red)
|
||||
}
|
||||
else if(carItemCount === 8){
|
||||
itemIdVal = 13; // Jungle 1 (Green)
|
||||
}
|
||||
else if(carItemCount === 9){
|
||||
itemIdVal = 14; // Jungle 2 (Brown)
|
||||
}
|
||||
else if(carItemCount === 10){
|
||||
itemIdVal = 15; // Dessert 1 (Red)
|
||||
}
|
||||
else if(carItemCount === 11){
|
||||
itemIdVal = 16; // Dessert 2 (Brown)
|
||||
}
|
||||
else if(carItemCount === 12){
|
||||
itemIdVal = 17; // Pirate 1 (Red)
|
||||
}
|
||||
else if(carItemCount === 13){
|
||||
itemIdVal = 18; // Pirate 2 (Blue)
|
||||
}
|
||||
else if(carItemCount === 14){
|
||||
itemIdVal = 19; // Fire Pattern 1 (Red)
|
||||
}
|
||||
else if(carItemCount === 15){
|
||||
itemIdVal = 20; // Fire Pattern 2 (Blue)
|
||||
}
|
||||
else if(carItemCount === 16){
|
||||
itemIdVal = 21; // Silver Access
|
||||
}
|
||||
else if(carItemCount === 17){
|
||||
itemIdVal = 22; // Gold Access
|
||||
}
|
||||
else if(carItemCount === 18){
|
||||
itemIdVal = 23; // Steampunk 1 (Gold)
|
||||
}
|
||||
else if(carItemCount === 19){
|
||||
itemIdVal = 24; // Steampunk 2 (Green)
|
||||
}
|
||||
else if(carItemCount === 20){
|
||||
itemIdVal = 25; // Dragon 1 (Gold)
|
||||
}
|
||||
else if(carItemCount === 21){
|
||||
itemIdVal = 26; // Dragon 2 (Blue)
|
||||
}
|
||||
else if(carItemCount === 22){
|
||||
itemIdVal = 27; // Light Line 1 (Blue)
|
||||
}
|
||||
else if(carItemCount === 23){
|
||||
itemIdVal = 28; // Light Line 2 (Orange)
|
||||
}
|
||||
|
||||
if(itemIdVal !== 0){
|
||||
console.log(`carID ${body.carId} do n*100 play, continue give reward... meter ID ${itemIdVal}`);
|
||||
await prisma.carItem.create({
|
||||
data: {
|
||||
carId: body.carId,
|
||||
category: 15,
|
||||
itemId: itemIdVal,
|
||||
amount: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { isRateLimited } from "@sentry/utils";
|
||||
import { prisma } from "..";
|
||||
import { Config } from "../config";
|
||||
|
||||
//Import Proto
|
||||
import * as wm from "../wmmt/wm.proto";
|
||||
|
||||
// *** CONSTANTS ***
|
||||
|
Loading…
Reference in New Issue
Block a user